home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / tcpip / amitcp-support / wustl-ftpdaemon / src / extensions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-29  |  26.7 KB  |  985 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. #include "config.h"
  33.  
  34. #include <stdio.h>
  35. #include <errno.h>
  36. #include <string.h>
  37. #ifdef SYSSYSLOG
  38. #include <sys/syslog.h>
  39. #else
  40. #include <syslog.h>
  41. #endif
  42. #include <time.h>
  43. #include <pwd.h>
  44. #include <grp.h>
  45.  
  46. #include <sys/types.h>
  47. #include <sys/stat.h>
  48. #ifndef AMIGA
  49. #include <sys/file.h>
  50. #endif
  51. #include <sys/param.h>
  52.  
  53. #ifdef HAVE_STATVFS
  54. #include <sys/statvfs.h>
  55. #endif
  56.  
  57. #include <arpa/ftp.h>
  58.  
  59. #include "pathnames.h"
  60. #include "extensions.h"
  61. #include "ftw.h"
  62.  
  63. #ifdef HAVE_REGEX_H
  64. #include <regex.h>
  65. #endif
  66.  
  67. #ifdef AMIGA
  68. #include <regexp.h>
  69. #endif
  70.  
  71. #if defined(REGEX) && defined(SOLARIS_21)
  72. #include <libgen.h>
  73. #endif
  74.  
  75. extern int fnmatch(),
  76.   type,
  77.   transflag,
  78.   autospout_free,
  79.   data,
  80.   anonymous,
  81.   guest;
  82. extern char **ftpglob(register char *v),
  83.  *globerr,
  84.   remotehost[],
  85.   hostname[],
  86.  *autospout,
  87.   Shutdown[];
  88.  
  89. char shuttime[30],
  90.   denytime[30],
  91.   disctime[30];
  92.  
  93. #ifndef REGEX
  94. char *re_comp();
  95. #elif defined(M_UNIX)
  96. extern char *regcmp(), *regex();
  97. #endif
  98.  
  99. extern FILE *dataconn(char *name, off_t size, char *mode);
  100. FILE *dout;
  101.  
  102. time_t newer_time;
  103.  
  104. int show_fullinfo;
  105.  
  106. check_newer(char *path, struct stat *st, int flag)
  107. {
  108.  
  109.     if (st->st_mtime > newer_time) {
  110.         if (show_fullinfo != 0) {
  111.             if (flag == FTW_F || flag == FTW_D) {
  112.                 fprintf(dout, "%s %d %d %s", flag == FTW_F ? "F" : "D",
  113.                         st->st_size, st->st_mtime, path);
  114.             }
  115.         } else if (flag == FTW_F)
  116.             fprintf(dout, "%s", path);
  117.     }
  118.     return 0;
  119. }
  120.  
  121. #ifdef HAVE_STATVFS
  122. int getSize(s)
  123. char *s;
  124. {
  125.     int c;
  126.     struct statvfs buf;
  127.  
  128.     if (( c = statvfs(s, &buf)) != 0)
  129.         return(0);
  130.  
  131.     return(buf.f_bavail * buf.f_frsize / 1024);
  132. }
  133. #endif
  134.  
  135. /*************************************************************************/
  136. /* FUNCTION  : msg_massage                                               */
  137. /* PURPOSE   : Scan a message line for magic cookies, replacing them as  */
  138. /*             needed.                                                   */
  139. /* ARGUMENTS : pointer input and output buffers                          */
  140. /*************************************************************************/
  141.  
  142. int
  143. msg_massage(char *inbuf, char *outbuf)
  144. {
  145.     char *inptr = inbuf;
  146.     char *outptr = outbuf;
  147.     char buffer[MAXPATHLEN];
  148.     time_t curtime;
  149.     int limit;
  150.     extern struct passwd *pw;
  151.     struct aclmember *entry = NULL;
  152.  
  153.     (void) time(&curtime);
  154.     (void) acl_getclass(buffer);
  155.  
  156.     limit = acl_getlimit(buffer, NULL);
  157.  
  158.     while (*inptr) {
  159.         if (*inptr != '%')
  160.             *outptr++ = *inptr;
  161.         else {
  162.             switch (*++inptr) {
  163.             case 'E':
  164.                 if ( (getaclentry("email", &entry)) && ARG0 )
  165.                     sprintf(outptr, "%s", ARG0); 
  166.                 break;
  167.             case 'N': 
  168.                 sprintf(outptr, "%d", acl_countusers(buffer)); 
  169.                 break; 
  170.             case 'M':
  171.                 sprintf(outptr, "%d", limit);
  172.                 break;
  173.  
  174.             case 'T':
  175.                 strncpy(outptr, ctime(&curtime), 24);
  176.                 *(outptr + 24) = NULL;
  177.                 break;
  178.  
  179.             case 'F':
  180. #ifdef HAVE_STATVFS
  181.                 sprintf(outptr, "%lu", getSize("."));
  182. #endif
  183.                 break;
  184.  
  185.             case 'C':
  186. #ifdef HAVE_GETCWD
  187.                 (void) getcwd(outptr, MAXPATHLEN);
  188. #else
  189.                 (void) getwd(outptr);
  190. #endif
  191.                 break;
  192.  
  193.             case 'R':
  194.                 strcpy(outptr, remotehost);
  195.                 break;
  196.  
  197.             case 'L':
  198.                 strcpy(outptr, hostname);
  199.                 break;
  200.  
  201.             case 'U':
  202.                 strcpy(outptr, pw->pw_name);
  203.                 break;
  204.  
  205.             case 's':
  206.                 strncpy(outptr, shuttime, 24);
  207.                 *(outptr + 24) = NULL;
  208.                 break;
  209.  
  210.             case 'd':
  211.                 strncpy(outptr, disctime, 24);
  212.                 *(outptr + 24) = NULL;
  213.                 break;
  214.  
  215.             case 'r':
  216.                 strncpy(outptr, denytime, 24);
  217.                 *(outptr + 24) = NULL;
  218.                 break;
  219.  
  220.             case '%':
  221.                 *outptr++ = '%';
  222.                 *outptr = '\0';
  223.                 break;
  224.  
  225.             default:
  226.                 *outptr++ = '%';
  227.                 *outptr++ = '?';
  228.                 *outptr = '\0';
  229.                 break;
  230.             }
  231.             while (*outptr)
  232.                 outptr++;
  233.         }
  234.         inptr++;
  235.     }
  236.     *outptr = NULL;
  237. }
  238.  
  239. /*************************************************************************/
  240. /* FUNCTION  : cwd_beenhere                                              */
  241. /* PURPOSE   : Return 1 if the user has already visited this directory   */
  242. /*             via C_WD.                                                 */
  243. /* ARGUMENTS : a power-of-two directory function code (README, MESSAGE)  */
  244. /*************************************************************************/
  245.  
  246. int
  247. cwd_beenhere(int dircode)
  248. {
  249.     struct dirlist {
  250.         struct dirlist *next;
  251.         int dircode;
  252.         char dirname[1];
  253.     };
  254.  
  255.     static struct dirlist *head = NULL;
  256.     struct dirlist *curptr;
  257.     char cwd[MAXPATHLEN];
  258.  
  259. #ifdef AMIGA
  260.     (void) realpath("", cwd);
  261. #else
  262.     (void) realpath(".", cwd);
  263. #endif
  264.  
  265.     for (curptr = head; curptr != NULL; curptr = curptr->next)
  266.         if (strcmp(curptr->dirname, cwd) == NULL) {
  267.             if (!(curptr->dircode & dircode)) {
  268.                 curptr->dircode |= dircode;
  269.                 return (0);
  270.             }
  271.             return (1);
  272.         }
  273.     curptr = (struct dirlist *) malloc(strlen(cwd) + 1 + sizeof(struct dirlist));
  274.  
  275.     if (curptr != NULL) {
  276.         curptr->next = head;
  277.         head = curptr;
  278.         curptr->dircode = dircode;
  279.         strcpy(curptr->dirname, cwd);
  280.     }
  281.     return (0);
  282. }
  283.  
  284. /*************************************************************************/
  285. /* FUNCTION  : show_banner                                               */
  286. /* PURPOSE   : Display a banner on the user's terminal before login      */
  287. /* ARGUMENTS : reply code to use                                         */
  288. /*************************************************************************/
  289.  
  290. void
  291. show_banner(int msgcode)
  292. {
  293.     char *crptr,
  294.       linebuf[1024],
  295.       outbuf[1024];
  296.     struct aclmember *entry = NULL;
  297.     FILE *infile;
  298.  
  299.     /* banner <path> */
  300.     while (getaclentry("banner", &entry)) {
  301.         if (ARG0 && strlen(ARG0) > 0) {
  302.             infile = fopen(ARG0, "r");
  303.             if (infile) {
  304.                 while (fgets(linebuf, 255, infile) != NULL) {
  305.                     if ((crptr = strchr(linebuf, '\n')) != NULL)
  306.                         *crptr = '\0';
  307.                     msg_massage(linebuf, outbuf);
  308.                     lreply(msgcode, "%s", outbuf);
  309.                 }
  310.                 fclose(infile);
  311.                 lreply(msgcode, "");
  312.             }
  313.         }
  314.     }
  315. }
  316.  
  317. /*************************************************************************/
  318. /* FUNCTION  : show_message                                              */
  319. /* PURPOSE   : Display a message on the user's terminal if the current   */
  320. /*             conditions are right                                      */
  321. /* ARGUMENTS : reply code to use, LOG_IN|CMD                             */
  322. /*************************************************************************/
  323.  
  324. void
  325. show_message(int msgcode, int mode)
  326. {
  327.     char *crptr,
  328.       linebuf[1024],
  329.       outbuf[1024],
  330.       class[MAXPATHLEN],
  331.       cwd[MAXPATHLEN];
  332.     int show,
  333.       which;
  334.     struct aclmember *entry = NULL;
  335.     FILE *infile;
  336.  
  337.     if (cwd_beenhere(1) != 0)
  338.         return;
  339.  
  340. #ifdef HAVE_GETCWD
  341.     (void) getcwd(cwd,MAXPATHLEN-1);
  342. #else
  343.     (void) getwd(cwd);
  344. #endif
  345.     (void) acl_getclass(class);
  346.  
  347.     /* message <path> [<when> [<class>]] */
  348.     while (getaclentry("message", &entry)) {
  349.         if (!ARG0)
  350.             continue;
  351.         show = 0;
  352.  
  353.         if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login")))
  354.             if (!ARG2)
  355.                 show++;
  356.             else {
  357.                 for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  358.                     if (strcasecmp(class, ARG[which]) == NULL)
  359.                         show++;
  360.             }
  361.         if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) &&
  362.             (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' ||
  363.             fnmatch((ARG1) + 4, cwd, FNM_PATHNAME)))
  364.             if (!ARG2)
  365.                 show++;
  366.             else {
  367.                 for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  368.                     if (strcasecmp(class, ARG[which]) == NULL)
  369.                         show++;
  370.             }
  371.         if (show && strlen(ARG0) > 0) {
  372.             infile = fopen(ARG0, "r");
  373.             if (infile) {
  374.                 while (fgets(linebuf, 255, infile) != NULL) {
  375.                     if ((crptr = strchr(linebuf, '\n')) != NULL)
  376.                         *crptr = '\0';
  377.                     msg_massage(linebuf, outbuf);
  378.                     lreply(msgcode, "%s", outbuf);
  379.                 }
  380.                 fclose(infile);
  381.                 lreply(msgcode, "");
  382.             }
  383.         }
  384.     }
  385. }
  386.  
  387. /*************************************************************************/
  388. /* FUNCTION  : show_readme                                               */
  389. /* PURPOSE   : Display a message about a README file to the user if the  */
  390. /*             current conditions are right                              */
  391. /* ARGUMENTS : pointer to ACL buffer, reply code, LOG_IN|C_WD            */
  392. /*************************************************************************/
  393.  
  394. void
  395. show_readme(int code, int mode)
  396. {
  397.     char **filelist,
  398.       class[MAXPATHLEN],
  399.       cwd[MAXPATHLEN];
  400.     int show,
  401.       which,
  402.       days;
  403.     time_t clock;
  404.  
  405.     struct stat buf;
  406.     struct tm *tp;
  407.     struct aclmember *entry = NULL;
  408.  
  409.     if (cwd_beenhere(2) != 0)
  410.         return;
  411.  
  412. #ifdef HAVE_GETCWD
  413.     (void) getcwd(cwd,MAXPATHLEN-1);
  414. #else
  415.     (void) getwd(cwd);
  416. #endif
  417.     (void) acl_getclass(class);
  418.  
  419.     /* readme  <path> {<when>} */
  420.     while (getaclentry("readme", &entry)) {
  421.         if (!ARG0)
  422.             continue;
  423.         show = 0;
  424.  
  425.         if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login")))
  426.             if (!ARG2)
  427.                 show++;
  428.             else {
  429.                 for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  430.                     if (strcasecmp(class, ARG[which]) == NULL)
  431.                         show++;
  432.             }
  433.         if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4)
  434.             && (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' ||
  435.                 fnmatch((ARG1) + 4, cwd, FNM_PATHNAME)))
  436.             if (!ARG2)
  437.                 show++;
  438.             else {
  439.                 for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  440.                     if (strcasecmp(class, ARG[which]) == NULL)
  441.                         show++;
  442.             }
  443.         if (show) {
  444.             globerr = NULL;
  445.             filelist = ftpglob(ARG0);
  446.             if (!globerr) {
  447.                 while (filelist && *filelist) {
  448.                    errno = 0;
  449.                    if (!stat(*filelist, &buf)) {
  450.                        lreply(code, "Please read the file %s", *filelist);
  451.                        (void) time(&clock);
  452.                        tp = localtime(&clock);
  453.                        days = 365 * tp->tm_year + tp->tm_yday;
  454.                        tp = localtime(&buf.st_mtime);
  455.                        days -= 365 * tp->tm_year + tp->tm_yday;
  456. /*
  457.                        if (days == 0) {
  458.                          lreply(code, "  it was last modified on %.24s - Today",
  459.                            ctime(&buf.st_mtime));
  460.                        } else {
  461. */
  462.                          lreply(code, 
  463.                            "  it was last modified on %.24s - %d day%s ago",
  464.                            ctime(&buf.st_mtime), days, days == 1 ? "" : "s");
  465. /*
  466.                        }
  467. */
  468.                    }
  469.                    filelist++;
  470.                 }
  471.             }
  472.         }
  473.     }
  474. }
  475.  
  476. /*************************************************************************/
  477. /* FUNCTION  : deny_badxfertype                                          */
  478. /* PURPOSE   : If user is in ASCII transfer mode and tries to retrieve a */
  479. /*             binary file, abort transfer and display appropriate error */
  480. /* ARGUMENTS : message code to use for denial, path of file to check for */
  481. /*             binary contents or NULL to assume binary file             */
  482. /*************************************************************************/
  483.  
  484. int
  485. deny_badasciixfer(int msgcode, char *filepath)
  486. {
  487.  
  488.     if (type == TYPE_A && !*filepath) {
  489.         reply(msgcode, "This is a BINARY file, using ASCII mode to transfer will corrupt it.");
  490.         return (1);
  491.     }
  492.     /* The hooks are here to prevent transfers of actual binary files, not
  493.      * just TAR or COMPRESS mode files... */
  494.     return (0);
  495. }
  496.  
  497. /*************************************************************************/
  498. /* FUNCTION  : is_shutdown                                               */
  499. /* PURPOSE   :                                                           */
  500. /* ARGUMENTS :                                                           */
  501. /*************************************************************************/
  502.  
  503. int
  504. is_shutdown(int quiet)
  505. {
  506.     static struct tm tmbuf;
  507.     static struct stat s_last;
  508.     static time_t last = 0,
  509.       shut,
  510.       deny,
  511.       disc;
  512.  
  513.     static char text[2048];
  514.  
  515.     struct stat s_cur;
  516.  
  517.     FILE *fp;
  518.  
  519.     int deny_off,
  520.       disc_off;
  521.  
  522.     time_t curtime = time(NULL);
  523.  
  524.     char buf[1024],
  525.       linebuf[1024];
  526.  
  527.     if (Shutdown[0] == '\0' || stat(Shutdown, &s_cur))
  528.         return (0);
  529.  
  530.     if (s_last.st_mtime != s_cur.st_mtime) {
  531.         s_last = s_cur;
  532.  
  533.         fp = fopen(Shutdown, "r");
  534.         if (fp == NULL)
  535.             return (0);
  536.         fgets(buf, sizeof(buf), fp);
  537.         if (sscanf(buf, "%d %d %d %d %d %d %d", &tmbuf.tm_year, &tmbuf.tm_mon,
  538.         &tmbuf.tm_mday, &tmbuf.tm_hour, &tmbuf.tm_min, &deny, &disc) != 7) {
  539.             return (0);
  540.         }
  541.         deny_off = 3600 * (deny / 100) + 60 * (deny % 100);
  542.         disc_off = 3600 * (disc / 100) + 60 * (disc % 100);
  543.  
  544.         tmbuf.tm_year -= 1900;
  545.         tmbuf.tm_isdst = -1;
  546.         shut = mktime(&tmbuf);
  547.         strcpy(shuttime, ctime(&shut));
  548.  
  549.         disc = shut - disc_off;
  550.         strcpy(disctime, ctime(&disc));
  551.  
  552.         deny = shut - deny_off;
  553.         strcpy(denytime, ctime(&deny));
  554.  
  555.         text[0] = '\0';
  556.  
  557.         while (fgets(buf, sizeof(buf), fp) != NULL) {
  558.             msg_massage(buf, linebuf);
  559.             if ((strlen(text) + strlen(linebuf)) < sizeof(text))
  560.                 strcat(text, linebuf);
  561.         }
  562.  
  563.         (void) fclose(fp);
  564.     }
  565.     /* if last == 0, then is_shutdown() only called with quiet == 1 so far */
  566.     if (last == 0 && !quiet) {
  567.         autospout = text;       /* warn them for the first time */
  568.         autospout_free = 0;
  569.         last = curtime;
  570.     }
  571.     /* if past disconnect time, tell caller to drop 'em */
  572.     if (curtime > disc)
  573.         return (1);
  574.  
  575.     /* if less than 60 seconds to disconnection, warn 'em continuously */
  576.     if (curtime > (disc - 60) && !quiet) {
  577.         autospout = text;
  578.         autospout_free = 0;
  579.         last = curtime;
  580.     }
  581.     /* if less than 15 minutes to disconnection, warn 'em every 5 mins */
  582.     if (curtime > (disc - 60 * 15)) {
  583.         if ((curtime - last) > (60 * 5) && !quiet) {
  584.             autospout = text;
  585.             autospout_free = 0;
  586.             last = curtime;
  587.         }
  588.     }
  589.     /* if less than 24 hours to disconnection, warn 'em every 30 mins */
  590.     if (curtime < (disc - 24 * 60 * 60) && !quiet) {
  591.         if ((curtime - last) > (60 * 30)) {
  592.             autospout = text;
  593.             autospout_free = 0;
  594.             last = curtime;
  595.         }
  596.     }
  597.     /* if more than 24 hours to disconnection, warn 'em every 60 mins */
  598.     if (curtime > (disc - 24 * 60 * 60) && !quiet) {
  599.         if ((curtime - last) >= (24 * 60 * 60)) {
  600.             autospout = text;
  601.             autospout_free = 0;
  602.             last = curtime;
  603.         }
  604.     }
  605.     return (0);
  606. }
  607.  
  608. newer(char *date, char *path, int showlots)
  609. {
  610.     struct tm tm;
  611.  
  612.     if (sscanf(date, "%04d%02d%02d%02d%02d%02d",
  613.                &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
  614.                &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
  615.  
  616.         tm.tm_year -= 1900;
  617.         tm.tm_mon--;
  618.         tm.tm_isdst = -1;
  619.         newer_time = mktime(&tm);
  620.         dout = dataconn("file list", (off_t) - 1, "w");
  621.         /* dout = dataconn("file list", (off_t)-1, "w", 0); */
  622.         transflag++;
  623.         if (dout != NULL) {
  624.  
  625.             show_fullinfo = showlots;
  626. #if defined(HAVE_FTW)
  627.             ftw(path, check_newer, -1);
  628. #else
  629.             treewalk(path, check_newer, -1, NULL);
  630. #endif
  631.  
  632.             if (ferror(dout) != 0)
  633.                 perror_reply(550, "Data connection");
  634.             else
  635.                 reply(226, "Transfer complete.");
  636.  
  637.             (void) fclose(dout);
  638.             data = -1;
  639.         }
  640.     } else
  641.         reply(501, "Bad DATE format");
  642.     transflag = 0;
  643. }
  644.  
  645. int
  646. type_match(char *typelist)
  647. {
  648.     if (anonymous && strcasestr(typelist, "anonymous"))
  649.         return (1);
  650.     if (guest && strcasestr(typelist, "guest"))
  651.         return (1);
  652.     if (!guest && !anonymous && strcasestr(typelist, "real"))
  653.         return (1);
  654.  
  655.     return (0);
  656. }
  657.  
  658. int
  659. path_compare(char *p1, char *p2)
  660. {
  661.     if ( fnmatch(p1, p2, NULL) != 0 )
  662.         return(strlen(p1));
  663.     else
  664.         return(-1);
  665. }
  666.  
  667. void
  668. expand_id(void)
  669. {
  670.     struct aclmember *entry = NULL;
  671.     struct passwd *pwent;
  672.     struct group *grent;
  673.     char buf[BUFSIZ];
  674.  
  675.     while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
  676.         if (ARG3 && ARG4) {
  677.             pwent = getpwnam(ARG3);
  678.             grent = getgrnam(ARG4);
  679.  
  680.             if (pwent)  sprintf(buf, "%d", pwent->pw_uid);
  681.             else        sprintf(buf, "%d", 0);
  682.             ARG3 = (char *) malloc(strlen(buf) + 1);
  683.             strcpy(ARG3, buf);
  684.  
  685.             if (grent)  sprintf(buf, "%d", grent->gr_gid);
  686.             else        sprintf(buf, "%d", 0);
  687.             ARG4 = (char *) malloc(strlen(buf) + 1);
  688.             strcpy(ARG4, buf);
  689.         }
  690.     }
  691. }
  692.  
  693. int
  694. fn_check(char *name)
  695. {
  696.   /* check to see if this is a valid file name... path-filter <type>
  697.    * <message_file> <allowed_charset> <disallowed> */
  698.  
  699.   struct aclmember *entry = NULL;
  700.   int   j;
  701. #ifdef AMIGA
  702.   regexp *sp;
  703.   int regp;
  704. #else
  705.   char *sp;
  706. #endif
  707.   char *path;
  708.  
  709. #ifdef M_UNIX
  710. # ifdef REGEX
  711.   char *regp;
  712. # endif
  713. #endif
  714.  
  715. #ifdef REGEXEC
  716.   regex_t regexbuf;
  717.   regmatch_t regmatchbuf;
  718. #endif
  719.  
  720.   while (getaclentry("path-filter", &entry) && ARG0 != NULL) {
  721.       if (type_match(ARG0) && ARG1 && ARG2) {
  722.  
  723.           /*
  724.            * check *only* the basename
  725.            */
  726.  
  727.           if (path = strrchr(name, '/'))  ++path;
  728.           else    path = name;
  729.  
  730.           /* is it in the allowed character set? */
  731. #if defined(AMIGA)
  732.           if ((sp = regcomp(ARG2)) == 0) {
  733.               reply(553, "REGEX error");
  734. #elif defined(REGEXEC)
  735.           if (regcomp(®exbuf, ARG2, REG_EXTENDED|REG_ICASE) != 0) {
  736.               reply(553, "REGEX error");
  737. #elif defined(REGEX)
  738.           if ((sp = regcmp(ARG2, (char *) 0)) == NULL) {
  739.               reply(553, "REGEX error");
  740. #else
  741.           if ((sp = re_comp(ARG2)) != 0) {
  742.               perror_reply(553, sp);
  743. #endif
  744.               return(0);
  745.           }
  746. #if defined(AMIGA)
  747.           regp = regexec(sp, path);
  748.           free(sp);
  749.           if (regp == 0) {
  750. #elif defined(REGEXEC)
  751.           if (regexec(®exbuf, path, 1, ®matchbuf, 0) != 0) {
  752. #elif defined(REGEX)
  753. # ifdef M_UNIX
  754.           regp = regex(sp, path);
  755.           free(sp);
  756.           if (regp == NULL) {
  757. # else
  758.           if ((regex(sp, path)) == NULL) {
  759. # endif
  760. #else
  761.           if ((re_exec(path)) != 1) {
  762. #endif
  763.               pr_mesg(553, ARG1);
  764.               reply(553, "%s: Permission denied. (Filename (accept))", name);
  765.               return(0);
  766.           }
  767.           /* is it in any of the disallowed regexps */
  768.  
  769.           for (j = 3; j < MAXARGS; ++j) {
  770.               /* ARGj == entry->arg[j] */
  771.               if (entry->arg[j]) {
  772. #if defined(AMIGA)
  773.                   if ((sp = regcomp(entry->arg[j])) == 0) {
  774.                       perror_reply(553, "REGEX error");
  775. #elif defined(REGEXEC)
  776.                   if (regcomp(®exbuf, entry->arg[j], 
  777.                         REG_EXTENDED|REG_ICASE) !=0) {
  778.                       reply(553, "REGEX error");
  779. #elif defined(REGEX)
  780.                   if ((sp = regcmp(entry->arg[j], (char *) 0)) == NULL) {
  781.                       reply(553, "REGEX error");
  782. #else
  783.                   if ((sp = re_comp(entry->arg[j])) != 0) {
  784.                       perror_reply(553, sp);
  785. #endif
  786.                       return(0);
  787.                   }
  788. #if defined(AMIGA)
  789.                   regp = regexec(sp, path);
  790.                   free(sp);
  791.                   if (regp != 0) {
  792. #elif defined(REGEXEC)
  793.                   if (regexec(®exbuf, path, 1, ®matchbuf, 0) == 0) {
  794. #elif defined(REGEX)
  795. # ifdef M_UNIX
  796.                   regp = regex(sp, path);
  797.                   free(sp);
  798.                   if (regp != NULL) {
  799. # else
  800.                   if ((regex(sp, path)) != NULL) {
  801. # endif
  802. #else
  803.                   if ((re_exec(path)) == 1) {
  804. #endif
  805.                       pr_mesg(553, ARG1);
  806.                       reply(553, "%s: Permission denied. (Filename (deny))", name);
  807.                       return(0);
  808.                   }
  809.               }
  810.           }
  811.       }
  812.   }
  813.   return(1);
  814. }
  815.  
  816. int
  817. dir_check(char *name, uid_t *uid, gid_t *gid, int *valid)
  818. {
  819.   struct aclmember *entry = NULL;
  820.  
  821.   int i,
  822.     match_value = -1;
  823.   char *ap2 = NULL,
  824.        *ap3 = NULL,
  825.        *ap4 = NULL,
  826.        *ap6 = NULL;
  827.   char cwdir[BUFSIZ];
  828.   char path[BUFSIZ];
  829.   char *sp;
  830.   extern struct passwd *pw;
  831.  
  832.   *valid = 0;
  833.  
  834.   strcpy(path, name);
  835. #ifdef AMIGA
  836.   if (sp = strrchr(path, '/'))  *sp = '\0';
  837.   else if (sp = strrchr(path, ':'))  *sp = '\0';
  838.   else path[0] = '\0';
  839. #else
  840.   if (sp = strrchr(path, '/'))  *sp = '\0';
  841.   else strcpy(path, ".");
  842. #endif
  843.  
  844.   if ((realpath(path, cwdir)) == NULL) {
  845.       perror_reply(553, "Could not determine cwdir");
  846.       return(0);
  847.   }
  848.  
  849.   i = match_value;
  850.   while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
  851.       if ( (!strcmp(ARG0, pw->pw_dir))  &&
  852.            ((i = path_compare(ARG1, cwdir)) >= match_value) ) {
  853.           match_value = i;
  854.           ap2 = ARG2;
  855.           if (ARG3)  ap3 = ARG3;
  856.           else       ap3 = NULL;
  857.           if (ARG4)  ap4 = ARG4;
  858.           else       ap4 = NULL;
  859.           if (ARG6)  ap6 = ARG6;
  860.           else       ap6 = NULL;
  861.       }
  862.   }
  863.  
  864.   if ( ((ap2 && !strcasecmp(ap2, "no")) && (ap3 && strcasecmp(ap3, "dirs"))) || 
  865.         (ap3 && !strcasecmp(ap3, "nodirs")) ||
  866.         (ap6 && !strcasecmp(ap6, "nodirs")) ) {
  867.       reply(530, "%s: Permission denied.  (Upload)", name);
  868.       return(0);
  869.   }
  870.  
  871.   if (ap3)
  872.      *uid = atoi(ap3);    /* the uid  */
  873.   if (ap4) {
  874.      *gid = atoi(ap4);    /* the gid  */
  875.      *valid = 1;
  876.    }
  877.   return(1);
  878. }
  879.  
  880. int
  881. upl_check(char *name, uid_t *uid, gid_t *gid, int *f_mode, int *valid)
  882. {
  883.   int  match_value = -1;
  884.   char cwdir[BUFSIZ];
  885.   char path[BUFSIZ];
  886.   char *sp;
  887.   int  i;
  888.  
  889.   char *ap1 = NULL,
  890.    *ap2 = NULL,
  891.    *ap3 = NULL,
  892.    *ap4 = NULL,
  893.    *ap5 = NULL;
  894.  
  895.   struct aclmember *entry = NULL;
  896.   extern struct passwd *pw;
  897.  
  898.   *valid = 0;
  899.  
  900.       /* what's our current directory? */
  901.  
  902.       strcpy(path, name);
  903. #ifdef AMIGA
  904.       if (sp = strrchr(path, '/'))  *sp = '\0';
  905.       else if (sp = strrchr(path, ':'))  *sp = '\0';
  906.       else path[0] = '\0';
  907. #else
  908.       if (sp = strrchr(path, '/'))  *sp = '\0';
  909.       else strcpy(path, ".");
  910. #endif
  911.  
  912.       if ((realpath(path, cwdir)) == NULL) {
  913.           perror_reply(553, "Could not determine cwdir");
  914.           return(-1);
  915.       }
  916.  
  917.       /* we are doing a "best match"... ..so we keep track of what "match
  918.        * value" we have received so far... */
  919.  
  920.       entry = NULL;
  921.       match_value = -1;
  922.       i = match_value;
  923.       while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
  924.           if ( (!strcmp(ARG0, pw->pw_dir))  &&
  925.                ((i = path_compare(ARG1, cwdir)) >= match_value) ) {
  926.               match_value = i;
  927.               ap1 = ARG1;
  928.               ap2 = ARG2;
  929.               if (ARG3) ap3 = ARG3;
  930.               else      ap3 = NULL;
  931.               if (ARG4) ap4 = ARG4;
  932.               else      ap4 = NULL;
  933.               if (ARG5) ap5 = ARG5;
  934.               else      ap5 = NULL;
  935.           }
  936.       }
  937.  
  938.       if (ap3 && ( (!strcasecmp("dirs",ap3)) || (!strcasecmp("nodirs", ap3)) ))
  939.         ap3 = NULL;
  940.  
  941.       /* if we did get matches... ..else don't do any of this stuff */
  942.       if (match_value >= 0) {
  943.           if (!strcasecmp(ap2, "yes")) {
  944.               if (ap3)
  945.                   *uid = atoi(ap3);    /* the uid  */
  946.               if (ap4) {
  947.                   *gid = atoi(ap4);    /* the gid  */
  948.           *valid = 1;
  949.         }
  950.               if (ap5)
  951.                   sscanf(ap5, "%o", f_mode); /* the mode */
  952.           } else {
  953.               reply(553, "%s: Permission denied. (Upload)", name);
  954.               return(-1);
  955.           }
  956.       } else {
  957.           /*
  958.            * upload defaults to "permitted"
  959.            */
  960.           return(1);
  961.       }
  962.  
  963.   return(match_value);
  964. }
  965.  
  966. int
  967. del_check(char *name)
  968. {
  969.   int pdelete = 1;
  970.   struct aclmember *entry = NULL;
  971.  
  972.   while (getaclentry("delete", &entry) && ARG0 && ARG1 != NULL) {
  973.       if (type_match(ARG1))
  974.           if (*ARG0 == 'n')
  975.               pdelete = 0;
  976.   }
  977.  
  978.   if (!pdelete) {
  979.       reply(553, "%s: Permission denied. (Delete)", name);
  980.       return(0);
  981.   } else {
  982.       return(1);
  983.   }
  984. }
  985.