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