diff options
author | Karel Zak | 2006-12-07 00:25:34 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:34 +0100 |
commit | fd6b7a7ffc50400704beb41d5a23af5f9edb1eed (patch) | |
tree | 997c0ca2abc018369babd7da59bcd0afe492068e /login-utils/login.c | |
parent | Imported from util-linux-2.5 tarball. (diff) | |
download | kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.gz kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.xz kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.zip |
Imported from util-linux-2.7.1 tarball.
Diffstat (limited to 'login-utils/login.c')
-rw-r--r-- | login-utils/login.c | 1679 |
1 files changed, 981 insertions, 698 deletions
diff --git a/login-utils/login.c b/login-utils/login.c index 33a0b03e7..c1626183e 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -1,57 +1,58 @@ /* This program is derived from 4.3 BSD software and is subject to the copyright notice below. - + The port to HP-UX has been motivated by the incapability of 'rlogin'/'rlogind' as per HP-UX 6.5 (and 7.0) to transfer window sizes. - + Changes: - + - General HP-UX portation. Use of facilities not available in HP-UX (e.g. setpriority) has been eliminated. Utmp/wtmp handling has been ported. - + - The program uses BSD command line options to be used in connection with e.g. 'rlogind' i.e. 'new login'. - + - HP features left out: logging of bad login attempts in /etc/btmp, - they are sent to syslog - + they are sent to syslog + password expiry - + '*' as login shell, add it if you need it - BSD features left out: quota checks - password expiry + password expiry analysis of terminal type (tset feature) - + - BSD features thrown in: Security logging to syslogd. This requires you to have a (ported) syslog system -- 7.0 comes with syslog - + 'Lastlog' feature. - + - A lot of nitty gritty details has been adjusted in favour of HP-UX, e.g. /etc/securetty, default paths and the environment variables assigned by 'login'. - + - We do *nothing* to setup/alter tty state, under HP-UX this is to be done by getty/rlogind/telnetd/some one else. - + Michael Glad (glad@daimi.dk) Computer Science Department Aarhus University Denmark - + 1990-07-04 - + 1991-09-24 glad@daimi.aau.dk: HP-UX 8.0 port: - - now explictly sets non-blocking mode on descriptors - - strcasecmp is now part of HP-UX + - now explictly sets non-blocking mode on descriptors + - strcasecmp is now part of HP-UX + 1992-02-05 poe@daimi.aau.dk: Ported the stuff to Linux 0.12 - From 1992 till now (1995) this code for Linux has been maintained at + From 1992 till now (1997) this code for Linux has been maintained at ftp.daimi.aau.dk:/pub/linux/poe/ -*/ - + */ + /* * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. * All rights reserved. @@ -71,7 +72,7 @@ #ifndef lint char copyright[] = -"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ + "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ @@ -85,6 +86,8 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; * login -f name (for pre-authenticated login: datakit, xterm, etc.) */ +#define _GNU_SOURCE /* to get definition of snprintf */ + /* #define TESTING */ #ifdef TESTING @@ -93,10 +96,12 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #include <sys/param.h> #endif +#include <stdio.h> #include <ctype.h> #include <unistd.h> #include <getopt.h> #include <memory.h> +#include <time.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/resource.h> @@ -106,18 +111,24 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #define index strchr #define rindex strrchr #include <sys/ioctl.h> +#include <sys/wait.h> #include <signal.h> #include <errno.h> #include <grp.h> #include <pwd.h> +#include <utmp.h> #include <setjmp.h> #include <stdlib.h> -#include <stdio.h> #include <string.h> #include <sys/syslog.h> #include <sys/sysmacros.h> #include <netdb.h> +#ifdef __linux__ +# include <sys/sysmacros.h> +# include <linux/major.h> +#endif + #ifdef TESTING # include "utmp.h" #else @@ -125,21 +136,39 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #endif #ifdef SHADOW_PWD -#include <shadow.h> +# include <shadow.h> #endif -#ifndef linux -#include <tzfile.h> +#ifdef USE_PAM +# include <security/pam_appl.h> +# include <security/pam_misc.h> +# define PAM_MAX_LOGIN_TRIES 3 +# define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ + fprintf(stderr,"\n%s\n",pam_strerror(retcode)); \ + syslog(LOG_ERR,"%s",pam_strerror(retcode)); \ + pam_end(pamh, retcode); exit(1); \ + } +# define PAM_END { retcode = pam_close_session(pamh,0); \ + pam_end(pamh,retcode); } +# define PAM_END { \ + retcode = pam_close_session(pamh,0); pam_end(pamh,retcode); \ +} +#endif + +#ifndef __linux__ +# include <tzfile.h> #endif #include <lastlog.h> +#define SLEEP_EXIT_TIMEOUT 5 + #if 0 /* from before we had a lastlog.h file in linux */ struct lastlog - { long ll_time; - char ll_line[12]; - char ll_host[16]; - }; +{ long ll_time; + char ll_line[12]; + char ll_host[16]; +}; #endif #include "pathnames.h" @@ -153,11 +182,13 @@ void motd P_((void)); void sigint P_((void)); void checknologin P_((void)); void dolastlog P_((int quiet)); -void badlogin P_((char *name)); +void badlogin P_((const char *name)); char *stypeof P_((char *ttyid)); void checktty P_((char *user, char *tty, struct passwd *pwd)); -void getstr P_((char *buf, int cnt, char *err)); void sleepexit P_((int eval)); +#ifdef CRYPTOCARD +int cryptocard P_((void)); +#endif #undef P_ #ifdef KERBEROS @@ -167,6 +198,12 @@ char realm[REALM_SZ]; int kerror = KSUCCESS, notickets = 1; #endif +#ifdef USE_TTY_GROUP +# define TTY_MODE 0620 +#else +# define TTY_MODE 0600 +#endif + #define TTYGRPNAME "tty" /* name of group to own ttys */ /**# define TTYGRPNAME "other" **/ @@ -178,7 +215,7 @@ int kerror = KSUCCESS, notickets = 1; * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. */ -#ifndef linux +#ifndef __linux__ int timeout = 300; #else int timeout = 60; @@ -190,19 +227,19 @@ char term[64], *hostname, *username, *tty; struct hostent hostaddress; char thishost[100]; -#ifndef linux +#ifndef __linux__ struct sgttyb sgttyb; struct tchars tc = { - CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK -}; + CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK + }; struct ltchars ltc = { - CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT -}; + CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT + }; #endif -char *months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" }; +const char *months[] = +{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; /* provided by Linus Torvalds 16-Feb-93 */ void @@ -210,7 +247,7 @@ opentty(const char * tty) { int i; int fd = open(tty, O_RDWR); - + for (i = 0 ; i < fd ; i++) close(i); for (i = 0 ; i < 3 ; i++) @@ -219,657 +256,916 @@ opentty(const char * tty) close(fd); } +/* true if the filedescriptor fd is a console tty, very Linux specific */ +static int +consoletty(int fd) +{ +#ifdef __linux__ + struct stat stb; + + if ((fstat(fd, &stb) >= 0) + && (major(stb.st_rdev) == TTY_MAJOR) + && (minor(stb.st_rdev) < 64)) { + return 1; + } +#endif + return 0; +} + + int main(argc, argv) - int argc; - char **argv; + int argc; + char **argv; { - extern int errno, optind; - extern char *optarg, **environ; - struct timeval tp; - struct tm *ttp; - struct group *gr; - register int ch; - register char *p; - int ask, fflag, hflag, pflag, cnt; - int quietlog, passwd_req, ioctlval; - char *domain, *salt, *ttyn, *pp; - char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; - char *ctime(), *ttyname(), *stypeof(); - time_t time(); - void timedout(); - char *termenv; - -#ifdef linux - char tmp[100]; - /* Just as arbitrary as mountain time: */ - /* (void)setenv("TZ", "MET-1DST",0); */ + extern int errno, optind; + extern char *optarg, **environ; + struct group *gr; + register int ch; + register char *p; + int ask, fflag, hflag, pflag, cnt; + int quietlog, passwd_req, ioctlval; + char *domain, *salt, *ttyn, *pp; + char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; + char *ctime(), *ttyname(), *stypeof(); + time_t time(); + void timedout(); + char *termenv; + char vcsn[20], vcsan[20]; + char * childArgv[10]; + char * buff; + int childArgc = 0; + int error = 0; +#ifdef USE_PAM + int retcode; + pam_handle_t *pamh = NULL; + struct pam_conv conv = { misc_conv, NULL }; + pid_t childPid; + int childStatus; + void * oldSigHandler; #endif - (void)signal(SIGALRM, timedout); - (void)alarm((unsigned int)timeout); - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)setpriority(PRIO_PROCESS, 0, 0); +#ifdef __linux__ + char tmp[100]; + /* Just as arbitrary as mountain time: */ + /* (void)setenv("TZ", "MET-1DST",0); */ +#endif + + signal(SIGALRM, timedout); + alarm((unsigned int)timeout); + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_IGN); + + setpriority(PRIO_PROCESS, 0, 0); #ifdef HAVE_QUOTA - (void)quota(Q_SETUID, 0, 0, 0); + quota(Q_SETUID, 0, 0, 0); #endif - - /* - * -p is used by getty to tell login not to destroy the environment - * -f is used to skip a second login authentication - * -h is used by other servers to pass the name of the remote - * host to login so that it may be placed in utmp and wtmp - */ - (void)gethostname(tbuf, sizeof(tbuf)); - (void)strncpy(thishost, tbuf, sizeof(thishost)-1); - domain = index(tbuf, '.'); - - hostname = NULL; - fflag = hflag = pflag = 0; - passwd_req = 1; - while ((ch = getopt(argc, argv, "fh:p")) != EOF) - switch (ch) { - case 'f': - fflag = 1; - break; - - case 'h': - if (getuid()) { - (void)fprintf(stderr, - "login: -h for super-user only.\n"); - exit(1); - } - hflag = 1; - if (domain && (p = index(optarg, '.')) && - strcasecmp(p, domain) == 0) - *p = 0; - hostname = optarg; - { - struct hostent *he = gethostbyname(hostname); - if (he) { - memcpy(&hostaddress, he, sizeof(hostaddress)); - } else { - memset(&hostaddress, 0, sizeof(hostaddress)); - } - } - break; - - case 'p': - pflag = 1; - break; - case '?': - default: - (void)fprintf(stderr, - "usage: login [-fp] [username]\n"); - exit(1); - } - argc -= optind; - argv += optind; - if (*argv) { - username = *argv; - ask = 0; - } else - ask = 1; - -#ifndef linux - ioctlval = 0; - (void)ioctl(0, TIOCLSET, &ioctlval); - (void)ioctl(0, TIOCNXCL, 0); - (void)fcntl(0, F_SETFL, ioctlval); - (void)ioctl(0, TIOCGETP, &sgttyb); - sgttyb.sg_erase = CERASE; - sgttyb.sg_kill = CKILL; - (void)ioctl(0, TIOCSLTC, <c); - (void)ioctl(0, TIOCSETC, &tc); - (void)ioctl(0, TIOCSETP, &sgttyb); - - /* - * Be sure that we're in - * blocking mode!!! - * This is really for HPUX - */ - ioctlval = 0; - (void)ioctl(0, FIOSNBIO, &ioctlval); + + /* + * -p is used by getty to tell login not to destroy the environment + * -f is used to skip a second login authentication + * -h is used by other servers to pass the name of the remote + * host to login so that it may be placed in utmp and wtmp + */ + gethostname(tbuf, sizeof(tbuf)); + strncpy(thishost, tbuf, sizeof(thishost)-1); + thishost[sizeof(thishost)-1] = 0; + domain = index(tbuf, '.'); + + username = tty = hostname = NULL; + fflag = hflag = pflag = 0; + passwd_req = 1; + while ((ch = getopt(argc, argv, "fh:p")) != EOF) + switch (ch) { + case 'f': + fflag = 1; + break; + + case 'h': + if (getuid()) { + fprintf(stderr, + "login: -h for super-user only.\n"); + exit(1); + } + hflag = 1; + if (domain && (p = index(optarg, '.')) && + strcasecmp(p, domain) == 0) + *p = 0; + hostname = optarg; + { + struct hostent *he = gethostbyname(hostname); + if (he) { + memcpy(&hostaddress, he, sizeof(hostaddress)); + } else { + memset(&hostaddress, 0, sizeof(hostaddress)); + } + } + break; + + case 'p': + pflag = 1; + break; + + case '?': + default: + fprintf(stderr, + "usage: login [-fp] [username]\n"); + exit(1); + } + argc -= optind; + argv += optind; + if (*argv) { + username = *argv; + ask = 0; + } else + ask = 1; + +#ifndef __linux__ + ioctlval = 0; + ioctl(0, TIOCLSET, &ioctlval); + ioctl(0, TIOCNXCL, 0); + fcntl(0, F_SETFL, ioctlval); + ioctl(0, TIOCGETP, &sgttyb); + sgttyb.sg_erase = CERASE; + sgttyb.sg_kill = CKILL; + ioctl(0, TIOCSLTC, <c); + ioctl(0, TIOCSETC, &tc); + ioctl(0, TIOCSETP, &sgttyb); + + /* + * Be sure that we're in + * blocking mode!!! + * This is really for HPUX + */ + ioctlval = 0; + ioctl(0, FIOSNBIO, &ioctlval); #endif - - for (cnt = getdtablesize(); cnt > 2; cnt--) - close(cnt); - - ttyn = ttyname(0); - if (ttyn == NULL || *ttyn == '\0') { - (void)sprintf(tname, "%s??", _PATH_TTY); - ttyn = tname; + + for (cnt = getdtablesize(); cnt > 2; cnt--) + close(cnt); + + ttyn = ttyname(0); + if (ttyn == NULL || *ttyn == '\0') { + snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); + ttyn = tname; + } + + /* find names of Virtual Console devices, for later mode change */ + { + char *p = ttyn; + /* find number of tty */ + while (*p && !isdigit(*p)) p++; + + strcpy(vcsn, "/dev/vcs"); strcat(vcsn, p); + strcpy(vcsan, "/dev/vcsa"); strcat(vcsan, p); + } + + setpgrp(); + + { + struct termios tt, ttt; + + tcgetattr(0, &tt); + ttt = tt; + ttt.c_cflag &= ~HUPCL; + + if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) { + tcsetattr(0,TCSAFLUSH,&ttt); + signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */ + vhangup(); + signal(SIGHUP, SIG_DFL); } + + setsid(); + + /* re-open stdin,stdout,stderr after vhangup() closed them */ + /* if it did, after 0.99.5 it doesn't! */ + opentty(ttyn); + tcsetattr(0,TCSAFLUSH,&tt); + } + + if ((tty = rindex(ttyn, '/'))) + ++tty; + else + tty = ttyn; + + openlog("login", LOG_ODELAY, LOG_AUTHPRIV); + +#ifdef USE_PAM + /* username is initialized to NULL + and if specified on the command line it is set. + Therefore, we are safe not setting it to anything + */ + + retcode = pam_start("login",username, &conv, &pamh); + if(retcode != PAM_SUCCESS) { + fprintf(stderr,"login: PAM Failure, aborting: %s\n", + pam_strerror(retcode)); + syslog(LOG_ERR,"Couldn't initialize PAM: %s", pam_strerror(retcode)); + exit(99); + } + /* hostname & tty are either set to NULL or their correct values, + depending on how much we know */ + retcode = pam_set_item(pamh, PAM_RHOST, hostname); + PAM_FAIL_CHECK; + retcode = pam_set_item(pamh, PAM_TTY, tty); + PAM_FAIL_CHECK; + /* if fflag == 1, then the user has already been authenticated */ + if (fflag && (getuid() == 0)) + passwd_req = 0; + else + passwd_req = 1; - setpgrp(); - - { - struct termios tt, ttt; - - tcgetattr(0, &tt); - ttt = tt; - ttt.c_cflag &= ~HUPCL; - - if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) { - tcsetattr(0,TCSAFLUSH,&ttt); - signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */ - vhangup(); - signal(SIGHUP, SIG_DFL); - } - - setsid(); - - /* re-open stdin,stdout,stderr after vhangup() closed them */ - /* if it did, after 0.99.5 it doesn't! */ - opentty(ttyn); - tcsetattr(0,TCSAFLUSH,&tt); + if(passwd_req == 1) { + int failcount=0; + + /* there may be better ways to deal with some of these + conditions, but at least this way I don't think we'll + be giving away information... */ + /* Perhaps someday we can trust that all PAM modules will + pay attention to failure count and get rid of MAX_LOGIN_TRIES? */ + + retcode = pam_authenticate(pamh, 0); + while((failcount++ < PAM_MAX_LOGIN_TRIES) && + ((retcode == PAM_AUTH_ERR) || + (retcode == PAM_USER_UNKNOWN) || + (retcode == PAM_CRED_INSUFFICIENT) || + (retcode == PAM_AUTHINFO_UNAVAIL))) { + pam_get_item(pamh, PAM_USER, (const void **) &username); + syslog(LOG_NOTICE,"FAILED LOGIN %d FROM %s FOR %s, %s", + failcount, hostname,username,pam_strerror(retcode)); + fprintf(stderr,"Login incorrect\n\n"); + pam_set_item(pamh,PAM_USER,NULL); + retcode = pam_authenticate(pamh, 0); } - if ((tty = rindex(ttyn, '/'))) - ++tty; - else - tty = ttyn; - - openlog("login", LOG_ODELAY, LOG_AUTH); - - for (cnt = 0;; ask = 1) { - ioctlval = 0; -#ifndef linux - (void)ioctl(0, TIOCSETD, &ioctlval); -#endif + if (retcode != PAM_SUCCESS) { + pam_get_item(pamh, PAM_USER, (const void **) &username); - if (ask) { - fflag = 0; - getloginname(); - } - - /* Dirty patch to fix a gigantic security hole when using - yellow pages. This problem should be solved by the - libraries, and not by programs, but this must be fixed - urgently! If the first char of the username is '+', we - avoid login success. - Feb 95 <alvaro@etsit.upm.es> */ - - if (username[0] == '+') { - puts("Illegal username"); - badlogin(username); - sleepexit(1); - } + if (retcode == PAM_MAXTRIES) + syslog(LOG_NOTICE,"TOO MANY LOGIN TRIES (%d) FROM %s FOR " + "%s, %s", failcount, hostname, username, + pam_strerror(retcode)); + else + syslog(LOG_NOTICE,"FAILED LOGIN SESSION FROM %s FOR %s, %s", + hostname, username, pam_strerror(retcode)); - (void)strcpy(tbuf, username); - if ((pwd = getpwnam(username))) - salt = pwd->pw_passwd; - else - salt = "xx"; - - checktty(username, tty, pwd); /* in checktty.c */ + fprintf(stderr,"\nLogin incorrect\n"); + pam_end(pamh, retcode); + exit(0); + } - /* if user not super-user, check for disabled logins */ - if (pwd == NULL || pwd->pw_uid) - checknologin(); + retcode = pam_acct_mgmt(pamh, 0); - /* - * Disallow automatic login to root; if not invoked by - * root, disallow if the uid's differ. - */ - if (fflag && pwd) { - int uid = getuid(); + if(retcode == PAM_AUTHTOKEN_REQD) { + retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + } - passwd_req = pwd->pw_uid == 0 || - (uid && uid != pwd->pw_uid); - } + PAM_FAIL_CHECK; + } - /* - * If trying to log in as root, but with insecure terminal, - * refuse the login attempt. - */ - if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) { - (void)fprintf(stderr, - "%s login refused on this terminal.\n", - pwd->pw_name); - - if (hostname) - syslog(LOG_NOTICE, - "LOGIN %s REFUSED FROM %s ON TTY %s", - pwd->pw_name, hostname, tty); - else - syslog(LOG_NOTICE, - "LOGIN %s REFUSED ON TTY %s", - pwd->pw_name, tty); - continue; - } + /* Grab the user information out of the password file for future usage + First get the username that we are actually using, though. + */ + retcode = pam_get_item(pamh, PAM_USER, (const void **) &username); + setpwent(); + pwd = getpwnam(username); + if (pwd) initgroups(username, pwd->pw_gid); - /* - * If no pre-authentication and a password exists - * for this user, prompt for one and verify it. - */ - if (!passwd_req || (pwd && !*pwd->pw_passwd)) - break; + retcode = pam_setcred(pamh, PAM_CRED_ESTABLISH); + PAM_FAIL_CHECK; - setpriority(PRIO_PROCESS, 0, -4); - pp = getpass("Password: "); - p = crypt(pp, salt); - setpriority(PRIO_PROCESS, 0, 0); + retcode = pam_open_session(pamh, 0); + PAM_FAIL_CHECK; -#ifdef KERBEROS +#else /* ! USE_PAM */ - /* - * If not present in pw file, act as we normally would. - * If we aren't Kerberos-authenticated, try the normal - * pw file for a password. If that's ok, log the user - * in without issueing any tickets. - */ - - if (pwd && !krb_get_lrealm(realm,1)) { - /* - * get TGT for local realm; be careful about uid's - * here for ticket file ownership - */ - (void)setreuid(geteuid(),pwd->pw_uid); - kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, - "krbtgt", realm, DEFAULT_TKT_LIFE, pp); - (void)setuid(0); - if (kerror == INTK_OK) { - memset(pp, 0, strlen(pp)); - notickets = 0; /* user got ticket */ - break; - } - } -#endif - (void) memset(pp, 0, strlen(pp)); - if (pwd && !strcmp(p, pwd->pw_passwd)) - break; - - (void)printf("Login incorrect\n"); - failures++; - badlogin(username); /* log ALL bad logins */ - - /* we allow 10 tries, but after 3 we start backing off */ - if (++cnt > 3) { - if (cnt >= 10) { - sleepexit(1); - } - sleep((unsigned int)((cnt - 3) * 5)); - } + for (cnt = 0;; ask = 1) { + ioctlval = 0; +# ifndef __linux__ + ioctl(0, TIOCSETD, &ioctlval); +# endif + + if (ask) { + fflag = 0; + getloginname(); } + + /* Dirty patch to fix a gigantic security hole when using + yellow pages. This problem should be solved by the + libraries, and not by programs, but this must be fixed + urgently! If the first char of the username is '+', we + avoid login success. + Feb 95 <alvaro@etsit.upm.es> */ + + if (username[0] == '+') { + puts("Illegal username"); + badlogin(username); + sleepexit(1); + } + + /* (void)strcpy(tbuf, username); why was this here? */ + if ((pwd = getpwnam(username))) { +# ifdef SHADOW_PWD + struct spwd *sp; + + if ((sp = getspnam(username))) + pwd->pw_passwd = sp->sp_pwdp; +# endif + salt = pwd->pw_passwd; + } else + salt = "xx"; + + if (pwd) { + initgroups(username, pwd->pw_gid); + checktty(username, tty, pwd); /* in checktty.c */ + } + + /* if user not super-user, check for disabled logins */ + if (pwd == NULL || pwd->pw_uid) + checknologin(); + + /* + * Disallow automatic login to root; if not invoked by + * root, disallow if the uid's differ. + */ + if (fflag && pwd) { + int uid = getuid(); + + passwd_req = pwd->pw_uid == 0 || + (uid && uid != pwd->pw_uid); + } + + /* + * If trying to log in as root, but with insecure terminal, + * refuse the login attempt. + */ + if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) { + fprintf(stderr, + "%s login refused on this terminal.\n", + pwd->pw_name); + + if (hostname) + syslog(LOG_NOTICE, + "LOGIN %s REFUSED FROM %s ON TTY %s", + pwd->pw_name, hostname, tty); + else + syslog(LOG_NOTICE, + "LOGIN %s REFUSED ON TTY %s", + pwd->pw_name, tty); + continue; + } + + /* + * If no pre-authentication and a password exists + * for this user, prompt for one and verify it. + */ + if (!passwd_req || (pwd && !*pwd->pw_passwd)) + break; + + setpriority(PRIO_PROCESS, 0, -4); + pp = getpass("Password: "); + +# ifdef CRYPTOCARD + if (strncmp(pp, "CRYPTO", 6) == 0) { + if (pwd && cryptocard()) break; + } +# endif /* CRYPTOCARD */ + + p = crypt(pp, salt); + setpriority(PRIO_PROCESS, 0, 0); - /* committed to login -- turn off timeout */ - (void)alarm((unsigned int)0); - +# ifdef KERBEROS + /* + * If not present in pw file, act as we normally would. + * If we aren't Kerberos-authenticated, try the normal + * pw file for a password. If that's ok, log the user + * in without issueing any tickets. + */ + + if (pwd && !krb_get_lrealm(realm,1)) { + /* + * get TGT for local realm; be careful about uid's + * here for ticket file ownership + */ + setreuid(geteuid(),pwd->pw_uid); + kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, + "krbtgt", realm, DEFAULT_TKT_LIFE, pp); + setuid(0); + if (kerror == INTK_OK) { + memset(pp, 0, strlen(pp)); + notickets = 0; /* user got ticket */ + break; + } + } +# endif /* KERBEROS */ + memset(pp, 0, strlen(pp)); + if (pwd && !strcmp(p, pwd->pw_passwd)) + break; + + printf("Login incorrect\n"); + badlogin(username); /* log ALL bad logins */ + failures++; + + /* we allow 10 tries, but after 3 we start backing off */ + if (++cnt > 3) { + if (cnt >= 10) { + sleepexit(1); + } + sleep((unsigned int)((cnt - 3) * 5)); + } + } +#endif /* !USE_PAM */ + + /* committed to login -- turn off timeout */ + alarm((unsigned int)0); + #ifdef HAVE_QUOTA - if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { - switch(errno) { - case EUSERS: - (void)fprintf(stderr, - "Too many users logged on already.\nTry again later.\n"); - break; - case EPROCLIM: - (void)fprintf(stderr, - "You have too many processes running.\n"); - break; - default: - perror("quota (Q_SETUID)"); - } - sleepexit(0); + if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { + switch(errno) { + case EUSERS: + fprintf(stderr, + "Too many users logged on already.\nTry again later.\n"); + break; + case EPROCLIM: + fprintf(stderr, + "You have too many processes running.\n"); + break; + default: + perror("quota (Q_SETUID)"); } + sleepexit(0); + } #endif + + /* paranoia... */ +#ifdef SHADOW_PWD + endspent(); +#endif + endpwent(); + + /* This requires some explanation: As root we may not be able to + read the directory of the user if it is on an NFS mounted + filesystem. We temporarily set our effective uid to the user-uid + making sure that we keep root privs. in the real uid. + + A portable solution would require a fork(), but we rely on Linux + having the BSD setreuid() */ + + { + char tmpstr[MAXPATHLEN]; + uid_t ruid = getuid(); + gid_t egid = getegid(); + + snprintf(tmpstr, sizeof(tmpstr), + "%s/%s", pwd->pw_dir, _PATH_HUSHLOGIN); + + setregid(-1, pwd->pw_gid); + setreuid(0, pwd->pw_uid); + quietlog = (access(tmpstr, R_OK) == 0); + setuid(0); /* setreuid doesn't do it alone! */ + setreuid(ruid, 0); + setregid(-1, egid); + } + +#ifndef __linux__ +# ifdef KERBEROS + if (notickets && !quietlog) + printf("Warning: no Kerberos tickets issued\n"); +# endif + +# ifndef USE_PAM /* PAM does all of this for us */ +# define TWOWEEKS (14*24*60*60) + if (pwd->pw_change || pwd->pw_expire) { + struct timeval tp; - /* paranoia... */ - endpwent(); - - /* This requires some explanation: As root we may not be able to - read the directory of the user if it is on an NFS mounted - filesystem. We temporarily set our effective uid to the user-uid - making sure that we keep root privs. in the real uid. - - A portable solution would require a fork(), but we rely on Linux - having the BSD setreuid() */ - - { - char tmpstr[MAXPATHLEN]; - uid_t ruid = getuid(); - gid_t egid = getegid(); - - strncpy(tmpstr, pwd->pw_dir, MAXPATHLEN-12); - strncat(tmpstr, ("/" _PATH_HUSHLOGIN), MAXPATHLEN); + gettimeofday(&tp, (struct timezone *)NULL); - setregid(-1, pwd->pw_gid); - setreuid(0, pwd->pw_uid); - quietlog = (access(tmpstr, R_OK) == 0); - setuid(0); /* setreuid doesn't do it alone! */ - setreuid(ruid, 0); - setregid(-1, egid); + if (pwd->pw_change) { + if (tp.tv_sec >= pwd->pw_change) { + printf("Sorry -- your password has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { + struct tm *ttp; + ttp = localtime(&pwd->pw_change); + printf("Warning: your password expires on %s %d, %d\n", + months[ttp->tm_mon], ttp->tm_mday, + TM_YEAR_BASE + ttp->tm_year); + } } -#ifndef linux -#ifdef KERBEROS - if (notickets && !quietlog) - (void)printf("Warning: no Kerberos tickets issued\n"); -#endif - -#define TWOWEEKS (14*24*60*60) - if (pwd->pw_change || pwd->pw_expire) - (void)gettimeofday(&tp, (struct timezone *)NULL); - if (pwd->pw_change) - if (tp.tv_sec >= pwd->pw_change) { - (void)printf("Sorry -- your password has expired.\n"); - sleepexit(1); - } - else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { - ttp = localtime(&pwd->pw_change); - (void)printf("Warning: your password expires on %s %d, %d\n", - months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); - } - if (pwd->pw_expire) - if (tp.tv_sec >= pwd->pw_expire) { - (void)printf("Sorry -- your account has expired.\n"); - sleepexit(1); - } - else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { - ttp = localtime(&pwd->pw_expire); - (void)printf("Warning: your account expires on %s %d, %d\n", - months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); - } - - /* nothing else left to fail -- really log in */ - { - struct utmp utmp; - - memset((char *)&utmp, 0, sizeof(utmp)); - (void)time(&utmp.ut_time); - strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); - if (hostname) - strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); - strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); - login(&utmp); + if (pwd->pw_expire) { + if (tp.tv_sec >= pwd->pw_expire) { + printf("Sorry -- your account has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { + struct tm *ttp; + ttp = localtime(&pwd->pw_expire); + printf("Warning: your account expires on %s %d, %d\n", + months[ttp->tm_mon], ttp->tm_mday, + TM_YEAR_BASE + ttp->tm_year); + } + } + } +# endif /* !USE_PAM */ + + /* nothing else left to fail -- really log in */ + { + struct utmp utmp; + + memset((char *)&utmp, 0, sizeof(utmp)); + time(&utmp.ut_time); + strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + /* ut_name may legally be non-null-terminated */ + if (hostname) { + strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + utmp.ut_host[sizeof(utmp.ut_host)-1] = 0; } + strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + utmp.ut_line[sizeof(utmp.ut_line)-1] = 0; + login(&utmp); + } #else - /* for linux, write entries in utmp and wtmp */ - { - struct utmp ut; - int wtmp; - struct utmp *utp; - pid_t mypid = getpid(); - - utmpname(_PATH_UTMP); - setutent(); - while ((utp = getutent()) - && !(utp->ut_pid == mypid)) /* nothing */; - - if (utp) { - memcpy(&ut, utp, sizeof(ut)); - } else { - /* some gettys/telnetds don't initialize utmp... */ - memset(&ut, 0, sizeof(ut)); - } - endutent(); - - if (ut.ut_id[0] == 0) - strncpy(ut.ut_id, ttyn + 8, sizeof(ut.ut_id)); - - strncpy(ut.ut_user, username, sizeof(ut.ut_user)); - strncpy(ut.ut_line, ttyn + 5, sizeof(ut.ut_line)); - time(&ut.ut_time); - ut.ut_type = USER_PROCESS; - ut.ut_pid = mypid; - if (hostname) { - strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); - if (hostaddress.h_addr_list) - memcpy(&ut.ut_addr, hostaddress.h_addr_list[0], - sizeof(ut.ut_addr)); - } - - pututline(&ut); - endutent(); - - if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { - flock(wtmp, LOCK_EX); - write(wtmp, (char *)&ut, sizeof(ut)); - flock(wtmp, LOCK_UN); - close(wtmp); - } + /* for linux, write entries in utmp and wtmp */ + { + struct utmp ut; + int wtmp; + struct utmp *utp; + time_t t; + pid_t mypid = getpid(); + + utmpname(_PATH_UTMP); + setutent(); + while ((utp = getutent()) + && !(utp->ut_pid == mypid)) /* nothing */; + + if (utp) { + memcpy(&ut, utp, sizeof(ut)); + } else { + /* some gettys/telnetds don't initialize utmp... */ + memset(&ut, 0, sizeof(ut)); } -#endif - - dolastlog(quietlog); + /* endutent(); superfluous, error for glibc */ -#ifndef linux - if (!hflag) { /* XXX */ - static struct winsize win = { 0, 0, 0, 0 }; - - (void)ioctl(0, TIOCSWINSZ, &win); + if (ut.ut_id[0] == 0) + strncpy(ut.ut_id, ttyn + 8, sizeof(ut.ut_id)); + + strncpy(ut.ut_user, username, sizeof(ut.ut_user)); + strncpy(ut.ut_line, ttyn + 5, sizeof(ut.ut_line)); + ut.ut_line[sizeof(ut.ut_line)-1] = 0; + time(&t); + ut.ut_time = t; /* ut_time is not always a time_t */ + /* (we might test #ifdef _HAVE_UT_TV ) */ + ut.ut_type = USER_PROCESS; + ut.ut_pid = mypid; + if (hostname) { + strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); + ut.ut_host[sizeof(ut.ut_host)-1] = 0; + if (hostaddress.h_addr_list) + memcpy(&ut.ut_addr, hostaddress.h_addr_list[0], + sizeof(ut.ut_addr)); } + + pututline(&ut); + endutent(); + + { + int lf; + if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { + flock(lf, LOCK_EX); + if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { + write(wtmp, (char *)&ut, sizeof(ut)); + close(wtmp); + } + flock(lf, LOCK_UN); + close(lf); + } + } + } #endif - (void)chown(ttyn, pwd->pw_uid, - (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); - -#ifdef USE_TTY_GROUP - chmod(ttyn, 0620); -#else - chmod(ttyn, 0600); + + dolastlog(quietlog); + +#ifndef __linux__ + if (!hflag) { /* XXX */ + static struct winsize win = { 0, 0, 0, 0 }; + + ioctl(0, TIOCSWINSZ, &win); + } #endif - - setgid(pwd->pw_gid); - initgroups(username, pwd->pw_gid); - + chown(ttyn, pwd->pw_uid, + (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); + chmod(ttyn, TTY_MODE); + + /* if tty is one of the VC's then change owner and mode of the + special /dev/vcs devices as well */ + if (consoletty(0)) { + chown(vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid)); + chown(vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid)); + chmod(vcsn, TTY_MODE); + chmod(vcsan, TTY_MODE); + } + + setgid(pwd->pw_gid); + #ifdef HAVE_QUOTA - quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); + quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); #endif - - if (*pwd->pw_shell == '\0') - pwd->pw_shell = _PATH_BSHELL; -#ifndef linux - /* turn on new line discipline for the csh */ - else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { - ioctlval = NTTYDISC; - (void)ioctl(0, TIOCSETD, &ioctlval); - } + + if (*pwd->pw_shell == '\0') + pwd->pw_shell = _PATH_BSHELL; +#ifndef __linux__ + /* turn on new line discipline for the csh */ + else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { + ioctlval = NTTYDISC; + ioctl(0, TIOCSETD, &ioctlval); + } #endif - - /* preserve TERM even without -p flag */ - { - char *ep; - - if(!((ep = getenv("TERM")) && (termenv = strdup(ep)))) - termenv = "dumb"; - } - - /* destroy environment unless user has requested preservation */ - if (!pflag) - { + + /* preserve TERM even without -p flag */ + { + char *ep; + + if(!((ep = getenv("TERM")) && (termenv = strdup(ep)))) + termenv = "dumb"; + } + + /* destroy environment unless user has requested preservation */ + if (!pflag) + { environ = (char**)malloc(sizeof(char*)); memset(environ, 0, sizeof(char*)); - } - -#ifndef linux - (void)setenv("HOME", pwd->pw_dir, 1); - (void)setenv("SHELL", pwd->pw_shell, 1); - if (term[0] == '\0') - strncpy(term, stypeof(tty), sizeof(term)); - (void)setenv("TERM", term, 0); - (void)setenv("USER", pwd->pw_name, 1); - (void)setenv("PATH", _PATH_DEFPATH, 0); + } + +#ifndef __linux__ + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", pwd->pw_shell, 1); + if (term[0] == '\0') { + strncpy(term, stypeof(tty), sizeof(term)); + term[sizeof(term)-1] = 0; + } + setenv("TERM", term, 0); + setenv("USER", pwd->pw_name, 1); + setenv("PATH", _PATH_DEFPATH, 0); #else - (void)setenv("HOME", pwd->pw_dir, 0); /* legal to override */ - if(pwd->pw_uid) - (void)setenv("PATH", _PATH_DEFPATH, 1); - else - (void)setenv("PATH", _PATH_DEFPATH_ROOT, 1); - (void)setenv("SHELL", pwd->pw_shell, 1); - (void)setenv("TERM", termenv, 1); - - /* mailx will give a funny error msg if you forget this one */ - (void)sprintf(tmp,"%s/%s",_PATH_MAILDIR,pwd->pw_name); - (void)setenv("MAIL",tmp,0); - - /* LOGNAME is not documented in login(1) but - HP-UX 6.5 does it. We'll not allow modifying it. - */ - (void)setenv("LOGNAME", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 0); /* legal to override */ + if(pwd->pw_uid) + setenv("PATH", _PATH_DEFPATH, 1); + else + setenv("PATH", _PATH_DEFPATH_ROOT, 1); + + setenv("SHELL", pwd->pw_shell, 1); + setenv("TERM", termenv, 1); + + /* mailx will give a funny error msg if you forget this one */ + snprintf(tmp, sizeof(tmp), "%s/%s", _PATH_MAILDIR, pwd->pw_name); + setenv("MAIL",tmp,0); + + /* LOGNAME is not documented in login(1) but + HP-UX 6.5 does it. We'll not allow modifying it. + */ + setenv("LOGNAME", pwd->pw_name, 1); #endif - if (tty[sizeof("tty")-1] == 'S') - syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); - - if (pwd->pw_uid == 0) - if (hostname) - syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", - tty, hostname); - else - syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); - - if (!quietlog) { - struct stat st; - - motd(); - (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); - if (stat(tbuf, &st) == 0 && st.st_size != 0) - (void)printf("You have %smail.\n", - (st.st_mtime > st.st_atime) ? "new " : ""); - } +#ifdef USE_PAM + { + int i; + const char * const * env; - (void)signal(SIGALRM, SIG_DFL); - (void)signal(SIGQUIT, SIG_DFL); - (void)signal(SIGINT, SIG_DFL); - (void)signal(SIGTSTP, SIG_IGN); - (void)signal(SIGHUP, SIG_DFL); + env = (const char * const *)pam_getenvlist(pamh); - /* discard permissions last so can't get killed and drop core */ - if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) { - syslog(LOG_ALERT, "setuid() failed"); - exit(1); + if (env != NULL) { + for (i=0; env[i++]; ) { + putenv(env[i-1]); + /* D(("env[%d] = %s", i-1,env[i-1])); */ + } } - - /* wait until here to change directory! */ - if (chdir(pwd->pw_dir) < 0) { - (void)printf("No directory %s!\n", pwd->pw_dir); - if (chdir("/")) - exit(0); - pwd->pw_dir = "/"; - (void)printf("Logging in with home = \"/\".\n"); + } +#endif + + if (tty[sizeof("tty")-1] == 'S') + syslog(LOG_INFO, "DIALUP AT %s BY %s", tty, pwd->pw_name); + + /* allow tracking of good logins. + -steve philp (sphilp@mail.alliance.net) */ + + if (pwd->pw_uid == 0) { + if (hostname) + syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", + tty, hostname); + else + syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); + } else { + if (hostname) + syslog(LOG_INFO, "LOGIN ON %s BY %s FROM %s", tty, + pwd->pw_name, hostname); + else + syslog(LOG_INFO, "LOGIN ON %s BY %s", tty, + pwd->pw_name); + } + + if (!quietlog) { + struct stat st; + + motd(); + snprintf(tbuf, sizeof(tbuf), + "%s/%s", _PATH_MAILDIR, pwd->pw_name); + if (stat(tbuf, &st) == 0 && st.st_size != 0) + printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); + } + + signal(SIGALRM, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_IGN); + signal(SIGHUP, SIG_DFL); + + /* discard permissions last so can't get killed and drop core */ + if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) { + syslog(LOG_ALERT, "setuid() failed"); +#ifdef USE_PAM + PAM_END; +#endif + exit(1); + } + + /* wait until here to change directory! */ + if (chdir(pwd->pw_dir) < 0) { + printf("No directory %s!\n", pwd->pw_dir); + if (chdir("/")) { +#ifdef USE_PAM + PAM_END; +#endif + exit(0); } - - /* if the shell field has a space: treat it like a shell script */ - if (strchr(pwd->pw_shell, ' ')) { - char *buff = malloc(strlen(pwd->pw_shell) + 6); - if (buff) { - strcpy(buff, "exec "); - strcat(buff, pwd->pw_shell); - execlp("/bin/sh", "-sh", "-c", buff, (char *)0); - fprintf(stderr, "login: couldn't exec shell script: %s.\n", - strerror(errno)); - exit(0); - } + pwd->pw_dir = "/"; + printf("Logging in with home = \"/\".\n"); + } + + /* if the shell field has a space: treat it like a shell script */ + if (strchr(pwd->pw_shell, ' ')) { + buff = malloc(strlen(pwd->pw_shell) + 6); + + if (!buff) { fprintf(stderr, "login: no memory for shell script.\n"); exit(0); } + strcpy(buff, "exec "); + strcat(buff, pwd->pw_shell); + childArgv[childArgc++] = "/bin/sh"; + childArgv[childArgc++] = "-sh"; + childArgv[childArgc++] = "-c"; + childArgv[childArgc++] = buff; + } else { tbuf[0] = '-'; - strcpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ? - p + 1 : pwd->pw_shell)); - - execlp(pwd->pw_shell, tbuf, (char *)0); - (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); + strncpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell), + sizeof(tbuf)-1); + tbuf[sizeof(tbuf)-1] = 0; + + childArgv[childArgc++] = pwd->pw_shell; + childArgv[childArgc++] = tbuf; + } + + childArgv[childArgc++] = NULL; + +#ifndef USE_PAM + execvp(childArgv[0], childArgv + 1); + error = 1; +#else /* USE_PAM */ + oldSigHandler = signal(SIGINT, SIG_IGN); + childPid = fork(); + if (childPid < 0) { + /* error in fork() */ + fprintf(stderr,"login: failure forking: %s", strerror(errno)); + PAM_END; exit(0); + } else if (childPid) { + /* parent */ + wait(&childStatus); + signal(SIGINT, oldSigHandler); + PAM_END; + + if (!WIFEXITED(&childStatus)) error = 1; + } else { + /* child */ + execvp(childArgv[0], childArgv + 1); + exit(1); + } +#endif /* USE_PAM */ + + if (error) { + if (!strcmp(childArgv[0], "/bin/sh")) + fprintf(stderr, "login: couldn't exec shell script: %s.\n", + strerror(errno)); + else + fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); + } + + exit(0); } void getloginname() { - register int ch; - register char *p; - static char nbuf[UT_NAMESIZE + 1]; - int cnt, cnt2; - - cnt2 = 0; - for (;;) { - cnt = 0; - (void)printf("\n%s login: ", thishost); fflush(stdout); - for (p = nbuf; (ch = getchar()) != '\n'; ) { - if (ch == EOF) { - badlogin("EOF"); - exit(0); - } - if (p < nbuf + UT_NAMESIZE) - *p++ = ch; - - cnt++; - if (cnt > UT_NAMESIZE + 20) { - fprintf(stderr, "login name much too long.\n"); - badlogin("NAME too long"); - exit(0); - } - } - if (p > nbuf) - if (nbuf[0] == '-') - (void)fprintf(stderr, - "login names may not start with '-'.\n"); - else { - *p = '\0'; - username = nbuf; - break; - } - - cnt2++; - if (cnt2 > 50) { - fprintf(stderr, "too many bare linefeeds.\n"); - badlogin("EXCESSIVE linefeeds"); - exit(0); - } + register int ch; + register char *p; + static char nbuf[UT_NAMESIZE + 1]; + int cnt, cnt2; + + cnt2 = 0; + for (;;) { + cnt = 0; + printf("\n%s login: ", thishost); fflush(stdout); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin("EOF"); + exit(0); + } + if (p < nbuf + UT_NAMESIZE) + *p++ = ch; + + cnt++; + if (cnt > UT_NAMESIZE + 20) { + fprintf(stderr, "login name much too long.\n"); + badlogin("NAME too long"); + exit(0); + } + } + if (p > nbuf) + if (nbuf[0] == '-') + fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } + + cnt2++; + if (cnt2 > 50) { + fprintf(stderr, "too many bare linefeeds.\n"); + badlogin("EXCESSIVE linefeeds"); + exit(0); } + } } -void timedout() +void +timedout() { - struct termio ti; - - (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); - - /* reset echo */ - (void) ioctl(0, TCGETA, &ti); - ti.c_lflag |= ECHO; - (void) ioctl(0, TCSETA, &ti); - exit(0); + struct termio ti; + + fprintf(stderr, "Login timed out after %d seconds\n", timeout); + + /* reset echo */ + ioctl(0, TCGETA, &ti); + ti.c_lflag |= ECHO; + ioctl(0, TCSETA, &ti); + exit(0); } int rootterm(ttyn) - char *ttyn; -#ifndef linux + char *ttyn; +#ifndef __linux__ { - struct ttyent *t; - - return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); + struct ttyent *t; + + return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); } #else { - int fd; - char buf[100],*p; - int cnt, more; - - fd = open(SECURETTY, O_RDONLY); - if(fd < 0) return 1; - - /* read each line in /etc/securetty, if a line matches our ttyline - then root is allowed to login on this tty, and we should return - true. */ - for(;;) { + int fd; + char buf[100],*p; + int cnt, more; + + fd = open(SECURETTY, O_RDONLY); + if(fd < 0) return 1; + + /* read each line in /etc/securetty, if a line matches our ttyline + then root is allowed to login on this tty, and we should return + true. */ + for(;;) { p = buf; cnt = 100; while(--cnt >= 0 && (more = read(fd, p, 1)) == 1 && *p != '\n') p++; if(more && *p == '\n') { - *p = '\0'; - if(!strcmp(buf, ttyn)) { - close(fd); - return 1; - } else - continue; + *p = '\0'; + if(!strcmp(buf, ttyn)) { + close(fd); + return 1; + } else + continue; } else { - close(fd); - return 0; + close(fd); + return 0; } - } + } } #endif @@ -878,121 +1174,108 @@ jmp_buf motdinterrupt; void motd() { - register int fd, nchars; - void (*oldint)(), sigint(); - char tbuf[8192]; - - if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) - return; - oldint = signal(SIGINT, sigint); - if (setjmp(motdinterrupt) == 0) - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); - (void)signal(SIGINT, oldint); - (void)close(fd); + register int fd, nchars; + void (*oldint)(), sigint(); + char tbuf[8192]; + + if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) + return; + oldint = signal(SIGINT, sigint); + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + write(fileno(stdout), tbuf, nchars); + signal(SIGINT, oldint); + close(fd); } -void sigint() +void +sigint() { - longjmp(motdinterrupt, 1); + longjmp(motdinterrupt, 1); } +#ifndef USE_PAM /* PAM takes care of this */ void checknologin() { - register int fd, nchars; - char tbuf[8192]; - - if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); - sleepexit(0); - } + register int fd, nchars; + char tbuf[8192]; + + if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + write(fileno(stdout), tbuf, nchars); + sleepexit(0); + } } +#endif void dolastlog(quiet) - int quiet; + int quiet; { - struct lastlog ll; - int fd; - - if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { - (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); - if (!quiet) { - if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && - ll.ll_time != 0) { - (void)printf("Last login: %.*s ", - 24-5, (char *)ctime(&ll.ll_time)); - - if (*ll.ll_host != '\0') - printf("from %.*s\n", - (int)sizeof(ll.ll_host), ll.ll_host); - else - printf("on %.*s\n", - (int)sizeof(ll.ll_line), ll.ll_line); - } - (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); - } - memset((char *)&ll, 0, sizeof(ll)); - (void)time(&ll.ll_time); - strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); - if (hostname) - strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); - (void)write(fd, (char *)&ll, sizeof(ll)); - (void)close(fd); + struct lastlog ll; + int fd; + + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { + lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + if (!quiet) { + if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && + ll.ll_time != 0) { + printf("Last login: %.*s ", + 24-5, (char *)ctime(&ll.ll_time)); + + if (*ll.ll_host != '\0') + printf("from %.*s\n", + (int)sizeof(ll.ll_host), ll.ll_host); + else + printf("on %.*s\n", + (int)sizeof(ll.ll_line), ll.ll_line); + } + lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); } + memset((char *)&ll, 0, sizeof(ll)); + time(&ll.ll_time); + strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + ll.ll_line[sizeof(ll.ll_line)-1] = 0; + if (hostname) { + strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + ll.ll_host[sizeof(ll.ll_host)-1] = 0; + } + write(fd, (char *)&ll, sizeof(ll)); + close(fd); + } } void -badlogin(name) - char *name; +badlogin(const char *name) { - if (hostname) - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", - failures, failures > 1 ? "S" : "", hostname, name); - else - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", - failures, failures > 1 ? "S" : "", tty, name); + if (hostname) + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", + failures, failures > 1 ? "S" : "", hostname, name); + else + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", + failures, failures > 1 ? "S" : "", tty, name); } #undef UNKNOWN #define UNKNOWN "su" -#ifndef linux +#ifndef __linux__ char * stypeof(ttyid) - char *ttyid; + char *ttyid; { - struct ttyent *t; + struct ttyent *t; - return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); + return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); } #endif -void -getstr(buf, cnt, err) - char *buf, *err; - int cnt; -{ - char ch; - - do { - if (read(0, &ch, sizeof(ch)) != sizeof(ch)) - exit(1); - if (--cnt < 0) { - (void)fprintf(stderr, "%s too long\r\n", err); - sleepexit(1); - } - *buf++ = ch; - } while (ch); -} - +/* should not be called from PAM code... Why? */ void sleepexit(eval) - int eval; + int eval; { - sleep((unsigned int)5); - exit(eval); + sleep(SLEEP_EXIT_TIMEOUT); + exit(eval); } - |