home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3339 / lmain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-17  |  12.8 KB  |  576 lines

  1. /*
  2.  * Copyright 1989, 1990, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  */
  11.  
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <stdio.h>
  15. #include "pwd.h"
  16. #include <utmp.h>
  17. #include <time.h>
  18. #include <signal.h>
  19. #include <syslog.h>
  20. #ifndef    BSD
  21. #include <string.h>
  22. #include <memory.h>
  23. #define    bzero(a,n)    memset(a, 0, n);
  24. #else
  25. #include <strings.h>
  26. #define    strchr    index
  27. #define    strrchr    rindex
  28. #endif
  29. #ifndef    BSD
  30. #include <termio.h>
  31. #else
  32. #include <sgtty.h>
  33. #endif
  34. #include "config.h"
  35. #include "lastlog.h"
  36. #include "faillog.h"
  37. #include "shadow.h"
  38.  
  39. #ifndef    lint
  40. static    char    sccsid[] = "%W%    %U%    %G%";
  41. #endif
  42.  
  43. #ifndef    ERASECHAR
  44. #define    ERASECHAR    '\b'        /* backspace */
  45. #endif
  46.  
  47. #ifndef    KILLCHAR
  48. #define    KILLCHAR    '\025'        /* control U */
  49. #endif
  50.  
  51. #ifdef    UT_HOST
  52. char    host[BUFSIZ];
  53. #endif
  54. #ifdef    HUSHLOGIN
  55. int    hushed;
  56. #endif
  57.  
  58. struct    passwd    pwent;
  59. struct    utmp    utent;
  60. struct    lastlog    lastlog;
  61. int    pflg;
  62. int    rflg;
  63. int    fflg;
  64. int    hflg;
  65. #ifndef    BSD
  66. struct    termio    termio;
  67. #endif
  68.  
  69. #ifndef    MAXENV
  70. #define    MAXENV    64
  71. #endif
  72.  
  73. /*
  74.  * Global variables.
  75.  */
  76.  
  77. char    *newenvp[MAXENV];
  78. char    *Prog;
  79. int    newenvc = 0;
  80. int    maxenv = MAXENV;
  81.  
  82. /*
  83.  * External identifiers.
  84.  */
  85.  
  86. extern    char    *getenv ();
  87. extern    char    *getpass ();
  88. extern    void    checkutmp ();
  89. extern    void    addenv ();
  90. extern    void    setenv ();
  91. extern    unsigned alarm ();
  92. extern    void    login ();
  93. extern    void    entry ();
  94. extern    void    setutmp ();
  95. extern    void    subsystem ();
  96. extern    void    log ();
  97. extern    void    setup ();
  98. extern    int    expire ();
  99. extern    void    motd ();
  100. extern    void    mailcheck ();
  101. extern    void    shell ();
  102. extern    long    a64l ();
  103. extern    int    c64i ();
  104. extern    int    optind;
  105. extern    char    *optarg;
  106. extern    char    **environ;
  107.  
  108. #ifdef    TZ
  109. FILE    *tzfile;
  110. char    tzbuf[32] = TZ;
  111. #endif
  112.  
  113. #ifndef    ALARM
  114. #define    ALARM    60
  115. #endif
  116.  
  117. #ifndef    RETRIES
  118. #define    RETRIES    3
  119. #endif
  120.  
  121. #ifdef    FAILLOG
  122. struct    faillog    faillog;
  123. #endif
  124.  
  125. #ifdef    FTMP
  126. struct    utmp    failent;
  127. #endif
  128.  
  129. #ifndef    UMASK
  130. #define    UMASK    0
  131. #endif
  132.  
  133. #ifndef    ULIMIT
  134. #define    ULIMIT    (1L<<21)
  135. #endif
  136.  
  137. #define    NO_SHADOW    "no shadow password for `%s' on `%s'\n"
  138. #define    BAD_PASSWD    "invalid password for `%s' on `%s'\n"
  139. #define    BAD_DIALUP    "invalid dialup password for `%s' on `%s'\n"
  140. #define    BAD_TIME    "invalid login time for `%s' on `%s'\n"
  141. #define    BAD_ROOT_LOGIN    "ILLEGAL ROOT LOGIN ON TTY `%s'\n"
  142. #define    ROOT_LOGIN    "ROOT LOGIN ON TTY `%s'\n"
  143. #define    FAILURE_CNT    "exceeded failure limit for `%s' on `%s'\n"
  144. #define    NOT_A_TTY    "not a tty\n"
  145. #define    NOT_ROOT    "-r or -f flag and not ROOT on `%s'\n"
  146.  
  147. /*
  148.  * usage - print login command usage and exit
  149.  */
  150.  
  151. usage ()
  152. {
  153.     fprintf (stderr, "usage: login [ -p ] [ name ]\n");
  154. #ifdef    UT_HOST
  155.     fprintf (stderr, "       login -r name\n");
  156.     fprintf (stderr, "       login [ -p ] -f name [ -h host ]\n");
  157. #else
  158.     fprintf (stderr, "       login [ -p ] -f name\n");
  159. #endif
  160.     exit (1);
  161. }
  162.  
  163. /*
  164.  * login - create a new login session for a user
  165.  *
  166.  *    login is typically called by getty as the second step of a
  167.  *    new user session.  getty is responsible for setting the line
  168.  *    characteristics to a reasonable set of values and getting
  169.  *    the name of the user to be logged in.  login may also be
  170.  *    called to create a new user session on a pty for a variety
  171.  *    of reasons, such as X servers or network logins.
  172.  *
  173.  *    the flags which login supports are
  174.  *    
  175.  *    -p - preserve the environment
  176.  *    -r - perform autologin protocol for rlogin
  177.  *    -f - do not perform authentication, user is preauthenticated
  178.  *    -h - the name of the remote host
  179.  */
  180.  
  181. int
  182. main (argc, argv, envp)
  183. int    argc;
  184. char    **argv;
  185. char    **envp;
  186. {
  187.     char    name[32];
  188.     char    pass[32];
  189.     char    hush[BUFSIZ];
  190.     char    tty[BUFSIZ];
  191.     int    retries;
  192.     int    failed;
  193.     int    flag;
  194.     int    subroot = 0;
  195.     char    *cp;
  196.     struct    passwd    *pwd;
  197.     struct    spwd    *spwd;
  198.     struct    spwd    *getspnam();
  199. #ifdef    CONSOLE
  200.     int    conflag;
  201.     char    console[BUFSIZ];
  202.     FILE    *fp;
  203.     struct    stat    statbuf;
  204. #endif    /* CONSOLE */
  205.  
  206.     /*
  207.      * Some quick initialization.
  208.      */
  209.  
  210.     name[0] = '\0';
  211.  
  212.     /*
  213.      * Get the utmp file entry and get the tty name from it.  The
  214.      * current process ID must match the process ID in the utmp
  215.      * file if there are no additional flags on the command line.
  216.      */
  217.  
  218.     checkutmp (argc > 1 && argv[1][0] != '-');
  219.     strncpy (tty, utent.ut_line, sizeof tty);
  220.     tty[sizeof tty - 1] = '\0';
  221.  
  222.     if (Prog = strrchr (argv[0], '/'))
  223.         Prog++;
  224.     else
  225.         Prog = argv[0];
  226.  
  227. #ifdef    UT_HOST
  228.     while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF)
  229. #else
  230.     while ((flag = getopt (argc, argv, "pf:")) != EOF)
  231. #endif
  232.     {
  233.         switch (flag) {
  234.             case 'p': pflg++;
  235.                 break;
  236.             case 'f': fflg++;
  237.                 strncpy (name, optarg, sizeof name);
  238.                 break;
  239. #ifdef    UT_HOST
  240.             case 'r': rflg++;
  241.                 strncpy (name, optarg, sizeof name);
  242.                 break;
  243.             case 'h': hflg++;
  244.                 strncpy (host, optarg, sizeof host);
  245.                 strncpy (utmp.ut_host, host,
  246.                             sizeof utmp.ut_host);
  247.                 break;
  248. #endif
  249.             default:
  250.                 usage ();
  251.         }
  252.     }
  253.  
  254.     /*
  255.      * The -r option is not valid with any other flags
  256.      */
  257.  
  258.     if (rflg && (hflg || fflg || pflg))
  259.         usage ();
  260.  
  261.     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  262.  
  263.     /*
  264.      * The -r and -f flags both require the real UID to be
  265.      * zero.  No authentication may be required for these
  266.      * flags, so the user must already be root.
  267.      */
  268.  
  269.     if ((rflg || fflg) && getuid () != 0)
  270.         exit (1);        /* only root can use -r or -f */
  271.  
  272.     if (! isatty (0) || ! isatty (1) || ! isatty (2))
  273.         exit (1);        /* must be a terminal */
  274.  
  275. #ifndef    BSD
  276.     (void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */
  277.  
  278.     /*
  279.      * Add your favorite terminal modes here ...
  280.      */
  281.  
  282.     termio.c_lflag |= ISIG;
  283.  
  284.     termio.c_cc[VERASE] = ERASECHAR;
  285.     termio.c_cc[VKILL] = KILLCHAR;
  286.     (void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */
  287. #endif    /* !BSD */
  288.     umask (UMASK);            /* set the default umask */
  289.     ulimit (2, (long) ULIMIT);    /* set the default ulimit */
  290.  
  291.     /*
  292.      * The entire environment will be preserved if the -p flag
  293.      * is used.
  294.      */
  295.  
  296.     if (pflg)
  297.         while (*envp)        /* add inherited environment, */
  298.             addenv (*envp++); /* some variables change later */
  299.  
  300. #ifdef    TZ
  301.     if (! pflg) {
  302.         if (tzbuf[0] == '/') {
  303.             if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
  304.                 if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
  305.                     tzbuf[strlen (tzbuf) - 1] = '\0';
  306.                     addenv (tzbuf);
  307.                 }
  308.                 fclose (tzfile);
  309.             }
  310.         } else {
  311.             addenv (tzbuf);
  312.         }
  313.     }
  314. #endif    /* TZ */
  315. #ifdef    HZ
  316.     if (! pflg)
  317.         addenv (HZ);        /* set the default $HZ, if one */
  318. #endif    /* HZ */
  319.     if (optind < argc) {    /* now set command line variables */
  320.         if (optind + 1 < argc)
  321.             setenv (argc - optind - 1, &argv[optind + 1]);
  322.  
  323.         (void) strncpy (name, argv[optind], sizeof name);
  324.     }
  325. top:
  326.     (void) alarm (ALARM);        /* only allow ALARM sec. for login */
  327.  
  328.     retries = RETRIES;
  329.     while (1) {    /* repeatedly get login/password pairs */
  330.         pass[0] = '\0';
  331.  
  332.         if (! name[0]) {    /* need to get a login id */
  333.             if (subroot)
  334.                 exit (1);
  335.  
  336.             rflg = fflg = 0;
  337.             login (name);
  338.             continue;
  339.         }
  340.         if (! (pwd = getpwnam (name)))
  341.             pwent.pw_name = (char *) 0;
  342.         else
  343.             pwent = *pwd;
  344.  
  345.         if (pwent.pw_name) {
  346.             if (! (spwd = getspnam (name)))
  347.                 syslog (LOG_WARN, NO_SHADOW, name, tty);
  348.             else
  349.                 pwent.pw_passwd = spwd->sp_pwdp;
  350.             failed = 0;    /* hasn't failed validation yet */
  351.         } else
  352.             failed = 1;    /* will never pass validation */
  353.  
  354.         /*
  355.          * The -r and -f flags provide a name which has already
  356.          * been authenticated by some server.
  357.          */
  358.  
  359.         if (pwent.pw_name && (rflg || fflg))
  360.             goto have_name;
  361.  
  362.     /*
  363.      * Get the user's password.  One will only be prompted for
  364.      * if the pw_passwd (or sp_passwd) field is non-blank.  It
  365.      * will then be checked against the password entry, along
  366.      * with other options which prevent logins.
  367.      */
  368.         cp = 0;
  369.         if ((! pwent.pw_name || (strlen (pwent.pw_passwd) > 0))
  370.                 && ! (cp = getpass ("Password:")))
  371.             continue;
  372.  
  373.         if (cp)
  374.             strncpy (pass, cp, sizeof pass);
  375.  
  376.         if (! valid (pass, &pwent)) { /* check encrypted passwords */
  377.             syslog (LOG_WARN, BAD_PASSWD, name, tty);
  378.             failed = 1;
  379.         }
  380.         bzero (pass, sizeof pass);
  381.  
  382.         /*
  383.          * This is the point where password-authenticated users
  384.          * wind up.  If you reach this far, your password has
  385.          * been authenticated and so on.
  386.          */
  387.  
  388. have_name:
  389. #ifdef    DIALUP
  390.         alarm (30);
  391.         if (pwent.pw_name && ! dialcheck (tty,
  392.                 pwent.pw_shell[0] ? pwent.pw_shell:"/bin/sh")) {
  393.             syslog (LOG_WARN, BAD_DIALUP, name, tty);
  394.             failed = 1;
  395.         }
  396. #endif    /* DIALUP */
  397. #ifdef    PORTTIME
  398.         if (pwent.pw_name &&
  399.             ! isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
  400.             syslog (LOG_WARN, BAD_TIME, name, tty);
  401.             failed = 1;
  402.         }
  403. #endif    /* PORTTIME */
  404. #ifdef    CONSOLE
  405.         if (! failed && pwent.pw_name &&
  406.             pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) {
  407.             if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
  408.                 fp = fopen (CONSOLE, "r");
  409.                 while (fp && fgets (console, BUFSIZ, fp)
  410.                         == console) {
  411.                     console[strlen (console) - 1] = '\0';
  412.                     if (! strcmp (console, tty))
  413.                         break;
  414.                 }
  415.                 if (! fp || feof (fp))
  416.                     failed = 1;
  417.  
  418.                 fclose (fp);
  419.             } else {
  420.                 if (strcmp (CONSOLE, tty))
  421.                     failed = 1;
  422.             }
  423.             if (failed)
  424.                 syslog (LOG_CRIT, BAD_ROOT_LOGIN, tty);
  425.         }
  426. #endif    /* CONSOLE */
  427. #ifdef    FAILLOG
  428.         if (pwent.pw_name &&
  429.             ! failcheck (pwent.pw_uid, &faillog, failed)) {
  430.             syslog (LOG_CRIT, FAILURE_CNT, name, tty);
  431.             failed = 1;
  432.         }
  433. #endif    /* FAILLOG */
  434.         if (! failed)
  435.             break;
  436.  
  437.         puts ("Login incorrect");
  438.         if (rflg || fflg)
  439.             exit (1);
  440. #ifdef    FAILLOG
  441.         if (pwent.pw_name)    /* don't log non-existent users */
  442.             failure (pwent.pw_uid, tty, &faillog);
  443. #endif    /* FAILLOG */
  444. #ifdef FTMP
  445.         failent = utent;
  446.  
  447.         if (pwent.pw_name)
  448.             strncpy (failent.ut_name,
  449.                 pwent.pw_name, sizeof failent.ut_name);
  450.         else
  451. #ifdef    UNKNOWNS
  452.             strcpy (failent.ut_name, name);
  453. #else    /* !UNKNOWNS */
  454.             strcpy (failent.ut_name, "UNKNOWN");
  455. #endif    /* UNKNOWNS */
  456.         time (&failent.ut_time);
  457.         failent.ut_type = USER_PROCESS;
  458.  
  459.         failtmp (&failent);
  460. #endif /* FTMP */
  461.         if (--retries <= 0)    /* only allow so many failures */
  462.             exit (1);
  463.  
  464.         bzero (name, sizeof name);
  465.         bzero (pass, sizeof pass);
  466.     }
  467.     (void) alarm (0);        /* turn off alarm clock */
  468. #ifdef    NOLOGINS
  469.     /*
  470.      * Check to see if system is turned off for non-root users.
  471.      * This would be useful to prevent users from logging in
  472.      * during system maintenance.
  473.      */
  474.  
  475.     if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) {
  476.         FILE    *fp;
  477.         int    c;
  478.  
  479.         if (fp = fopen (NOLOGINS, "r")) {
  480.             while ((c = getc (fp)) != EOF) {
  481.                 if (c == '\n')
  482.                     putchar ('\r');
  483.  
  484.                 putchar (c);
  485.             }
  486.             fflush (stdout);
  487.             fclose (fp);
  488.         } else
  489.             printf ("\r\nSystem closed for routine maintenance\n");
  490.  
  491.         exit (0);
  492.     }
  493. #endif    /* NOLOGINS */
  494.     environ = newenvp;        /* make new environment active */
  495.  
  496.     if (getenv ("IFS"))        /* don't export user IFS ... */
  497.         addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  498.  
  499.     setutmp (name, tty);        /* make entry in utmp & wtmp files */
  500.     if (pwent.pw_shell[0] == '*') {    /* subsystem root */
  501.         subsystem (&pwent);    /* figure out what to execute */
  502.         subroot++;        /* say i was here again */
  503.         endpwent ();        /* close all of the file which were */
  504.         endgrent ();        /* open in the original rooted file */
  505.         endspent ();        /* system.  they will be re-opened */
  506.         endsgent ();        /* in the new rooted file system */
  507.         goto top;        /* go do all this all over again */
  508.     }
  509.  
  510. #ifdef    LASTLOG
  511.     log ();                /* give last login and log this one */
  512. #endif    /* LASTLOG */
  513.     setup (&pwent);            /* set UID, GID, HOME, etc ... */
  514. #ifdef    AGING
  515.     if (spwd) {            /* check for age of password */
  516.         if (expire (&pwent, spwd)) {
  517.             spwd = getspnam (name);
  518.             pwd = getpwnam (name);
  519.             pwent = *pwd;
  520.         }
  521.     }
  522. #ifdef    ATT_AGE
  523.     else if (pwent.pw_age && pwent.pw_age[0]) {
  524.         if (expire (&pwent, (void *) 0)) {
  525.             pwd = getpwnam (name);
  526.             pwent = *pwd;
  527.         }
  528.     }
  529. #endif    /* ATT_AGE */
  530. #endif    /* AGING */
  531. #ifdef    HUSHLOGIN
  532.     sprintf (hush, "%s/.hushlogin", pwent.pw_dir, 0);
  533.     hushed = access (hush, 0) == 0;
  534. #endif    /* HUSHLOGIN */
  535. #ifdef    MOTD
  536.     if (! hushed)
  537.         motd ();        /* print the message of the day */
  538. #endif
  539. #ifdef    FAILLOG
  540.     if (faillog.fail_cnt != 0)
  541.         failprint (pwent.pw_uid, &faillog);
  542. #endif    /* FAILLOG */
  543. #ifdef    LASTLOG
  544.     if (lastlog.ll_time != 0 && ! hushed)
  545.         printf ("Last login: %.19s on %s\n",
  546.             ctime (&lastlog.ll_time), lastlog.ll_line);
  547. #endif    /* LASTLOG */
  548. #ifdef    AGING
  549.     if (! hushed)
  550.         agecheck (&pwent, spwd);
  551. #endif    /* AGING */
  552. #ifdef    MAILCHECK
  553.     if (! hushed)
  554.         mailcheck ();        /* report on the status of mail */
  555. #endif    /* MAILCHECK */
  556. #ifdef    TTYTYPE
  557.     if (! pflg)
  558.         ttytype (tty);
  559. #endif    /* TTYTYPE */
  560.     signal (SIGINT, SIG_DFL);    /* default interrupt signal */
  561.     signal (SIGQUIT, SIG_DFL);    /* default quit signal */
  562.     signal (SIGTERM, SIG_DFL);    /* default terminate signal */
  563.     signal (SIGALRM, SIG_DFL);    /* default alarm signal */
  564.  
  565.     endpwent ();            /* stop access to password file */
  566.     endgrent ();            /* stop access to group file */
  567.     endspent ();            /* stop access to shadow passwd file */
  568.     endsgent ();            /* stop access to shadow group file */
  569.  
  570.     if (pwent.pw_uid == 0)
  571.         syslog (LOG_INFO, ROOT_LOGIN, tty);
  572.  
  573.     shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
  574.     /*NOTREACHED*/
  575. }
  576.