home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / port.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-28  |  8.8 KB  |  409 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 <stdio.h>
  13. #include <time.h>
  14. #include <sys/types.h>
  15. #include <ctype.h>
  16. #include <errno.h>
  17. #ifndef    BSD
  18. #include <string.h>
  19. #else
  20. #include <strings.h>
  21. #define    strchr    index
  22. #define    strrchr    rindex
  23. #endif
  24. #include "port.h"
  25.  
  26. #ifndef    lint
  27. static    char    _sccsid[] = "@(#)port.c    3.2    11:58:29    12/28/91";
  28. #endif
  29.  
  30. extern    int    errno;
  31.  
  32. static    FILE    *ports;
  33.  
  34. /*
  35.  * setportent - open /etc/porttime file or rewind
  36.  *
  37.  *    the /etc/porttime file is rewound if already open, or
  38.  *    opened for reading.
  39.  */
  40.  
  41. void
  42. setportent ()
  43. {
  44.     if (ports)
  45.         rewind (ports);
  46.     else 
  47.         ports = fopen (PORTS, "r");
  48. }
  49.  
  50. /*
  51.  * endportent - close the /etc/porttime file
  52.  *
  53.  *    the /etc/porttime file is closed and the ports variable set
  54.  *    to NULL to indicate that the /etc/porttime file is no longer
  55.  *    open.
  56.  */
  57.  
  58. void
  59. endportent ()
  60. {
  61.     if (ports)
  62.         fclose (ports);
  63.  
  64.     ports = (FILE *) 0;
  65. }
  66.  
  67. /*
  68.  * getportent - read a single entry from /etc/porttime
  69.  *
  70.  *    the next line in /etc/porttime is converted to a (struct port)
  71.  *    and a pointer to a static (struct port) is returned to the
  72.  *    invoker.  NULL is returned on either EOF or error.  errno is
  73.  *    set to EINVAL on error to distinguish the two conditions.
  74.  */
  75.  
  76. struct port *
  77. getportent ()
  78. {
  79.     static    struct    port    port;    /* static struct to point to         */
  80.     static    char    buf[BUFSIZ];    /* some space for stuff              */
  81.     static    char    *ttys[PORT_TTY+1]; /* some pointers to tty names     */
  82.     static    char    *users[PORT_IDS+1]; /* some pointers to user ids     */
  83.     static    struct    pt_time    times[PORT_TIMES+1]; /* time ranges          */
  84.     char    *cp;            /* pointer into line                 */
  85.     int    time;            /* scratch time of day               */
  86.     int    i, j;
  87.     int    saveerr = errno;    /* errno value on entry              */
  88.  
  89.     /*
  90.      * If the ports file is not open, open the file.  Do not rewind
  91.      * since we want to search from the beginning each time.
  92.      */
  93.  
  94.     if (! ports)
  95.         setportent ();
  96.  
  97.     if (! ports) {
  98.         errno = saveerr;
  99.         return 0;
  100.     }
  101.  
  102.     /*
  103.      * Common point for beginning a new line -
  104.      *
  105.      *    - read a line, and NUL terminate
  106.      *    - skip lines which begin with '#'
  107.      *    - parse off the tty names
  108.      *    - parse off a list of user names
  109.      *    - parse off a list of days and times
  110.      */
  111.  
  112. again:
  113.  
  114.     /*
  115.      * Get the next line and remove the last character, which
  116.      * is a '\n'.  Lines which begin with '#' are all ignored.
  117.      */
  118.  
  119.     if (fgets (buf, BUFSIZ, ports) == 0) {
  120.         errno = saveerr;
  121.         return 0;
  122.     }
  123.     if (buf[0] == '#')
  124.         goto again;
  125.  
  126.     /*
  127.      * Get the name of the TTY device.  It is the first colon
  128.      * separated field, and is the name of the TTY with no
  129.      * leading "/dev".  The entry '*' is used to specify all
  130.      * TTY devices.
  131.      */
  132.  
  133.     buf[strlen (buf) - 1] = 0;
  134.  
  135.     port.pt_names = ttys;
  136.     for (cp = buf, j = 0;j < PORT_TTY;j++) {
  137.         port.pt_names[j] = cp;
  138.         while (*cp && *cp != ':' && *cp != ',')
  139.             cp++;
  140.  
  141.         if (! *cp)
  142.             goto again;    /* line format error */
  143.  
  144.         if (*cp == ':')        /* end of tty name list */
  145.             break;
  146.  
  147.         if (*cp == ',')        /* end of current tty name */
  148.             *cp++ = '\0';
  149.     }
  150.     *cp++ = 0;
  151.     port.pt_names[j + 1] = (char *) 0;
  152.  
  153.     /*
  154.      * Get the list of user names.  It is the second colon
  155.      * separated field, and is a comma separated list of user
  156.      * names.  The entry '*' is used to specify all usernames.
  157.      * The last entry in the list is a (char *) 0 pointer.
  158.      */
  159.  
  160.     if (*cp != ':') {
  161.         port.pt_users = users;
  162.         port.pt_users[0] = cp;
  163.  
  164.         for (j = 1;*cp != ':';cp++) {
  165.             if (*cp == ',' && j < PORT_IDS) {
  166.                 *cp++ = 0;
  167.                 port.pt_users[j++] = cp;
  168.             }
  169.         }
  170.         port.pt_users[j] = 0;
  171.     } else
  172.         port.pt_users = 0;
  173.  
  174.     if (*cp != ':')
  175.         goto again;
  176.  
  177.     *cp++ = 0;
  178.  
  179.     /*
  180.      * Get the list of valid times.  The times field is the third
  181.      * colon separated field and is a list of days of the week and
  182.      * times during which this port may be used by this user.  The
  183.      * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
  184.      *
  185.      * In addition, the value 'Al' represents all 7 days, and 'Wk'
  186.      * represents the 5 weekdays.
  187.      *
  188.      * Times are given as HHMM-HHMM.  The ending time may be before
  189.      * the starting time.  Days are presumed to wrap at 0000.
  190.      */
  191.  
  192.     if (*cp == '\0') {
  193.         port.pt_times = 0;
  194.         return &port;
  195.     }
  196.  
  197.     port.pt_times = times;
  198.  
  199.     /*
  200.      * Get the next comma separated entry
  201.      */
  202.  
  203.     for (j = 0;*cp && j < PORT_TIMES;j++) {
  204.  
  205.         /*
  206.          * Start off with no days of the week
  207.          */
  208.  
  209.         port.pt_times[j].t_days = 0;
  210.  
  211.         /*
  212.          * Check each two letter sequence to see if it is
  213.          * one of the abbreviations for the days of the
  214.          * week or the other two values.
  215.          */
  216.  
  217.         for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
  218.             switch ((cp[i] << 8) | (cp[i + 1])) {
  219.                 case ('S' << 8) | 'u':
  220.                     port.pt_times[j].t_days |= 01;
  221.                     break;
  222.                 case ('M' << 8) | 'o':
  223.                     port.pt_times[j].t_days |= 02;
  224.                     break;
  225.                 case ('T' << 8) | 'u':
  226.                     port.pt_times[j].t_days |= 04;
  227.                     break;
  228.                 case ('W' << 8) | 'e':
  229.                     port.pt_times[j].t_days |= 010;
  230.                     break;
  231.                 case ('T' << 8) | 'h':
  232.                     port.pt_times[j].t_days |= 020;
  233.                     break;
  234.                 case ('F' << 8) | 'r':
  235.                     port.pt_times[j].t_days |= 040;
  236.                     break;
  237.                 case ('S' << 8) | 'a':
  238.                     port.pt_times[j].t_days |= 0100;
  239.                     break;
  240.                 case ('W' << 8) | 'k':
  241.                     port.pt_times[j].t_days |= 076;
  242.                     break;
  243.                 case ('A' << 8) | 'l':
  244.                     port.pt_times[j].t_days |= 0177;
  245.                     break;
  246.                 default:
  247.                     errno = EINVAL;
  248.                     return 0;
  249.             }
  250.         }
  251.  
  252.         /*
  253.          * The default is 'Al' if no days were seen.
  254.          */
  255.  
  256.         if (i == 0)
  257.             port.pt_times[j].t_days = 0177;
  258.  
  259.         /*
  260.          * The start and end times are separated from each
  261.          * other by a '-'.  The times are four digit numbers
  262.          * representing the times of day.
  263.          */
  264.  
  265.         for (time = 0;cp[i] && isdigit (cp[i]);i++)
  266.             time = time * 10 + cp[i] - '0';
  267.  
  268.         if (cp[i] != '-' || time > 2400 || time % 100 > 59)
  269.             goto again;
  270.         port.pt_times[j].t_start = time;
  271.         cp = cp + i + 1;
  272.  
  273.         for (time = i = 0;cp[i] && isdigit (cp[i]);i++)
  274.             time = time * 10 + cp[i] - '0';
  275.  
  276.         if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59)
  277.             goto again;
  278.  
  279.         port.pt_times[j].t_end = time;
  280.         cp = cp + i + 1;
  281.     }
  282.  
  283.     /*
  284.      * The end of the list is indicated by a pair of -1's for the
  285.      * start and end times.
  286.      */
  287.  
  288.     port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
  289.  
  290.     return &port;
  291. }
  292.  
  293. /*
  294.  * getttyuser - get ports information for user and tty
  295.  *
  296.  *    getttyuser() searches the ports file for an entry with a TTY
  297.  *    and user field both of which match the supplied TTY and
  298.  *    user name.  The file is searched from the beginning, so the
  299.  *    entries are treated as an ordered list.
  300.  */
  301.  
  302. struct port *
  303. getttyuser (tty, user)
  304. char    *tty;
  305. char    *user;
  306. {
  307.     int    i, j;
  308.     struct    port    *port;
  309.  
  310.     setportent ();
  311.  
  312.     while (port = getportent ()) {
  313.         if (port->pt_names == 0 || port->pt_users == 0)
  314.             continue;
  315.  
  316.         for (i = 0;port->pt_names[i];i++)
  317.             if (strcmp (port->pt_names[i], tty) == 0 ||
  318.                     strcmp (port->pt_names[i], "*") == 0)
  319.                 break;
  320.  
  321.         if (port->pt_names[i] == 0)
  322.             continue;
  323.  
  324.         for (j = 0;port->pt_users[j];j++)
  325.             if (strcmp (user, port->pt_users[j]) == 0 ||
  326.                     strcmp (port->pt_users[j], "*") == 0)
  327.                 break;
  328.  
  329.         if (port->pt_users[j] != 0)
  330.             break;
  331.     }
  332.     endportent ();
  333.     return port;
  334. }
  335.  
  336. /*
  337.  * isttytime - tell if a given user may login at a particular time
  338.  *
  339.  *    isttytime searches the ports file for an entry which matches
  340.  *    the user name and TTY given.
  341.  */
  342.  
  343. int
  344. isttytime (id, port, clock)
  345. char    *id;
  346. char    *port;
  347. long    clock;
  348. {
  349.     int    i;
  350.     int    time;
  351.     struct    port    *pp;
  352.     struct    tm    *tm,
  353.             *localtime();
  354.  
  355.     /*
  356.      * Try to find a matching entry for this user.  Default to
  357.      * letting the user in - there are pleny of ways to have an
  358.      * entry to match all users.
  359.      */
  360.  
  361.     if (! (pp = getttyuser (port, id)))
  362.         return 1;
  363.  
  364.     /*
  365.      * The entry is there, but has not time entries - don't
  366.      * ever let them login.
  367.      */
  368.  
  369.     if (pp->pt_times == 0)
  370.         return 0;
  371.  
  372.     /*
  373.      * The current time is converted to HHMM format for
  374.      * comparision against the time values in the TTY entry.
  375.      */
  376.  
  377.     tm = localtime (&clock);
  378.     time = tm->tm_hour * 100 + tm->tm_min;
  379.  
  380.     /*
  381.      * Each time entry is compared against the current
  382.      * time.  For entries with the start after the end time,
  383.      * the comparision is made so that the time is between
  384.      * midnight and either the start or end time.
  385.      */
  386.  
  387.     for (i = 0;pp->pt_times[i].t_start != -1;i++) {
  388.         if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
  389.             continue;
  390.  
  391.         if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
  392.             if (time >= pp->pt_times[i].t_start &&
  393.                     time <= pp->pt_times[i].t_end)
  394.                 return 1;
  395.         } else {
  396.             if (time >= pp->pt_times[i].t_start ||
  397.                     time <= pp->pt_times[i].t_end)
  398.                 return 1;
  399.         }
  400.     }
  401.  
  402.     /*
  403.      * No matching time entry was found, user shouldn't
  404.      * be let in right now.
  405.      */
  406.  
  407.     return 0;
  408. }
  409.