PageRenderTime 67ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/extensions.c

https://bitbucket.org/nexenta/onnv_134
C | 2368 lines | 1970 code | 232 blank | 166 comment | 735 complexity | 855fa1eeb4b9cf23ea36338de9c126b3 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.0, AGPL-3.0, BSD-3-Clause, GPL-3.0, LGPL-3.0, 0BSD

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file