1 /*
   2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 #pragma ident   "%Z%%M% %I%     %E% SMI"
   7 
   8 /****************************************************************************  
   9  
  10   Copyright (c) 1999,2000 WU-FTPD Development Group.  
  11   All rights reserved.
  12   
  13   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
  14     The Regents of the University of California.
  15   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
  16   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
  17   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
  18   Portions Copyright (c) 1998 Sendmail, Inc.
  19   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
  20   Portions Copyright (c) 1997 by Stan Barber.
  21   Portions Copyright (c) 1997 by Kent Landfield.
  22   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
  23     Free Software Foundation, Inc.  
  24  
  25   Use and distribution of this software and its source code are governed 
  26   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
  27  
  28   If you did not receive a copy of the license, it may be obtained online
  29   at http://www.wu-ftpd.org/license.html.
  30  
  31   $Id: access.c,v 1.30 2000/07/01 18:17:38 wuftpd Exp $
  32  
  33 ****************************************************************************/
  34 #include "config.h"
  35 
  36 #include <stdio.h>
  37 #include <errno.h>
  38 #include <string.h>
  39 #include <stdlib.h>
  40 
  41 #ifdef HAVE_SYS_SYSLOG_H
  42 #include <sys/syslog.h>
  43 #endif
  44 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
  45 #include <syslog.h>
  46 #endif
  47 
  48 #ifdef TIME_WITH_SYS_TIME
  49 #include <time.h>
  50 #include <sys/time.h>
  51 #elif defined(HAVE_SYS_TIME_H)
  52 #include <sys/time.h>
  53 #else
  54 #include <time.h>
  55 #endif
  56 
  57 #include <ctype.h>
  58 #include <pwd.h>
  59 #include <grp.h>
  60 #include <limits.h>
  61 
  62 #include <sys/types.h>
  63 #include <sys/stat.h>
  64 #include <sys/file.h>
  65 #include <sys/param.h>
  66 
  67 #ifdef HAVE_PATHS_H
  68 #include <paths.h>
  69 #endif
  70 
  71 #include "pathnames.h"
  72 #include "extensions.h"
  73 #include "proto.h"
  74 
  75 #if defined(HAVE_FCNTL_H)
  76 #include <fcntl.h>
  77 #endif
  78 
  79 #ifdef OTHER_PASSWD
  80 #include "getpwnam.h"
  81 extern char _path_passwd[];
  82 #ifdef SHADOW_PASSWORD
  83 extern char _path_shadow[];
  84 #endif
  85 #endif
  86 
  87 #if defined(USE_PAM) && defined(OTHER_PASSWD)
  88 extern int use_pam;
  89 #endif
  90 
  91 extern char remotehost[], remoteaddr[], *remoteident, *aclbuf;
  92 extern int nameserved, anonymous, guest, TCPwindowsize, use_accessfile;
  93 extern mode_t defumask;
  94 char Shutdown[MAXPATHLEN];
  95 int keepalive = 0;
  96 #define MAXLINE 80
  97 static char incline[MAXLINE];
  98 static int pidfd = -1;
  99 extern int Bypass_PID_Files;
 100 
 101 #ifndef HELP_CRACKERS
 102 extern char DelayedMessageFile[];
 103 #endif
 104 
 105 #include "wu_fnmatch.h"
 106 
 107 #define ACL_COUNT       0
 108 #define ACL_JOIN        1
 109 #define ACL_REMOVE      2
 110 
 111 /*************************************************************************/
 112 /* FUNCTION  : parse_time                                                */
 113 /* PURPOSE   : Check a single valid-time-string against the current time */
 114 /*             and return whether or not a match occurs.                 */
 115 /* ARGUMENTS : a pointer to the time-string                              */
 116 /*************************************************************************/
 117 
 118 int parsetime(char *whattime)
 119 {
 120     static char *days[] =
 121     {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk"};
 122     time_t clock;
 123     struct tm *curtime;
 124     int wday, start, stop, ltime, validday, loop, match;
 125 
 126     (void) time(&clock);
 127     curtime = localtime(&clock);
 128     wday = curtime->tm_wday;
 129     validday = 0;
 130     match = 1;
 131 
 132     while (match && isalpha(*whattime) && isupper(*whattime)) {
 133         match = 0;
 134         for (loop = 0; loop < 8; loop++) {
 135             if (strncmp(days[loop], whattime, 2) == 0) {
 136                 whattime += 2;
 137                 match = 1;
 138                 if ((wday == loop) || ((loop == 7) && wday && (wday < 6))) {
 139                     validday = 1;
 140                 }
 141             }
 142         }
 143     }
 144 
 145     if (!validday) {
 146         if (strncmp(whattime, "Any", 3) == 0) {
 147             validday = 1;
 148             whattime += 3;
 149         }
 150         else
 151             return (0);
 152     }
 153 
 154     if (sscanf(whattime, "%d-%d", &start, &stop) == 2) {
 155         ltime = curtime->tm_min + 100 * curtime->tm_hour;
 156         if ((start < stop) && ((ltime >= start) && ltime < stop))
 157             return (1);
 158         if ((start > stop) && ((ltime >= start) || ltime < stop))
 159             return (1);
 160     }
 161     else
 162         return (1);
 163 
 164     return (0);
 165 }
 166 
 167 /*************************************************************************/
 168 /* FUNCTION  : validtime                                                 */
 169 /* PURPOSE   : Break apart a set of valid time-strings and pass them to  */
 170 /*             parse_time, returning whether or not ANY matches occurred */
 171 /* ARGUMENTS : a pointer to the time-string                              */
 172 /*************************************************************************/
 173 
 174 int validtime(char *ptr)
 175 {
 176     char *nextptr;
 177     int good;
 178 
 179     while (1) {
 180         nextptr = strchr(ptr, '|');
 181         if (strchr(ptr, '|') == NULL)
 182             return (parsetime(ptr));
 183         *nextptr = '\0';
 184         good = parsetime(ptr);
 185         /* gotta restore the | or things get skipped! */
 186         *nextptr++ = '|';
 187         if (good)
 188             return (1);
 189         ptr = nextptr;
 190     }
 191 }
 192 
 193 #ifdef INET6
 194 /*************************************************************************/
 195 /* FUNCTION  : ipv6str                                                   */
 196 /* PURPOSE   : Convert an IPv6 address string with optional /CIDR suffix */
 197 /*             into an IPv6 address and a CIDR, which are returned in    */
 198 /*             the arguments pointed to by in6p and cidrp.               */
 199 /* ARGUMENTS : The IPv6 address string and pointers to in6_addr and CIDR */
 200 /* RETURNS   : 1 if addr is an IPv6 address string, 0 if not             */
 201 /*************************************************************************/
 202 
 203 static int ipv6str(char *addr, struct in6_addr *in6p, int *cidrp)
 204 {
 205     int cidr = 128;     /* IPv6 addresses are 128-bits long */
 206     char *ptr;
 207 
 208     if ((ptr = strstr(addr, "/")))
 209         *ptr = '\0';
 210 
 211     if (inet_pton(AF_INET6, addr, in6p) != 1) {
 212         if (ptr)
 213             *ptr = '/';
 214         return 0;
 215     }
 216 
 217     if (ptr) {
 218         *ptr++ = '/';
 219         cidr = atoi(ptr);
 220         if (cidr < 0)
 221             cidr = 0;
 222         else if (cidr > 128)
 223             cidr = 128;
 224     }
 225     *cidrp = cidr;
 226     return 1;
 227 }
 228 #endif
 229 
 230 /*************************************************************************/
 231 /* FUNCTION  : hostmatch                                                 */
 232 /* PURPOSE   : Match remote hostname or address against a glob string    */
 233 /* ARGUMENTS : The string to match, remote address, remote hostname      */
 234 /* RETURNS   : 0 if no match, 1 if a match occurs                        */
 235 /*************************************************************************/
 236 
 237 int hostmatch(char *addr, char *remoteaddr, char *remotehost)
 238 {
 239     FILE *incfile;
 240     char *ptr, junk, s[4][4];
 241     int found = 1;
 242     int not_found = 0;
 243     int match = 0;
 244     int i, a[4], m[4], r[4], cidr;
 245 #ifdef INET6
 246     struct in6_addr addr_in6;
 247 #endif
 248 
 249     if (addr == NULL)
 250         return (0);
 251 
 252     if (*addr == '!') {
 253         found = 0;
 254         not_found = 1;
 255         addr++;
 256     }
 257 
 258     if (sscanf(addr, "%d.%d.%d.%d/%d", a, a + 1, a + 2, a + 3, &cidr) == 5) {
 259         m[0] = 0;
 260         m[1] = 0;
 261         m[2] = 0;
 262         m[3] = 0;
 263         if (cidr < 0)
 264             cidr = 0;
 265         else if (cidr > 32)
 266             cidr = 32;
 267         for (i = 0; cidr > 8; i++) {
 268             m[i] = 255;
 269             cidr -= 8;
 270         }
 271         switch (cidr) {
 272         case 8:
 273             m[i] += 1;
 274         case 7:
 275             m[i] += 2;
 276         case 6:
 277             m[i] += 4;
 278         case 5:
 279             m[i] += 8;
 280         case 4:
 281             m[i] += 16;
 282         case 3:
 283             m[i] += 32;
 284         case 2:
 285             m[i] += 64;
 286         case 1:
 287             m[i] += 128;
 288         }
 289         /* make sure remoteaddr is an IPv4 address */
 290         if (sscanf(remoteaddr, "%d.%d.%d.%d", r, r + 1, r + 2, r + 3) != 4)
 291             return not_found;
 292         for (i = 0; i < 4; i++)
 293             if ((a[i] & m[i]) != (r[i] & m[i]))
 294                 return not_found;
 295         return found;
 296     }
 297     else if (sscanf(addr, "%d.%d.%d.%d:%d.%d.%d.%d", a, a + 1, a + 2, a + 3, m, m + 1, m + 2, m + 3) == 8) {
 298         /* make sure remoteaddr is an IPv4 address */
 299         if (sscanf(remoteaddr, "%d.%d.%d.%d", r, r + 1, r + 2, r + 3) != 4)
 300             return not_found;
 301         for (i = 0; i < 4; i++)
 302             if ((a[i] & m[i]) != (r[i] & m[i]))
 303                 return not_found;
 304         return found;
 305     }
 306     else if (sscanf(addr, "%3[0-9*].%3[0-9*].%3[0-9*].%3[0-9*]%c",
 307                     s[0], s[1], s[2], s[3], &junk) == 4 &&
 308             (!strcmp(s[0],"*") || !strchr(s[0],'*')) &&
 309             (!strcmp(s[1],"*") || !strchr(s[1],'*')) &&
 310             (!strcmp(s[2],"*") || !strchr(s[2],'*')) &&
 311             (!strcmp(s[3],"*") || !strchr(s[3],'*'))  ) {
 312         /* make sure remoteaddr is an IPv4 address */
 313         if (sscanf(remoteaddr, "%d.%d.%d.%d", r, r + 1, r + 2, r + 3) != 4)
 314             return not_found;
 315         for (i = 0; i < 4; i++)
 316             if ( (strcmp(s[i],"*")) && (atoi(s[i]) != r[i]) )
 317                 return not_found;
 318         return found;
 319     }
 320 #ifdef INET6
 321     else if (ipv6str(addr, &addr_in6, &cidr)) {
 322         struct in6_addr rem_in6;
 323         uint32_t addr32[4], rem32[4];
 324         int bitstozero;
 325 
 326         if (inet_pton6(remoteaddr, &rem_in6) != 1)
 327             return not_found;
 328 
 329         memcpy(addr32, addr_in6.s6_addr, sizeof(addr32));
 330         memcpy(rem32, rem_in6.s6_addr, sizeof(rem32));
 331 
 332         /* IPv6 addresses are 128-bits long */
 333         bitstozero = 128 - cidr;
 334 
 335         /* zero bits starting with the least significant */
 336         for (i = 3; (bitstozero > 0) && (i >= 0); i--, bitstozero -= 32) {
 337             if (bitstozero >= 32)
 338                 addr32[i] = rem32[i] = 0;
 339             else {
 340                 addr32[i] = (ntohl(addr32[i]) >> bitstozero) << bitstozero;
 341                 rem32[i] = (ntohl(rem32[i]) >> bitstozero) << bitstozero;
 342             }
 343         }
 344         if (memcmp(addr32, rem32, sizeof(addr32)))
 345             return not_found;
 346         return found;
 347     }
 348 #endif
 349     else if (*addr == '/') {
 350         /*
 351          * read addrglobs from named path using similar format as addrglobs
 352          * in access file
 353          */
 354         if ((incfile = fopen(addr, "r")) == NULL) {
 355             if (errno != ENOENT)
 356                 syslog(LOG_ERR,
 357                        "cannot open addrglob file %s: %m", addr);
 358             return (0);
 359         }
 360 
 361         while (!match && (fgets(incline, MAXLINE, incfile) != NULL)) {
 362             ptr = strtok(incline, " \t\n");
 363             if (ptr && hostmatch(ptr, remoteaddr, remotehost))
 364                 match = 1;
 365             while (!match && ((ptr = strtok(NULL, " \t\n")) != NULL)) {
 366                 if (ptr && hostmatch(ptr, remoteaddr, remotehost))
 367                     match = 1;
 368             }
 369         }
 370         fclose(incfile);
 371         return (match ? found : not_found);
 372     }
 373     else {                      /* match a hostname or hostname glob */
 374         match = (!wu_fnmatch(addr, remotehost, FNM_CASEFOLD)) ||
 375                 (!wu_fnmatch(addr, remoteaddr, 0));
 376         return (match ? found : not_found);
 377     }
 378 }
 379 
 380 /*************************************************************************/
 381 /* FUNCTION  : acl_guestgroup                                            */
 382 /* PURPOSE   : If the real user is a member of any of the listed groups, */
 383 /*             return 1.  Otherwise return 0.                            */
 384 /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
 385 /*************************************************************************/
 386 
 387 int acl_guestgroup(struct passwd *pw)
 388 {
 389     /*
 390      * guestuser <name> [<name> ...]
 391      *
 392      * If name begins with '%' treat as numeric.
 393      * Numeric names may be ranges.
 394      *   %<uid>       A single numeric UID
 395      *   %<uid>+      All UIDs greater or equal to UID
 396      *   %<uid>-      All UIDs greater or equal to UID
 397      *   %-<uid>      All UIDs less or equal to UID
 398      *   %<uid>-<uid> All UIDs between the two (inclusive)
 399      *   *            All UIDs
 400      */
 401     if (uid_match("guestuser", pw->pw_uid))
 402         return (1);
 403 
 404     /*
 405      * guestgroup <group> [<group> ...]
 406      *
 407      * If group begins with '%' treat as numeric.
 408      * Numeric groups may be ranges.
 409      *   %<gid>       A single GID
 410      *   %<gid>+      All GIDs greater or equal to GID
 411      *   %<gid>-      All GIDs greater or equal to GID
 412      *   %-<gid>      All GIDs less or equal to GID
 413      *   %<gid>-<gid> All GIDs between the two (inclusive)
 414      *   *            All GIDs
 415      */
 416     if (gid_match("guestgroup", pw->pw_gid, pw->pw_name))
 417         return (1);
 418 
 419     return (0);
 420 }
 421 
 422 int acl_realgroup(struct passwd *pw)
 423 {
 424     /*
 425      * realuser <name> [<name> ...]
 426      *
 427      * If name begins with '%' treat as numeric.
 428      * Numeric names may be ranges.
 429      *   %<uid>       A single numeric UID
 430      *   %<uid>+      All UIDs greater or equal to UID
 431      *   %<uid>-      All UIDs greater or equal to UID
 432      *   %-<uid>      All UIDs less or equal to UID
 433      *   %<uid>-<uid> All UIDs between the two (inclusive)
 434      *   *            All UIDs
 435      */
 436     if (uid_match("realuser", pw->pw_uid))
 437         return (1);
 438 
 439     /*
 440      * realgroup <group> [<group> ...]
 441      *
 442      * If group begins with '%' treat as numeric.
 443      * Numeric groups may be ranges.
 444      *   %<gid>       A single GID
 445      *   %<gid>+      All GIDs greater or equal to GID
 446      *   %<gid>-      All GIDs greater or equal to GID
 447      *   %-<gid>      All GIDs less or equal to GID
 448      *   %<gid>-<gid> All GIDs between the two (inclusive)
 449      *   *            All GIDs
 450      */
 451     if (gid_match("realgroup", pw->pw_gid, pw->pw_name))
 452         return (1);
 453 
 454     return (0);
 455 }
 456 
 457 /*************************************************************************/
 458 /* FUNCTION  : acl_autogroup                                             */
 459 /* PURPOSE   : If the guest user is a member of any of the classes in    */
 460 /*             the autogroup comment, cause a setegid() to the specified */
 461 /*             group.                                                    */
 462 /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
 463 /*************************************************************************/
 464 
 465 void acl_autogroup(struct passwd *pw)
 466 {
 467     char class[BUFSIZ];
 468 
 469     struct aclmember *entry = NULL;
 470     struct group *grp;
 471     int which;
 472 
 473     (void) acl_getclass(class);
 474 
 475     /* autogroup <group> <class> [<class> ...] */
 476     while (getaclentry("autogroup", &entry)) {
 477         if (!ARG0 || !ARG1)
 478             continue;
 479         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
 480             if (!strcasecmp(ARG[which], class)) {
 481                 if (ARG0[0] == '%')
 482                     pw->pw_gid = atoi(ARG0 + 1);
 483                 else {
 484                     if ((grp = getgrnam(ARG0)))
 485                         pw->pw_gid = grp->gr_gid;
 486                     else
 487                         syslog(LOG_ERR, "autogroup: set group %s not found", ARG0);
 488                     endgrent();
 489                 }
 490                 return;
 491             }
 492         }
 493     }
 494 }
 495 
 496 /*************************************************************************/
 497 /* FUNCTION  : acl_setfunctions                                          */
 498 /* PURPOSE   : Scan the ACL buffer and determine what logging to perform */
 499 /*             for this user, and whether or not user is allowed to use  */
 500 /*             the automatic TAR and COMPRESS functions.  Also, set the  */
 501 /*             current process priority of this copy of the ftpd server  */
 502 /*             to a `nice' value value if this user is a member of a     */
 503 /*             group which the ftpaccess file says should be nice'd.     */
 504 /* ARGUMENTS : none                                                      */
 505 /*************************************************************************/
 506 
 507 void acl_setfunctions(void)
 508 {
 509     char class[BUFSIZ];
 510 
 511     extern int log_incoming_xfers, log_outbound_xfers, mangleopts, log_commands,
 512         log_security, syslogmsg, lgi_failure_threshold;
 513 
 514     struct aclmember *entry = NULL;
 515 
 516     int l_compress, l_tar, inbound = 0, outbound = 0, which, set;
 517 
 518     log_security = 0;
 519 
 520     /* Initialize to the logging value specified on the command line, can't
 521        just use the current value as it may have been set by a previous call. */
 522     log_incoming_xfers = (log_incoming_xfers & 2) ? 3 : 0;
 523     log_outbound_xfers = (log_outbound_xfers & 2) ? 3 : 0;
 524     log_commands = (log_commands & 2) ? 3 : 0;
 525 
 526     memset((void *) &class[0], 0, sizeof(class));
 527 
 528     (void) acl_getclass(class);
 529 
 530     entry = (struct aclmember *) NULL;
 531     if (getaclentry("loginfails", &entry) && ARG0 != NULL) {
 532         lgi_failure_threshold = atoi(ARG0);
 533     }
 534 #ifndef NO_PRIVATE
 535     entry = (struct aclmember *) NULL;
 536     if (getaclentry("private", &entry) && ARG0 != NULL)
 537         if (!strcasecmp(ARG0, "yes"))
 538             priv_setup(_path_private);
 539 #endif /* !NO_PRIVATE */
 540 
 541     entry = (struct aclmember *) NULL;
 542     set = 0;
 543     while (!set && getaclentry("compress", &entry)) {
 544         if (!ARG0)
 545             continue;
 546         l_compress = 0;
 547         if (!strcasecmp(ARG0, "yes"))
 548             l_compress = 1;
 549         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
 550             if (!wu_fnmatch(ARG[which], class, FNM_CASEFOLD)) {
 551                 mangleopts |= l_compress * (O_COMPRESS | O_UNCOMPRESS);
 552                 set = 1;
 553             }
 554         }
 555     }
 556 
 557     entry = (struct aclmember *) NULL;
 558     set = 0;
 559     while (!set && getaclentry("tar", &entry)) {
 560         if (!ARG0)
 561             continue;
 562         l_tar = 0;
 563         if (!strcasecmp(ARG0, "yes"))
 564             l_tar = 1;
 565         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
 566             if (!wu_fnmatch(ARG[which], class, FNM_CASEFOLD)) {
 567                 mangleopts |= l_tar * O_TAR;
 568                 set = 1;
 569             }
 570         }
 571     }
 572 
 573     /* plan on expanding command syntax to include classes for each of these */
 574 
 575     entry = (struct aclmember *) NULL;
 576     while (getaclentry("log", &entry)) {
 577         if (!ARG0)
 578             continue;
 579         if (!strcasecmp(ARG0, "commands")) {
 580             if (!ARG1)
 581                 continue;
 582             if (anonymous && strcasestr(ARG1, "anonymous"))
 583                 log_commands |= 1;
 584             if (guest && strcasestr(ARG1, "guest"))
 585                 log_commands |= 1;
 586             if (!guest && !anonymous && strcasestr(ARG1, "real"))
 587                 log_commands |= 1;
 588         }
 589         if (!strcasecmp(ARG0, "transfers")) {
 590             if (!ARG1 || !ARG2)
 591                 continue;
 592             set = 0;
 593             if (strcasestr(ARG1, "anonymous") && anonymous)
 594                 set = 1;
 595             if (strcasestr(ARG1, "guest") && guest)
 596                 set = 1;
 597             if (strcasestr(ARG1, "real") && !guest && !anonymous)
 598                 set = 1;
 599             if (strcasestr(ARG2, "inbound"))
 600                 inbound = 1;
 601             if (strcasestr(ARG2, "outbound"))
 602                 outbound = 1;
 603             if (set)
 604                 log_incoming_xfers |= inbound;
 605             if (set)
 606                 log_outbound_xfers |= outbound;
 607         }
 608         if (!strcasecmp(ARG0, "security")) {
 609             if (!ARG1)
 610                 continue;
 611             if (strcasestr(ARG1, "anonymous") && anonymous)
 612                 log_security = 1;
 613             if (strcasestr(ARG1, "guest") && guest)
 614                 log_security = 1;
 615             if (strcasestr(ARG1, "real") && !guest && !anonymous)
 616                 log_security = 1;
 617         }
 618         if (!strcasecmp(ARG0, "syslog"))
 619             syslogmsg = 1;
 620         if (!strcasecmp(ARG0, "xferlog"))
 621             syslogmsg = 0;
 622         if (!strcasecmp(ARG0, "syslog+xferlog")
 623             || !strcasecmp(ARG0, "xferlog+syslog"))
 624             syslogmsg = 2;
 625     }
 626 }
 627 
 628 /*************************************************************************/
 629 /* FUNCTION  : acl_getclass                                              */
 630 /* PURPOSE   : Scan the ACL buffer and determine what class user is in   */
 631 /* ARGUMENTS : pointer to buffer to class name, pointer to ACL buffer    */
 632 /*************************************************************************/
 633 
 634 int acl_getclass(char *classbuf)
 635 {
 636     int which;
 637     struct aclmember *entry = NULL;
 638 
 639     while (getaclentry("class", &entry)) {
 640         if (ARG0)
 641             strlcpy(classbuf, ARG0, BUFSIZ);
 642 
 643         for (which = 2; (which < MAXARGS) && ARG[which]; which++) {
 644             if (anonymous && strcasestr(ARG1, "anonymous") &&
 645                 hostmatch(ARG[which], remoteaddr, remotehost))
 646                 return (1);
 647 
 648             if (guest && strcasestr(ARG1, "guest") && hostmatch(ARG[which], remoteaddr, remotehost))
 649                 return (1);
 650 
 651             if (!guest && !anonymous && strcasestr(ARG1, "real") &&
 652                 hostmatch(ARG[which], remoteaddr, remotehost))
 653                 return (1);
 654         }
 655     }
 656 
 657     *classbuf = (char) NULL;
 658     return (0);
 659 
 660 }
 661 
 662 /*************************************************************************/
 663 /* FUNCTION  : acl_getlimit                                              */
 664 /* PURPOSE   : Scan the ACL buffer and determine what limit applies to   */
 665 /*             the user                                                  */
 666 /* ARGUMENTS : pointer class name, pointer to ACL buffer                 */
 667 /*************************************************************************/
 668 
 669 int acl_getlimit(char *class, char *msgpathbuf)
 670 {
 671     int limit;
 672     struct aclmember *entry = NULL;
 673 
 674     if (msgpathbuf)
 675         *msgpathbuf = '\0';
 676 
 677     /* limit <class> <n> <times> [<message_file>] */
 678     while (getaclentry("limit", &entry)) {
 679         if (!ARG0 || !ARG1 || !ARG2)
 680             continue;
 681         if (!strcasecmp(class, ARG0)) {
 682             limit = atoi(ARG1);
 683             if (validtime(ARG2)) {
 684                 if (ARG3 && msgpathbuf)
 685                     strcpy(msgpathbuf, ARG3);
 686                 return (limit);
 687             }
 688         }
 689     }
 690     return (-1);
 691 }
 692 
 693 /*************************************************************************/
 694 /* FUNCTION  : acl_getnice                                               */
 695 /* PURPOSE   : Scan the ACL buffer and determine what nice value applies */
 696 /*             to the user                                               */
 697 /* ARGUMENTS : pointer class name                                        */
 698 /*************************************************************************/
 699 
 700 int acl_getnice(char *class)
 701 {
 702     int nice_delta_for_class_found = 0;
 703     int nice_delta = 0;
 704     int default_nice_delta = 0;
 705 
 706     struct aclmember *entry = NULL;
 707 
 708     /* nice <nice_delta> [<class>] */
 709     while (getaclentry("nice", &entry)) {
 710         if (!ARG0)
 711             continue;
 712         if (!ARG1)
 713             default_nice_delta = atoi(ARG0);
 714         else if (!strcasecmp(class, ARG1)) {
 715             nice_delta_for_class_found = 1;
 716             nice_delta = atoi(ARG0);
 717         }
 718     }
 719     if (!nice_delta_for_class_found)
 720         nice_delta = default_nice_delta;
 721     return nice_delta;
 722 }
 723 
 724 
 725 /*************************************************************************/
 726 /* FUNCTION  : acl_getdefumask                                           */
 727 /* PURPOSE   : Scan the ACL buffer to determine what umask value applies */
 728 /*             to the user                                               */
 729 /* ARGUMENTS : pointer to class name                                     */
 730 /*************************************************************************/
 731 
 732 void acl_getdefumask(char *class)
 733 {
 734     struct aclmember *entry = NULL;
 735     char *ptr;
 736     unsigned int val;
 737 
 738     /* defumask <umask> [<class>] */
 739     while (getaclentry("defumask", &entry)) {
 740         if (!ARG0)
 741             continue;
 742         if (!ARG1 || !strcasecmp(class, ARG1)) {
 743             ptr = ARG0;
 744             val = 0;
 745             while (*ptr && *ptr >= '0' && *ptr <= '7')
 746                 val = val * 8 + *ptr++ - '0';
 747             if (!*ptr && val <= 0777) {
 748                 defumask = val;
 749                 if (ARG1)
 750                     break;
 751             }
 752             else
 753                 syslog(LOG_WARNING, "bad umask in %s ignored: defumask %s",
 754                        _path_ftpaccess, ARG0);
 755         }
 756     }
 757     umask(defumask);
 758 }
 759 
 760 /*************************************************************************/
 761 /* FUNCTION  : acl_tcpwindow                                             */
 762 /* PURPOSE   : Scan the ACL buffer and determine what TCP window size to */
 763 /*             use based upon the class                                  */
 764 /* ARGUMENTS : pointer to class name                                     */
 765 /*************************************************************************/
 766 
 767 void acl_tcpwindow(char *class)
 768 {
 769     struct aclmember *entry = NULL;
 770 
 771     /* tcpwindow <size> [<class>] */
 772     while (getaclentry("tcpwindow", &entry)) {
 773         if (!ARG0)
 774             continue;
 775         if (!ARG1)
 776             TCPwindowsize = strtoul(ARG0, NULL, 0);
 777         else if (!strcasecmp(class, ARG1)) {
 778             TCPwindowsize = strtoul(ARG0, NULL, 0);
 779             break;
 780         }
 781     }
 782 }
 783 
 784 /*************************************************************************/
 785 /* FUNCTION  : acl_bufsize                                               */
 786 /* PURPOSE   : Scan the ACL buffer and determine the send and receive    */
 787 /*             buffer sizes to use                                       */
 788 /* ARGUMENTS : None                                                      */
 789 /*************************************************************************/
 790 
 791 static void acl_bufsize()
 792 {
 793     struct aclmember *entry;
 794     extern size_t sendbufsz, recvbufsz;
 795 
 796     /* sendbuf <size> [<typelist>] */
 797     entry = (struct aclmember *) NULL;
 798     sendbufsz = 0;
 799     while (getaclentry("sendbuf", &entry)) {
 800         if (!ARG0)
 801             continue;
 802         if (!ARG1)
 803             sendbufsz = strtoul(ARG0, NULL, 0);
 804         else if (type_match(ARG1)) {
 805             sendbufsz = strtoul(ARG0, NULL, 0);
 806             break;
 807         }
 808     }
 809 
 810     /* recvbuf <size> [<typelist>] */
 811     entry = (struct aclmember *) NULL;
 812     recvbufsz = 0;
 813     while (getaclentry("recvbuf", &entry)) {
 814         if (!ARG0)
 815             continue;
 816         if (!ARG1)
 817             recvbufsz = strtoul(ARG0, NULL, 0);
 818         else if (type_match(ARG1)) {
 819             recvbufsz = strtoul(ARG0, NULL, 0);
 820             break;
 821         }
 822     }
 823 }
 824 
 825 #ifdef TRANSFER_COUNT
 826 #ifdef TRANSFER_LIMIT
 827 
 828 /*************************************************************************/
 829 /* FUNCTION  : acl_filelimit                                             */
 830 /* PURPOSE   : Scan the ACL buffer and determine what file limit to use  */
 831 /*             based upon the class                                      */
 832 /* ARGUMENTS : pointer to class name                                     */
 833 /*************************************************************************/
 834 
 835 void acl_filelimit(char *class)
 836 {
 837     struct aclmember *entry = NULL;
 838     int raw_in = 0;
 839     int raw_out = 0;
 840     int raw_total = 0;
 841     int data_in = 0;
 842     int data_out = 0;
 843     int data_total = 0;
 844     extern int file_limit_raw_in;
 845     extern int file_limit_raw_out;
 846     extern int file_limit_raw_total;
 847     extern int file_limit_data_in;
 848     extern int file_limit_data_out;
 849     extern int file_limit_data_total;
 850 
 851     /* file-limit [<raw>] <in|out|total> <count> [<class>] */
 852     while (getaclentry("file-limit", &entry)) {
 853         if (!ARG0 || !ARG1)
 854             continue;
 855         if (!strcasecmp(ARG0, "raw")) {
 856             if (!ARG2)
 857                 continue;
 858             if (!strcasecmp(ARG1, "in")) {
 859                 if (!ARG3) {
 860                     if (!raw_in)
 861                         file_limit_raw_in = atoi(ARG2);
 862                 }
 863                 else if (!strcasecmp(class, ARG3)) {
 864                     raw_in = 1;
 865                     file_limit_raw_in = atoi(ARG2);
 866                 }
 867             }
 868             else if (!strcasecmp(ARG1, "out")) {
 869                 if (!ARG3) {
 870                     if (!raw_out)
 871                         file_limit_raw_out = atoi(ARG2);
 872                 }
 873                 else if (!strcasecmp(class, ARG3)) {
 874                     raw_out = 1;
 875                     file_limit_raw_out = atoi(ARG2);
 876                 }
 877             }
 878             else if (!strcasecmp(ARG1, "total")) {
 879                 if (!ARG3) {
 880                     if (!raw_total)
 881                         file_limit_raw_total = atoi(ARG2);
 882                 }
 883                 else if (!strcasecmp(class, ARG3)) {
 884                     raw_total = 1;
 885                     file_limit_raw_total = atoi(ARG2);
 886                 }
 887             }
 888         }
 889         else if (!strcasecmp(ARG0, "in")) {
 890             if (!ARG2) {
 891                 if (!data_in)
 892                     file_limit_data_in = atoi(ARG1);
 893             }
 894             else if (!strcasecmp(class, ARG2)) {
 895                 data_in = 1;
 896                 file_limit_data_in = atoi(ARG1);
 897             }
 898         }
 899         else if (!strcasecmp(ARG0, "out")) {
 900             if (!ARG2) {
 901                 if (!data_out)
 902                     file_limit_data_out = atoi(ARG1);
 903             }
 904             else if (!strcasecmp(class, ARG2)) {
 905                 data_out = 1;
 906                 file_limit_data_out = atoi(ARG1);
 907             }
 908         }
 909         else if (!strcasecmp(ARG0, "total")) {
 910             if (!ARG2) {
 911                 if (!data_total)
 912                     file_limit_data_total = atoi(ARG1);
 913             }
 914             else if (!strcasecmp(class, ARG2)) {
 915                 data_total = 1;
 916                 file_limit_data_total = atoi(ARG1);
 917             }
 918         }
 919     }
 920 }
 921 
 922 /*************************************************************************/
 923 /* FUNCTION  : acl_datalimit                                             */
 924 /* PURPOSE   : Scan the ACL buffer and determine what data limit to use  */
 925 /*             based upon the class                                      */
 926 /* ARGUMENTS : pointer to class name                                     */
 927 /*************************************************************************/
 928 
 929 void acl_datalimit(char *class)
 930 {
 931     struct aclmember *entry = NULL;
 932     int raw_in = 0;
 933     int raw_out = 0;
 934     int raw_total = 0;
 935     int data_in = 0;
 936     int data_out = 0;
 937     int data_total = 0;
 938     extern off_t data_limit_raw_in;
 939     extern off_t data_limit_raw_out;
 940     extern off_t data_limit_raw_total;
 941     extern off_t data_limit_data_in;
 942     extern off_t data_limit_data_out;
 943     extern off_t data_limit_data_total;
 944 
 945     /* data-limit [<raw>] <in|out|total> <count> [<class>] */
 946     while (getaclentry("data-limit", &entry)) {
 947         if (!ARG0 || !ARG1)
 948             continue;
 949         if (!strcasecmp(ARG0, "raw")) {
 950             if (!ARG2)
 951                 continue;
 952             if (!strcasecmp(ARG1, "in")) {
 953                 if (!ARG3) {
 954                     if (!raw_in)
 955                         data_limit_raw_in = atoi(ARG2);
 956                 }
 957                 else if (!strcasecmp(class, ARG3)) {
 958                     raw_in = 1;
 959                     data_limit_raw_in = atoi(ARG2);
 960                 }
 961             }
 962             else if (!strcasecmp(ARG1, "out")) {
 963                 if (!ARG3) {
 964                     if (!raw_out)
 965                         data_limit_raw_out = atoi(ARG2);
 966                 }
 967                 else if (!strcasecmp(class, ARG3)) {
 968                     raw_out = 1;
 969                     data_limit_raw_out = atoi(ARG2);
 970                 }
 971             }
 972             else if (!strcasecmp(ARG1, "total")) {
 973                 if (!ARG3) {
 974                     if (!raw_total)
 975                         data_limit_raw_total = atoi(ARG2);
 976                 }
 977                 else if (!strcasecmp(class, ARG3)) {
 978                     raw_total = 1;
 979                     data_limit_raw_total = atoi(ARG2);
 980                 }
 981             }
 982         }
 983         else if (!strcasecmp(ARG0, "in")) {
 984             if (!ARG2) {
 985                 if (!data_in)
 986                     data_limit_data_in = atoi(ARG1);
 987             }
 988             else if (!strcasecmp(class, ARG2)) {
 989                 data_in = 1;
 990                 data_limit_data_in = atoi(ARG1);
 991             }
 992         }
 993         else if (!strcasecmp(ARG0, "out")) {
 994             if (!ARG2) {
 995                 if (!data_out)
 996                     data_limit_data_out = atoi(ARG1);
 997             }
 998             else if (!strcasecmp(class, ARG2)) {
 999                 data_out = 1;
1000                 data_limit_data_out = atoi(ARG1);
1001             }
1002         }
1003         else if (!strcasecmp(ARG0, "total")) {
1004             if (!ARG2) {
1005                 if (!data_total)
1006                     data_limit_data_total = atoi(ARG1);
1007             }
1008             else if (!strcasecmp(class, ARG2)) {
1009                 data_total = 1;
1010                 data_limit_data_total = atoi(ARG1);
1011             }
1012         }
1013     }
1014 }
1015 
1016 
1017 #ifdef RATIO
1018 
1019 /*************************************************************************/
1020 /* FUNCTION  : acl_downloadrate                                          */
1021 /* PURPOSE   : Scan the ACL buffer and determine what data limit to use  */
1022 /*             based upon the class                                      */
1023 /* ARGUMENTS : pointer to class name                                     */
1024 /*************************************************************************/
1025 
1026 void acl_downloadrate(char *class)
1027 {
1028     struct aclmember *entry = NULL;
1029     extern int upload_download_rate;
1030     int which;
1031 
1032     /* ul-dl-rate <rate> [<class> ...] */
1033     while (getaclentry("ul-dl-rate", &entry)) {
1034         if (!ARG0 )
1035             continue;
1036 
1037         if (!ARG1) {
1038             upload_download_rate = atol(ARG0);
1039         }
1040         else {
1041             for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
1042                 if (!strcasecmp(ARG[which], class))
1043                     upload_download_rate = atol(ARG0);
1044             }
1045         }
1046 
1047     }
1048 }
1049 #endif /* RATIO */
1050 
1051 #endif
1052 #endif
1053 
1054 /*************************************************************************/
1055 /* FUNCTION  : acl_deny                                                  */
1056 /* PURPOSE   : Scan the ACL buffer and determine if access is denied.    */
1057 /* ARGUMENTS : Pointer to buffer into which the path of the message file */
1058 /*             is copied.                                                */
1059 /*************************************************************************/
1060 
1061 int acl_deny(char *msgpathbuf)
1062 {
1063     struct aclmember *entry = NULL;
1064 
1065     if (msgpathbuf)
1066         *msgpathbuf = (char) NULL;
1067 
1068     /* deny <addrglob> [<message_file>] */
1069     while (getaclentry("deny", &entry)) {
1070         if (!ARG0)
1071             continue;
1072         if (strcasecmp(ARG0, "!nameserved") == 0) {
1073             if (!nameserved) {
1074                 if (ARG1)
1075                     strcpy(msgpathbuf, entry->arg[1]);
1076                 return (1);
1077             }
1078         }
1079         else if (hostmatch(ARG0, remoteaddr, remotehost)) {
1080             if (ARG1)
1081                 strcpy(msgpathbuf, entry->arg[1]);
1082             return (1);
1083         }
1084     }
1085     return (0);
1086 }
1087 
1088 /*************************************************************************/
1089 /* FUNCTION  : lock_fd                                                   */
1090 /* PURPOSE   : Lock a file.                                              */
1091 /* ARGUMENTS : File descriptor of file to lock.                          */
1092 /*************************************************************************/
1093 
1094 static void lock_fd(int fd)
1095 {
1096 #if !defined(HAVE_FLOCK)
1097     struct flock arg;
1098 #endif /* !defined(HAVE_FLOCK) */
1099 
1100 #if defined(HAVE_FLOCK)
1101     while (flock(fd, LOCK_EX)) {
1102 #  if !defined(NO_PID_SLEEP_MSGS)
1103         syslog(LOG_ERR, "sleeping: flock of pid file failed: %m");
1104 #  endif /* !defined(NO_PID_SLEEP_MSGS) */
1105 #else /* !(defined(HAVE_FLOCK)) */
1106     arg.l_type = F_WRLCK;
1107     arg.l_whence = arg.l_start = arg.l_len = 0;
1108     while (-1 == fcntl(fd, F_SETLK, &arg)) {
1109 #  if !defined(NO_PID_SLEEP_MSGS)
1110         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %m");
1111 #  endif /* !defined(NO_PID_SLEEP_MSGS) */
1112 #endif /* !(defined(HAVE_FLOCK)) */
1113         sleep(1);
1114     }
1115 }
1116 
1117 /*************************************************************************/
1118 /* FUNCTION  : unlock_fd                                                 */
1119 /* PURPOSE   : Unlock a file locked by lock_fd.                          */
1120 /* ARGUMENTS : File descriptor of file to unlock.                        */
1121 /*************************************************************************/
1122 
1123 static void unlock_fd(int fd)
1124 {
1125 #if !defined(HAVE_FLOCK)
1126     struct flock arg;
1127 #endif /* !defined(HAVE_FLOCK) */
1128 
1129 #if defined(HAVE_FLOCK)
1130     flock(fd, LOCK_UN);
1131 #else /* !(defined(HAVE_FLOCK)) */
1132     arg.l_type = F_UNLCK;
1133     arg.l_whence = arg.l_start = arg.l_len = 0;
1134     fcntl(fd, F_SETLK, &arg);
1135 #endif /* !(defined(HAVE_FLOCK)) */
1136 }
1137 
1138 /*************************************************************************/
1139 /* FUNCTION  : limit_op                                                  */
1140 /* PURPOSE   : Carry out the specified limit operation, returning the    */
1141 /*             number of users in the class or -1 on failure.            */
1142 /* ARGUMENTS : Operation (ACL_COUNT/ACL_JOIN/ACL_REMOVE), user limit     */
1143 /*************************************************************************/
1144 
1145 static int limit_op(int operation, int limit)
1146 {
1147     int i, j, n, count;
1148     int bit_changed, toomany, write_all_header;
1149     off_t offset;
1150     pid_t pid, procid;
1151     time_t now;
1152     struct pidfile_header hdr;
1153     unsigned char bits, buf[BUFSIZ];
1154 
1155     if (pidfd < 0)
1156         return (-1);
1157 
1158     if (lseek(pidfd, (off_t)0, SEEK_SET) != 0)
1159         return (-1);
1160 
1161     if (operation == ACL_COUNT) {
1162         lock_fd(pidfd);
1163         n = read(pidfd, (void *)&hdr.count, sizeof(hdr.count));
1164         unlock_fd(pidfd);
1165         if (n != sizeof(hdr.count))
1166             return (-1);
1167         return (hdr.count);
1168     }
1169 
1170     toomany = 0;
1171     write_all_header = 0;
1172     lock_fd(pidfd);
1173     if (read(pidfd, (void *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
1174         hdr.count = 0;
1175         hdr.last_checked = 0;
1176     }
1177     now = time(NULL);
1178 
1179     /* check bitmap accuracy and re-calculate the count every 15 minutes */
1180     if ((now >= (hdr.last_checked + (15 * 60))) || (now < hdr.last_checked)) {
1181         count = 0;
1182         procid = 0;
1183         bit_changed = 0;
1184         while ((n = read(pidfd, (void *)buf, sizeof(buf))) > 0) {
1185             for (i = 0; i < n; i++) {
1186                 if (buf[i] == 0) {
1187                     procid += CHAR_BIT;
1188                 }
1189                 else {
1190                     bits = 1;
1191                     for (j = 0; j < CHAR_BIT; j++) {
1192                         if ((buf[i] & bits) != 0) {
1193                             if (kill(procid, 0) == 0) {
1194                                 count++;
1195                             }
1196                             else {
1197                                 bit_changed = 1;
1198                                 buf[i] &= ~bits;
1199                             }
1200                         }
1201                         bits <<= 1;
1202                         procid++;
1203                     }
1204                 }
1205             }
1206             if (bit_changed) {
1207                 lseek(pidfd, (off_t)-n, SEEK_CUR);
1208                 write(pidfd, (void *)buf, n);
1209                 bit_changed = 0;
1210             }
1211         }
1212         if (hdr.count != count) {
1213             syslog(LOG_INFO, "pid file header count (%d) corrected to %d",
1214                    hdr.count, count);
1215             hdr.count = count;
1216         }
1217         hdr.last_checked = time(NULL);
1218         write_all_header = 1;
1219     }
1220 
1221     /* limit set to -1 when no limit defined */
1222     if ((operation == ACL_JOIN) && (limit != -1) && (hdr.count >= limit)) {
1223         /* return if no need to update the header */
1224         if (write_all_header == 0) {
1225             unlock_fd(pidfd);
1226             return (-1);
1227         }
1228         toomany = 1;
1229     }
1230     else {
1231         /* update the count */
1232         if (operation == ACL_JOIN)
1233             hdr.count++;
1234         else if (hdr.count > 0) /* ACL_REMOVE */
1235             hdr.count--;
1236     }
1237 
1238     /* update the header */
1239     lseek(pidfd, (off_t)0, SEEK_SET);
1240     if (write_all_header)
1241         write(pidfd, (void *)&hdr, sizeof(hdr));
1242     else
1243         write(pidfd, (void *)&hdr.count, sizeof(hdr.count));
1244 
1245     /* return if no need to update the bitmap */
1246     if (toomany) {
1247         unlock_fd(pidfd);
1248         return (-1);
1249     }
1250 
1251     /* update the bitmap entry for the process */
1252     pid = getpid();
1253     offset = (off_t)(sizeof(hdr) + (pid/CHAR_BIT));
1254     lseek(pidfd, offset, SEEK_SET);
1255     if (read(pidfd, (void *)&bits, sizeof(bits)) != sizeof(bits))
1256         bits = 0;
1257     if (operation == ACL_JOIN)
1258         bits |= (1 << (pid%CHAR_BIT));
1259     else /* ACL_REMOVE */
1260         bits &= ~(1 << (pid%CHAR_BIT));
1261     lseek(pidfd, offset, SEEK_SET);
1262     write(pidfd, (void *)&bits, sizeof(bits));
1263     unlock_fd(pidfd);
1264     return (hdr.count);
1265 }
1266 
1267 /*************************************************************************/
1268 /* FUNCTION  : open_pidfile                                              */
1269 /* PURPOSE   : Return a file descriptor of an opened PID file.           */
1270 /* ARGUMENTS : Users class.                                              */
1271 /*************************************************************************/
1272 
1273 static int open_pidfile(char *class)
1274 {
1275     int fd;
1276     mode_t oldmask;
1277     char pidfile[MAXPATHLEN];
1278 
1279     snprintf(pidfile, sizeof(pidfile), _PATH_PIDNAMES, class);
1280     oldmask = umask(0);
1281     fd = open(pidfile, O_RDWR | O_CREAT, 0644);
1282     (void) umask(oldmask);
1283     if (fd < 0)
1284             syslog(LOG_ERR, "cannot open pid file %s: %m", pidfile);
1285     return (fd);
1286 }
1287 
1288 /*************************************************************************/
1289 /* FUNCTION  : acl_countusers                                            */
1290 /* PURPOSE   : Return the number of users in the specified class.        */
1291 /* ARGUMENTS : The name of the class to count.                           */
1292 /*************************************************************************/
1293 
1294 int acl_countusers(char *class)
1295 {
1296     int count = 0, opidfd = pidfd;
1297 
1298     if (Bypass_PID_Files)
1299         return (0);
1300 
1301     if (pidfd < 0) {
1302         if ((pidfd = open_pidfile(class)) < 0)
1303             return (-1);
1304     }
1305 
1306     count = limit_op(ACL_COUNT, 0);
1307 
1308     /*
1309      * acl_countusers may be called from msg_massage before the correct class
1310      * is known, so close the pid file if we opened it.
1311      */
1312     if (opidfd < 0) {
1313         close(pidfd);
1314         pidfd = -1;
1315     }
1316     return (count);
1317 }
1318 
1319 /*************************************************************************/
1320 /* FUNCTION  : acl_join                                                  */
1321 /* PURPOSE   : Add the current process to the list of processes in the   */
1322 /*             specified class.                                          */
1323 /* ARGUMENTS : The name of the class to join, user limit for the class.  */
1324 /* RETURNS   : 0 on success, -1 on failure                               */
1325 /*************************************************************************/
1326 
1327 int acl_join(char *class, int limit)
1328 {
1329     if (Bypass_PID_Files)
1330         return (0);
1331 
1332     if (pidfd < 0) {
1333         if ((pidfd = open_pidfile(class)) < 0)
1334             return (-1);
1335     }
1336 
1337     if (limit_op(ACL_JOIN, limit) < 0) {
1338         /* no need to leave the pid file open as we were not added to it */
1339         close(pidfd);
1340         pidfd = -1;
1341         return (-1);
1342     }
1343     /* pidfd left open so can be updated after a chroot */
1344     return (0);
1345 }
1346 
1347 /*************************************************************************/
1348 /* FUNCTION  : acl_remove                                                */
1349 /* PURPOSE   : Remove the current process from the list of processes in  */
1350 /*             our class.                                                */
1351 /* ARGUMENTS : None.                                                     */
1352 /*************************************************************************/
1353 
1354 void acl_remove(void)
1355 {
1356     if (pidfd < 0)
1357         return;
1358     (void) limit_op(ACL_REMOVE, 0);
1359     close(pidfd);
1360     pidfd = -1;
1361 }
1362 
1363 /*************************************************************************/
1364 /* FUNCTION  : pr_mesg                                                   */
1365 /* PURPOSE   : Display a message to the user                             */
1366 /* ARGUMENTS : message code, name of file to display                     */
1367 /*************************************************************************/
1368 
1369 void pr_mesg(int msgcode, char *msgfile)
1370 {
1371     FILE *infile;
1372     char inbuf[BUFSIZ], outbuf[BUFSIZ], *cr;
1373 
1374     if (msgfile && (int) strlen(msgfile) > 0) {
1375         infile = fopen(msgfile, "r");
1376         if (infile) {
1377             while (fgets(inbuf, sizeof(inbuf), infile) != NULL) {
1378                 if ((cr = strchr(inbuf, '\n')) != NULL)
1379                     *cr = '\0';
1380                 msg_massage(inbuf, outbuf, sizeof(outbuf));
1381                 lreply(msgcode, "%s", outbuf);
1382             }
1383             fclose(infile);
1384         }
1385     }
1386 }
1387 
1388 /*************************************************************************/
1389 /* FUNCTION  : access_init                                               */
1390 /* PURPOSE   : Read and parse the access lists to set things up          */
1391 /* ARGUMENTS : none                                                      */
1392 /*************************************************************************/
1393 
1394 void access_init(void)
1395 {
1396     struct aclmember *entry;
1397     static struct stat sbuf_last;
1398     struct stat sbuf_cur;
1399 
1400     if (!use_accessfile)
1401         return;
1402 
1403     if (stat(_path_ftpaccess, &sbuf_cur) != 0) {
1404         syslog(LOG_ERR, "cannot stat access file %s: %s", _path_ftpaccess,
1405                strerror(errno));
1406         return;
1407     }
1408     /* only reload the ftpaccess file if its changed */
1409     if ((sbuf_last.st_mtime == sbuf_cur.st_mtime) &&
1410         (sbuf_last.st_ino == sbuf_cur.st_ino) &&
1411         (sbuf_last.st_dev == sbuf_cur.st_dev))
1412         return;
1413 
1414     sbuf_last = sbuf_cur;
1415 
1416 #ifdef OTHER_PASSWD
1417     strcpy(_path_passwd, "/etc/passwd");
1418 #ifdef SHADOW_PASSWORD
1419     strcpy(_path_shadow, "/etc/shadow");
1420 #endif
1421 #endif
1422 #if defined(USE_PAM) && defined(OTHER_PASSWD)
1423     use_pam = 1;
1424 #endif
1425     Shutdown[0] = '\0';
1426     keepalive = 0;
1427 
1428     if (!readacl(_path_ftpaccess))
1429         return;
1430     (void) parseacl();
1431 
1432     entry = (struct aclmember *) NULL;
1433     if (getaclentry("shutdown", &entry) && ARG0 != NULL)
1434         (void) strncpy(Shutdown, ARG0, sizeof(Shutdown));
1435 #ifdef OTHER_PASSWD
1436     entry = (struct aclmember *) NULL;
1437     while (getaclentry("passwd", &entry) && ARG0 != NULL) {
1438             strcpy(_path_passwd, ARG0);
1439 #ifdef USE_PAM
1440             use_pam = 0;
1441 #endif
1442     }
1443 #ifdef SHADOW_PASSWORD
1444     entry = (struct aclmember *) NULL;
1445     while (getaclentry("shadow", &entry) && ARG0 != NULL) {
1446             strcpy(_path_shadow, ARG0);
1447 #ifdef USE_PAM
1448             use_pam = 0;
1449 #endif
1450     }
1451 #endif
1452 #endif
1453     entry = (struct aclmember *) NULL;
1454     if (getaclentry("keepalive", &entry) && ARG0 != NULL)
1455         if (!strcasecmp(ARG0, "yes"))
1456             keepalive = 1;
1457 }
1458 
1459 /*************************************************************************/
1460 /* FUNCTION  : access_ok                                                 */
1461 /* PURPOSE   : Check the anonymous FTP access lists to see if this       */
1462 /*             access is permitted.                                      */
1463 /* ARGUMENTS : reply code to use                                         */
1464 /*************************************************************************/
1465 
1466 int access_ok(int msgcode)
1467 {
1468     char class[BUFSIZ], msgfile[MAXPATHLEN];
1469     int limit;
1470     int nice_delta;
1471 
1472     if (!use_accessfile)
1473         return (1);
1474 
1475     if (aclbuf == NULL) {
1476         syslog(LOG_NOTICE,
1477                "ACCESS DENIED (error reading access file) TO %s",
1478                remoteident);
1479         return (0);
1480     }
1481     if (acl_deny(msgfile)) {
1482 #ifndef HELP_CRACKERS
1483         memcpy(DelayedMessageFile, msgfile, sizeof(msgfile));
1484 #else
1485         pr_mesg(msgcode, msgfile);
1486 #endif
1487         syslog(LOG_NOTICE, "ACCESS DENIED (deny command) TO %s",
1488                remoteident);
1489         return (0);
1490     }
1491     /* if user is not in any class, deny access */
1492     if (!acl_getclass(class)) {
1493         syslog(LOG_NOTICE, "ACCESS DENIED (not in any class) TO %s",
1494                remoteident);
1495         return (0);
1496     }
1497 
1498     limit = acl_getlimit(class, msgfile);
1499     if (acl_join(class, limit) < 0) {
1500 #ifdef LOG_TOOMANY
1501         syslog(LOG_NOTICE, "ACCESS DENIED (user limit %d; class %s) TO %s",
1502                limit, class, remoteident);
1503 #endif
1504 #ifndef HELP_CRACKERS
1505         memcpy(DelayedMessageFile, msgfile, sizeof(msgfile));
1506 #else
1507         pr_mesg(msgcode, msgfile);
1508 #endif
1509         return (-1);
1510     }
1511 
1512     if ((nice_delta = acl_getnice(class))) {
1513         if (nice_delta < 0)
1514             syslog(LOG_NOTICE, "Process nice value adjusted by %d", nice_delta);
1515         nice(nice_delta);
1516     }
1517     acl_getdefumask(class);
1518     acl_tcpwindow(class);
1519 #ifdef TRANSFER_COUNT
1520 #ifdef TRANSFER_LIMIT
1521     acl_filelimit(class);
1522     acl_datalimit(class);
1523 #ifdef RATIO
1524     acl_downloadrate(class);
1525 #endif
1526 #endif
1527 #endif
1528     acl_bufsize();
1529     get_xferlog_format();
1530     return (1);
1531 }