home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1989, 1990, John F. Haugh II
- * All rights reserved.
- *
- * Permission is granted to copy and create derivative works for any
- * non-commercial purpose, provided this copyright notice is preserved
- * in all copies of source code, or included in human readable form
- * and conspicuously displayed on all copies of object code or
- * distribution media.
- */
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include "pwd.h"
- #include <utmp.h>
- #include <time.h>
- #include <signal.h>
- #include <syslog.h>
- #ifndef BSD
- #include <string.h>
- #include <memory.h>
- #define bzero(a,n) memset(a, 0, n);
- #else
- #include <strings.h>
- #define strchr index
- #define strrchr rindex
- #endif
- #ifndef BSD
- #include <termio.h>
- #else
- #include <sgtty.h>
- #endif
- #include "config.h"
- #include "lastlog.h"
- #include "faillog.h"
- #include "shadow.h"
-
- #ifndef lint
- static char sccsid[] = "%W% %U% %G%";
- #endif
-
- #ifndef ERASECHAR
- #define ERASECHAR '\b' /* backspace */
- #endif
-
- #ifndef KILLCHAR
- #define KILLCHAR '\025' /* control U */
- #endif
-
- #ifdef UT_HOST
- char host[BUFSIZ];
- #endif
- #ifdef HUSHLOGIN
- int hushed;
- #endif
-
- struct passwd pwent;
- struct utmp utent;
- struct lastlog lastlog;
- int pflg;
- int rflg;
- int fflg;
- int hflg;
- #ifndef BSD
- struct termio termio;
- #endif
-
- #ifndef MAXENV
- #define MAXENV 64
- #endif
-
- /*
- * Global variables.
- */
-
- char *newenvp[MAXENV];
- char *Prog;
- int newenvc = 0;
- int maxenv = MAXENV;
-
- /*
- * External identifiers.
- */
-
- extern char *getenv ();
- extern char *getpass ();
- extern void checkutmp ();
- extern void addenv ();
- extern void setenv ();
- extern unsigned alarm ();
- extern void login ();
- extern void entry ();
- extern void setutmp ();
- extern void subsystem ();
- extern void log ();
- extern void setup ();
- extern int expire ();
- extern void motd ();
- extern void mailcheck ();
- extern void shell ();
- extern long a64l ();
- extern int c64i ();
- extern int optind;
- extern char *optarg;
- extern char **environ;
-
- #ifdef TZ
- FILE *tzfile;
- char tzbuf[32] = TZ;
- #endif
-
- #ifndef ALARM
- #define ALARM 60
- #endif
-
- #ifndef RETRIES
- #define RETRIES 3
- #endif
-
- #ifdef FAILLOG
- struct faillog faillog;
- #endif
-
- #ifdef FTMP
- struct utmp failent;
- #endif
-
- #ifndef UMASK
- #define UMASK 0
- #endif
-
- #ifndef ULIMIT
- #define ULIMIT (1L<<21)
- #endif
-
- #define NO_SHADOW "no shadow password for `%s' on `%s'\n"
- #define BAD_PASSWD "invalid password for `%s' on `%s'\n"
- #define BAD_DIALUP "invalid dialup password for `%s' on `%s'\n"
- #define BAD_TIME "invalid login time for `%s' on `%s'\n"
- #define BAD_ROOT_LOGIN "ILLEGAL ROOT LOGIN ON TTY `%s'\n"
- #define ROOT_LOGIN "ROOT LOGIN ON TTY `%s'\n"
- #define FAILURE_CNT "exceeded failure limit for `%s' on `%s'\n"
- #define NOT_A_TTY "not a tty\n"
- #define NOT_ROOT "-r or -f flag and not ROOT on `%s'\n"
-
- /*
- * usage - print login command usage and exit
- */
-
- usage ()
- {
- fprintf (stderr, "usage: login [ -p ] [ name ]\n");
- #ifdef UT_HOST
- fprintf (stderr, " login -r name\n");
- fprintf (stderr, " login [ -p ] -f name [ -h host ]\n");
- #else
- fprintf (stderr, " login [ -p ] -f name\n");
- #endif
- exit (1);
- }
-
- /*
- * login - create a new login session for a user
- *
- * login is typically called by getty as the second step of a
- * new user session. getty is responsible for setting the line
- * characteristics to a reasonable set of values and getting
- * the name of the user to be logged in. login may also be
- * called to create a new user session on a pty for a variety
- * of reasons, such as X servers or network logins.
- *
- * the flags which login supports are
- *
- * -p - preserve the environment
- * -r - perform autologin protocol for rlogin
- * -f - do not perform authentication, user is preauthenticated
- * -h - the name of the remote host
- */
-
- int
- main (argc, argv, envp)
- int argc;
- char **argv;
- char **envp;
- {
- char name[32];
- char pass[32];
- char hush[BUFSIZ];
- char tty[BUFSIZ];
- int retries;
- int failed;
- int flag;
- int subroot = 0;
- char *cp;
- struct passwd *pwd;
- struct spwd *spwd;
- struct spwd *getspnam();
- #ifdef CONSOLE
- int conflag;
- char console[BUFSIZ];
- FILE *fp;
- struct stat statbuf;
- #endif /* CONSOLE */
-
- /*
- * Some quick initialization.
- */
-
- name[0] = '\0';
-
- /*
- * Get the utmp file entry and get the tty name from it. The
- * current process ID must match the process ID in the utmp
- * file if there are no additional flags on the command line.
- */
-
- checkutmp (argc > 1 && argv[1][0] != '-');
- strncpy (tty, utent.ut_line, sizeof tty);
- tty[sizeof tty - 1] = '\0';
-
- if (Prog = strrchr (argv[0], '/'))
- Prog++;
- else
- Prog = argv[0];
-
- #ifdef UT_HOST
- while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF)
- #else
- while ((flag = getopt (argc, argv, "pf:")) != EOF)
- #endif
- {
- switch (flag) {
- case 'p': pflg++;
- break;
- case 'f': fflg++;
- strncpy (name, optarg, sizeof name);
- break;
- #ifdef UT_HOST
- case 'r': rflg++;
- strncpy (name, optarg, sizeof name);
- break;
- case 'h': hflg++;
- strncpy (host, optarg, sizeof host);
- strncpy (utmp.ut_host, host,
- sizeof utmp.ut_host);
- break;
- #endif
- default:
- usage ();
- }
- }
-
- /*
- * The -r option is not valid with any other flags
- */
-
- if (rflg && (hflg || fflg || pflg))
- usage ();
-
- openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
-
- /*
- * The -r and -f flags both require the real UID to be
- * zero. No authentication may be required for these
- * flags, so the user must already be root.
- */
-
- if ((rflg || fflg) && getuid () != 0)
- exit (1); /* only root can use -r or -f */
-
- if (! isatty (0) || ! isatty (1) || ! isatty (2))
- exit (1); /* must be a terminal */
-
- #ifndef BSD
- (void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */
-
- /*
- * Add your favorite terminal modes here ...
- */
-
- termio.c_lflag |= ISIG;
-
- termio.c_cc[VERASE] = ERASECHAR;
- termio.c_cc[VKILL] = KILLCHAR;
- (void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */
- #endif /* !BSD */
- umask (UMASK); /* set the default umask */
- ulimit (2, (long) ULIMIT); /* set the default ulimit */
-
- /*
- * The entire environment will be preserved if the -p flag
- * is used.
- */
-
- if (pflg)
- while (*envp) /* add inherited environment, */
- addenv (*envp++); /* some variables change later */
-
- #ifdef TZ
- if (! pflg) {
- if (tzbuf[0] == '/') {
- if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
- if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
- tzbuf[strlen (tzbuf) - 1] = '\0';
- addenv (tzbuf);
- }
- fclose (tzfile);
- }
- } else {
- addenv (tzbuf);
- }
- }
- #endif /* TZ */
- #ifdef HZ
- if (! pflg)
- addenv (HZ); /* set the default $HZ, if one */
- #endif /* HZ */
- if (optind < argc) { /* now set command line variables */
- if (optind + 1 < argc)
- setenv (argc - optind - 1, &argv[optind + 1]);
-
- (void) strncpy (name, argv[optind], sizeof name);
- }
- top:
- (void) alarm (ALARM); /* only allow ALARM sec. for login */
-
- retries = RETRIES;
- while (1) { /* repeatedly get login/password pairs */
- pass[0] = '\0';
-
- if (! name[0]) { /* need to get a login id */
- if (subroot)
- exit (1);
-
- rflg = fflg = 0;
- login (name);
- continue;
- }
- if (! (pwd = getpwnam (name)))
- pwent.pw_name = (char *) 0;
- else
- pwent = *pwd;
-
- if (pwent.pw_name) {
- if (! (spwd = getspnam (name)))
- syslog (LOG_WARN, NO_SHADOW, name, tty);
- else
- pwent.pw_passwd = spwd->sp_pwdp;
- failed = 0; /* hasn't failed validation yet */
- } else
- failed = 1; /* will never pass validation */
-
- /*
- * The -r and -f flags provide a name which has already
- * been authenticated by some server.
- */
-
- if (pwent.pw_name && (rflg || fflg))
- goto have_name;
-
- /*
- * Get the user's password. One will only be prompted for
- * if the pw_passwd (or sp_passwd) field is non-blank. It
- * will then be checked against the password entry, along
- * with other options which prevent logins.
- */
- cp = 0;
- if ((! pwent.pw_name || (strlen (pwent.pw_passwd) > 0))
- && ! (cp = getpass ("Password:")))
- continue;
-
- if (cp)
- strncpy (pass, cp, sizeof pass);
-
- if (! valid (pass, &pwent)) { /* check encrypted passwords */
- syslog (LOG_WARN, BAD_PASSWD, name, tty);
- failed = 1;
- }
- bzero (pass, sizeof pass);
-
- /*
- * This is the point where password-authenticated users
- * wind up. If you reach this far, your password has
- * been authenticated and so on.
- */
-
- have_name:
- #ifdef DIALUP
- alarm (30);
- if (pwent.pw_name && ! dialcheck (tty,
- pwent.pw_shell[0] ? pwent.pw_shell:"/bin/sh")) {
- syslog (LOG_WARN, BAD_DIALUP, name, tty);
- failed = 1;
- }
- #endif /* DIALUP */
- #ifdef PORTTIME
- if (pwent.pw_name &&
- ! isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
- syslog (LOG_WARN, BAD_TIME, name, tty);
- failed = 1;
- }
- #endif /* PORTTIME */
- #ifdef CONSOLE
- if (! failed && pwent.pw_name &&
- pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) {
- if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
- fp = fopen (CONSOLE, "r");
- while (fp && fgets (console, BUFSIZ, fp)
- == console) {
- console[strlen (console) - 1] = '\0';
- if (! strcmp (console, tty))
- break;
- }
- if (! fp || feof (fp))
- failed = 1;
-
- fclose (fp);
- } else {
- if (strcmp (CONSOLE, tty))
- failed = 1;
- }
- if (failed)
- syslog (LOG_CRIT, BAD_ROOT_LOGIN, tty);
- }
- #endif /* CONSOLE */
- #ifdef FAILLOG
- if (pwent.pw_name &&
- ! failcheck (pwent.pw_uid, &faillog, failed)) {
- syslog (LOG_CRIT, FAILURE_CNT, name, tty);
- failed = 1;
- }
- #endif /* FAILLOG */
- if (! failed)
- break;
-
- puts ("Login incorrect");
- if (rflg || fflg)
- exit (1);
- #ifdef FAILLOG
- if (pwent.pw_name) /* don't log non-existent users */
- failure (pwent.pw_uid, tty, &faillog);
- #endif /* FAILLOG */
- #ifdef FTMP
- failent = utent;
-
- if (pwent.pw_name)
- strncpy (failent.ut_name,
- pwent.pw_name, sizeof failent.ut_name);
- else
- #ifdef UNKNOWNS
- strcpy (failent.ut_name, name);
- #else /* !UNKNOWNS */
- strcpy (failent.ut_name, "UNKNOWN");
- #endif /* UNKNOWNS */
- time (&failent.ut_time);
- failent.ut_type = USER_PROCESS;
-
- failtmp (&failent);
- #endif /* FTMP */
- if (--retries <= 0) /* only allow so many failures */
- exit (1);
-
- bzero (name, sizeof name);
- bzero (pass, sizeof pass);
- }
- (void) alarm (0); /* turn off alarm clock */
- #ifdef NOLOGINS
- /*
- * Check to see if system is turned off for non-root users.
- * This would be useful to prevent users from logging in
- * during system maintenance.
- */
-
- if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) {
- FILE *fp;
- int c;
-
- if (fp = fopen (NOLOGINS, "r")) {
- while ((c = getc (fp)) != EOF) {
- if (c == '\n')
- putchar ('\r');
-
- putchar (c);
- }
- fflush (stdout);
- fclose (fp);
- } else
- printf ("\r\nSystem closed for routine maintenance\n");
-
- exit (0);
- }
- #endif /* NOLOGINS */
- environ = newenvp; /* make new environment active */
-
- if (getenv ("IFS")) /* don't export user IFS ... */
- addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */
-
- setutmp (name, tty); /* make entry in utmp & wtmp files */
- if (pwent.pw_shell[0] == '*') { /* subsystem root */
- subsystem (&pwent); /* figure out what to execute */
- subroot++; /* say i was here again */
- endpwent (); /* close all of the file which were */
- endgrent (); /* open in the original rooted file */
- endspent (); /* system. they will be re-opened */
- endsgent (); /* in the new rooted file system */
- goto top; /* go do all this all over again */
- }
-
- #ifdef LASTLOG
- log (); /* give last login and log this one */
- #endif /* LASTLOG */
- setup (&pwent); /* set UID, GID, HOME, etc ... */
- #ifdef AGING
- if (spwd) { /* check for age of password */
- if (expire (&pwent, spwd)) {
- spwd = getspnam (name);
- pwd = getpwnam (name);
- pwent = *pwd;
- }
- }
- #ifdef ATT_AGE
- else if (pwent.pw_age && pwent.pw_age[0]) {
- if (expire (&pwent, (void *) 0)) {
- pwd = getpwnam (name);
- pwent = *pwd;
- }
- }
- #endif /* ATT_AGE */
- #endif /* AGING */
- #ifdef HUSHLOGIN
- sprintf (hush, "%s/.hushlogin", pwent.pw_dir, 0);
- hushed = access (hush, 0) == 0;
- #endif /* HUSHLOGIN */
- #ifdef MOTD
- if (! hushed)
- motd (); /* print the message of the day */
- #endif
- #ifdef FAILLOG
- if (faillog.fail_cnt != 0)
- failprint (pwent.pw_uid, &faillog);
- #endif /* FAILLOG */
- #ifdef LASTLOG
- if (lastlog.ll_time != 0 && ! hushed)
- printf ("Last login: %.19s on %s\n",
- ctime (&lastlog.ll_time), lastlog.ll_line);
- #endif /* LASTLOG */
- #ifdef AGING
- if (! hushed)
- agecheck (&pwent, spwd);
- #endif /* AGING */
- #ifdef MAILCHECK
- if (! hushed)
- mailcheck (); /* report on the status of mail */
- #endif /* MAILCHECK */
- #ifdef TTYTYPE
- if (! pflg)
- ttytype (tty);
- #endif /* TTYTYPE */
- signal (SIGINT, SIG_DFL); /* default interrupt signal */
- signal (SIGQUIT, SIG_DFL); /* default quit signal */
- signal (SIGTERM, SIG_DFL); /* default terminate signal */
- signal (SIGALRM, SIG_DFL); /* default alarm signal */
-
- endpwent (); /* stop access to password file */
- endgrent (); /* stop access to group file */
- endspent (); /* stop access to shadow passwd file */
- endsgent (); /* stop access to shadow group file */
-
- if (pwent.pw_uid == 0)
- syslog (LOG_INFO, ROOT_LOGIN, tty);
-
- shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
- /*NOTREACHED*/
- }
-