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

  1. /*
  2.  * Copyright 1989, 1990, 1991, 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 <stdio.h>
  14.  
  15. #ifndef    lint
  16. static    char    sccsid[] = "%W%    %U%    %G%";
  17. #endif
  18.  
  19. /*
  20.  * Set up some BSD defines so that all the BSD ifdef's are
  21.  * kept right here 
  22.  */
  23.  
  24. #ifndef    BSD
  25. #include <string.h>
  26. #include <memory.h>
  27. #define    bzero(a,n)    memset(a, 0, n)
  28. #include <termio.h>
  29. #else
  30. #include <strings.h>
  31. #include <sgtty.h>
  32. #define    strchr    index
  33. #define    strrchr    rindex
  34. #endif
  35.  
  36. #include <signal.h>
  37. #include <syslog.h>
  38. #include "config.h"
  39. #include "lastlog.h"
  40. #include "pwd.h"
  41. #include "shadow.h"
  42.  
  43. /*
  44.  * Password aging constants
  45.  *
  46.  *    DAY - seconds in a day
  47.  *    WEEK - seconds in a week
  48.  *    SCALE - convert from clock to aging units
  49.  */
  50.  
  51. #define    DAY    (24L*3600L)
  52. #define    WEEK    (7L*DAY)
  53.  
  54. #ifdef    ITI_AGING
  55. #define    SCALE    (1)
  56. #else
  57. #define    SCALE    DAY
  58. #endif
  59.  
  60. /*
  61.  * Assorted #defines to control su's behavior
  62.  */
  63.  
  64. #ifndef    MAXENV
  65. #define    MAXENV    128
  66. #endif
  67.  
  68. #ifndef    PATH
  69. #define    PATH    ":/bin:/usr/bin"
  70. #endif
  71.  
  72. #ifndef    SUPATH
  73. #define    SUPATH    ":/bin:/usr/bin:/etc"
  74. #endif
  75.  
  76. /*
  77.  * Global variables
  78.  */
  79.  
  80. #ifdef    HUSHLOGIN
  81. char    hush[BUFSIZ];
  82. int    hushed;
  83. #endif
  84.  
  85. char    name[BUFSIZ];
  86. char    pass[BUFSIZ];
  87. char    home[BUFSIZ];
  88. char    prog[BUFSIZ];
  89. char    mail[BUFSIZ];
  90. char    oldname[BUFSIZ];
  91. char    *newenvp[MAXENV];
  92. char    *Prog;
  93. int    newenvc = 0;
  94. int    maxenv = MAXENV;
  95. struct    passwd    pwent;
  96.  
  97. #ifdef    TZ
  98. FILE    *tzfile;
  99. char    tzbuf[16] = TZ;
  100. #endif
  101.  
  102. /*
  103.  * External identifiers
  104.  */
  105.  
  106. extern    void    addenv ();
  107. extern    void    entry ();
  108. extern    void    sulog ();
  109. extern    void    subsystem ();
  110. extern    void    setup ();
  111. extern    void    motd ();
  112. extern    void    mailcheck ();
  113. extern    void    shell ();
  114. extern    char    *ttyname ();
  115. extern    char    *getenv ();
  116. extern    char    *getpass ();
  117. extern    struct    passwd    *getpwuid ();
  118. extern    struct    passwd    *getpwnam ();
  119. extern    struct    spwd    *getspnam ();
  120. extern    char    **environ;
  121.  
  122. /*
  123.  * die - set or reset termio modes.
  124.  *
  125.  *    die() is called before processing begins.  signal() is then
  126.  *    called with die() as the signal handler.  If signal later
  127.  *    calls die() with a signal number, the terminal modes are
  128.  *    then reset.
  129.  */
  130.  
  131. void    die (killed)
  132. int    killed;
  133. {
  134. #ifdef    BSD
  135.     static    struct    sgtty    sgtty;
  136.  
  137.     if (killed)
  138.         stty (0, &sgtty);
  139.     else
  140.         gtty (0, &sgtty);
  141. #else
  142.     static    struct    termio    sgtty;
  143.  
  144.     if (killed)
  145.         ioctl (0, TCSETA, &sgtty);
  146.     else
  147.         ioctl (0, TCGETA, &sgtty);
  148. #endif
  149.     if (killed) {
  150.         closelog ();
  151.         exit (killed);
  152.     }
  153. }
  154.  
  155. /*
  156.  * su - switch user id
  157.  *
  158.  *    su changes the user's ids to the values for the specified user.
  159.  *    if no new user name is specified, "root" is used by default.
  160.  *
  161.  *    The only valid option is a "-" character, which is interpreted
  162.  *    as requiring a new login session to be simulated.
  163.  *
  164.  *    Any additional arguments are passed to the user's shell.  In
  165.  *    particular, the argument "-c" will cause the next argument to
  166.  *    be interpreted as a command by the common shell programs.
  167.  */
  168.  
  169. int    main (argc, argv, envp)
  170. int    argc;
  171. char    **argv;
  172. char    **envp;
  173. {
  174.     void    (*oldsig)();
  175.     char    *cp;
  176.     char    *tty = 0;        /* Name of tty SU is run from        */
  177.     int    doshell = 0;
  178.     int    fakelogin = 0;
  179.     int    amroot = 0;
  180.     struct    passwd    *pw = 0;
  181.     struct    spwd    *spwd = 0;
  182.  
  183.     /*
  184.      * Get the program name.  The program name is used as a
  185.      * prefix to most error messages.  It is also used as input
  186.      * to the openlog() function for error logging.
  187.      */
  188.  
  189.     if (Prog = strrchr (argv[0], '/'))
  190.         Prog++;
  191.     else
  192.         Prog = argv[0];
  193.  
  194.     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  195.  
  196.     /*
  197.      * Get the tty name.  Entries will be logged indicating that
  198.      * the user tried to change to the named new user from the
  199.      * current terminal.
  200.      */
  201.  
  202.     if (isatty (0) && (cp = ttyname (0))) {
  203.         if (strncmp (cp, "/dev/", 5) == 0)
  204.             tty = cp + 5;
  205.         else
  206.             tty = cp;
  207.     } else
  208.         tty = "???";
  209.  
  210.     /*
  211.      * Process the command line arguments. 
  212.      */
  213.  
  214.     argc--; argv++;            /* shift out command name */
  215.  
  216.     if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
  217.         fakelogin = 1;
  218.         argc--; argv++;        /* shift ... */
  219.     }
  220.  
  221.     /*
  222.      * If a new login is being set up, the old environment will
  223.      * be ignored and a new one created later on.
  224.      */
  225.  
  226.     if (! fakelogin)
  227.         while (*envp)
  228.             addenv (*envp++);
  229.  
  230. #ifdef    TZ
  231.  
  232.     /*
  233.      * The timezone will be reset to the login value if required.
  234.      */
  235.  
  236.     if (fakelogin) {
  237.         if (tzbuf[0] == '/') {
  238.             if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
  239.                 if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
  240.                     tzbuf[strlen (tzbuf) - 1] = '\0';
  241.                     addenv (tzbuf);
  242.                 }
  243.                 fclose (tzfile);
  244.             }
  245.         } else {
  246.             addenv (tzbuf);
  247.         }
  248.     }
  249. #endif    /* TZ */
  250. #ifdef    HZ
  251.  
  252.     /*
  253.      * The clock frequency will be reset to the login value if required
  254.      */
  255.  
  256.     if (fakelogin)
  257.         addenv (HZ);        /* set the default $HZ, if one */
  258. #endif    /* HZ */
  259.  
  260.     /*
  261.      * The next argument must be either a user ID, or some flag to
  262.      * a subshell.  Pretty sticky since you can't have an argument
  263.      * which doesn't start with a "-" unless you specify the new user
  264.      * name.  Any remaining arguments will be passed to the user's
  265.      * login shell.
  266.      */
  267.  
  268.     if (argc > 0 && argv[0][0] != '-') {
  269.         (void) strcpy (name, argv[0]);    /* use this login id */
  270.         argc--; argv++;        /* shift ... */
  271.     }
  272.     if (! name[0])             /* use default user ID */
  273.         (void) strcpy (name, "root");
  274.  
  275.     doshell = argc == 0;        /* any arguments remaining? */
  276.  
  277.     /*
  278.      * Get the user's real name.  The current UID is used to determine
  279.      * who has executed su.  That user ID must exist.
  280.      */
  281.  
  282.     if (pw = getpwuid (getuid ()))    /* need old user name */
  283.         (void) strcpy (oldname, pw->pw_name);
  284.     else {                /* user ID MUST exist */ 
  285.         syslog (LOG_CRIT, "Unknown UID: %d\n", getuid ());
  286.         goto failure;
  287.     }
  288.     amroot = getuid () == 0;    /* currently am super user */
  289.  
  290. top:
  291.     /*
  292.      * This is the common point for validating a user whose name
  293.      * is known.  It will be reached either by normal processing,
  294.      * or if the user is to be logged into a subsystem root.
  295.      *
  296.      * The password file entries for the user is gotten and the
  297.      * accont validated.
  298.      */
  299.  
  300.     if (pw = getpwnam (name)) {
  301.         if (spwd = getspnam (name))
  302.             pw->pw_passwd = spwd->sp_pwdp;
  303.     } else {
  304.         (void) fprintf (stderr, "Unknown id: %s\n", name);
  305.         closelog ();
  306.         exit (1);
  307.     }
  308.     pwent = *pw;
  309.  
  310. #ifdef    NOLOGIN
  311.  
  312.     /*
  313.      * See if the account is usable for anything but login.
  314.      */
  315.  
  316.     if (strcmp (pwent.pw_shell, NOLOGIN) == 0)
  317.         pwent.pw_shell = getenv ("SHELL");
  318. #endif    /* NOLOGIN */
  319.  
  320.     /*
  321.      * Set the default shell.
  322.      */
  323.  
  324.     if (pwent.pw_shell == 0 || pwent.pw_shell[0] == '\0')
  325.         pwent.pw_shell = "/bin/sh";
  326.  
  327.     /*
  328.      * Set up a signal handler in case the user types QUIT.
  329.      */
  330.  
  331.     die (0);
  332.     oldsig = signal (SIGQUIT, die);
  333.  
  334.     /*
  335.      * Get the password from the invoker
  336.      */
  337.  
  338.     if (! amroot && pwent.pw_passwd[0]) {
  339.         if (! (cp = getpass ("Password:"))) {
  340.             syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  341.                 "Unable to get password for %s\n", name);
  342.             goto failure;
  343.         } else
  344.             strncpy (pass, cp, sizeof pass);
  345.     } else
  346.         bzero (pass, sizeof pass);
  347.  
  348.     /*
  349.      * check encrypted passwords ...
  350.      */
  351.  
  352.     if (! amroot && ((pass[0] != '\0' || pwent.pw_passwd[0] != '\0') &&
  353.             strcmp (pwent.pw_passwd,
  354.                 pw_encrypt (pass, pwent.pw_passwd)) != 0)) {
  355.         syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  356.             "Invalid password for %s\n", name);
  357. failure:    sulog (0);        /* log failed attempt */
  358.         syslog (pwent.pw_uid ? LOG_INFO:LOG_CRIT,
  359.             "- %s %s-%s\n", tty ? tty:"???",
  360.             oldname[0] ? oldname:"???", name[0] ? name:"???");
  361.         puts ("Sorry.");
  362.         closelog ();
  363.         exit (1);
  364.     }
  365.     signal (SIGQUIT, oldsig);
  366.  
  367.     /*
  368.      * Check to see if the account is expired.  root gets to
  369.      * ignore any expired accounts, but normal users can't become
  370.      * a user with an expired password.
  371.      */
  372.  
  373.     if (! amroot) {
  374.         if (spwd) {
  375.             if (isexpired (&pwent, spwd)) {
  376.                 syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  377.                     "Expired account %s\n", name);
  378.                 goto failure;
  379.             }
  380.         }
  381. #ifdef    ATT_AGE
  382.         else if (pwent.pw_age[0] &&
  383.                 isexpired (&pwent, (struct spwd *) 0)) {
  384.             syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  385.                 "Expired account %s\n", name);
  386.             goto failure;
  387.         }
  388. #endif    /* ATT_AGE */
  389.     }
  390.     if (pwent.pw_uid == 0)
  391.         addenv (SUPATH);
  392.     else
  393.         addenv (PATH);
  394.  
  395.     environ = newenvp;        /* make new environment active */
  396.  
  397.     if (getenv ("IFS"))        /* don't export user IFS ... */
  398.         addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  399.  
  400.     if (doshell && pwent.pw_shell[0] == '*') { /* subsystem root required */
  401.         subsystem (&pwent);    /* figure out what to execute */
  402.         endpwent ();
  403.         endspent ();
  404.         goto top;
  405.     }
  406.  
  407.     sulog (1);            /* save SU information */
  408.     syslog (LOG_INFO, "+ %s %s-%s\n", tty ? tty:"???",
  409.         oldname[0] ? oldname:"???", name[0] ? name:"???");
  410.  
  411.     if (fakelogin)
  412.         setup (&pwent);        /* set UID, GID, HOME, etc ... */
  413.     else {
  414.         if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid))  {
  415.             perror ("Can't set ID");
  416.             syslog (LOG_CRIT, "Unable to set uid = %d, gid = %d\n",
  417.                 pwent.pw_uid, pwent.pw_gid);
  418.             closelog ();
  419.             exit (1);
  420.         }
  421.     }
  422.     if (! doshell) {        /* execute arguments as command */
  423.         if (cp = getenv ("SHELL"))
  424.             pwent.pw_shell = cp;
  425.         argv[-1] = pwent.pw_shell;
  426.         (void) execv (pwent.pw_shell, &argv[-1]);
  427.         (void) fprintf (stderr, "No shell\n");
  428.         syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  429.         closelog ();
  430.         exit (1);
  431.     }
  432.     if (fakelogin) {
  433. #ifdef    HUSHLOGIN
  434.         sprintf (hush, "%s/.hushlogin", pwent.pw_dir);
  435.         hushed = access (hush, 0) != -1;
  436. #endif    /* HUSHLOGIN */
  437. #ifdef    MOTD
  438.         motd ();        /* print the message of the day */
  439. #endif    /* MOTD */
  440. #ifdef    MAILCHECK
  441.         if (! hushed)
  442.             mailcheck ();    /* report on the status of mail */
  443. #endif    /* MAILCHECK */
  444.         shell (pwent.pw_shell, "-su"); /* exec the shell finally. */
  445.     } else {
  446.         if (cp = strrchr (pwent.pw_shell, '/'))
  447.             cp++;
  448.         else
  449.             cp = pwent.pw_shell;
  450.  
  451.         shell (pwent.pw_shell, cp);
  452.     }
  453.     syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  454.  
  455.     /*NOTREACHED*/
  456. }
  457.