extensions.c
上传用户:zibowangxu
上传日期:2007-01-04
资源大小:331k
文件大小:52k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /****************************************************************************  
  2.  
  3.   Copyright (c) 1999 WU-FTPD Development Group.  
  4.   All rights reserved.
  5.   
  6.   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
  7.     The Regents of the University of California.
  8.   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
  9.   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
  10.   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
  11.   Portions Copyright (c) 1998 Sendmail, Inc.
  12.   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
  13.   Portions Copyright (c) 1997 by Stan Barber.
  14.   Portions Copyright (c) 1997 by Kent Landfield.
  15.   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
  16.     Free Software Foundation, Inc.  
  17.  
  18.   Use and distribution of this software and its source code are governed 
  19.   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
  20.  
  21.   If you did not receive a copy of the license, it may be obtained online
  22.   at http://www.wu-ftpd.org/license.html.
  23.  
  24.   $Id: extensions.c,v 1.46 1999/10/14 14:36:52 wuftpd Exp $
  25.  
  26. ****************************************************************************/
  27. #include "config.h"
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <string.h>
  31. #ifdef HAVE_SYS_SYSLOG_H
  32. #include <sys/syslog.h>
  33. #elif defined(HAVE_SYSLOG_H) || !defined(AUTOCONF)
  34. #include <syslog.h>
  35. #endif
  36. #ifdef TIME_WITH_SYS_TIME
  37. #include <time.h>
  38. #include <sys/time.h>
  39. #else
  40. #ifdef HAVE_SYS_TIME_H
  41. #include <sys/time.h>
  42. #else
  43. #include <time.h>
  44. #endif
  45. #endif
  46. #include <pwd.h>
  47. #include <setjmp.h>
  48. #include <grp.h>
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <sys/file.h>
  52. #include <sys/param.h>
  53. #ifdef HAVE_SYS_FS_UFS_QUOTA_H
  54. #include <sys/fs/ufs_quota.h>
  55. #elif defined(HAVE_UFS_UFS_QUOTA_H)
  56. #include <ufs/ufs/quota.h>
  57. #elif defined(HAVE_UFS_QUOTA_H)
  58. #include <ufs/quota.h>
  59. #elif defined(HAVE_SYS_MNTENT_H)
  60. #include <sys/mntent.h>
  61. #elif defined(HAVE_SYS_MNTTAB_H)
  62. #include <sys/mnttab.h>
  63. #endif
  64. #if defined(HAVE_STATVFS)
  65. #include <sys/statvfs.h>
  66. #elif defined(HAVE_SYS_VFS)
  67. #include <sys/vfs.h>
  68. #elif defined(HAVE_SYS_MOUNT)
  69. #include <sys/mount.h>
  70. #endif
  71. #include "../support/ftp.h"
  72. #ifdef HAVE_PATHS_H
  73. #include <paths.h>
  74. #endif
  75. #include "pathnames.h"
  76. #include "extensions.h"
  77. #include "wu_fnmatch.h"
  78. #include "proto.h"
  79. #if defined(HAVE_FTW)
  80. #include <ftw.h>
  81. #else
  82. #include "support/ftw.h"
  83. #endif
  84. #ifdef QUOTA
  85. struct dqblk quota;
  86. char *time_quota(long curstate, long softlimit, long timelimit, char *timeleft);
  87. #endif
  88. #ifdef HAVE_REGEX_H
  89. #include <regex.h>
  90. #endif
  91. #if defined(HAVE_REGEX) && defined(SVR4) && ! (defined(NO_LIBGEN))
  92. #include <libgen.h>
  93. #endif
  94. extern int type, transflag, ftwflag, authenticated, autospout_free, data,
  95.     pdata, anonymous, guest;
  96. #ifdef LOG_FAILED
  97. extern char the_user[];
  98. #endif
  99. extern char *globerr, remotehost[];
  100. #ifdef THROUGHPUT
  101. extern char remoteaddr[];
  102. #endif
  103. #ifndef HAVE_REGEX
  104. char *re_comp(const char *regex);
  105. int re_exec(const char *p1);
  106. #endif
  107. char shuttime[30], denytime[30], disctime[30];
  108. FILE *dout;
  109. time_t newer_time;
  110. int show_fullinfo;
  111. /* This always was a bug, because neither st_size nor time_t were required to
  112.    be compatible with int, but needs fixing properly for C9X. */
  113. /* Some systems use one format, some another.  This takes care of the garbage */
  114. /* Do the system specific stuff only if we aren't autoconfed */
  115. #if !defined(L_FORMAT)
  116. #if (defined(BSD) && (BSD >= 199103)) && !defined(LONGOFF_T)
  117. #define L_FORMAT "qd"
  118. #else
  119. #define L_FORMAT "d"
  120. #endif
  121. #endif
  122. #if !defined(T_FORMAT)
  123. #define T_FORMAT "d"
  124. #endif
  125. #if !defined(PW_UID_FORMAT)
  126. #define PW_UID_FORMAT "d"
  127. #endif
  128. #if !defined(GR_GID_FORMAT)
  129. #define GR_GID_FORMAT "d"
  130. #endif
  131. int snprintf(char *str, size_t count, const char *fmt,...);
  132. int check_newer(char *path, struct stat *st, int flag)
  133. {
  134.     if (st->st_mtime > newer_time) {
  135. if (show_fullinfo != 0) {
  136.     if (flag == FTW_F || flag == FTW_D) {
  137. fprintf(dout, "%s %" L_FORMAT " %" T_FORMAT " %sn",
  138. flag == FTW_F ? "F" : "D",
  139. st->st_size, st->st_mtime, path);
  140.     }
  141. }
  142. else if (flag == FTW_F)
  143.     fprintf(dout, "%sn", path);
  144.     }
  145.     /* When an ABOR has been received (which sets ftwflag > 1) return a
  146.      * non-zero value which causes ftw to stop tree traversal and return. 
  147.      */
  148.     return (ftwflag > 1 ? 1 : 0);
  149. }
  150. #if defined(HAVE_STATVFS)
  151. long getSize(char *s)
  152. {
  153.     int c;
  154.     struct statvfs buf;
  155.     if ((c = statvfs(s, &buf)) != 0)
  156. return (0);
  157.     return (buf.f_bavail * buf.f_frsize / 1024);
  158. }
  159. #elif defined(HAVE_SYS_VFS) || defined (HAVE_SYS_MOUNT)
  160. long getSize(char *s)
  161. {
  162.     int c;
  163.     struct statfs buf;
  164.     if ((c = statfs(s, &buf)) != 0)
  165. return (0);
  166.     return (buf.f_bavail * buf.f_bsize / 1024);
  167. }
  168. #endif
  169. /*************************************************************************/
  170. /* FUNCTION  : msg_massage                                               */
  171. /* PURPOSE   : Scan a message line for magic cookies, replacing them as  */
  172. /*             needed.                                                   */
  173. /* ARGUMENTS : pointer input and output buffers                          */
  174. /*************************************************************************/
  175. void msg_massage(const char *inbuf, char *outbuf, size_t outlen)
  176. {
  177.     const char *inptr = inbuf;
  178.     char *outptr = outbuf;
  179. #ifdef QUOTA
  180.     char timeleft[80];
  181. #endif
  182.     char buffer[MAXPATHLEN];
  183.     time_t curtime;
  184.     int limit;
  185. #ifndef LOG_FAILED
  186.     extern struct passwd *pw;
  187. #endif
  188.     struct aclmember *entry;
  189. #ifdef VIRTUAL
  190.     extern int virtual_mode;
  191.     extern int virtual_ftpaccess;
  192.     extern char virtual_email[];
  193. #endif
  194.     extern char hostname[];
  195.     extern char authuser[];
  196.     (void) acl_getclass(buffer);
  197.     limit = acl_getlimit(buffer, NULL);
  198.     while ((outlen > 1) && (*inptr != '')) {
  199. if (*inptr != '%') {
  200.     *outptr++ = *inptr;
  201.     outlen -= 1;
  202. }
  203. else {
  204.     entry = NULL;
  205.     switch (*++inptr) {
  206.     case 'E':
  207. #ifdef VIRTUAL
  208. if (virtual_mode && !virtual_ftpaccess && virtual_email[0] != '')
  209.     snprintf(outptr, outlen, "%s", virtual_email);
  210. else
  211. #endif
  212. if ((getaclentry("email", &entry)) && ARG0)
  213.     snprintf(outptr, outlen, "%s", ARG0);
  214. else
  215.     *outptr = '';
  216. break;
  217.     case 'N':
  218. snprintf(outptr, outlen, "%d", acl_countusers(buffer));
  219. break;
  220.     case 'M':
  221. if (limit == -1)
  222.     strncpy(outptr, "unlimited", outlen);
  223. else
  224.     snprintf(outptr, outlen, "%d", limit);
  225. break;
  226.     case 'T':
  227. (void) time(&curtime);
  228. strncpy(outptr, ctime(&curtime), outlen);
  229. if (outlen > 24)
  230.     *(outptr + 24) = '';
  231. break;
  232.     case 'F':
  233. #if defined(HAVE_STATVFS) || defined(HAVE_SYS_VFS) || defined(HAVE_SYS_MOUNT)
  234. snprintf(outptr, outlen, "%lu", (long) getSize("."));
  235. #else
  236. *outptr = '';
  237. #endif
  238. break;
  239.     case 'C':
  240. #ifdef HAVE_GETCWD
  241. (void) getcwd(outptr, outlen);
  242. #else
  243. #error wu-ftpd on this platform has security deficiencies!!!
  244. (void) getwd(outptr);
  245. #endif
  246. break;
  247.     case 'R':
  248. strncpy(outptr, remotehost, outlen);
  249. break;
  250.     case 'L':
  251. strncpy(outptr, hostname, outlen);
  252. break;
  253.     case 'U':
  254. #ifdef LOG_FAILED
  255. strncpy(outptr, the_user, outlen);
  256. #else /* LOG_FAILED */
  257. strncpy(outptr,
  258. (pw == NULL) ? "[unknown]" : pw->pw_name, outlen);
  259. #endif /* LOG_FAILED */
  260. break;
  261.     case 's':
  262. strncpy(outptr, shuttime, outlen);
  263. if (outlen > 24)
  264.     *(outptr + 24) = '';
  265. break;
  266.     case 'd':
  267. strncpy(outptr, disctime, outlen);
  268. if (outlen > 24)
  269.     *(outptr + 24) = '';
  270. break;
  271.     case 'r':
  272. strncpy(outptr, denytime, outlen);
  273. if (outlen > 24)
  274.     *(outptr + 24) = '';
  275. break;
  276. /* KH : cookie %u for RFC931 name */
  277.     case 'u':
  278. if (authenticated)
  279.     strncpy(outptr, authuser, outlen);
  280. else
  281.     strncpy(outptr, "[unknown]", outlen);
  282. break;
  283. #ifdef QUOTA
  284.     case 'B':
  285. #ifdef QUOTA_BLOCKS /* 1024-blocks instead of 512-blocks */
  286. snprintf(outptr, outlen, "%ld", quota.dqb_bhardlimit % 2 ?
  287.  (long) (quota.dqb_bhardlimit / 2 + 1) : (long) (quota.dqb_bhardlimit / 2));
  288. #else
  289. snprintf(outptr, outlen, "%ld", (long) quota.dqb_bhardlimit);
  290. #endif
  291. break;
  292.     case 'b':
  293. #ifdef QUOTA_BLOCKS /* 1024-blocks instead of 512-blocks */
  294. snprintf(outptr, outlen, "%ld", quota.dqb_bsoftlimit % 2 ?
  295.  (long) (quota.dqb_bsoftlimit / 2 + 1) : (long) (quota.dqb_bsoftlimit / 2));
  296. #else
  297. snprintf(outptr, outlen, "%ld", (long) quota.dqb_bsoftlimit);
  298. #endif
  299. break;
  300.     case 'Q':
  301. #ifdef QUOTA_BLOCKS /* 1024-blocks instead of 512-blocks */
  302. snprintf(outptr, outlen, "%ld", quota.dqb_curblocks % 2 ?
  303.  (long) (quota.dqb_curblocks / 2 + 1) : (long) (quota.dqb_curblocks / 2));
  304. #else
  305. snprintf(outptr, outlen, "%ld", quota.dqb_curblocks);
  306. #endif
  307. break;
  308.     case 'I':
  309. #if defined(QUOTA_INODE)
  310. snprintf(outptr, outlen, "%d", quota.dqb_ihardlimit);
  311. #else
  312. snprintf(outptr, outlen, "%ld", (long) quota.dqb_fhardlimit);
  313. #endif
  314. break;
  315.     case 'i':
  316. #if defined(QUOTA_INODE)
  317. snprintf(outptr, outlen, "%d", quota.dqb_isoftlimit);
  318. #else
  319. snprintf(outptr, outlen, "%ld", (long) quota.dqb_fsoftlimit);
  320. #endif
  321. break;
  322.     case 'q':
  323. #if defined(QUOTA_INODE)
  324. snprintf(outptr, outlen, "%d", quota.dqb_curinodes);
  325. #else
  326. snprintf(outptr, outlen, "%ld", (long) quota.dqb_curfiles);
  327. #endif
  328. break;
  329.     case 'H':
  330. time_quota(quota.dqb_curblocks, quota.dqb_bsoftlimit,
  331. #if defined(QUOTA_INODE)
  332.    quota.dqb_btime, timeleft);
  333. #else
  334.    quota.dqb_btimelimit, timeleft);
  335. #endif
  336. strncpy(outptr, timeleft, outlen);
  337. break;
  338.     case 'h':
  339. #if defined(QUOTA_INODE)
  340. time_quota(quota.dqb_curinodes, quota.dqb_isoftlimit,
  341.    quota.dqb_itime, timeleft);
  342. #else
  343. time_quota(quota.dqb_curfiles, quota.dqb_fsoftlimit,
  344.    quota.dqb_ftimelimit, timeleft);
  345. #endif
  346. strncpy(outptr, timeleft, outlen);
  347. break;
  348. #endif /* QUOTA */
  349.     case '%':
  350. *outptr++ = '%';
  351. outlen -= 1;
  352. *outptr = '';
  353. break;
  354.     default:
  355. *outptr++ = '%';
  356. outlen -= 1;
  357. if (outlen > 1) {
  358.     *outptr++ = *inptr;
  359.     outlen -= 1;
  360. }
  361. *outptr = '';
  362. break;
  363.     }
  364.     outptr[outlen - 1] = '';
  365.     while (*outptr) {
  366. outptr++;
  367. outlen -= 1;
  368.     }
  369. }
  370. inptr++;
  371.     }
  372.     if (outlen > 0)
  373. *outptr = '';
  374. }
  375. /*************************************************************************/
  376. /* FUNCTION  : cwd_beenhere                                              */
  377. /* PURPOSE   : Return 1 if the user has already visited this directory   */
  378. /*             via C_WD.                                                 */
  379. /* ARGUMENTS : a power-of-two directory function code (README, MESSAGE)  */
  380. /*************************************************************************/
  381. int cwd_beenhere(int dircode)
  382. {
  383.     struct dirlist {
  384. struct dirlist *next;
  385. int dircode;
  386. char dirname[1];
  387.     };
  388.     static struct dirlist *head = NULL;
  389.     struct dirlist *curptr;
  390.     char cwd[MAXPATHLEN];
  391.     (void) fb_realpath(".", cwd);
  392.     for (curptr = head; curptr != NULL; curptr = curptr->next)
  393. if (strcmp(curptr->dirname, cwd) == 0) {
  394.     if (!(curptr->dircode & dircode)) {
  395. curptr->dircode |= dircode;
  396. return (0);
  397.     }
  398.     return (1);
  399. }
  400.     curptr = (struct dirlist *) malloc(strlen(cwd) + 1 + sizeof(struct dirlist));
  401.     if (curptr != NULL) {
  402. curptr->next = head;
  403. head = curptr;
  404. curptr->dircode = dircode;
  405. strcpy(curptr->dirname, cwd);
  406.     }
  407.     return (0);
  408. }
  409. /*************************************************************************/
  410. /* FUNCTION  : show_banner                                               */
  411. /* PURPOSE   : Display a banner on the user's terminal before login      */
  412. /* ARGUMENTS : reply code to use                                         */
  413. /*************************************************************************/
  414. void show_banner(int msgcode)
  415. {
  416.     char *crptr, linebuf[1024], outbuf[1024];
  417.     struct aclmember *entry = NULL;
  418.     FILE *infile;
  419. #ifdef VIRTUAL
  420.     extern int virtual_mode;
  421.     extern int virtual_ftpaccess;
  422.     extern char virtual_banner[];
  423.     if (virtual_mode && !virtual_ftpaccess) {
  424. infile = fopen(virtual_banner, "r");
  425. if (infile) {
  426.     while (fgets(linebuf, sizeof(linebuf), infile) != NULL) {
  427. if ((crptr = strchr(linebuf, 'n')) != NULL)
  428.     *crptr = '';
  429. msg_massage(linebuf, outbuf, sizeof(outbuf));
  430. lreply(msgcode, "%s", outbuf);
  431.     }
  432.     fclose(infile);
  433. #ifndef NO_SUCKING_NEWLINES
  434.     lreply(msgcode, "");
  435. #endif
  436. }
  437.     }
  438.     else {
  439. #endif
  440. /* banner <path> */
  441. while (getaclentry("banner", &entry)) {
  442.     infile = fopen(ARG0, "r");
  443.     if (infile) {
  444. while (fgets(linebuf, sizeof(linebuf), infile) != NULL) {
  445.     if ((crptr = strchr(linebuf, 'n')) != NULL)
  446. *crptr = '';
  447.     msg_massage(linebuf, outbuf, sizeof(outbuf));
  448.     lreply(msgcode, "%s", outbuf);
  449. }
  450. fclose(infile);
  451. #ifndef NO_SUCKING_NEWLINES
  452. lreply(msgcode, "");
  453. #endif
  454.     }
  455. }
  456. #ifdef VIRTUAL
  457.     }
  458. #endif
  459. }
  460. /*************************************************************************/
  461. /* FUNCTION  : show_message                                              */
  462. /* PURPOSE   : Display a message on the user's terminal if the current   */
  463. /*             conditions are right                                      */
  464. /* ARGUMENTS : reply code to use, LOG_IN|CMD                             */
  465. /*************************************************************************/
  466. void show_message(int msgcode, int mode)
  467. {
  468.     char *crptr, linebuf[1024], outbuf[1024], class[MAXPATHLEN], cwd[MAXPATHLEN];
  469.     int show, which;
  470.     struct aclmember *entry = NULL;
  471.     FILE *infile;
  472.     if (mode == C_WD && cwd_beenhere(1) != 0)
  473. return;
  474. #ifdef HAVE_GETCWD
  475.     (void) getcwd(cwd, MAXPATHLEN - 1);
  476. #else
  477.     (void) getwd(cwd);
  478. #endif
  479.     (void) acl_getclass(class);
  480.     /* message <path> [<when> [<class>]] */
  481.     while (getaclentry("message", &entry)) {
  482. if (!ARG0)
  483.     continue;
  484. show = 0;
  485. if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login")))
  486.     if (!ARG2)
  487. show++;
  488.     else {
  489. for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  490.     if (strcasecmp(class, ARG[which]) == 0)
  491. show++;
  492.     }
  493. if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) &&
  494.     (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' ||
  495.      !wu_fnmatch((ARG1) + 4, cwd, FNM_PATHNAME)))
  496.     if (!ARG2)
  497. show++;
  498.     else {
  499. for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  500.     if (strcasecmp(class, ARG[which]) == 0)
  501. show++;
  502.     }
  503. if (show && (int) strlen(ARG0) > 0) {
  504.     infile = fopen(ARG0, "r");
  505.     if (infile) {
  506. while (fgets(linebuf, sizeof(linebuf), infile) != NULL) {
  507.     if ((crptr = strchr(linebuf, 'n')) != NULL)
  508. *crptr = '';
  509.     msg_massage(linebuf, outbuf, sizeof(outbuf));
  510.     lreply(msgcode, "%s", outbuf);
  511. }
  512. fclose(infile);
  513. #ifndef NO_SUCKING_NEWLINES
  514. lreply(msgcode, "");
  515. #endif
  516.     }
  517. }
  518.     }
  519. }
  520. /*************************************************************************/
  521. /* FUNCTION  : show_readme                                               */
  522. /* PURPOSE   : Display a message about a README file to the user if the  */
  523. /*             current conditions are right                              */
  524. /* ARGUMENTS : pointer to ACL buffer, reply code, LOG_IN|C_WD            */
  525. /*************************************************************************/
  526. void show_readme(int code, int mode)
  527. {
  528.     char **filelist, **sfilelist, class[MAXPATHLEN], cwd[MAXPATHLEN];
  529.     int show, which, days;
  530.     time_t clock;
  531.     struct stat buf;
  532.     struct tm *tp;
  533.     struct aclmember *entry = NULL;
  534.     if (cwd_beenhere(2) != 0)
  535. return;
  536. #ifdef HAVE_GETCWD
  537.     (void) getcwd(cwd, MAXPATHLEN - 1);
  538. #else
  539.     (void) getwd(cwd);
  540. #endif
  541.     (void) acl_getclass(class);
  542.     /* readme  <path> {<when>} */
  543.     while (getaclentry("readme", &entry)) {
  544. if (!ARG0)
  545.     continue;
  546. show = 0;
  547. if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login")))
  548.     if (!ARG2)
  549. show++;
  550.     else {
  551. for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  552.     if (strcasecmp(class, ARG[which]) == 0)
  553. show++;
  554.     }
  555. if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4)
  556.     && (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' ||
  557. !wu_fnmatch((ARG1) + 4, cwd, FNM_PATHNAME)))
  558.     if (!ARG2)
  559. show++;
  560.     else {
  561. for (which = 2; (which < MAXARGS) && ARG[which]; which++)
  562.     if (strcasecmp(class, ARG[which]) == 0)
  563. show++;
  564.     }
  565. if (show) {
  566.     globerr = NULL;
  567.     filelist = ftpglob(ARG0);
  568.     sfilelist = filelist; /* save to free later */
  569.     if (!globerr) {
  570. while (filelist && *filelist) {
  571.     errno = 0;
  572.     if (!stat(*filelist, &buf) &&
  573. (buf.st_mode & S_IFMT) == S_IFREG) {
  574. lreply(code, "Please read the file %s", *filelist);
  575. (void) time(&clock);
  576. tp = localtime(&clock);
  577. days = 365 * tp->tm_year + tp->tm_yday;
  578. tp = localtime((time_t *) & buf.st_mtime);
  579. days -= 365 * tp->tm_year + tp->tm_yday;
  580. /*
  581.    if (days == 0) {
  582.    lreply(code, "  it was last modified on %.24s - Today",
  583.    ctime((time_t *)&buf.st_mtime));
  584.    } else {
  585.  */
  586. lreply(code,
  587.    "  it was last modified on %.24s - %d day%s ago",
  588.        ctime((time_t *) & buf.st_mtime), days, days == 1 ? "" : "s");
  589. /*
  590.    }
  591.  */
  592.     }
  593.     filelist++;
  594. }
  595.     }
  596.     if (sfilelist) {
  597. blkfree(sfilelist);
  598. free((char *) sfilelist);
  599.     }
  600. }
  601.     }
  602. }
  603. /*************************************************************************/
  604. /* FUNCTION  : deny_badxfertype                                          */
  605. /* PURPOSE   : If user is in ASCII transfer mode and tries to retrieve a */
  606. /*             binary file, abort transfer and display appropriate error */
  607. /* ARGUMENTS : message code to use for denial, path of file to check for */
  608. /*             binary contents or NULL to assume binary file             */
  609. /*************************************************************************/
  610. int deny_badasciixfer(int msgcode, char *filepath)
  611. {
  612.     if (type == TYPE_A && !*filepath) {
  613. reply(msgcode, "This is a BINARY file, using ASCII mode to transfer will corrupt it.");
  614. return (1);
  615.     }
  616.     /* The hooks are here to prevent transfers of actual binary files, not
  617.      * just TAR or COMPRESS mode files... */
  618.     return (0);
  619. }
  620. /*************************************************************************/
  621. /* FUNCTION  : is_shutdown                                               */
  622. /* PURPOSE   :                                                           */
  623. /* ARGUMENTS :                                                           */
  624. /*************************************************************************/
  625. int is_shutdown(int quiet, int new)
  626. {
  627.     static struct tm tmbuf;
  628.     static struct stat s_last;
  629.     static time_t last = 0, shut, deny, disc;
  630.     static int valid;
  631.     static char text[2048];
  632.     struct stat s_cur;
  633.     extern char *autospout, Shutdown[];
  634.     FILE *fp;
  635.     int deny_off, disc_off;
  636.     time_t curtime = time(NULL);
  637.     char buf[1024], linebuf[1024];
  638.     if (Shutdown[0] == '' || stat(Shutdown, &s_cur))
  639. return (0);
  640.     if (s_last.st_mtime != s_cur.st_mtime) {
  641. s_last = s_cur;
  642. valid = 0;
  643. fp = fopen(Shutdown, "r");
  644. if (fp == NULL)
  645.     return (0);
  646. fgets(buf, sizeof(buf), fp);
  647. if (sscanf(buf, "%d %d %d %d %d %ld %ld", &tmbuf.tm_year, &tmbuf.tm_mon,
  648. &tmbuf.tm_mday, &tmbuf.tm_hour, &tmbuf.tm_min, &deny, &disc) != 7) {
  649.     (void) fclose(fp);
  650.     return (0);
  651. }
  652. valid = 1;
  653. deny_off = 3600 * (deny / 100) + 60 * (deny % 100);
  654. disc_off = 3600 * (disc / 100) + 60 * (disc % 100);
  655. tmbuf.tm_year -= 1900;
  656. tmbuf.tm_isdst = -1;
  657. shut = mktime(&tmbuf);
  658. strcpy(shuttime, ctime(&shut));
  659. disc = shut - disc_off;
  660. strcpy(disctime, ctime(&disc));
  661. deny = shut - deny_off;
  662. strcpy(denytime, ctime(&deny));
  663. text[0] = '';
  664. while (fgets(buf, sizeof(buf), fp) != NULL) {
  665.     msg_massage(buf, linebuf, sizeof(linebuf));
  666.     if ((strlen(text) + strlen(linebuf)) < sizeof(text))
  667. strcat(text, linebuf);
  668. }
  669. (void) fclose(fp);
  670.     }
  671.     if (!valid)
  672. return (0);
  673.     /* if last == 0, then is_shutdown() only called with quiet == 1 so far */
  674.     if (last == 0 && !quiet) {
  675. autospout = text; /* warn them for the first time */
  676. autospout_free = 0;
  677. last = curtime;
  678.     }
  679.     /* if a new connection and past deny time, tell caller to drop 'em */
  680.     if (new && curtime > deny)
  681. return (1);
  682.     /* if past disconnect time, tell caller to drop 'em */
  683.     if (curtime > disc)
  684. return (1);
  685.     /* if less than 60 seconds to disconnection, warn 'em continuously */
  686.     if (curtime > (disc - 60) && !quiet) {
  687. autospout = text;
  688. autospout_free = 0;
  689. last = curtime;
  690.     }
  691.     /* if less than 15 minutes to disconnection, warn 'em every 5 mins */
  692.     if (curtime > (disc - 60 * 15)) {
  693. if ((curtime - last) > (60 * 5) && !quiet) {
  694.     autospout = text;
  695.     autospout_free = 0;
  696.     last = curtime;
  697. }
  698.     }
  699.     /* if less than 24 hours to disconnection, warn 'em every 30 mins */
  700.     if (curtime < (disc - 24 * 60 * 60) && !quiet) {
  701. if ((curtime - last) > (60 * 30)) {
  702.     autospout = text;
  703.     autospout_free = 0;
  704.     last = curtime;
  705. }
  706.     }
  707.     /* if more than 24 hours to disconnection, warn 'em every 60 mins */
  708.     if (curtime > (disc - 24 * 60 * 60) && !quiet) {
  709. if ((curtime - last) >= (24 * 60 * 60)) {
  710.     autospout = text;
  711.     autospout_free = 0;
  712.     last = curtime;
  713. }
  714.     }
  715.     return (0);
  716. }
  717. void newer(char *date, char *path, int showlots)
  718. {
  719.     extern int ftw(const char *path, int (*fn) (char *, struct stat *, int), int depth);
  720.     struct tm tm;
  721.     if (sscanf(date, "%04d%02d%02d%02d%02d%02d",
  722.        &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
  723.        &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
  724. tm.tm_year -= 1900;
  725. tm.tm_mon--;
  726. tm.tm_isdst = -1;
  727. newer_time = mktime(&tm);
  728. dout = dataconn("file list", (off_t) - 1, "w");
  729. if (dout != NULL) {
  730.     /* As ftw allocates storage it needs a chance to cleanup, setting
  731.      * ftwflag prevents myoob from calling longjmp, incrementing
  732.      * ftwflag instead which causes check_newer to return non-zero
  733.      * which makes ftw return. */
  734.     ftwflag = 1;
  735.     transflag++;
  736.     show_fullinfo = showlots;
  737. #if defined(HAVE_FTW)
  738.     ftw(path, check_newer, -1);
  739. #else
  740.     treewalk(path, check_newer, -1, NULL);
  741. #endif
  742.     /* don't send a reply if myoob has already replied */
  743.     if (ftwflag == 1) {
  744. if (ferror(dout) != 0)
  745.     perror_reply(550, "Data connection");
  746. else
  747.     reply(226, "Transfer complete.");
  748.     }
  749.     (void) fclose(dout);
  750.     data = -1;
  751.     pdata = -1;
  752.     transflag = 0;
  753.     ftwflag = 0;
  754. }
  755.     }
  756.     else
  757. reply(501, "Bad DATE format");
  758. }
  759. int type_match(char *typelist)
  760. {
  761.     if (anonymous && strcasestr(typelist, "anonymous"))
  762. return (1);
  763.     if (guest && strcasestr(typelist, "guest"))
  764. return (1);
  765.     if (!guest && !anonymous && strcasestr(typelist, "real"))
  766. return (1);
  767.     if (strncasecmp(typelist, "class=", 6) == 0) {
  768. char class[1024];
  769. (void) acl_getclass(class);
  770. if (strcasecmp(typelist + 6, class) == 0)
  771.     return (1);
  772.     }
  773.     return (0);
  774. }
  775. int path_compare(char *p1, char *p2)
  776. {
  777.     if ((strcmp(p1, "*") == 0) || (wu_fnmatch(p1, p2, FNM_PATHNAME) == 0)) /* 0 means they matched */
  778. return (strlen(p1));
  779.     else
  780. return (-2);
  781. }
  782. void expand_id(void)
  783. {
  784.     char class[1024];
  785.     struct aclmember *entry = NULL;
  786.     (void) acl_getclass(class);
  787.     while (getaclentry("upload", &entry)) {
  788. char *q;
  789. int i = 0;
  790. int options = 1;
  791. int classfound = 0;
  792. int classmatched = 0;
  793. while (options
  794.        && (i < MAXARGS)
  795.        && ((q = entry->arg[i]) != (char *) NULL)
  796.        && (q[0] != '')) {
  797.     if (strcasecmp(q, "absolute") == 0)
  798. i++;
  799.     else if (strcasecmp(q, "relative") == 0)
  800. i++;
  801.     else if (strncasecmp(q, "class=", 6) == 0) {
  802. i++;
  803. classfound = 1;
  804. if (strcasecmp(q + 6, class) == 0)
  805.     classmatched = 1;
  806.     }
  807.     else if (strcmp(q, "-") == 0) {
  808. i++;
  809. options = 0;
  810.     }
  811.     else
  812. options = 0;
  813. }
  814. if (!classfound || classmatched) {
  815.     char buf[BUFSIZ];
  816.     /*
  817.        *  UID
  818.      */
  819.     if (((i + 3) < MAXARGS)
  820. && ((q = entry->arg[i + 3]) != (char *) NULL)
  821. && (q[0] != '')
  822. && (strcmp(q, "*") != 0)) {
  823. if (q[0] == '%')
  824.     sprintf(buf, "%s", q + 1);
  825. else {
  826.     struct passwd *pwent = getpwnam(q);
  827.     if (pwent)
  828. sprintf(buf, "%" PW_UID_FORMAT, pwent->pw_uid);
  829.     else
  830. sprintf(buf, "%d", 0);
  831. }
  832. entry->arg[i + 3] = (char *) malloc(strlen(buf) + 1);
  833. if (entry->arg[i + 3] == NULL) {
  834.     syslog(LOG_ERR, "calloc error in expand_id");
  835.     exit(0);
  836. }
  837. strcpy(entry->arg[i + 3], buf);
  838.     }
  839.     /*
  840.        *  GID
  841.      */
  842.     if (((i + 4) < MAXARGS)
  843. && ((q = entry->arg[i + 4]) != (char *) NULL)
  844. && (q[0] != '')
  845. && (strcmp(q, "*") != 0)) {
  846. if (q[0] == '%')
  847.     sprintf(buf, "%s", q + 1);
  848. else {
  849.     struct group *grent = getgrnam(q);
  850.     if (grent)
  851. sprintf(buf, "%" GR_GID_FORMAT, grent->gr_gid);
  852.     else
  853. sprintf(buf, "%d", 0);
  854.     endgrent();
  855. }
  856. entry->arg[i + 4] = (char *) malloc(strlen(buf) + 1);
  857. if (entry->arg[i + 4] == NULL) {
  858.     syslog(LOG_ERR, "calloc error in expand_id");
  859.     exit(0);
  860. }
  861. strcpy(entry->arg[i + 4], buf);
  862.     }
  863. }
  864.     }
  865. }
  866. int fn_check(char *name)
  867. {
  868.     /* check to see if this is a valid file name... path-filter <type>
  869.      * <message_file> <allowed_charset> <disallowed> */
  870.     struct aclmember *entry = NULL;
  871.     int j;
  872.     char *path;
  873. #if ! defined(HAVE_REGEXEC)
  874.     char *sp;
  875. #endif
  876. #ifdef M_UNIX
  877. #ifdef HAVE_REGEX
  878.     char *regp;
  879. #endif
  880. #endif
  881. #ifdef HAVE_REGEXEC
  882.     regex_t regexbuf;
  883.     regmatch_t regmatchbuf;
  884. #endif
  885. #ifdef LINUX
  886.     re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
  887. #endif
  888.     while (getaclentry("path-filter", &entry) && ARG0 != NULL) {
  889. if (type_match(ARG0) && ARG1 && ARG2) {
  890.     /*
  891.      * check *only* the basename
  892.      */
  893.     if ((path = strrchr(name, '/')))
  894. ++path;
  895.     else
  896. path = name;
  897.     /* is it in the allowed character set? */
  898. #if defined(HAVE_REGEXEC)
  899.     if (regcomp(&regexbuf, ARG2, REG_EXTENDED) != 0) {
  900. reply(550, "HAVE_REGEX error");
  901. #elif defined(HAVE_REGEX)
  902. if ((sp = regcmp(ARG2, (char *) 0)) == NULL) {
  903.     reply(550, "HAVE_REGEX error");
  904. #else
  905.     if ((sp = re_comp(ARG2)) != 0) {
  906. perror_reply(550, sp);
  907. #endif
  908. return (0);
  909.     }
  910. #if defined(HAVE_REGEXEC)
  911.     if (regexec(&regexbuf, path, 1, &regmatchbuf, 0) != 0) {
  912. #elif defined(HAVE_REGEX)
  913. #ifdef M_UNIX
  914. regp = regex(sp, path);
  915. free(sp);
  916. if (regp == NULL) {
  917. #else
  918. if ((regex(sp, path)) == NULL) {
  919. #endif
  920. #else
  921.     if ((re_exec(path)) != 1) {
  922. #endif
  923. pr_mesg(550, ARG1);
  924. reply(550, "%s: Permission denied on server. (Filename (accept))", name);
  925. return (0);
  926.     }
  927.     /* is it in any of the disallowed regexps */
  928.     for (j = 3; j < MAXARGS; ++j) {
  929. /* ARGj == entry->arg[j] */
  930. if (entry->arg[j]) {
  931. #if defined(HAVE_REGEXEC)
  932.     if (regcomp(&regexbuf, entry->arg[j], REG_EXTENDED) != 0) {
  933. reply(550, "HAVE_REGEX error");
  934. #elif defined(HAVE_REGEX)
  935. if ((sp = regcmp(entry->arg[j], (char *) 0)) == NULL) {
  936.     reply(550, "HAVE_REGEX error");
  937. #else
  938.     if ((sp = re_comp(entry->arg[j])) != 0) {
  939. perror_reply(550, sp);
  940. #endif
  941. return (0);
  942.     }
  943. #if defined(HAVE_REGEXEC)
  944.     if (regexec(&regexbuf, path, 1, &regmatchbuf, 0) == 0) {
  945. #elif defined(HAVE_REGEX)
  946. #ifdef M_UNIX
  947. regp = regex(sp, path);
  948. free(sp);
  949. if (regp != NULL) {
  950. #else
  951. if ((regex(sp, path)) != NULL) {
  952. #endif
  953. #else
  954.     if ((re_exec(path)) == 1) {
  955. #endif
  956. pr_mesg(550, ARG1);
  957. reply(550, "%s: Permission denied on server. (Filename (deny))", name);
  958. return (0);
  959.     }
  960. }
  961.     }
  962. }
  963.     }
  964.     return (1);
  965. }
  966. int dir_check(char *name, uid_t * uid, gid_t * gid, int *d_mode, int *valid)
  967. {
  968.     struct aclmember *entry = NULL;
  969.     int match_value = -1;
  970.     char *ap2 = NULL;
  971.     char *ap3 = NULL;
  972.     char *ap4 = NULL;
  973.     char *ap5 = NULL;
  974.     char *ap6 = NULL;
  975.     char *ap7 = NULL;
  976.     char cwdir[MAXPATHLEN];
  977.     char *pwdir;
  978.     char abspwdir[MAXPATHLEN];
  979.     char relpwdir[MAXPATHLEN];
  980.     char path[MAXPATHLEN];
  981.     char *sp;
  982.     struct stat stbuf;
  983.     int stat_result = -1;
  984.     char class[1024];
  985.     extern char *home;
  986.     extern char chroot_path[];
  987.     (void) acl_getclass(class);
  988.     *valid = 0;
  989.     /* what's our current directory? */
  990.     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
  991.        out with an error. The rest of wu is so crufy that a long path might
  992.        just blow up later */
  993.     if ((strlen(name) + 1) > sizeof(path)) {
  994. perror_reply(550, "Path too long");
  995. return (-1);
  996.     }
  997.     strcpy(path, name);
  998.     sp = strrchr(path, '/');
  999.     if (sp)
  1000. *sp = '';
  1001.     else
  1002. strcpy(path, ".");
  1003.     if ((fb_realpath(path, cwdir)) == NULL) {
  1004. perror_reply(550, "Could not determine cwdir");
  1005. return (-1);
  1006.     }
  1007.     if ((fb_realpath(home, relpwdir)) == NULL) {
  1008. perror_reply(550, "Could not determine pwdir");
  1009. return (-1);
  1010.     }
  1011.     if ((wu_realpath(home, abspwdir, chroot_path)) == NULL) {
  1012. perror_reply(550, "Could not determine pwdir");
  1013. return (-1);
  1014.     }
  1015.     while (getaclentry("upload", &entry)) {
  1016. char *q;
  1017. int i = 0;
  1018. int options = 1;
  1019. int classfound = 0;
  1020. int classmatched = 0;
  1021. pwdir = abspwdir;
  1022. while (options
  1023.        && (i < MAXARGS)
  1024.        && ((q = entry->arg[i]) != (char *) NULL)
  1025.        && (q[0] != '')) {
  1026.     if (strcasecmp(q, "absolute") == 0) {
  1027. i++;
  1028. pwdir = abspwdir;
  1029.     }
  1030.     else if (strcasecmp(q, "relative") == 0) {
  1031. i++;
  1032. pwdir = relpwdir;
  1033.     }
  1034.     else if (strncasecmp(q, "class=", 6) == 0) {
  1035. i++;
  1036. classfound = 1;
  1037. if (strcasecmp(q + 6, class) == 0)
  1038.     classmatched = 1;
  1039.     }
  1040.     else if (strcmp(q, "-") == 0) {
  1041. i++;
  1042. options = 0;
  1043.     }
  1044.     else
  1045. options = 0;
  1046. }
  1047. if (!classfound || classmatched) {
  1048.     int j;
  1049.     if (((i + 1) < MAXARGS)
  1050. && ((q = entry->arg[i]) != (char *) NULL)
  1051. && (q[0] != '')
  1052. && (0 < path_compare(q, pwdir))
  1053. && ((j = path_compare(entry->arg[i + 1], cwdir)) >= match_value)) {
  1054. match_value = j;
  1055. ap2 = NULL;
  1056. if (((i + 2) < MAXARGS)
  1057.     && ((q = entry->arg[i + 2]) != (char *) NULL)
  1058.     && (q[0] != ''))
  1059.     ap2 = q;
  1060. ap3 = NULL;
  1061. if (((i + 3) < MAXARGS)
  1062.     && ((q = entry->arg[i + 3]) != (char *) NULL)
  1063.     && (q[0] != ''))
  1064.     ap3 = q;
  1065. ap4 = NULL;
  1066. if (((i + 4) < MAXARGS)
  1067.     && ((q = entry->arg[i + 4]) != (char *) NULL)
  1068.     && (q[0] != ''))
  1069.     ap4 = q;
  1070. ap5 = NULL;
  1071. if (((i + 5) < MAXARGS)
  1072.     && ((q = entry->arg[i + 5]) != (char *) NULL)
  1073.     && (q[0] != ''))
  1074.     ap5 = q;
  1075. ap6 = NULL;
  1076. if (((i + 6) < MAXARGS)
  1077.     && ((q = entry->arg[i + 6]) != (char *) NULL)
  1078.     && (q[0] != ''))
  1079.     ap6 = q;
  1080. ap7 = NULL;
  1081. if (((i + 7) < MAXARGS)
  1082.     && ((q = entry->arg[i + 7]) != (char *) NULL)
  1083.     && (q[0] != ''))
  1084.     ap7 = q;
  1085.     }
  1086. }
  1087.     }
  1088.     if (anonymous && (match_value < 0)) {
  1089. reply(550, "%s: Permission denied on server. (Upload dirs)", name);
  1090. return (0);
  1091.     }
  1092.     if ((ap2 && !strcasecmp(ap2, "no"))
  1093. || (ap3 && !strcasecmp(ap3, "nodirs"))
  1094. || (ap6 && !strcasecmp(ap6, "nodirs"))) {
  1095. reply(550, "%s: Permission denied on server. (Upload dirs)", name);
  1096. return (0);
  1097.     }
  1098.     if ((ap3 && *ap3 == '*') || (ap4 && *ap4 == '*'))
  1099. stat_result = stat(path, &stbuf);
  1100.     if (ap3) {
  1101. if ((ap3[0] != '*') || (ap3[1] != ''))
  1102.     *uid = atoi(ap3); /* the uid  */
  1103. else if (stat_result == 0)
  1104.     *uid = stbuf.st_uid;
  1105.     }
  1106.     if (ap4) {
  1107. if ((ap4[0] != '*') || (ap4[1] != ''))
  1108.     *gid = atoi(ap4); /* the gid */
  1109. else if (stat_result == 0)
  1110.     *gid = stbuf.st_gid;
  1111.     }
  1112.     if (ap7) {
  1113. sscanf(ap7, "%o", d_mode);
  1114. *valid = 1;
  1115.     }
  1116.     else if (ap5) {
  1117. sscanf(ap5, "%o", d_mode);
  1118. if (*d_mode & 0600)
  1119.     *d_mode |= 0100;
  1120. if (*d_mode & 0060)
  1121.     *d_mode |= 0010;
  1122. if (*d_mode & 0006)
  1123.     *d_mode |= 0001;
  1124. *valid = 1;
  1125.     }
  1126.     return (1);
  1127. }
  1128. int upl_check(char *name, uid_t * uid, gid_t * gid, int *f_mode, int *valid)
  1129. {
  1130.     int match_value = -1;
  1131.     char cwdir[MAXPATHLEN];
  1132.     char *pwdir;
  1133.     char abspwdir[MAXPATHLEN];
  1134.     char relpwdir[MAXPATHLEN];
  1135.     char path[MAXPATHLEN];
  1136.     char *sp;
  1137.     struct stat stbuf;
  1138.     int stat_result = -1;
  1139.     char *ap2 = NULL;
  1140.     char *ap3 = NULL;
  1141.     char *ap4 = NULL;
  1142.     char *ap5 = NULL;
  1143.     struct aclmember *entry = NULL;
  1144.     char class[1024];
  1145.     extern char *home;
  1146.     extern char chroot_path[];
  1147.     *valid = 0;
  1148.     (void) acl_getclass(class);
  1149.     /* what's our current directory? */
  1150.     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
  1151.        out with an error. The rest of wu is so crufy that a long path might
  1152.        just blow up later */
  1153.     if ((strlen(name) + 1) > sizeof(path)) {
  1154. perror_reply(553, "Path too long");
  1155. return (-1);
  1156.     }
  1157.     strcpy(path, name);
  1158.     sp = strrchr(path, '/');
  1159.     if (sp)
  1160. *sp = '';
  1161.     else
  1162. strcpy(path, ".");
  1163.     if ((fb_realpath(path, cwdir)) == NULL) {
  1164. perror_reply(553, "Could not determine cwdir");
  1165. return (-1);
  1166.     }
  1167.     if ((wu_realpath(home, abspwdir, chroot_path)) == NULL) {
  1168. perror_reply(553, "Could not determine pwdir");
  1169. return (-1);
  1170.     }
  1171.     if ((fb_realpath(home, relpwdir)) == NULL) {
  1172. perror_reply(553, "Could not determine pwdir");
  1173. return (-1);
  1174.     }
  1175.     /*
  1176.        *  we are doing a "best match"... ..so we keep track of what "match
  1177.        *  value" we have received so far...
  1178.      */
  1179.     while (getaclentry("upload", &entry)) {
  1180. char *q;
  1181. int i = 0;
  1182. int options = 1;
  1183. int classfound = 0;
  1184. int classmatched = 0;
  1185. pwdir = abspwdir;
  1186. while (options
  1187.        && (i < MAXARGS)
  1188.        && ((q = entry->arg[i]) != (char *) NULL)
  1189.        && (q[0] != '')) {
  1190.     if (strcasecmp(q, "absolute") == 0) {
  1191. i++;
  1192. pwdir = abspwdir;
  1193.     }
  1194.     else if (strcasecmp(q, "relative") == 0) {
  1195. i++;
  1196. pwdir = relpwdir;
  1197.     }
  1198.     else if (strncasecmp(q, "class=", 6) == 0) {
  1199. i++;
  1200. classfound = 1;
  1201. if (strcasecmp(q + 6, class) == 0)
  1202.     classmatched = 1;
  1203.     }
  1204.     else if (strcmp(q, "-") == 0) {
  1205. i++;
  1206. options = 0;
  1207.     }
  1208.     else
  1209. options = 0;
  1210. }
  1211. if (!classfound || classmatched) {
  1212.     int j;
  1213.     if (((i + 1) < MAXARGS)
  1214. && ((q = entry->arg[i]) != (char *) NULL)
  1215. && (q[0] != '')
  1216. && (0 < path_compare(q, pwdir))
  1217. && ((j = path_compare(entry->arg[i + 1], cwdir)) >= match_value)) {
  1218. match_value = j;
  1219. ap2 = NULL;
  1220. if (((i + 2) < MAXARGS)
  1221.     && ((q = entry->arg[i + 2]) != (char *) NULL)
  1222.     && (q[0] != ''))
  1223.     ap2 = q;
  1224. ap3 = NULL;
  1225. if (((i + 3) < MAXARGS)
  1226.     && ((q = entry->arg[i + 3]) != (char *) NULL)
  1227.     && (q[0] != ''))
  1228.     ap3 = q;
  1229. ap4 = NULL;
  1230. if (((i + 4) < MAXARGS)
  1231.     && ((q = entry->arg[i + 4]) != (char *) NULL)
  1232.     && (q[0] != ''))
  1233.     ap4 = q;
  1234. ap5 = NULL;
  1235. if (((i + 5) < MAXARGS)
  1236.     && ((q = entry->arg[i + 5]) != (char *) NULL)
  1237.     && (q[0] != ''))
  1238.     ap5 = q;
  1239.     }
  1240. }
  1241.     }
  1242.     if (ap3
  1243. && ((!strcasecmp("dirs", ap3))
  1244.     || (!strcasecmp("nodirs", ap3))))
  1245. ap3 = NULL;
  1246.     /*
  1247.        *  if we did get matches ... else don't do any of this stuff
  1248.      */
  1249.     if (match_value >= 0) {
  1250. if (!strcasecmp(ap2, "yes")) {
  1251.     if ((ap3 && *ap3 == '*') || (ap4 && *ap4 == '*'))
  1252. stat_result = stat(path, &stbuf);
  1253.     if (ap3) {
  1254. if ((ap3[0] != '*') || (ap3[1] != ''))
  1255.     *uid = atoi(ap3); /* the uid  */
  1256. else if (stat_result == 0)
  1257.     *uid = stbuf.st_uid;
  1258.     }
  1259.     if (ap4) {
  1260. if ((ap4[0] != '*') || (ap4[1] != ''))
  1261.     *gid = atoi(ap4); /* the gid  */
  1262. else if (stat_result == 0)
  1263.     *gid = stbuf.st_gid;
  1264. *valid = 1;
  1265.     }
  1266.     if (ap5)
  1267. sscanf(ap5, "%o", f_mode); /* the mode */
  1268. }
  1269. else {
  1270.     reply(553, "%s: Permission denied on server. (Upload)", name);
  1271.     return (-1);
  1272. }
  1273.     }
  1274.     else {
  1275. /*
  1276.    *  upload defaults to "permitted"
  1277.  */
  1278. /* Not if anonymous */
  1279. if (anonymous) {
  1280.     reply(553, "%s: Permission denied on server. (Upload)", name);
  1281.     return (-1);
  1282. }
  1283. return (1);
  1284.     }
  1285.     return (match_value);
  1286. }
  1287. int del_check(char *name)
  1288. {
  1289.     int pdelete = (anonymous ? 0 : 1);
  1290.     struct aclmember *entry = NULL;
  1291.     while (getaclentry("delete", &entry) && ARG0 && ARG1 != NULL) {
  1292. if (type_match(ARG1))
  1293.     if (anonymous) {
  1294. if (*ARG0 == 'y')
  1295.     pdelete = 1;
  1296.     }
  1297.     else if (*ARG0 == 'n')
  1298. pdelete = 0;
  1299.     }
  1300. /* H* fix: no deletion, period. You put a file here, I get to look at it. */
  1301. #ifdef PARANOID
  1302.     pdelete = 0;
  1303. #endif
  1304.     if (!pdelete) {
  1305. reply(553, "%s: Permission denied on server. (Delete)", name);
  1306. return (0);
  1307.     }
  1308.     else {
  1309. return (1);
  1310.     }
  1311. }
  1312. /* The following is from the Debian add-ons. */
  1313. #define lbasename(x) (strrchr(x,'/')?1+strrchr(x,'/'):x)
  1314. int regexmatch(char *name, char *rgexp)
  1315. {
  1316. #ifdef M_UNIX
  1317. #ifdef HAVE_REGEX
  1318.     char *regp;
  1319. #endif
  1320. #endif
  1321. #ifdef HAVE_REGEXEC
  1322.     regex_t regexbuf;
  1323.     regmatch_t regmatchbuf;
  1324. #else
  1325.     char *sp;
  1326. #endif
  1327. #if defined(HAVE_REGEXEC)
  1328.     if (regcomp(&regexbuf, rgexp, REG_EXTENDED) != 0) {
  1329. reply(553, "HAVE_REGEX error");
  1330. #elif defined(HAVE_REGEX)
  1331. if ((sp = regcmp(rgexp, (char *) 0)) == NULL) {
  1332.     reply(553, "HAVE_REGEX error");
  1333. #else
  1334.     if ((sp = re_comp(rgexp)) != 0) {
  1335. perror_reply(553, sp);
  1336. #endif
  1337. return (0);
  1338.     }
  1339. #if defined(HAVE_REGEXEC)
  1340.     if (regexec(&regexbuf, name, 1, &regmatchbuf, 0) != 0) {
  1341. #elif defined(HAVE_REGEX)
  1342. #ifdef M_UNIX
  1343. regp = regex(sp, name);
  1344. free(sp);
  1345. if (regp == NULL) {
  1346. #else
  1347. if ((regex(sp, name)) == NULL) {
  1348. #endif
  1349. #else
  1350.     if ((re_exec(name)) != 1) {
  1351. #endif
  1352. return (0);
  1353.     }
  1354.     return (1);
  1355. }
  1356. static int allow_retrieve(char *name)
  1357. {
  1358.     char realname[MAXPATHLEN + 1];
  1359.     char localname[MAXPATHLEN + 1];
  1360.     char *whichname;
  1361.     int i;
  1362.     size_t len;
  1363.     struct aclmember *entry = NULL;
  1364.     char *p, *q;
  1365.     int options;
  1366.     int classfound;
  1367.     int classmatched;
  1368.     char class[1024];
  1369.     extern char chroot_path[];
  1370.     (void) acl_getclass(class);
  1371.     if ((name == (char *) NULL)
  1372. || (*name == ''))
  1373. return 0;
  1374.     fb_realpath(name, localname);
  1375.     wu_realpath(name, realname, chroot_path);
  1376.     while (getaclentry("allow-retrieve", &entry)) {
  1377. whichname = realname;
  1378. i = 0;
  1379. options = 1;
  1380. classfound = 0;
  1381. classmatched = 0;
  1382. while (options
  1383.        && (i < MAXARGS)
  1384.        && ((q = entry->arg[i]) != (char *) NULL)
  1385.        && (q[0] != '')) {
  1386.     if (strcasecmp(q, "absolute") == 0) {
  1387. i++;
  1388. whichname = realname;
  1389.     }
  1390.     else if (strcasecmp(q, "relative") == 0) {
  1391. i++;
  1392. whichname = localname;
  1393.     }
  1394.     else if (strncasecmp(q, "class=", 6) == 0) {
  1395. i++;
  1396. classfound = 1;
  1397. if (strcasecmp(q + 6, class) == 0)
  1398.     classmatched = 1;
  1399.     }
  1400.     else if (strcmp(q, "-") == 0) {
  1401. i++;
  1402. options = 0;
  1403.     }
  1404.     else
  1405. options = 0;
  1406. }
  1407. if (!classfound || classmatched) {
  1408.     for (; (i < MAXARGS) && ((q = entry->arg[i]) != (char *) NULL) && (q[0] != ''); i++) {
  1409. len = strlen(q);
  1410. p = (q[0] == '/') ? whichname : lbasename(whichname);
  1411. if (!wu_fnmatch(q, p, FNM_PATHNAME | FNM_LEADING_DIR)) {
  1412.     return 1;
  1413. }
  1414.     }
  1415. }
  1416.     }
  1417.     return 0;
  1418. }
  1419. int checknoretrieve(char *name)
  1420. {
  1421.     char realname[MAXPATHLEN + 1];
  1422.     char localname[MAXPATHLEN + 1];
  1423.     char *whichname;
  1424.     int i;
  1425.     size_t len;
  1426.     struct aclmember *entry = NULL;
  1427.     char *p, *q;
  1428.     int options;
  1429.     int classfound;
  1430.     int classmatched;
  1431.     char class[1024];
  1432.     extern struct passwd *pw;
  1433.     extern char chroot_path[];
  1434.     extern char *remoteident;
  1435.     (void) acl_getclass(class);
  1436.     if ((name == (char *) NULL)
  1437. || (*name == ''))
  1438. return 0;
  1439.     fb_realpath(name, localname);
  1440.     wu_realpath(name, realname, chroot_path);
  1441.     while (getaclentry("noretrieve", &entry)) {
  1442. whichname = realname;
  1443. i = 0;
  1444. options = 1;
  1445. classfound = 0;
  1446. classmatched = 0;
  1447. while (options
  1448.        && (i < MAXARGS)
  1449.        && ((q = entry->arg[i]) != (char *) NULL)
  1450.        && (q[0] != '')) {
  1451.     if (strcasecmp(q, "absolute") == 0) {
  1452. i++;
  1453. whichname = realname;
  1454.     }
  1455.     else if (strcasecmp(q, "relative") == 0) {
  1456. i++;
  1457. whichname = localname;
  1458.     }
  1459.     else if (strncasecmp(q, "class=", 6) == 0) {
  1460. i++;
  1461. classfound = 1;
  1462. if (strcasecmp(q + 6, class) == 0)
  1463.     classmatched = 1;
  1464.     }
  1465.     else if (strcmp(q, "-") == 0) {
  1466. i++;
  1467. options = 0;
  1468.     }
  1469.     else
  1470. options = 0;
  1471. }
  1472. if (!classfound || classmatched) {
  1473.     for (; (i < MAXARGS) && ((q = entry->arg[i]) != (char *) NULL) && (q[0] != ''); i++) {
  1474. len = strlen(q);
  1475. p = (q[0] == '/') ? whichname : lbasename(whichname);
  1476. if (!wu_fnmatch(q, p, FNM_PATHNAME | FNM_LEADING_DIR)) {
  1477.     if (!allow_retrieve(name)) {
  1478. #ifdef VERBOSE_ERROR_LOGING
  1479. syslog(LOG_NOTICE, "%s of %s tried to download %s", pw->pw_name, remoteident, realname);
  1480. #endif
  1481. reply(550, "%s is marked unretrievable", localname);
  1482. return 1;
  1483.     }
  1484. }
  1485.     }
  1486. }
  1487.     }
  1488.     return 0;
  1489. }
  1490. #ifdef QUOTA
  1491. #ifndef MNTMAXSTR
  1492. #define MNTMAXSTR 2048 /* And hope it's enough */
  1493. #endif
  1494. #ifdef QUOTA_DEVICE
  1495. int path_to_device(char *pathname, char *result)
  1496. {
  1497.     FILE *fp;
  1498. #ifdef HAS_OLDSTYLE_GETMNTENT
  1499.     struct mnttab static_mp;
  1500.     struct mnttab *mp = &static_mp;
  1501. #else
  1502.     struct mntent *mp;
  1503. #endif
  1504.     struct mount_ent {
  1505. char mnt_fsname[MNTMAXSTR], mnt_dir[MNTMAXSTR];
  1506. struct mount_ent *next;
  1507.     } mountent;
  1508.     struct mount_ent *current, *start, *new;
  1509.     char path[1024], mnt_dir[1024], *pos;
  1510.     int flag = 1;
  1511.     extern char chroot_path[];
  1512.     start = current = NULL;
  1513. #ifdef HAS_OLDSTYLE_GETMNTENT
  1514.     fp = fopen(MNTTAB, "r");
  1515. #else
  1516.     fp = setmntent(MNTTAB, "r");
  1517. #endif
  1518.     if (fp == NULL)
  1519. return 0;
  1520. #ifdef HAS_OLDSTYLE_GETMNTENT
  1521.     while (getmntent(fp, &static_mp) == 0)
  1522. #else
  1523.     while (mp = getmntent(fp))
  1524. #endif
  1525.     {
  1526. if (!(new = (struct mount_ent *) malloc(sizeof(mountent)))) {
  1527.     perror("malloc");
  1528.     flag = 0;
  1529.     break;
  1530. }
  1531. if (!start)
  1532.     start = current = new;
  1533. else
  1534.     current = current->next = new;
  1535. #ifdef HAS_OLDSTYLE_GETMNTENT
  1536. strncpy(current->mnt_fsname, mp->mnt_special, strlen(mp->mnt_special) + 1);
  1537. strncpy(current->mnt_dir, mp->mnt_mountp, strlen(mp->mnt_mountp) + 1);
  1538. #else
  1539. strncpy(current->mnt_fsname, mp->mnt_fsname, strlen(mp->mnt_fsname) + 1);
  1540. strncpy(current->mnt_dir, mp->mnt_dir, strlen(mp->mnt_dir) + 1);
  1541. #endif
  1542.     }
  1543. #ifdef HAS_OLDSTYLE_GETMNTENT
  1544.     fclose(fp);
  1545. #else
  1546.     endmntent(fp);
  1547. #endif
  1548.     current->next = NULL;
  1549.     wu_realpath(pathname, path, chroot_path);
  1550.     while (*path && flag) {
  1551. current = start;
  1552. while (current && flag) {
  1553.     if (strcmp(current->mnt_dir, "swap")) {
  1554. wu_realpath(current->mnt_dir, mnt_dir, chroot_path);
  1555. if (!strcmp(mnt_dir, path)) {
  1556.     flag = 0;
  1557.     /* no support for remote quota yet */
  1558.     if (!strchr(current->mnt_fsname, ':'))
  1559. strcpy(result, current->mnt_fsname);
  1560. }
  1561.     }
  1562.     current = current->next;
  1563. }
  1564. if (!((pos = strrchr(path, '/')) - path) && strlen(path) > 1)
  1565.     strcpy(path, "/");
  1566. else
  1567.     path[pos - path] = '';
  1568.     }
  1569.     while (current) {
  1570. new = current->next;
  1571. free(current);
  1572. current = new;
  1573.     }
  1574.     return 1;
  1575. }
  1576. #endif
  1577. void get_quota(char *fs, int uid)
  1578. {
  1579.     char mnt_fsname[MNTMAXSTR];
  1580. #ifdef HAS_NO_QUOTACTL
  1581.     int dirfd;
  1582.     struct quotctl qp;
  1583.     if (path_to_device(fs, mnt_fsname)) {
  1584. dirfd = open(fs, O_RDONLY);
  1585. qp.op = Q_GETQUOTA;
  1586. qp.uid = uid;
  1587. qp.addr = (char *) &quota;
  1588. ioctl(dirfd, Q_QUOTACTL, &qp);
  1589. close(dirfd);
  1590.     }
  1591. #else
  1592. #ifdef QUOTA_DEVICE
  1593.     if (path_to_device(fs, mnt_fsname))
  1594. #ifdef QCMD
  1595. quotactl(QCMD(Q_GETQUOTA, USRQUOTA), mnt_fsname, uid, (char *) &quota);
  1596. #else
  1597. quotactl(Q_GETQUOTA, mnt_fsname, uid, (char *) &quota);
  1598. #endif
  1599. #else
  1600.     quotactl(fs, QCMD(Q_GETQUOTA, USRQUOTA), uid, (char *) &quota);
  1601. #endif
  1602. #endif /* HAS_NO_QUOTACTL */
  1603. }
  1604. char *time_quota(long curstate, long softlimit, long timelimit, char *timeleft)
  1605. {
  1606.     struct timeval tv;
  1607.     gettimeofday(&tv, NULL);
  1608.     if (softlimit && curstate >= softlimit) {
  1609. if (timelimit == 0) {
  1610.     strcpy(timeleft, "NOT STARTED");
  1611. }
  1612. else if (timelimit > tv.tv_sec) {
  1613.     fmttime(timeleft, timelimit - tv.tv_sec);
  1614. }
  1615. else {
  1616.     strcpy(timeleft, "EXPIRED");
  1617. }
  1618.     }
  1619.     else {
  1620. timeleft[0] = '';
  1621.     }
  1622.     return (timeleft);
  1623. }
  1624. void fmttime(char *buf, register long time)
  1625. {
  1626.     int i;
  1627.     static struct {
  1628. int c_secs; /* conversion units in secs */
  1629. char *c_str; /* unit string */
  1630.     } cunits[] = {
  1631. {
  1632.     60 *60 * 24 * 28, "months"
  1633. } ,
  1634. {
  1635.     60 *60 * 24 * 7, "weeks"
  1636. } ,
  1637. {
  1638.     60 *60 * 24, "days"
  1639. } ,
  1640. {
  1641.     60 *60, "hours"
  1642. } ,
  1643. {
  1644.     60, "mins"
  1645. } ,
  1646. {
  1647.     1, "secs"
  1648. }
  1649.     };
  1650.     if (time <= 0) {
  1651. strcpy(buf, "EXPIRED");
  1652. return;
  1653.     }
  1654.     for (i = 0; i < sizeof(cunits) / sizeof(cunits[0]); i++) {
  1655. if (time >= cunits[i].c_secs)
  1656.     break;
  1657.     }
  1658.     sprintf(buf, "%.1f %s", (double) time / cunits[i].c_secs, cunits[i].c_str);
  1659. }
  1660. #endif
  1661. #ifdef QUOTA
  1662. #if (defined(LINUX) && !defined(AUTOCONF)) || (defined(AUTOCONF) && !defined(HAVE_QUOTACTL) && defined(__linux__))
  1663. /* I have no idea why I can't find 'quotactl()' in my libs, here's the source - GAL */
  1664. /* This was a bug in truly ancient libc's (prior to 5.3.something). It isn't
  1665.    needed on any modern version of Linux. */
  1666. /*
  1667.  * QUOTA    An implementation of the diskquota system for the LINUX
  1668.  *          operating system. QUOTA is implemented using the BSD systemcall
  1669.  *          interface as the means of communication with the user level.
  1670.  *          Should work for all filesystems because of integration into the
  1671.  *          VFS layer of the operating system.
  1672.  *          This is based on the Melbourne quota system wich uses both user and
  1673.  *          group quota files.
  1674.  *
  1675.  *          System call interface.
  1676.  *
  1677.  * Version: $Id: extensions.c,v 1.46 1999/10/14 14:36:52 wuftpd Exp $
  1678.  *
  1679.  * Author:  Marco van Wieringen <mvw@planets.ow.nl> <mvw@tnix.net>
  1680.  *
  1681.  *          This program is free software; you can redistribute it and/or
  1682.  *          modify it under the terms of the GNU General Public License
  1683.  *          as published by the Free Software Foundation; either version
  1684.  *          2 of the License, or (at your option) any later version.
  1685.  */
  1686. #if defined(__alpha__)
  1687. #include <errno.h>
  1688. #include <sys/types.h>
  1689. #include <syscall.h>
  1690. #include <asm/unistd.h>
  1691. int quotactl(int cmd, const char *special, int id, caddr_t addr)
  1692. {
  1693.     return syscall(__NR_quotactl, cmd, special, id, addr);
  1694. }
  1695. #else /* __alpha__ */
  1696. #include <sys/types.h>
  1697. #define __LIBRARY__
  1698. #include <linux/unistd.h>
  1699. _syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
  1700. #endif /* __alpha__ */
  1701. #elif !defined(HAVE_QUOTACTL) /* LINUX */
  1702. #ifdef QUOTA_DEVICE
  1703. /* I have no idea why I can't find 'quotactl()' in my libs, here's the source - keller */
  1704. int quotactl(int cmd, const char *special, int id, caddr_t addr)
  1705. {
  1706.     struct quotctl {
  1707. int op;
  1708. uid_t uid;
  1709. caddr_t addr;
  1710.     } qp;
  1711.     /*
  1712.      * open up the quota file in the root directory to get the file descriptor.
  1713.      * if no quota file exists, quotas are not enabled.
  1714.      */
  1715.     FILE *qf;
  1716.     char mnt_pnt[1024];
  1717.     mnt_pnt[0] = '';
  1718.     strncpy(mnt_pnt, special, strlen(mnt_pnt));
  1719.     strncat(mnt_pnt, "/quota", strlen(mnt_pnt));
  1720.     qf = fopen(mnt_pnt, "r");
  1721.     if (qf == NULL)
  1722. return(-1);
  1723.     qp.op = Q_GETQUOTA;
  1724.     qp.uid = id;
  1725.     qp.addr = addr;
  1726.     return ioctl((int) qf, (int) Q_QUOTACTL, qp);
  1727. }
  1728. #endif /* QUOTA_DEVICE */
  1729. #endif /* LINUX */
  1730. #endif /* QUOTA */
  1731. #ifdef THROUGHPUT
  1732. int file_compare(char *patterns, char *file)
  1733. {
  1734.     char buf[MAXPATHLEN];
  1735.     char *cp;
  1736.     char *cp2;
  1737.     int i;
  1738.     int matches = 0;
  1739.     strncpy(buf, patterns, sizeof(buf));
  1740.     buf[sizeof(buf) - 1] = '';
  1741.     i = strlen(buf);
  1742.     buf[i++] = ',';
  1743.     buf[i++] = '';
  1744.     cp = buf;
  1745.     while ((cp2 = strchr(cp, ',')) != NULL) {
  1746. *cp2++ = '';
  1747. if (wu_fnmatch(cp, file, FNM_PATHNAME) == 0) {
  1748.     matches = 1;
  1749.     break;
  1750. }
  1751.     }
  1752.     return matches;
  1753. }
  1754. int remote_compare(char *patterns)
  1755. {
  1756.     char buf[MAXPATHLEN];
  1757.     char *cp;
  1758.     char *cp2;
  1759.     int i;
  1760.     int matches = 0;
  1761.     strncpy(buf, patterns, sizeof(buf));
  1762.     buf[sizeof(buf) - 1] = '';
  1763.     i = strlen(buf);
  1764.     buf[i++] = ',';
  1765.     buf[i++] = '';
  1766.     cp = buf;
  1767.     while ((cp2 = strchr(cp, ',')) != NULL) {
  1768. *cp2++ = '';
  1769. if (hostmatch(cp, remoteaddr, remotehost)) {
  1770.     matches = 1;
  1771.     break;
  1772. }
  1773.     }
  1774.     return matches;
  1775. }
  1776. void throughput_calc(char *name, int *bps, double *bpsmult)
  1777. {
  1778.     int match_value = -1;
  1779.     char cwdir[MAXPATHLEN];
  1780.     char pwdir[MAXPATHLEN];
  1781.     char path[MAXPATHLEN];
  1782.     char file[MAXPATHLEN];
  1783.     char *ap3 = NULL, *ap4 = NULL;
  1784.     struct aclmember *entry = NULL;
  1785.     extern char *home;
  1786.     extern char chroot_path[];
  1787.     char *sp;
  1788.     int i;
  1789.     /* default is maximum throughput */
  1790.     *bps = -1;
  1791.     *bpsmult = 1.0;
  1792.     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
  1793.        out with an error. The rest of wu is so crufy that a long path might
  1794.        just blow up later */
  1795.     if ((strlen(name) + 1) > sizeof(path)) {
  1796. return;
  1797.     }
  1798.     /* what's our current directory? */
  1799.     strcpy(path, name);
  1800.     if ((sp = strrchr(path, '/')))
  1801. *sp = '';
  1802.     else
  1803. strcpy(path, ".");
  1804.     if ((sp = strrchr(name, '/')))
  1805. strcpy(file, sp + 1);
  1806.     else
  1807. strcpy(file, name);
  1808.     if ((fb_realpath(path, cwdir)) == NULL) {
  1809. return;
  1810.     }
  1811.     wu_realpath(home, pwdir, chroot_path);
  1812.     /* find best matching entry */
  1813.     while (getaclentry("throughput", &entry) && ARG0 && ARG1 && ARG2 && ARG3 && ARG4 && ARG5 != NULL) {
  1814. if ((0 < path_compare(ARG0, pwdir))
  1815.     && ((i = path_compare(ARG1, cwdir)) >= match_value)
  1816.     ) {
  1817.     if (file_compare(ARG2, file)) {
  1818. if (remote_compare(ARG5)) {
  1819.     match_value = i;
  1820.     ap3 = ARG3;
  1821.     ap4 = ARG4;
  1822. }
  1823.     }
  1824. }
  1825.     }
  1826.     /* if we did get matches */
  1827.     if (match_value >= 0) {
  1828. if (strcasecmp(ap3, "oo") == 0)
  1829.     *bps = -1;
  1830. else
  1831.     *bps = atoi(ap3);
  1832. if (strcmp(ap4, "-") == 0)
  1833.     *bpsmult = 1.0;
  1834. else
  1835.     *bpsmult = atof(ap4);
  1836.     }
  1837.     return;
  1838. }
  1839. void throughput_adjust(char *name)
  1840. {
  1841.     int match_value = -1;
  1842.     char pwdir[MAXPATHLEN];
  1843.     char cwdir[MAXPATHLEN];
  1844.     char path[MAXPATHLEN];
  1845.     char file[MAXPATHLEN];
  1846.     char buf[MAXPATHLEN];
  1847.     char *ap3 = NULL, *ap4 = NULL;
  1848.     char **pap3;
  1849.     struct aclmember *entry = NULL;
  1850.     extern char *home;
  1851.     extern char chroot_path[];
  1852.     char *sp;
  1853.     int i;
  1854.     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
  1855.        out with an error. The rest of wu is so crufy that a long path might
  1856.        just blow up later */
  1857.     if ((strlen(name) + 1) > sizeof(path)) {
  1858. return;
  1859.     }
  1860.     /* what's our current directory? */
  1861.     strcpy(path, name);
  1862.     if ((sp = strrchr(path, '/')))
  1863. *sp = '';
  1864.     else
  1865. strcpy(path, ".");
  1866.     if ((sp = strrchr(name, '/')))
  1867. strcpy(file, sp + 1);
  1868.     else
  1869. strcpy(file, name);
  1870.     if ((fb_realpath(path, cwdir)) == NULL) {
  1871. return;
  1872.     }
  1873.     wu_realpath(home, pwdir, chroot_path);
  1874.     /* find best matching entry */
  1875.     while (getaclentry("throughput", &entry) && ARG0 && ARG1 && ARG2 && ARG3 && ARG4 && ARG5 != NULL) {
  1876. if ((0 < path_compare(ARG0, pwdir))
  1877.     && ((i = path_compare(ARG1, cwdir)) >= match_value)
  1878.     ) {
  1879.     if (file_compare(ARG2, file)) {
  1880. if (remote_compare(ARG5)) {
  1881.     match_value = i;
  1882.     ap3 = ARG3;
  1883.     pap3 = &ARG3;
  1884.     ap4 = ARG4;
  1885. }
  1886.     }
  1887. }
  1888.     }
  1889.     /* if we did get matches */
  1890.     if (match_value >= 0) {
  1891. if (strcasecmp(ap3, "oo") != 0) {
  1892.     if (strcmp(ap4, "-") != 0) {
  1893. sprintf(buf, "%.0f", atoi(ap3) * atof(ap4));
  1894. *pap3 = (char *) malloc(strlen(buf) + 1);
  1895. if (*pap3 == NULL) {
  1896.     syslog(LOG_ERR, "malloc error in throughput_adjust");
  1897.     exit(0);
  1898. }
  1899. strcpy(*pap3, buf);
  1900.     }
  1901. }
  1902.     }
  1903.     return;
  1904. }
  1905. #endif
  1906. static int CheckMethod = 0;
  1907. void SetCheckMethod(const char *method)
  1908. {
  1909.     if ((strcasecmp(method, "md5") == 0)
  1910. || (strcasecmp(method, "rfc1321") == 0))
  1911. CheckMethod = 0;
  1912.     else if ((strcasecmp(method, "crc") == 0)
  1913.      || (strcasecmp(method, "posix") == 0))
  1914. CheckMethod = 1;
  1915.     else {
  1916. reply(500, "Unrecognized checksum method");
  1917. return;
  1918.     }
  1919.     switch (CheckMethod) {
  1920.     default:
  1921. reply(200, "Checksum method is now: MD5 (RFC1321)");
  1922. break;
  1923.     case 1:
  1924. reply(200, "Checksum method is now: CRC (POSIX)");
  1925. break;
  1926.     }
  1927. }
  1928. void ShowCheckMethod(void)
  1929. {
  1930.     switch (CheckMethod) {
  1931.     default:
  1932. reply(200, "Current checksum method: MD5 (RFC1321)");
  1933. break;
  1934.     case 1:
  1935. reply(200, "Current checksum method: CRC (POSIX)");
  1936. break;
  1937.     }
  1938. }
  1939. void CheckSum(char *pathname)
  1940. {
  1941.     char *cmd;
  1942.     char buf[MAXPATHLEN];
  1943.     FILE *cmdf;
  1944.     struct stat st;
  1945.     if (stat(pathname, &st) == 0) {
  1946. if ((st.st_mode & S_IFMT) != S_IFREG) {
  1947.     reply(500, "%s: not a plain file.", pathname);
  1948.     return;
  1949. }
  1950.     }
  1951.     else {
  1952. perror_reply(550, pathname);
  1953. return;
  1954.     }
  1955.     switch (CheckMethod) {
  1956.     default:
  1957. cmd = "/bin/md5sum";
  1958. break;
  1959.     case 1:
  1960. cmd = "/bin/cksum";
  1961. break;
  1962.     }
  1963.     if (strlen(cmd) + 1 + strlen(pathname) + 1 > sizeof(buf)) {
  1964. reply(500, "Pathname too long");
  1965. return;
  1966.     }
  1967.     sprintf(buf, "%s %s", cmd, pathname);
  1968.     cmdf = ftpd_popen(buf, "r", 0);
  1969.     if (!cmdf) {
  1970. perror_reply(550, cmd);
  1971.     }
  1972.     else {
  1973. if (fgets(buf, sizeof buf, cmdf)) {
  1974.     char *crptr = strchr(buf, 'n');
  1975.     if (crptr != NULL)
  1976. *crptr = '';
  1977.     reply(200, "%s", buf);
  1978. }
  1979. ftpd_pclose(cmdf);
  1980.     }
  1981. }
  1982. void CheckSumLastFile(void)
  1983. {
  1984.     extern char LastFileTransferred[];
  1985.     if (LastFileTransferred[0] == '')
  1986. reply(500, "Nothing transferred yet");
  1987.     else
  1988. CheckSum(LastFileTransferred);
  1989. }