home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Networking / wu-ftpd-2.4.2b13-MIHS / src / access.c next >
Encoding:
C/C++ Source or Header  |  1997-03-03  |  25.9 KB  |  911 lines

  1. /* Copyright (c) 1993, 1994  Washington University in Saint Louis
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met: 1. Redistributions of source code must retain the above copyright
  7.  * notice, this list of conditions and the following disclaimer. 2.
  8.  * Redistributions in binary form must reproduce the above copyright notice,
  9.  * this list of conditions and the following disclaimer in the documentation
  10.  * and/or other materials provided with the distribution. 3. All advertising
  11.  * materials mentioning features or use of this software must display the
  12.  * following acknowledgement: This product includes software developed by the
  13.  * Washington University in Saint Louis and its contributors. 4. Neither the
  14.  * name of the University nor the names of its contributors may be used to
  15.  * endorse or promote products derived from this software without specific
  16.  * prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY WASHINGTON UNIVERSITY AND CONTRIBUTORS
  19.  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21.  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASHINGTON
  22.  * UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  26.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  28.  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29.  * POSSIBILITY OF SUCH DAMAGE.
  30.  */
  31.  
  32. #ifndef lint
  33. static char rcsid[] = "@(#)$Id: access.c,v 1.11 1997/03/03 09:39:42 sob Exp sob $";
  34. #endif /* not lint */
  35.  
  36. #include "config.h"
  37.  
  38. #include <stdio.h>
  39. #include <errno.h>
  40. #include <string.h>
  41. #ifdef SYSSYSLOG
  42. #include <sys/syslog.h>
  43. #else
  44. #include <syslog.h>
  45. #endif
  46. #include <time.h>
  47. #include <ctype.h>
  48. #include <pwd.h>
  49. #include <grp.h>
  50.  
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include <sys/file.h>
  54. #include <sys/param.h>
  55.  
  56. #include "pathnames.h"
  57. #include "extensions.h"
  58.  
  59. #if defined(SVR4) || defined(ISC)
  60. #include <fcntl.h>
  61. #endif
  62.  
  63. extern char remotehost[],
  64.   remoteaddr[],
  65.  *aclbuf;
  66. extern int nameserved,
  67.   anonymous,
  68.   guest,
  69.   use_accessfile;
  70. char Shutdown[MAXPATHLEN];
  71. #define MAXLINE    80
  72. static  char  incline[MAXLINE];
  73. int pidfd = -1;
  74.  
  75. extern int fnmatch();
  76.  
  77. /*************************************************************************/
  78. /* FUNCTION  : parse_time                                                */
  79. /* PURPOSE   : Check a single valid-time-string against the current time */
  80. /*             and return whether or not a match occurs.                 */
  81. /* ARGUMENTS : a pointer to the time-string                              */
  82. /*************************************************************************/
  83.  
  84. int
  85. #ifdef __STDC__
  86. parsetime(char *whattime)
  87. #else
  88. parsetime(whattime)
  89. char *whattime;
  90. #endif
  91. {
  92.     static char *days[] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk"};
  93.     time_t clock;
  94.     struct tm *curtime;
  95.     int wday,
  96.       start,
  97.       stop,
  98.       ltime,
  99.       validday,
  100.       loop,
  101.       match;
  102.  
  103.     (void) time(&clock);
  104.     curtime = localtime(&clock);
  105.     wday = curtime->tm_wday;
  106.     validday = 0;
  107.     match = 1;
  108.  
  109.     while (match && isalpha(*whattime) && isupper(*whattime)) {
  110.         match = 0;
  111.         for (loop = 0; loop < 8; loop++) {
  112.             if (strncmp(days[loop], whattime, 2) == 0) {
  113.                 whattime += 2;
  114.                 match = 1;
  115.                 if ((wday == loop) || ((loop == 7) && wday && (wday < 6))) {
  116.                     validday = 1;
  117.                 }
  118.             }
  119.         }
  120.     }
  121.  
  122.     if (!validday){
  123.       if (strncmp(whattime, "Any", 3) == 0) {
  124.             validday = 1;
  125.             whattime += 3;
  126.       }
  127.     }else
  128.         return (0);
  129.  
  130.     if (sscanf(whattime, "%d-%d", &start, &stop) == 2) {
  131.         ltime = curtime->tm_min + 100 * curtime->tm_hour;
  132.         if ((start < stop) && ((ltime > start) && ltime < stop))
  133.             return (1);
  134.         if ((start > stop) && ((ltime > start) || ltime < stop))
  135.             return (1);
  136.     } else
  137.         return (1);
  138.  
  139.     return (0);
  140. }
  141.  
  142. /*************************************************************************/
  143. /* FUNCTION  : validtime                                                 */
  144. /* PURPOSE   : Break apart a set of valid time-strings and pass them to  */
  145. /*             parse_time, returning whether or not ANY matches occurred */
  146. /* ARGUMENTS : a pointer to the time-string                              */
  147. /*************************************************************************/
  148.  
  149. int
  150. #ifdef __STDC__
  151. validtime(char *ptr)
  152. #else
  153. validtime(ptr)
  154. char *ptr;
  155. #endif
  156. {
  157.     char *nextptr;
  158.     int good;
  159.  
  160.     while (1) {
  161.         nextptr = strchr(ptr, '|');
  162.         if (strchr(ptr, '|') == NULL)
  163.             return (parsetime(ptr));
  164.         *nextptr = '\0';
  165.         good = parsetime(ptr);
  166.         /* gotta restore the | or things get skipped! */
  167.         *nextptr++ = '|';
  168.         if (good)
  169.             return (1);
  170.         ptr = nextptr;
  171.     }
  172. }
  173.  
  174. /*************************************************************************/
  175. /* FUNCTION  : hostmatch                                                 */
  176. /* PURPOSE   : Match remote hostname or address against a glob string    */
  177. /* ARGUMENTS : The string to match                                       */
  178. /* RETURNS   : 0 if no match, 1 if a match occurs                        */
  179. /*************************************************************************/
  180.  
  181. #ifdef __STDC__
  182. hostmatch(char *addr)
  183. #else
  184. hostmatch(addr)
  185. char *addr;
  186. #endif
  187. {
  188.     FILE  *incfile;
  189.     char  *ptr;
  190.     int   found = 0;
  191.  
  192.     if (addr == NULL) return(0);
  193.  
  194.     if (isdigit(*addr))
  195.         return(!fnmatch(addr, remoteaddr, NULL));
  196.     else if (*addr == '/') {
  197.         /*
  198.          * read addrglobs from named path using similar format as addrglobs
  199.          * in access file
  200.          */
  201.         if ((incfile = fopen(addr, "r")) == NULL) {
  202.             if (errno != ENOENT) syslog(LOG_ERR,
  203.                 "cannot open addrglob file %s: %s", addr, strerror(errno));
  204.             return(0);
  205.         }
  206.         
  207.         while (!found && (fgets(incline, MAXLINE, incfile) != NULL)) {
  208.             ptr = strtok(incline, " \t\n");
  209.             if (ptr && hostmatch(ptr))
  210.                 found = 1;
  211.             while (!found && ((ptr = strtok(NULL, " \t\n")) != NULL)) {
  212.                 if (ptr && hostmatch(ptr))
  213.                     found = 1;
  214.             }
  215.         }
  216.         fclose(incfile);
  217.         return(found);
  218.     }
  219.     else
  220.       {   /* match a hostname or hostname glob */
  221.         char *addrncase,*hostncase;
  222.         int i,j;
  223.         /* must convert both to lower case for match */
  224.         if ((addrncase = (char *)malloc(strlen(addr)+1)) == NULL)
  225.           return(0);
  226.         if ((hostncase = (char *)malloc(strlen(remotehost)+1)) == NULL){
  227.       free(addrncase);
  228.           return(0);
  229.     }
  230.         j = strlen(addr) + 1;
  231.         for (i = 0;i < j; i++)
  232.           addrncase[i] = tolower(addr[i]);
  233.         j = strlen(remotehost) + 1;
  234.         for (i = 0;i < j; i++)
  235.           hostncase[i] = tolower(remotehost[i]);
  236.         found = !fnmatch(addrncase, hostncase, NULL); 
  237.         free(addrncase);
  238.         free(hostncase);
  239.         return(found);
  240.       }
  241.  
  242. }
  243.  
  244. /*************************************************************************/
  245. /* FUNCTION  : acl_guestgroup                                            */
  246. /* PURPOSE   : If the real user is a member of any of the listed groups, */
  247. /*             return 1.  Otherwise return 0.                            */
  248. /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
  249. /*************************************************************************/
  250.  
  251. int
  252. #ifdef __STDC__
  253. acl_guestgroup(struct passwd *pw)
  254. #else
  255. acl_guestgroup(pw)
  256. struct passwd *pw;
  257. #endif
  258. {
  259.     struct aclmember *entry = NULL;
  260.     struct group *grp;
  261.     int which;
  262.     char **member;
  263.  
  264.     /* guestgroup <group> [<group> ...] */
  265.     while (getaclentry("guestgroup", &entry)) {
  266.         for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
  267.             if (!(grp = getgrnam(ARG[which])))
  268.                 continue;
  269.             if (pw->pw_gid == grp->gr_gid)
  270.                 return (1);
  271.             for (member = grp->gr_mem; *member; member++) {
  272.                 if (!strcmp(*member, pw->pw_name))
  273.                     return (1);
  274.             }
  275.         }
  276.     }
  277.     return (0);
  278. }
  279.  
  280. /*************************************************************************/
  281. /* FUNCTION  : acl_autogroup                                             */
  282. /* PURPOSE   : If the guest user is a member of any of the classes in    */
  283. /*             the autogroup comment, cause a setegid() to the specified */
  284. /*             group.                                                    */
  285. /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
  286. /*************************************************************************/
  287.  
  288. void
  289. #ifdef __STDC__
  290. acl_autogroup(struct passwd *pw)
  291. #else
  292. acl_autogroup(pw)
  293. struct passwd *pw;
  294. #endif
  295. {
  296.     char class[1024];
  297.  
  298.     struct aclmember *entry = NULL;
  299.     struct group *grp;
  300.     int which;
  301.  
  302.     (void) acl_getclass(class);
  303.  
  304.     /* autogroup <group> <class> [<class> ...] */
  305.     while (getaclentry("autogroup", &entry)) {
  306.         if (!ARG0 || !ARG1)
  307.             continue;
  308.         if ((grp = getgrnam(ARG0))) {
  309.             for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
  310.                 if (!strcmp(ARG[which], class)) {
  311.                     pw->pw_gid = grp->gr_gid;
  312.                     endgrent();
  313.                     return;
  314.                 }
  315.             }
  316.         } else
  317.             syslog(LOG_ERR, "autogroup: set group %s not found", ARG0);
  318.         endgrent();
  319.     }
  320. }
  321.  
  322. /*************************************************************************/
  323. /* FUNCTION  : acl_setfunctions                                          */
  324. /* PURPOSE   : Scan the ACL buffer and determine what logging to perform */
  325. /*             for this user, and whether or not user is allowed to use  */
  326. /*             the automatic TAR and COMPRESS functions.                 */
  327. /* ARGUMENTS : pointer to buffer to class name, pointer to ACL buffer    */
  328. /*************************************************************************/
  329.  
  330. void
  331. #ifdef __STDC__
  332. acl_setfunctions(void)
  333. #else
  334. acl_setfunctions()
  335. #endif
  336. {
  337.     char class[1024];
  338.  
  339.     extern int log_incoming_xfers,
  340.       log_outbound_xfers,
  341.       mangleopts,
  342.       log_commands,
  343.       lgi_failure_threshold;
  344.  
  345.     struct aclmember *entry = NULL;
  346.  
  347.     int l_compress = 0,
  348.       l_tar = 0,
  349.       inbound = 0,
  350.       outbound = 0,
  351.       which,
  352.       set;
  353.  
  354.     log_incoming_xfers = 0;
  355.     log_outbound_xfers = 0;
  356.     log_commands = 0;
  357.  
  358.     memset((void *)&class, 0, sizeof(class));
  359.  
  360.     (void) acl_getclass(class);
  361.  
  362.     entry = (struct aclmember *) NULL;
  363.     if (getaclentry("loginfails", &entry) && ARG0 != NULL) {
  364.         lgi_failure_threshold = atoi(ARG0);
  365.     }
  366. #ifndef NO_PRIVATE
  367.     entry = (struct aclmember *) NULL;
  368.     if (getaclentry("private", &entry) && !strcmp(ARG0, "yes"))
  369.         priv_setup(_PATH_PRIVATE);
  370. #endif /* !NO_PRIVATE */
  371.  
  372.     entry = (struct aclmember *) NULL;
  373.     set = 0;
  374.     while (!set && getaclentry("compress", &entry)) {
  375.         if (!strcasecmp(ARG0, "yes"))
  376.             l_compress = 1;
  377.         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
  378.             if (!fnmatch(ARG[which], class, NULL)) {
  379.                 mangleopts |= l_compress * (O_COMPRESS | O_UNCOMPRESS);
  380.                 set = 1;
  381.             }
  382.         }
  383.     }
  384.  
  385.     entry = (struct aclmember *) NULL;
  386.     set = 0;
  387.     while (!set && getaclentry("tar", &entry)) {
  388.         if (!strcasecmp(ARG0, "yes"))
  389.             l_tar = 1;
  390.         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
  391.             if (!fnmatch(ARG[which], class, NULL)) {
  392.                 mangleopts |= l_tar * O_TAR;
  393.                 set = 1;
  394.             }
  395.         }
  396.     }
  397.  
  398.     /* plan on expanding command syntax to include classes for each of these */
  399.  
  400.     entry = (struct aclmember *) NULL;
  401.     while (getaclentry("log", &entry)) {
  402.         if (!strcasecmp(ARG0, "commands")) {
  403.             if (anonymous && strcasestr(ARG1, "anonymous"))
  404.                 log_commands = 1;
  405.             if (guest && strcasestr(ARG1, "guest"))
  406.                 log_commands = 1;
  407.             if (!guest && !anonymous && strcasestr(ARG1, "real"))
  408.                 log_commands = 1;
  409.         }
  410.         if (!strcasecmp(ARG0, "transfers")) {
  411.             set = 0;
  412.             if (strcasestr(ARG1, "anonymous") && anonymous)
  413.                 set = 1;
  414.             if (strcasestr(ARG1, "guest") && guest)
  415.                 set = 1;
  416.             if (strcasestr(ARG1, "real") && !guest && !anonymous)
  417.                 set = 1;
  418.             if (strcasestr(ARG2, "inbound"))
  419.                 inbound = 1;
  420.             if (strcasestr(ARG2, "outbound"))
  421.                 outbound = 1;
  422.             if (set)
  423.                 log_incoming_xfers = inbound;
  424.             if (set)
  425.                 log_outbound_xfers = outbound;
  426.         }
  427.     }
  428. }
  429.  
  430. /*************************************************************************/
  431. /* FUNCTION  : acl_getclass                                              */
  432. /* PURPOSE   : Scan the ACL buffer and determine what class user is in   */
  433. /* ARGUMENTS : pointer to buffer to class name, pointer to ACL buffer    */
  434. /*************************************************************************/
  435.  
  436. int
  437. #ifdef __STDC__
  438. acl_getclass(char *classbuf)
  439. #else
  440. acl_getclass(classbuf)
  441. char *classbuf;
  442. #endif
  443. {
  444.     int which;
  445.     struct aclmember *entry = NULL;
  446.  
  447.     while (getaclentry("class", &entry)) {
  448.         if (ARG0)
  449.             strcpy(classbuf, ARG0);
  450.  
  451.         for (which = 2; (which < MAXARGS) && ARG[which]; which++) {
  452.             if (anonymous && strcasestr(ARG1, "anonymous") &&
  453.                 hostmatch(ARG[which]))
  454.                 return (1);
  455.  
  456.             if (guest && strcasestr(ARG1, "guest") && hostmatch(ARG[which]))
  457.                 return (1);
  458.  
  459.             if (!guest && !anonymous && strcasestr(ARG1, "real") &&
  460.                 hostmatch(ARG[which]))
  461.                 return (1);
  462.         }
  463.     }
  464.  
  465.     *classbuf = (char) NULL;
  466.     return (0);
  467.  
  468. }
  469.  
  470. /*************************************************************************/
  471. /* FUNCTION  : acl_getlimit                                              */
  472. /* PURPOSE   : Scan the ACL buffer and determine what limit applies to   */
  473. /*             the user                                                  */
  474. /* ARGUMENTS : pointer class name, pointer to ACL buffer                 */
  475. /*************************************************************************/
  476.  
  477. int
  478. #ifdef __STDC__
  479. acl_getlimit(char *class, char *msgpathbuf)
  480. #else
  481. acl_getlimit(class,msgpathbuf)
  482. char *class;
  483. char *msgpathbuf;
  484. #endif
  485. {
  486.     int limit;
  487.     struct aclmember *entry = NULL;
  488.  
  489.     if (msgpathbuf)
  490.         *msgpathbuf = '\0';
  491.  
  492.     /* limit <class> <n> <times> [<message_file>] */
  493.     while (getaclentry("limit", &entry)) {
  494.         if (!ARG0 || !ARG1 || !ARG2)
  495.             continue;
  496.         if (!strcmp(class, ARG0)) {
  497.             limit = atoi(ARG1);
  498.             if (validtime(ARG2)) {
  499.                 if (ARG3 && msgpathbuf)
  500.                     strcpy(msgpathbuf, ARG3);
  501.                 return (limit);
  502.             }
  503.         }
  504.     }
  505.     return (-1);
  506. }
  507.  
  508. /*************************************************************************/
  509. /* FUNCTION  : acl_deny                                                  */
  510. /* PURPOSE   : Scan the ACL buffer and determine a deny command applies  */
  511. /* ARGUMENTS : pointer class name, pointer to ACL buffer                 */
  512. /*************************************************************************/
  513.  
  514. int
  515. #ifdef __STDC__
  516. acl_deny(char *msgpathbuf)
  517. #else
  518. acl_deny(msgpathbuf)
  519. char *msgpathbuf;
  520. #endif
  521. {
  522.     struct aclmember *entry = NULL;
  523.  
  524.     if (msgpathbuf)
  525.         *msgpathbuf = (char) NULL;
  526.  
  527.     /* deny <addrglob> [<message_file>] */
  528.     while (getaclentry("deny", &entry)) {
  529.         if (!ARG0)
  530.             continue;
  531.         if (!nameserved && !strcmp(ARG0, "!nameserved")) {
  532.             if (ARG1)
  533.                 strcpy(msgpathbuf, entry->arg[1]);
  534.             return (1);
  535.         }
  536.         if (hostmatch(ARG0)) {
  537.             if (ARG1)
  538.                 strcpy(msgpathbuf, entry->arg[1]);
  539.             return (1);
  540.         }
  541.     }
  542.     return (0);
  543. }
  544.  
  545. /*************************************************************************/
  546. /* FUNCTION  : acl_countusers                                            */
  547. /* PURPOSE   : Check the anonymous FTP access lists to see if this       */
  548. /*             access is permitted.                                      */
  549. /* ARGUMENTS : none                                                      */
  550. /*************************************************************************/
  551.  
  552. int
  553. #ifdef __STDC__
  554. acl_countusers(char *class)
  555. #else
  556. acl_countusers(class)
  557. char *class;
  558. #endif
  559. {
  560.     int count,
  561.       which;
  562.     char pidfile[MAXPATHLEN];
  563.     pid_t buf[MAXUSERS];
  564. #ifndef HAVE_FLOCK
  565. struct flock arg;
  566. #endif
  567.  
  568.     /* 
  569.      * if pidfd was not opened previously... 
  570.      * pidfd must stay open after the chroot(~ftp)  
  571.      */
  572.  
  573.     sprintf(pidfile, _PATH_PIDNAMES, class);
  574.  
  575.     if (pidfd < 0) {
  576.         pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
  577.     }
  578.  
  579.     if (pidfd < 0) {
  580.         syslog(LOG_ERR, "cannot open pid file %s: %s", pidfile,
  581.                strerror(errno));
  582.         return -1;
  583.     }
  584.  
  585. #ifdef HAVE_FLOCK
  586.     while (flock(pidfd, LOCK_EX)) {
  587.         syslog(LOG_ERR, "sleeping: flock of pid file failed: %s",
  588. #else 
  589.     arg.l_type = F_WRLCK;
  590.     arg.l_whence = arg.l_start = arg.l_len = 0;
  591.     while ( -1 == fcntl( pidfd, F_SETLK, &arg) ) {
  592.         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %s",
  593. #endif
  594.                strerror(errno));
  595.         sleep(1);
  596.     }
  597.     lseek(pidfd, 0, L_SET);
  598.  
  599.     count = 0;
  600.  
  601.     if (read(pidfd, buf, sizeof(buf)) == sizeof(buf)) {
  602.         for (which = 0; which < MAXUSERS; which++)
  603.             if (buf[which] && !kill(buf[which], 0))
  604.                 count++;
  605.     }
  606. #ifdef HAVE_FLOCK
  607.     flock(pidfd, LOCK_UN);
  608. #else
  609.     arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0;
  610.     fcntl(pidfd, F_SETLK, &arg);
  611. #endif
  612.     return (count);
  613. }
  614.  
  615. /*************************************************************************/
  616. /* FUNCTION  : acl_join                                                  */
  617. /* PURPOSE   : Add the current process to the list of processes in the   */
  618. /*             specified class.                                          */
  619. /* ARGUMENTS : The name of the class to join                             */
  620. /*************************************************************************/
  621.  
  622. void
  623. #ifdef __STDC__
  624. acl_join(char *class)
  625. #else
  626. acl_join(class)
  627. char *class;
  628. #endif
  629. {
  630.     int which,
  631.       avail;
  632.     pid_t buf[MAXUSERS];
  633.     char pidfile[MAXPATHLEN];
  634.     pid_t procid;
  635. #ifndef HAVE_FLOCK
  636.     struct flock arg;
  637. #endif
  638.  
  639.     /* 
  640.      * if pidfd was not opened previously... 
  641.      * pidfd must stay open after the chroot(~ftp)  
  642.      */
  643.  
  644.     sprintf(pidfile, _PATH_PIDNAMES, class);
  645.  
  646.     if (pidfd < 0) {
  647.         pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
  648.     }
  649.  
  650.     if (pidfd < 0) {
  651.         syslog(LOG_ERR, "cannot open pid file %s: %s", pidfile,
  652.                strerror(errno));
  653.         return;
  654.     }
  655.  
  656. #ifdef HAVE_FLOCK
  657.     while (flock(pidfd, LOCK_EX)) {
  658.         syslog(LOG_ERR, "sleeping: flock of pid file failed: %s",
  659. #else 
  660.     arg.l_type = F_WRLCK;
  661.     arg.l_whence = arg.l_start = arg.l_len = 0;
  662.     while ( -1 == fcntl( pidfd, F_SETLK, &arg) ) {
  663.         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %s",
  664. #endif
  665.                strerror(errno));
  666.         sleep(1);
  667.     }
  668.  
  669.     procid = getpid();
  670.  
  671.     lseek(pidfd, 0, L_SET);
  672.     if (read(pidfd, buf, sizeof(buf)) < sizeof(buf))
  673.         for (which = 0; which < MAXUSERS; buf[which++] = 0)
  674.             continue;
  675.  
  676.     avail = 0;
  677.     for (which = 0; which < MAXUSERS; which++) {
  678.         if ((buf[which] == 0) || (kill(buf[which], 0) == -1)) {
  679.             avail = which;
  680.             buf[which] = 0;
  681.         } else if (buf[which] == procid) {
  682.             /* already exists in pid file... */
  683. #ifdef HAVE_FLOCK
  684.             flock(pidfd, LOCK_UN);
  685. #else
  686.             arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0; 
  687.             fcntl(pidfd, F_SETLK, &arg);
  688. #endif
  689.             return;
  690.         }
  691.     }
  692.  
  693.     buf[avail] = procid;
  694.  
  695.     lseek(pidfd, 0, L_SET);
  696.     write(pidfd, buf, sizeof(buf));
  697. #ifdef HAVE_FLOCK
  698.     flock(pidfd, LOCK_UN);
  699. #else
  700.     arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0;
  701.     fcntl(pidfd, F_SETLK, &arg);
  702. #endif
  703.  
  704. }
  705.  
  706. /*************************************************************************/
  707. /* FUNCTION  : acl_remove                                                */
  708. /* PURPOSE   : remove the current process to the list of processes in    */
  709. /*             the specified class.                                      */
  710. /* ARGUMENTS : The name of the class to remove                           */
  711. /*************************************************************************/
  712.  
  713. void
  714. #ifdef __STDC__
  715. acl_remove(void)
  716. #else
  717. acl_remove()
  718. #endif
  719. {
  720.     char class[1024];
  721.     int which,
  722.       avail;
  723.     pid_t buf[MAXUSERS];
  724.     char pidfile[MAXPATHLEN];
  725.     pid_t procid;
  726. #ifndef HAVE_FLOCK
  727.     struct flock arg;
  728. #endif
  729.  
  730.     if (!acl_getclass(class)) {
  731.         return;
  732.     }
  733.  
  734.     /* 
  735.      * if pidfd was not opened previously... 
  736.      * pidfd must stay open after the chroot(~ftp)  
  737.      */
  738.  
  739.     sprintf(pidfile, _PATH_PIDNAMES, class);
  740.  
  741.     if (pidfd < 0) {
  742.         pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
  743.     }
  744.  
  745.     if (pidfd < 0) {
  746.         syslog(LOG_ERR, "cannot open pid file %s: %s", pidfile,
  747.                strerror(errno));
  748.         return;
  749.     }
  750.  
  751. #ifdef HAVE_FLOCK
  752.     while (flock(pidfd, LOCK_EX)) {
  753.         syslog(LOG_ERR, "sleeping: flock of pid file failed: %s",
  754. #else 
  755.     arg.l_type = F_WRLCK;
  756.     arg.l_whence = arg.l_start = arg.l_len = 0;
  757.     while ( -1 == fcntl( pidfd, F_SETLK, &arg) ) {
  758.         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %s",
  759. #endif
  760.                strerror(errno));
  761.         sleep(1);
  762.     }
  763.  
  764.     procid = getpid();
  765.  
  766.     lseek(pidfd, 0, L_SET);
  767.     if (read(pidfd, buf, sizeof(buf)) < sizeof(buf))
  768.         for (which = 0; which < MAXUSERS; buf[which++] = 0)
  769.             continue;
  770.  
  771.     avail = 0;
  772.     for (which = 0; which < MAXUSERS; which++) {
  773.         if ((buf[which] == 0) || (kill(buf[which], 0) == -1)) {
  774.             avail = which;
  775.             buf[which] = 0;
  776.         } else if (buf[which] == procid) {
  777.             buf[which] = 0;
  778.         }
  779.     }
  780.  
  781.     lseek(pidfd, 0, L_SET);
  782.     write(pidfd, buf, sizeof(buf));
  783. #ifdef HAVE_FLOCK
  784.     flock(pidfd, LOCK_UN);
  785. #else
  786.     arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0;
  787.     fcntl(pidfd, F_SETLK, &arg);
  788. #endif
  789.  
  790.     close(pidfd);
  791.     pidfd = -1;
  792. }
  793.  
  794. /*************************************************************************/
  795. /* FUNCTION  : pr_mesg                                                   */
  796. /* PURPOSE   : Display a message to the user                             */
  797. /* ARGUMENTS : message code, name of file to display                     */
  798. /*************************************************************************/
  799.  
  800. int
  801. #ifdef __STDC__
  802. pr_mesg(int msgcode, char *msgfile)
  803. #else
  804. pr_mesg(msgcode,msgfile)
  805. int msgcode;
  806. char *msgfile;
  807. #endif
  808. {
  809.     FILE *infile;
  810.     char inbuf[1024],
  811.       outbuf[1024],
  812.      *cr;
  813.  
  814.     if (msgfile && (int)strlen(msgfile) > 0) {
  815.         infile = fopen(msgfile, "r");
  816.         if (infile) {
  817.             while (fgets(inbuf, 255, infile) != NULL) {
  818.                 if ((cr = strchr(inbuf, '\n')) != NULL)
  819.                     *cr = '\0';
  820.                 msg_massage(inbuf, outbuf);
  821.                 lreply(msgcode, "%s", outbuf);
  822.             }
  823.             fclose(infile);
  824.         }
  825.     }
  826. }
  827.  
  828. /*************************************************************************/
  829. /* FUNCTION  : access_init                                               */
  830. /* PURPOSE   : Read and parse the access lists to set things up          */
  831. /* ARGUMENTS : none                                                      */
  832. /*************************************************************************/
  833.  
  834. void
  835. #ifdef __STDC__
  836. access_init(void)
  837. #else
  838. access_init()
  839. #endif
  840. {
  841.     struct aclmember *entry;
  842.  
  843.     if (!readacl(_PATH_FTPACCESS))
  844.         return;
  845.     (void) parseacl();
  846.  
  847.     Shutdown[0] = '\0';
  848.     entry = (struct aclmember *) NULL;
  849.     if (getaclentry("shutdown", &entry) && ARG0 != NULL)
  850.         (void) strncpy(Shutdown, ARG0, sizeof(Shutdown));
  851.  
  852. }
  853.  
  854. /*************************************************************************/
  855. /* FUNCTION  : access_ok                                                 */
  856. /* PURPOSE   : Check the anonymous FTP access lists to see if this       */
  857. /*             access is permitted.                                      */
  858. /* ARGUMENTS : none                                                      */
  859. /*************************************************************************/
  860.  
  861. int
  862. #ifdef __STDC__
  863. access_ok(int msgcode)
  864. #else
  865. access_ok(msgcode)
  866. int msgcode;
  867. #endif
  868. {
  869.     char class[1024],
  870.       msgfile[MAXPATHLEN];
  871.     int limit;
  872.  
  873.     if (!use_accessfile)
  874.         return (1);
  875.  
  876.     if (aclbuf == NULL) {
  877.         syslog(LOG_NOTICE, 
  878.         "ACCESS DENIED (error reading access file) TO %s [%s]",
  879.                  remotehost, remoteaddr);
  880.         return (0);
  881.     }
  882.     if (acl_deny(msgfile)) {
  883.         pr_mesg(msgcode, msgfile);
  884.         syslog(LOG_NOTICE, "ACCESS DENIED (deny command) TO %s [%s]",
  885.                remotehost, remoteaddr);
  886.         return (0);
  887.     }
  888.     /* if user is not in any class, deny access */
  889.     if (!acl_getclass(class)) {
  890.         syslog(LOG_NOTICE, "ACCESS DENIED (not in any class) TO %s [%s]",
  891.                remotehost, remoteaddr);
  892.         return (0);
  893.     }
  894.     /* if no limits defined, no limits apply -- access OK */
  895.     limit = acl_getlimit(class, msgfile);
  896.  
  897.     if ((limit == -1) || (acl_countusers(class) < limit)) {
  898.         acl_join(class);
  899.         return (1);
  900.     } else {
  901. #ifdef LOG_TOOMANY
  902.         syslog(LOG_NOTICE, "ACCESS DENIED (user limit %d; class %s) TO %s [%s]",
  903.                limit, class, remotehost, remoteaddr);
  904. #endif
  905.         pr_mesg(msgcode, msgfile);
  906.         return (-1);
  907.     }
  908.  
  909.     /* NOTREACHED */
  910. }
  911.