PageRenderTime 59ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/buffyg/illumos-gate-1514
C | 2365 lines | 1969 code | 231 blank | 165 comment | 735 complexity | 534ee11a1b57c953a4e176b2dcf1beca MD5 | raw file
Possible License(s): BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-3.0, GPL-2.0, GPL-3.0, LGPL-3.0, 0BSD, AGPL-1.0, BSD-3-Clause, LGPL-2.1, LGPL-2.0, BSD-2-Clause

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

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

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