1 #include <config.h>
2
3 #define DEFINE_GLOBALS
4 #include "messages.h"
5 #include "ftpd_p.h"
6 #include "dynamic.h"
7 #include "ftpwho-update.h"
8 #include "ftpwho-read.h"
9 #include "globals.h"
10 #include "caps.h"
11 #include "alt_arc4random.h"
12 #if defined(WITH_UPLOAD_SCRIPT)
13 # include "upload-pipe.h"
14 #endif
15 #ifdef WITH_ALTLOG
16 # include "altlog.h"
17 #endif
18 #ifdef QUOTAS
19 # include "quotas.h"
20 #endif
21 #ifdef WITH_DIRALIASES
22 # include "diraliases.h"
23 #endif
24 #include "ftpd.h"
25 #include "bsd-glob.h"
26 #include "getloadavg.h"
27 #include "safe_rw.h"
28 #include "utils.h"
29 #ifndef MINIMAL
30 # include "simpleconf.h"
31 # include "simpleconf_ftpd.h"
32 #endif
33 #ifndef WITHOUT_PRIVSEP
34 # include "privsep.h"
35 #endif
36 #ifdef WITH_TLS
37 # include "tls.h"
38 # include "tls_extcert.h"
39 #endif
40 #ifdef WITH_BONJOUR
41 # include "bonjour.h"
42 #endif
43 #ifdef HAVE_LIBSODIUM
44 # include <sodium.h>
45 #endif
46 #ifdef WITH_DMALLOC
47 # include <dmalloc.h>
48 #endif
49
disablesignals(void)50 void disablesignals(void)
51 {
52 sigset_t sigs;
53
54 sigfillset(&sigs);
55 if (sigprocmask(SIG_BLOCK, &sigs, &old_sigmask) < 0) {
56 _EXIT(EXIT_FAILURE);
57 }
58 }
59
enablesignals(void)60 static void enablesignals(void)
61 {
62 if (sigprocmask(SIG_SETMASK, &old_sigmask, NULL) < 0) {
63 _EXIT(EXIT_FAILURE);
64 }
65 }
66
usleep2(const unsigned long microsec)67 void usleep2(const unsigned long microsec)
68 {
69 disablesignals();
70 usleep(microsec);
71 enablesignals();
72 }
73
74 #ifdef WITH_TLS
secure_safe_write(void * const tls_fd,const void * buf_,size_t count)75 ssize_t secure_safe_write(void * const tls_fd, const void *buf_, size_t count)
76 {
77 ssize_t written;
78 const char *buf = (const char *) buf_;
79
80 while (count > (size_t) 0U) {
81 for (;;) {
82 if ((written = SSL_write(tls_fd, buf, count)) <= (ssize_t) 0) {
83 if (SSL_get_error(tls_fd, written) != SSL_ERROR_NONE) {
84 return (ssize_t) -1;
85 }
86 continue;
87 }
88 break;
89 }
90 buf += written;
91 count -= written;
92 }
93 return (ssize_t) (buf - (const char *) buf_);
94 }
95 #endif
96
safe_nonblock_write(const int fd,void * const tls_fd,const void * buf_,size_t count)97 static ssize_t safe_nonblock_write(const int fd, void * const tls_fd,
98 const void *buf_, size_t count)
99 {
100 ssize_t written;
101 const char *buf = (const char *) buf_;
102 struct pollfd pfd;
103
104 while (count > (size_t) 0U) {
105 for (;;) {
106 if (tls_fd == NULL) {
107 written = write(fd, buf, count);
108 } else {
109 #ifdef WITH_TLS
110 written = SSL_write(tls_fd, buf, count);
111 if (SSL_get_error(tls_fd, written) == SSL_ERROR_WANT_WRITE) {
112 errno = EAGAIN;
113 }
114 #else
115 abort();
116 #endif
117 }
118 if (written > (ssize_t) 0) {
119 break;
120 }
121 if (errno == EAGAIN || errno == EWOULDBLOCK) {
122 pfd.fd = fd;
123 pfd.events = POLLOUT | POLLERR | POLLHUP;
124 pfd.revents = 0;
125 if (poll(&pfd, 1U, idletime * 1000UL) <= 0 ||
126 (pfd.revents & (POLLERR | POLLHUP)) != 0 ||
127 (pfd.revents & POLLOUT) == 0) {
128 errno = EPIPE;
129 return -1;
130 }
131 } else if (errno != EINTR) {
132 return -1;
133 }
134 }
135 buf += written;
136 count -= written;
137 }
138 return 0;
139 }
140
overlapcpy(char * d,const char * s)141 static void overlapcpy(char *d, const char *s)
142 {
143 while (*s != 0) {
144 *d++ = *s++;
145 }
146 *d = 0;
147 }
148
safe_fd_set(const int fd,fd_set * const fds)149 static void safe_fd_set(const int fd, fd_set * const fds)
150 {
151 if (fd == -1) {
152 return;
153 }
154 FD_SET(fd, fds);
155 }
156
safe_fd_isset(const int fd,const fd_set * const fds)157 static int safe_fd_isset(const int fd, const fd_set * const fds)
158 {
159 if (fd == -1) {
160 return 0;
161 }
162 return FD_ISSET(fd, fds);
163 }
164
init_tz(void)165 static int init_tz(void)
166 {
167 char stbuf[10];
168 struct tm *tm;
169 time_t now = time(NULL);
170
171 #ifdef HAVE_TZSET
172 tzset();
173 #endif
174 #ifdef HAVE_PUTENV
175 if ((tm = localtime(&now)) != NULL &&
176 strftime(stbuf, sizeof stbuf, "%z", tm) == (size_t) 5U) {
177 snprintf(default_tz_for_putenv, sizeof default_tz_for_putenv,
178 "TZ=UTC%c%c%c:%c%c", (*stbuf == '-' ? '+' : '-'),
179 stbuf[1], stbuf[2], stbuf[3], stbuf[4]);
180 }
181 putenv(default_tz_for_putenv);
182 #endif
183 (void) localtime(&now);
184 (void) gmtime(&now);
185
186 return 0;
187 }
188
simplify(char * subdir)189 void simplify(char *subdir)
190 {
191 char *a;
192
193 if (subdir == NULL || *subdir == 0) {
194 return;
195 }
196 while ((a = strstr(subdir, "//")) != NULL) {
197 overlapcpy(a, a + 1);
198 }
199 while ((a = strstr(subdir, "/./")) != NULL) {
200 overlapcpy(a, a + 2);
201 }
202 while (strncmp(subdir, "../", 3) == 0) {
203 subdir += 3;
204 }
205 a = strstr(subdir, "/../");
206 if (a != NULL) {
207 if (a == subdir) {
208 while (strncmp(subdir, "/../", 4) == 0) {
209 overlapcpy(subdir, subdir + 3);
210 }
211 a = strstr(subdir, "/../");
212 }
213 while (a != NULL) {
214 char *nextcomponent = a + 4;
215 if (a != subdir && *a == '/') {
216 a--;
217 }
218 while (a != subdir && *a != '/') {
219 a--;
220 }
221 if (*a == '/') {
222 a++;
223 }
224 overlapcpy(a, nextcomponent);
225 a = strstr(subdir, "/../");
226 }
227 }
228 a = subdir;
229 if (*a == '.') {
230 a++;
231 if (*a == 0) {
232 return;
233 }
234 if (*a == '/') {
235 while (*a == '/') {
236 a++;
237 }
238 overlapcpy(subdir, a);
239 }
240 }
241 if (*a == 0) {
242 return;
243 }
244 a = subdir + strlen(subdir) - (size_t) 1U;
245 if (*a != '.' || a == subdir) {
246 return;
247 }
248 a--;
249 if (*a == '/') {
250 a[1] = 0;
251 return;
252 }
253 if (*a != '.' || a == subdir) {
254 return;
255 }
256 a--;
257 if (*a != '/') {
258 return;
259 }
260 *a = 0;
261 if ((a = strrchr(subdir, '/')) == NULL) {
262 *subdir = '/';
263 subdir[1] = 0;
264 return;
265 }
266 a[1] = 0;
267 }
268
checkprintable(const char * s)269 int checkprintable(const char *s)
270 {
271 int ret = 0;
272 unsigned char c;
273
274 while ((c = (unsigned char) *s) != 0U) {
275 if (ISCTRLCODE(c)) {
276 ret--;
277 break;
278 }
279 s++;
280 }
281
282 return ret;
283 }
284
skip_telnet_controls(const char * str)285 char *skip_telnet_controls(const char *str)
286 {
287 if (str == NULL) {
288 return NULL;
289 }
290 while (*str != 0 && (unsigned char) *str >= 240U) {
291 str++;
292 }
293 return (char *) str;
294 }
295
_EXIT(const int status)296 void _EXIT(const int status)
297 {
298 delete_atomic_file();
299 #ifdef FTPWHO
300 ftpwho_exit();
301 #endif
302 _exit(status);
303 }
304
305 static char replybuf[MAX_SERVER_REPLY_LEN * 4U];
306 static char *replybuf_pos = replybuf;
307 static size_t replybuf_left;
308
client_init_reply_buf(void)309 static void client_init_reply_buf(void)
310 {
311 replybuf_pos = replybuf;
312 replybuf_left = sizeof replybuf - 1U;
313 }
314
client_fflush(void)315 void client_fflush(void)
316 {
317 if (replybuf_pos == replybuf) {
318 return;
319 }
320 safe_write(clientfd, replybuf, (size_t) (replybuf_pos - replybuf), -1);
321 client_init_reply_buf();
322 }
323
client_printf(const char * const format,...)324 void client_printf(const char * const format, ...)
325 {
326 va_list va;
327 char buf[MAX_SERVER_REPLY_LEN];
328 size_t len;
329 int vlen;
330
331 va_start(va, format);
332 vlen = vsnprintf(buf, sizeof buf, format, va);
333 if (vlen < 0 || (size_t) vlen >= sizeof buf) {
334 buf[MAX_SERVER_REPLY_LEN - 1] = 0;
335 len = strlen(buf);
336 } else {
337 len = (size_t) vlen;
338 }
339 if (len >= replybuf_left) {
340 client_fflush();
341 }
342 if (len > replybuf_left) {
343 va_end(va);
344 abort();
345 }
346 memcpy(replybuf_pos, buf, len);
347 replybuf_pos += len;
348 replybuf_left -= len;
349
350 va_end(va);
351 }
352
die(const int err,const int priority,const char * const format,...)353 void die(const int err, const int priority, const char * const format, ...)
354 {
355 va_list va;
356 char line[MAX_SYSLOG_LINE];
357
358 disablesignals();
359 logging = 0;
360 va_start(va, format);
361 vsnprintf(line, sizeof line, format, va);
362 addreply(err, "%s", line);
363 va_end(va);
364 doreply();
365 logfile(priority, "%s", line);
366 _EXIT(-priority - 1);
367 }
368
die_mem(void)369 void die_mem(void)
370 {
371 die(421, LOG_ERR, MSG_OUT_OF_MEMORY);
372 }
373
sigalarm(int sig)374 static void sigalarm(int sig)
375 {
376 (void) sig;
377 disablesignals();
378 die(421, LOG_INFO, MSG_TIMEOUT);
379 }
380
381 #ifndef NO_STANDALONE
sigchild(int sig)382 static void sigchild(int sig)
383 {
384 const int olderrno = errno;
385 pid_t pid;
386
387 (void) sig;
388 # ifdef HAVE_WAITPID
389 while ((pid = waitpid((pid_t) -1, NULL, WNOHANG)) > (pid_t) 0) {
390 if (nb_children > 0U) {
391 nb_children--;
392 }
393 # ifdef FTPWHO
394 ftpwho_unlinksbfile(pid);
395 # endif
396 iptrack_delete_pid(pid);
397 }
398 # endif
399 errno = olderrno;
400 }
401 #endif
402
sigterm_client(int sig)403 static void sigterm_client(int sig)
404 {
405 (void) sig;
406
407 disablesignals();
408 _EXIT(EXIT_SUCCESS);
409 }
410
411 #ifndef NO_STANDALONE
sigterm(int sig)412 static void sigterm(int sig)
413 {
414 const int olderrno = errno;
415 (void) sig;
416
417 stop_server = 1;
418 if (listenfd != -1) {
419 shutdown(listenfd, 2);
420 (void) close(listenfd);
421 }
422 if (listenfd6 != -1) {
423 shutdown(listenfd6, 2);
424 (void) close(listenfd6);
425 }
426 errno = olderrno;
427 }
428
set_cloexec_flag(const int fd)429 static void set_cloexec_flag(const int fd)
430 {
431 fcntl(fd, F_SETFD, FD_CLOEXEC);
432 }
433 #endif
434
clearargs(int argc,char ** argv)435 static void clearargs(int argc, char **argv)
436 {
437 #ifndef NO_PROCNAME_CHANGE
438 # if defined(__linux__) && !defined(HAVE_SETPROCTITLE)
439 int i;
440 char *first = NULL;
441 char *next = NULL;
442
443 for (i = 0; i < argc; i++) {
444 if (first == NULL) {
445 first = argv[i];
446 }
447 if (next == NULL || argv[i] == next + 1) {
448 next = argv[i] + strlen(argv[i]);
449 }
450 }
451 for (i = 0; environ[i] != NULL; i++) {
452 if (first == NULL) {
453 first = argv[i];
454 }
455 if (next == NULL) {
456 next = argv[i] + strlen(argv[i]);
457 }
458 }
459 if (first == NULL || next == NULL) {
460 return;
461 }
462 argv_lth = next - first;
463 argv0 = argv;
464 if (environ != NULL) {
465 char **new_environ;
466 unsigned int env_nb = 0U;
467
468 while (environ[env_nb] != NULL) {
469 env_nb++;
470 }
471 if ((new_environ = malloc((1U + env_nb) * sizeof (char *))) == NULL) {
472 abort();
473 }
474 new_environ[env_nb] = NULL;
475 while (env_nb > 0U) {
476 env_nb--;
477 new_environ[env_nb] = strdup(environ[env_nb]);
478 }
479 environ = new_environ;
480 }
481 # else
482 (void) argc;
483 (void) argv;
484 # endif
485 #endif
486 }
487
setprocessname(const char * const title)488 void setprocessname(const char * const title)
489 {
490 #ifndef NO_PROCNAME_CHANGE
491 # ifdef HAVE_SETPROCTITLE
492 setproctitle("-%s", title);
493 # elif defined(__linux__)
494 if (argv0 != NULL && argv_lth > strlen(title) - 2) {
495 memset(argv0[0], 0, argv_lth);
496 strncpy(argv0[0], title, argv_lth - 2);
497 argv0[1] = NULL;
498 }
499 # elif defined(__hpux__)
500 union pstun pst;
501
502 pst.pst_command = title;
503 pstat(PSTAT_SETCMD, pst, strlen(title), 0, 0);
504 # endif
505 #endif
506 (void) title;
507 }
508
509 /* Check whether an address is valid, return 1 if ok, 0 otherwise.
510 * Unfortunately, multicasting with the FTP protocol is impossible,
511 * you have to use things like MTP instead. So prohibit multicast.
512 */
513
checkvalidaddr(const struct sockaddr_storage * const addr)514 static int checkvalidaddr(const struct sockaddr_storage * const addr)
515 {
516 if (addr == NULL) {
517 return 0;
518 }
519 /* Some versions of MacOS X have broken IN* macros */
520 #ifdef __APPLE_CC__
521 return 1;
522 #endif
523 if (STORAGE_FAMILY(*addr) == AF_INET6) {
524 if (IN6_IS_ADDR_MULTICAST(&STORAGE_SIN_ADDR6_NF_CONST(*addr)) ||
525 IN6_IS_ADDR_UNSPECIFIED(&STORAGE_SIN_ADDR6_NF_CONST(*addr))) {
526 return 0;
527 }
528 return 1;
529 } else if (STORAGE_FAMILY(*addr) == AF_INET) {
530 if (ntohl(STORAGE_SIN_ADDR_CONST(*addr)) == INADDR_ANY ||
531 ntohl(STORAGE_SIN_ADDR_CONST(*addr)) == INADDR_NONE ||
532 ntohl(STORAGE_SIN_ADDR_CONST(*addr)) == INADDR_BROADCAST ||
533 IN_MULTICAST(ntohl(STORAGE_SIN_ADDR_CONST(*addr)))) {
534 return 0;
535 }
536 return 1;
537 }
538 return 0;
539 }
540
541 /* Convert a 4-in-6 address to pure IPv4 */
542
fourinsix(struct sockaddr_storage * v6)543 static void fourinsix(struct sockaddr_storage *v6)
544 {
545 struct sockaddr_storage v4;
546
547 if (v6ready == 0 || STORAGE_FAMILY(*v6) != AF_INET6 ||
548 IN6_IS_ADDR_V4MAPPED(&STORAGE_SIN_ADDR6_NF_CONST(*v6)) == 0) {
549 return;
550 }
551 memset(&v4, 0, sizeof v4);
552 STORAGE_FAMILY(v4) = AF_INET;
553 memcpy(&STORAGE_SIN_ADDR(v4),
554 (unsigned char *) &STORAGE_SIN_ADDR6_CONST(*v6) + 12,
555 sizeof STORAGE_SIN_ADDR(v4));
556 STORAGE_PORT(v4) = STORAGE_PORT6_CONST(*v6);
557 SET_STORAGE_LEN(v4, sizeof(struct sockaddr_in));
558 *v6 = v4;
559 }
560
561 /* Return 0 if s1 == s2 , 1 if s1 != s2 , -1 if error */
562
addrcmp(const struct sockaddr_storage * const s1,const struct sockaddr_storage * const s2)563 static int addrcmp(const struct sockaddr_storage * const s1,
564 const struct sockaddr_storage * const s2)
565 {
566 if (STORAGE_FAMILY(*s1) == AF_INET6) {
567 if (STORAGE_FAMILY(*s2) != AF_INET6) {
568 return 1;
569 }
570 if (IN6_ARE_ADDR_EQUAL(&STORAGE_SIN_ADDR6_NF_CONST(*s1), &STORAGE_SIN_ADDR6_NF_CONST(*s2))) {
571 return 0;
572 } else {
573 return 1;
574 }
575 } else if (STORAGE_FAMILY(*s1) == AF_INET) {
576 if (STORAGE_FAMILY(*s2) != AF_INET) {
577 return 1;
578 }
579 if (STORAGE_SIN_ADDR_CONST(*s1) == STORAGE_SIN_ADDR_CONST(*s2)) {
580 return 0;
581 } else {
582 return 1;
583 }
584 }
585 return -1;
586 }
587
generic_aton(const char * src,struct sockaddr_storage * a)588 static int generic_aton(const char *src, struct sockaddr_storage *a)
589 {
590 if (inet_pton(AF_INET6, src, &STORAGE_SIN_ADDR6(*a)) > 0) {
591 STORAGE_FAMILY(*a) = AF_INET6;
592 return 0;
593 }
594 if (inet_pton(AF_INET, src, &STORAGE_SIN_ADDR(*a)) > 0) {
595 STORAGE_FAMILY(*a) = AF_INET;
596 return 0;
597 }
598 memset(a, 0, sizeof *a);
599
600 return -1;
601 }
602
logfile(const int crit,const char * format,...)603 void logfile(const int crit, const char *format, ...)
604 {
605 #if defined(NON_ROOT_FTP)
606 (void) crit;
607 (void) format;
608 #else
609 const char *urgency;
610 va_list va;
611 char line[MAX_SYSLOG_LINE];
612
613 if (no_syslog != 0) {
614 va_end(va);
615 return;
616 }
617 va_start(va, format);
618 vsnprintf(line, sizeof line, format, va);
619 va_end(va);
620 switch (crit) {
621 case LOG_INFO:
622 urgency = "[INFO] ";
623 break;
624 case LOG_WARNING:
625 urgency = "[WARNING] ";
626 break;
627 case LOG_ERR:
628 urgency = "[ERROR] ";
629 break;
630 case LOG_NOTICE:
631 urgency = "[NOTICE] ";
632 break;
633 case LOG_DEBUG:
634 urgency = "[DEBUG] ";
635 break;
636 default:
637 urgency = "";
638 }
639 # ifdef SAVE_DESCRIPTORS
640 openlog("pure-ftpd", log_pid, syslog_facility);
641 # endif
642 syslog(crit, "(%s@%s) %s%s",
643 ((loggedin != 0 && *account != 0) ? account : "?"),
644 (*host != 0 ? host : "?"),
645 urgency, line);
646 # ifdef SAVE_DESCRIPTORS
647 closelog();
648 # endif
649 #endif
650 }
651
652 #ifndef NO_STANDALONE
653
654 /* this is taken from the code examples for Stevens' "Advanced
655 * Programming in the Unix Environment. The code is publicly available
656 * at ftp://ftp.uu.net/published/books/stevens.advprog.tar.Z */
657
open_max(void)658 static unsigned int open_max(void)
659 {
660 long z;
661
662 if ((z = (long) sysconf(_SC_OPEN_MAX)) < 0L) {
663 perror("_SC_OPEN_MAX");
664 _EXIT(EXIT_FAILURE);
665 }
666 return (unsigned int) z;
667 }
668
669 #endif
670
addreply_newline(const char * const str,const size_t size)671 static void addreply_newline(const char * const str, const size_t size)
672 {
673 struct reply *newline;
674
675 if ((newline = (struct reply *) malloc(offsetof(struct reply, line) +
676 size)) == NULL) {
677 die_mem();
678 }
679 if (firstreply == NULL) {
680 firstreply = newline;
681 } else {
682 lastreply->next = newline;
683 }
684 newline->next = NULL;
685 lastreply = newline;
686 memcpy(newline->line, str, size);
687 }
688
addreply_noformat(const int code,const char * const line)689 void addreply_noformat(const int code, const char * const line)
690 {
691 if (code != 0) {
692 replycode = code;
693 }
694 addreply_newline(line, strlen(line) + (size_t) 1U);
695 }
696
addreply(const int code,const char * const line,...)697 void addreply(const int code, const char * const line, ...)
698 {
699 char *a;
700 char *b;
701 va_list ap;
702 int last;
703 char buf[MAX_SERVER_REPLY_LEN];
704
705 if (code != 0) {
706 replycode = code;
707 }
708 va_start(ap, line);
709 vsnprintf(buf, sizeof buf, line, ap);
710 va_end(ap);
711 last = 0;
712 a = buf;
713 for (;;) {
714 b = strchr(a, '\n');
715 if (b != NULL) {
716 *b = 0;
717 } else {
718 b = a;
719 while (*b != 0) {
720 b++;
721 }
722 last++;
723 }
724 addreply_newline(a, (size_t) (b - a) + (size_t) 1U);
725 if (last != 0) {
726 break;
727 }
728 a = b + 1;
729 }
730 }
731
doreply(void)732 void doreply(void)
733 {
734 struct reply *scannedentry;
735 struct reply *nextentry;
736
737 if ((scannedentry = firstreply) == NULL) {
738 return;
739 }
740 do {
741 nextentry = scannedentry->next;
742 #ifdef WITH_TLS
743 if (tls_cnx != NULL) {
744 char buf[MAX_SERVER_REPLY_LEN];
745
746 snprintf(buf, sizeof buf, "%3d%c%s\r\n", replycode,
747 nextentry == NULL ? ' ' : '-', scannedentry->line);
748 SSL_write(tls_cnx, buf, strlen(buf));
749 } else
750 #endif
751 {
752 client_printf("%3d%c%s\r\n", replycode,
753 nextentry == NULL ? ' ' : '-',
754 scannedentry->line);
755 }
756 if (logging > 1) {
757 logfile(LOG_DEBUG, "%3d%c%s", replycode,
758 nextentry == NULL ? ' ' : '-', scannedentry->line);
759 }
760 } while ((scannedentry = nextentry) != NULL);
761 client_fflush();
762 scannedentry = firstreply;
763 do {
764 nextentry = scannedentry->next;
765 free(scannedentry);
766 } while ((scannedentry = nextentry) != NULL);
767 firstreply = lastreply = NULL;
768 }
769
770 /* Check whether a file name is valid. Files names starting
771 * with a dot are only allowed to root and to users
772 * chroot()ed in their home directories -Jedi. */
773
checknamesanity(const char * name,int dot_ok)774 static int checknamesanity(const char *name, int dot_ok)
775 {
776 const char *namepnt;
777
778 #ifdef PARANOID_FILE_NAMES
779 const char *validchars =
780 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
781 "abcdefgihjklmnopqrstuvwxyz"
782 "0123456789./-_";
783 #endif
784
785 if (name == NULL || *name == 0) {
786 return -1;
787 }
788 /* optimize . and .. */
789 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
790 return 0;
791 }
792 namepnt = name;
793 #ifdef PARANOID_FILE_NAMES
794 /* we want to make sure we don't get any non-alphanumeric file name */
795 if (strlen(namepnt) != strspn(namepnt, validchars)) {
796 return -1;
797 }
798 #endif
799 #ifdef QUOTAS
800 if (hasquota() == 0) {
801 if (strstr(namepnt, QUOTA_FILE) != NULL) {
802 return -1; /* .ftpquota => *NO* */
803 }
804 # ifndef ALLOW_DELETION_OF_TEMPORARY_FILES
805 if (strstr(namepnt, PUREFTPD_TMPFILE_PREFIX) == namepnt) {
806 return -1;
807 }
808 # endif
809 }
810 #endif
811 while (*namepnt != 0) {
812 #ifndef ALLOW_EVERYTHING_IN_FILE_NAMES
813 if (ISCTRLCODE(*namepnt) || *namepnt == '\\') {
814 return -1;
815 }
816 #endif
817 if (dot_ok == 0) {
818 if (*namepnt == '/') {
819 namepnt++;
820 } else if (namepnt != name) {
821 namepnt++;
822 continue;
823 }
824 if (namepnt[0] == 0) { /* /$ */
825 return 0;
826 }
827 if (namepnt[0] == '.') { /* /. */
828 if (namepnt[1] == 0) { /* /.$ => ok */
829 return 0;
830 }
831 if (namepnt[1] == '.') { /* /.. */
832 if (namepnt[2] == 0) { /* /..$ => ok */
833 return 0;
834 }
835 if (namepnt[2] != '/') { /* /..[^/] => *NO* */
836 return -1;
837 }
838 } else if (namepnt[1] != '/') { /* /.[^/]/ => *NO* */
839 return -1;
840 }
841 }
842 if (namepnt != name) {
843 continue;
844 }
845 }
846 namepnt++;
847 }
848 return 0;
849 }
850
do_ipv6_port(char * p,char delim)851 static void do_ipv6_port(char *p, char delim)
852 {
853 char *deb;
854 struct sockaddr_storage a;
855
856 deb = p;
857 while (*p && strchr("0123456789abcdefABCDEF:", *p) != NULL) {
858 p++;
859 }
860 if (*p != delim || atoi(p + 1) == 0) {
861 nope:
862 (void) close(datafd);
863 datafd = -1;
864 addreply_noformat(501, MSG_SYNTAX_ERROR_IP);
865 return;
866 }
867 *p++ = 0;
868 if (generic_aton(deb, &a) != 0) {
869 goto nope;
870 }
871 doport2(a, (unsigned int) atoi(p));
872 }
873
874 #ifndef MINIMAL
doesta(void)875 void doesta(void)
876 {
877 struct sockaddr_storage dataconn;
878 socklen_t socksize;
879 char hbuf[NI_MAXHOST];
880 char pbuf[NI_MAXSERV];
881
882 if (passive != 0 || datafd == -1) {
883 addreply_noformat(520, MSG_ACTIVE_DISABLED);
884 return;
885 }
886 if (xferfd == -1) {
887 opendata();
888 if (xferfd == -1) {
889 addreply_noformat(425, MSG_CANT_CREATE_DATA_SOCKET);
890 return;
891 }
892 }
893 socksize = (socklen_t) sizeof dataconn;
894 if (getsockname(xferfd, (struct sockaddr *) &dataconn, &socksize) < 0 ||
895 getnameinfo((struct sockaddr *) &dataconn, STORAGE_LEN(dataconn),
896 hbuf, sizeof hbuf, pbuf, sizeof pbuf,
897 NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
898 addreply_noformat(425, MSG_GETSOCKNAME_DATA);
899 closedata();
900 return;
901 }
902 addreply(225, "Connected from (|%c|%s|%s|)",
903 STORAGE_FAMILY(dataconn) == AF_INET6 ? '2' : '1', hbuf, pbuf);
904 }
905
doestp(void)906 void doestp(void)
907 {
908 struct sockaddr_storage dataconn;
909 socklen_t socksize;
910 char hbuf[NI_MAXHOST];
911 char pbuf[NI_MAXSERV];
912
913 if (passive == 0 || datafd == -1) {
914 addreply_noformat(520, MSG_CANT_PASSIVE);
915 return;
916 }
917 if (xferfd == -1) {
918 opendata();
919 if (xferfd == -1) {
920 addreply_noformat(425, MSG_CANT_CREATE_DATA_SOCKET);
921 return;
922 }
923 }
924 socksize = (socklen_t) sizeof dataconn;
925 if (getpeername(xferfd, (struct sockaddr *) &dataconn, &socksize) < 0 ||
926 getnameinfo((struct sockaddr *) &dataconn, STORAGE_LEN(dataconn),
927 hbuf, sizeof hbuf, pbuf, sizeof pbuf,
928 NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
929 addreply_noformat(425, MSG_GETSOCKNAME_DATA);
930 closedata();
931 return;
932 }
933 addreply(225, "Connected to (|%c|%s|%s|)",
934 STORAGE_FAMILY(dataconn) == AF_INET6 ? '2' : '1', hbuf, pbuf);
935 }
936 #endif
937
doeprt(char * p)938 void doeprt(char *p)
939 {
940 char delim;
941 int family;
942
943 delim = *p++;
944 family = atoi(p);
945 while (isdigit((unsigned char) *p)) {
946 p++;
947 }
948 if (*p == delim) {
949 p++;
950 } else {
951 addreply_noformat(501, MSG_SYNTAX_ERROR_IP);
952 return;
953 }
954 if (family == 2 && v6ready) {
955 do_ipv6_port(p, delim);
956 return;
957 }
958 if (family != 1) {
959 if (v6ready) {
960 addreply_noformat(522, MSG_ONLY_IPV4V6);
961 } else {
962 addreply_noformat(522, MSG_ONLY_IPV4);
963 }
964 return;
965 }
966
967 {
968 unsigned int a1, a2, a3, a4, port = 0U;
969 /* there should be dot-decimal ip as rfc2428 states,
970 * but troll used for some reason "comma-decimal" notation
971 * so I decided to leave it */
972 if ((sscanf(p, "%u,%u,%u,%u", &a1, &a2, &a3, &a4) != 4 &&
973 sscanf(p, "%u.%u.%u.%u", &a1, &a2, &a3, &a4) != 4) ||
974 a1 > 255U || a2 > 255U || a3 > 255U || a4 > 255U ||
975 (a1 | a2 | a3 | a4) == 0U) {
976 addreply_noformat(501, MSG_SYNTAX_ERROR_IP);
977 return;
978 }
979 while (*p && strchr("0123456789.,", *p)) {
980 p++;
981 }
982 if (*p == delim) {
983 port = (unsigned int) atoi(++p);
984 while (*p && isdigit((unsigned char) *p)) {
985 p++;
986 }
987 }
988 if (*p != delim || port > 65535U || port <= 0U) {
989 addreply_noformat(501, MSG_SYNTAX_ERROR_IP);
990 return;
991 } else {
992 struct sockaddr_storage a;
993
994 memset(&a, 0, sizeof a);
995 STORAGE_FAMILY(a) = AF_INET;
996 STORAGE_SIN_ADDR(a) =
997 htonl(((uint32_t) a1 << 24) |
998 ((uint32_t) a2 << 16) | (a3 << 8) | a4);
999 SET_STORAGE_LEN(a, sizeof(struct sockaddr_in));
1000 doport2(a, port);
1001 }
1002 }
1003 }
1004
stripctrl(char * const buf,size_t len)1005 void stripctrl(char * const buf, size_t len)
1006 {
1007 if (len <= (size_t) 0U) {
1008 return;
1009 }
1010 do {
1011 len--;
1012 if (ISCTRLCODE(buf[len]) &&
1013 buf[len] != 0 && buf[len] != '\n') {
1014 buf[len] = '_';
1015 }
1016 } while (len != (size_t) 0U);
1017 }
1018
1019 #ifndef MINIMAL
1020
1021 /*
1022 * small help routine to display a banner
1023 * type = 0 reads .banner/welcome.msg
1024 * type = 1 reads .message (after cd'ing into a directory)
1025 */
dobanner(const int type)1026 void dobanner(const int type)
1027 {
1028 char buffer[512];
1029 FILE *msg;
1030 size_t buflen;
1031 unsigned int nblines = BANNER_MAXLINES;
1032
1033 switch (type) {
1034 case 0:
1035 if ((msg = fopen(".banner", "r")) == NULL
1036 # ifdef WITH_WELCOME_MSG
1037 && (msg = fopen("welcome.msg", "r")) == NULL
1038 # endif
1039 ) {
1040 return;
1041 }
1042 break;
1043 case 1:
1044 if ((msg = fopen(".message", "r")) == NULL) {
1045 return;
1046 }
1047 break;
1048 default:
1049 return;
1050 }
1051
1052 while (fgets(buffer, sizeof buffer, msg) != NULL && nblines > 0U) {
1053 nblines--;
1054 if ((buflen = strlen(buffer)) > (size_t) 0U) {
1055 buflen--;
1056 while (buffer[buflen] == '\n' || buffer[buflen] == '\r') {
1057 buffer[buflen] = 0;
1058 if (buflen == (size_t) 0U) {
1059 break;
1060 }
1061 buflen--;
1062 }
1063 stripctrl(buffer, buflen);
1064 }
1065 addreply_noformat(0, buffer);
1066 }
1067 (void) fclose(msg);
1068 }
1069
1070 #endif
1071
1072 #ifndef MINIMAL
1073
modernformat(const char * file,char * target,size_t target_size,const char * const prefix)1074 int modernformat(const char *file, char *target, size_t target_size,
1075 const char * const prefix)
1076 {
1077 char link_target[PATH_MAX + 1U];
1078 const char *ft;
1079 const char *ftx = "";
1080 struct tm *t;
1081 struct stat st;
1082 int ret = 0;
1083
1084 if (lstat(file, &st) != 0 || !(t = gmtime((time_t *) &st.st_mtime))) {
1085 return -1;
1086 }
1087 #if !defined(MINIMAL) && !defined(ALWAYS_SHOW_SYMLINKS_AS_SYMLINKS)
1088 if (
1089 # ifndef ALWAYS_SHOW_RESOLVED_SYMLINKS
1090 broken_client_compat != 0 &&
1091 # endif
1092 S_ISLNK(st.st_mode)) {
1093 struct stat sts;
1094
1095 if (stat(file, &sts) == 0 && !S_ISLNK(sts.st_mode)) {
1096 st = sts;
1097 }
1098 } /* Show non-dangling symlinks as files/directories */
1099 #endif
1100 if (S_ISREG(st.st_mode)) {
1101 ft = "file";
1102 } else if (S_ISDIR(st.st_mode)) {
1103 ret = 1;
1104 ft = "dir";
1105 if (*file == '.') {
1106 if (file[1] == '.' && file[2] == 0) {
1107 ft = "pdir";
1108 } else if (file[1] == 0) {
1109 ft = "cdir";
1110 }
1111 } else if (*file == '/' && file[1] == 0) {
1112 ft = "pdir";
1113 }
1114 } else if (S_ISLNK(st.st_mode)) {
1115 ssize_t sx;
1116
1117 ft = "OS.unix=symlink";
1118 if ((sx = readlink(file, link_target, sizeof link_target - 1U)) > 0) {
1119 link_target[sx] = 0;
1120 if (strpbrk(link_target, "\r\n;") == NULL) {
1121 ftx = link_target;
1122 ft = "OS.unix=slink:";
1123 }
1124 }
1125 } else {
1126 ft = "unknown";
1127 }
1128 if (guest != 0) {
1129 if (SNCHECK(snprintf(target, target_size,
1130 "%stype=%s%s;siz%c=%llu;modify=%04d%02d%02d%02d%02d%02d;UNIX.mode=0%o;unique=%xg%llx; %s",
1131 prefix,
1132 ft, ftx,
1133 ret ? 'd' : 'e',
1134 (unsigned long long) st.st_size,
1135 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1136 t->tm_hour, t->tm_min, t->tm_sec,
1137 (unsigned int) st.st_mode & 07777,
1138 (unsigned int) st.st_dev,
1139 (unsigned long long) st.st_ino,
1140 file), target_size)) {
1141 _EXIT(EXIT_FAILURE);
1142 }
1143 } else {
1144 if (SNCHECK(snprintf(target, target_size,
1145 "%stype=%s;siz%c=%llu;modify=%04d%02d%02d%02d%02d%02d;UNIX.mode=0%o;UNIX.uid=%lld;UNIX.gid=%lld;unique=%xg%llx; %s",
1146 prefix,
1147 ft,
1148 ret ? 'd' : 'e',
1149 (unsigned long long) st.st_size,
1150 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1151 t->tm_hour, t->tm_min, t->tm_sec,
1152 (unsigned int) st.st_mode & 07777,
1153 (unsigned long long) st.st_uid,
1154 (unsigned long long) st.st_gid,
1155 (unsigned int) st.st_dev,
1156 (unsigned long long) st.st_ino,
1157 file), target_size)) {
1158 _EXIT(EXIT_FAILURE);
1159 }
1160 }
1161 return ret;
1162 }
1163
1164 #define MLST_BEGIN "Begin" CRLF
1165
domlst(const char * const file)1166 void domlst(const char * const file)
1167 {
1168 char line[PATH_MAX + 256U] = MLST_BEGIN;
1169
1170 if (modernformat(file, line + (sizeof MLST_BEGIN - 1U),
1171 sizeof line - (sizeof MLST_BEGIN - 1U), " ") < 0) {
1172 addreply_noformat(550, MSG_STAT_FAILURE2);
1173 return;
1174 }
1175 addreply_noformat(0, line);
1176 addreply_noformat(250, "End.");
1177 }
1178
donoop(void)1179 void donoop(void)
1180 {
1181 #ifdef BORING_MODE
1182 addreply_noformat(200, "dc.w $4E71");
1183 #else
1184 addreply_noformat(200, MSG_SLEEPING);
1185 #endif
1186 }
1187
doallo(const off_t size)1188 void doallo(const off_t size)
1189 {
1190 int ret = -1;
1191 #ifdef QUOTAS
1192 Quota quota;
1193 #endif
1194
1195 if (size <= 0) {
1196 ret = 0;
1197 } else if (ul_check_free_space(wd, (double) size) != 0) {
1198 ret = 0;
1199 }
1200 #ifdef QUOTAS
1201 if (quota_update("a, 0LL, 0LL, NULL) == 0) {
1202 if (quota.files >= user_quota_files ||
1203 quota.size >= user_quota_size ||
1204 (unsigned long long) size > user_quota_size - quota.size) {
1205 ret = -1;
1206 }
1207 }
1208 #endif
1209 if (ret == 0) {
1210 #ifdef DISABLE_HUMOR
1211 addreply_noformat(200, "OK");
1212 #else
1213 addreply_noformat(200, "A L'HUILE");
1214 #endif
1215 } else {
1216 addreply_noformat(552, MSG_NO_DISK_SPACE);
1217 }
1218 }
1219
1220 #endif
1221
dositetime(void)1222 void dositetime(void)
1223 {
1224 char tmp[64];
1225 const struct tm *tm;
1226 time_t now;
1227
1228 if ((now = time(NULL)) == (time_t) -1 || (tm = localtime(&now)) == NULL) {
1229 addreply_noformat(451, "time()");
1230 return;
1231 }
1232 strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S", tm);
1233 addreply_noformat(211, tmp);
1234 }
1235
doinitsupgroups(const char * user,const uid_t uid,const gid_t gid)1236 static int doinitsupgroups(const char *user, const uid_t uid, const gid_t gid)
1237 {
1238 #ifndef NON_ROOT_FTP
1239 # ifdef HAVE_SETGROUPS
1240 if (setgroups(1U, &gid) != 0) {
1241 return -1;
1242 }
1243 # else
1244 (void) gid;
1245 # endif
1246 # ifdef HAVE_INITGROUPS
1247 if (user == NULL) {
1248 const struct passwd * const lpwd = getpwuid(uid);
1249
1250 if (lpwd != NULL && lpwd->pw_name != NULL) {
1251 user = lpwd->pw_name;
1252 } else {
1253 return 0;
1254 }
1255 }
1256 initgroups(user, gid);
1257 # else
1258 (void) user;
1259 (void) uid;
1260 # endif
1261 #else
1262 (void) user;
1263 (void) uid;
1264 (void) gid;
1265 #endif
1266 return 0;
1267 }
1268
douser(const char * username)1269 void douser(const char *username)
1270 {
1271 struct passwd *pw = NULL;
1272
1273 if (loggedin) {
1274 if (username) {
1275 if (!guest) {
1276 addreply_noformat(530, MSG_ALREADY_LOGGED);
1277 } else if (broken_client_compat != 0) {
1278 addreply_noformat(331, MSG_ANY_PASSWORD);
1279 } else {
1280 addreply_noformat(230, MSG_ANONYMOUS_LOGGED);
1281 dot_read_ok = dot_read_anon_ok;
1282 dot_write_ok = 0;
1283 }
1284 }
1285 return;
1286 }
1287 if (anon_only <= 0 && username != NULL && *username != 0 &&
1288 (anon_only < 0 || (strcasecmp(username, "ftp") &&
1289 strcasecmp(username, "anonymous")))) {
1290 strncpy(account, username, sizeof(account) - 1);
1291 account[sizeof(account) - (size_t) 1U] = 0;
1292 addreply(331, MSG_USER_OK, account);
1293 loggedin = 0;
1294 } else if (anon_only < 0) {
1295 if (broken_client_compat != 0) {
1296 addreply(331, MSG_USER_OK, username);
1297 return;
1298 } else {
1299 die(530, LOG_DEBUG, MSG_NO_ANONYMOUS_LOGIN);
1300 }
1301 } else {
1302 #ifdef WITH_VIRTUAL_HOSTS
1303 char name[PATH_MAX];
1304 char hbuf[NI_MAXHOST];
1305 #endif
1306 if (chrooted != 0) {
1307 die(421, LOG_DEBUG, MSG_CANT_DO_TWICE);
1308 }
1309
1310 #ifdef PER_USER_LIMITS
1311 if (per_anon_max > 0U && ftpwho_read_count("ftp") >= per_anon_max) {
1312 addreply(421, MSG_PERUSER_MAX, (unsigned long) per_anon_max);
1313 doreply();
1314 _EXIT(1);
1315 }
1316 #endif
1317
1318 #ifdef NON_ROOT_FTP
1319 {
1320 static struct passwd pw_;
1321 char s[PATH_MAX + 1U];
1322
1323 if (getcwd(s, sizeof s - (size_t) 1U) == NULL) {
1324 cantsec:
1325 die(421, LOG_ERR, MSG_UNABLE_SECURE_ANON);
1326 }
1327 pw_.pw_uid = geteuid();
1328 pw_.pw_gid = getegid();
1329 pw_.pw_dir = (char *) NON_ROOT_ANON_DIR;
1330 if (home_directory != NULL) {
1331 pw_.pw_dir = (char *) home_directory;
1332 }
1333 if (getenv("FTP_ANON_DIR") != NULL) {
1334 pw_.pw_dir = getenv("FTP_ANON_DIR");
1335 }
1336 if (pw_.pw_dir == NULL) {
1337 pw_.pw_dir = strdup(s); /* checked for == NULL later */
1338 }
1339 pw = &pw_;
1340 }
1341 #else
1342 if (((pw = getpwnam("ftp")) == NULL &&
1343 (pw = getpwnam("_ftp")) == NULL) ||
1344 pw->pw_uid == 0 || pw->pw_gid == 0 ||
1345 (doinitsupgroups("ftp", (uid_t) -1, pw->pw_gid) != 0 &&
1346 doinitsupgroups("_ftp", (uid_t) -1, pw->pw_gid) != 0) ||
1347 setgid(pw->pw_gid) || setegid(pw->pw_gid)) {
1348 cantsec:
1349 die(421, LOG_ERR, MSG_UNABLE_SECURE_ANON);
1350 }
1351 # ifdef ANON_DIR
1352 if ((pw->pw_dir = strdup(ANON_DIR)) == NULL) {
1353 die_mem();
1354 }
1355 # endif
1356 #endif
1357 #ifdef WITH_VIRTUAL_HOSTS
1358 if (getnameinfo((struct sockaddr *) &ctrlconn, STORAGE_LEN(ctrlconn),
1359 hbuf, sizeof hbuf, NULL,
1360 (size_t) 0U, NI_NUMERICHOST) != 0
1361 || SNCHECK(snprintf(name, sizeof name, VHOST_PATH "/%s", hbuf),
1362 sizeof name)) {
1363 _EXIT(EXIT_FAILURE);
1364 }
1365 if (chdir(name) != 0) /* non-virtual */
1366 #endif
1367 {
1368 char *hd;
1369 size_t rd_len;
1370
1371 if (pw->pw_dir == NULL || *pw->pw_dir != '/') {
1372 goto cantsec;
1373 }
1374 if ((hd = strstr(pw->pw_dir, "/./")) != NULL) {
1375 rd_len = (size_t) (hd - pw->pw_dir) + sizeof "/";
1376 if ((root_directory = malloc(rd_len)) == NULL) {
1377 goto cantsec;
1378 }
1379 memcpy(root_directory, pw->pw_dir, rd_len);
1380 root_directory[rd_len - (size_t) 1U] = 0;
1381 hd += 2;
1382 } else {
1383 rd_len = strlen(pw->pw_dir) + sizeof "/";
1384 if ((root_directory = malloc(rd_len)) == NULL) {
1385 goto cantsec;
1386 }
1387 snprintf(root_directory, rd_len, "%s/", pw->pw_dir);
1388 hd = (char *) "/";
1389 }
1390 if (chdir(root_directory) || chroot(root_directory) || chdir(hd)) {
1391 die(421, LOG_ERR, MSG_CANT_CHANGE_DIR " [%s]", root_directory, hd);
1392 }
1393 logfile(LOG_INFO, MSG_ANONYMOUS_LOGGED);
1394 }
1395 #ifdef WITH_VIRTUAL_HOSTS
1396 else { /* virtual host */
1397 const size_t rd_len = strlen(hbuf) + sizeof ":/";
1398
1399 if ((root_directory = malloc(rd_len)) == NULL ||
1400 chdir(name) || chroot(name) || chdir("/") ||
1401 SNCHECK(snprintf(root_directory, rd_len, "%s:/", hbuf),
1402 rd_len)) {
1403 goto cantsec;
1404 }
1405 logfile(LOG_INFO, MSG_ANONYMOUS_LOGGED_VIRTUAL ": %s", hbuf);
1406 }
1407 #endif
1408 if (pw == NULL) {
1409 goto cantsec;
1410 }
1411 chrooted = 1;
1412 authresult.uid = pw->pw_uid;
1413 authresult.gid = pw->pw_gid;
1414 if ((authresult.dir = strdup(pw->pw_dir)) == NULL) {
1415 die_mem();
1416 }
1417
1418 #ifdef THROTTLING
1419 if (throttling != 0) {
1420 addreply_noformat(0, MSG_BANDWIDTH_RESTRICTED);
1421 (void) nice(NICE_VALUE);
1422 } else {
1423 throttling_delay = throttling_bandwidth_ul =
1424 throttling_bandwidth_dl = 0UL;
1425 }
1426 #endif
1427
1428 #ifndef NON_ROOT_FTP
1429 if (authresult.uid > (uid_t) 0) {
1430 # ifndef WITHOUT_PRIVSEP
1431 if (setuid(authresult.uid) != 0 || seteuid(authresult.uid) != 0) {
1432 goto cantsec;
1433 }
1434 # else
1435 if (seteuid(authresult.uid) != 0) {
1436 goto cantsec;
1437 }
1438 # ifdef USE_CAPABILITIES
1439 drop_login_caps();
1440 # endif
1441 # endif
1442 }
1443 #endif
1444
1445 #ifndef MINIMAL
1446 dobanner(0);
1447 #endif
1448
1449 if (broken_client_compat != 0) {
1450 addreply_noformat(331, MSG_ANONYMOUS_ANY_PASSWORD);
1451 } else {
1452 addreply_noformat(230, MSG_ANONYMOUS_LOGGED);
1453 }
1454 dot_write_ok = 0;
1455 dot_read_ok = dot_read_anon_ok;
1456 strncpy(account, "ftp", sizeof account - (size_t) 1U);
1457 account[(sizeof account) - 1U] = 0;
1458 #ifdef FTPWHO
1459 if (shm_data_cur != NULL) {
1460 ftpwho_lock();
1461 strncpy(shm_data_cur->account, account,
1462 sizeof shm_data_cur->account - (size_t) 1U);
1463 shm_data_cur->account[sizeof shm_data_cur->account - 1U] = 0;
1464 ftpwho_unlock();
1465 state_needs_update = 1;
1466 }
1467 #endif
1468 loggedin = guest = 1;
1469 #ifdef QUOTAS
1470 user_quota_size = user_quota_files = ULONG_LONG_MAX;
1471 #endif
1472 }
1473 if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) {
1474 wd[0] = '/';
1475 wd[1] = 0;
1476 }
1477 #ifdef WITH_BONJOUR
1478 refreshManager();
1479 #endif
1480 }
1481
pw_check(const char * account,const char * password,const struct sockaddr_storage * const sa,const struct sockaddr_storage * const peer)1482 static AuthResult pw_check(const char *account, const char *password,
1483 const struct sockaddr_storage * const sa,
1484 const struct sockaddr_storage * const peer)
1485 {
1486 Authentications *auth_scan = first_authentications;
1487 AuthResult result;
1488
1489 result.auth_ok = -1;
1490 while (auth_scan != NULL) {
1491 #ifdef THROTTLING
1492 result.throttling_bandwidth_ul = throttling_bandwidth_ul;
1493 result.throttling_bandwidth_dl = throttling_bandwidth_dl;
1494 result.throttling_ul_changed = result.throttling_dl_changed = 0;
1495 #endif
1496 #ifdef QUOTAS
1497 result.user_quota_size = user_quota_size;
1498 result.user_quota_files = user_quota_files;
1499 result.quota_size_changed = result.quota_files_changed = 0;
1500 #endif
1501 #ifdef RATIOS
1502 result.ratio_upload = ratio_upload;
1503 result.ratio_download = ratio_download;
1504 result.ratio_ul_changed = result.ratio_dl_changed = 0;
1505 #endif
1506 #ifdef PER_USER_LIMITS
1507 result.per_user_max = per_user_max;
1508 #endif
1509 result.backend_data = NULL;
1510 auth_scan->auth->check(&result, account, password, sa, peer);
1511 if (result.auth_ok < 0) {
1512 break;
1513 } else if (result.auth_ok > 0) {
1514 #ifdef THROTTLING
1515 if ((result.throttling_ul_changed |
1516 result.throttling_dl_changed) != 0) {
1517 if (result.throttling_ul_changed != 0 &&
1518 result.throttling_bandwidth_ul > 0UL) {
1519 throttling_bandwidth_ul = result.throttling_bandwidth_ul;
1520 }
1521 if (result.throttling_dl_changed != 0 &&
1522 result.throttling_bandwidth_dl > 0UL) {
1523 throttling_bandwidth_dl = result.throttling_bandwidth_dl;
1524 }
1525 throttling_delay = 1000000 /
1526 (throttling_bandwidth_dl | throttling_bandwidth_ul);
1527 throttling = 2;
1528 }
1529 #endif
1530 #ifdef QUOTAS
1531 if (result.quota_size_changed != 0) {
1532 user_quota_size = result.user_quota_size;
1533 }
1534 if (result.quota_files_changed != 0) {
1535 user_quota_files = result.user_quota_files;
1536 }
1537 #endif
1538 #ifdef RATIOS
1539 if (result.ratio_ul_changed != 0) {
1540 ratio_upload = result.ratio_upload;
1541 ratio_for_non_anon = 1;
1542 }
1543 if (result.ratio_dl_changed != 0) {
1544 ratio_download = result.ratio_download;
1545 }
1546 #endif
1547 #ifdef PER_USER_LIMITS
1548 per_user_max = result.per_user_max;
1549 #endif
1550
1551 #ifdef NON_ROOT_FTP
1552 result.uid = geteuid();
1553 result.gid = getegid();
1554 #endif
1555
1556 return result;
1557 }
1558 auth_scan = auth_scan->next;
1559 }
1560
1561 return result;
1562 }
1563
1564 /*
1565 * Check if an user belongs to the trusted group, either in his
1566 * primary group, or his supplementary groups. Root is always trusted.
1567 */
1568
check_trustedgroup(const uid_t uid,const gid_t gid)1569 static int check_trustedgroup(const uid_t uid, const gid_t gid)
1570 {
1571 GETGROUPS_T *alloca_suppgroups;
1572 int n;
1573 int n2;
1574 int result = 0;
1575
1576 if (uid == (uid_t) 0) {
1577 return 1;
1578 }
1579 if (userchroot == 2) {
1580 return 0;
1581 }
1582 if (gid == chroot_trustedgid) {
1583 return 1;
1584 }
1585 #ifdef HAVE_GETGROUPS
1586 if ((n = getgroups(0, NULL)) <= 0) {
1587 return 0;
1588 }
1589 if ((alloca_suppgroups =
1590 ALLOCA(n * (sizeof *alloca_suppgroups))) == NULL) {
1591 die_mem();
1592 }
1593 n2 = getgroups(n, alloca_suppgroups);
1594 /* Jedi's paranoia */
1595 if (n2 < n) {
1596 n = n2;
1597 }
1598 result = 0;
1599 while (n != 0) {
1600 n--;
1601 if (alloca_suppgroups[n] == (GETGROUPS_T) chroot_trustedgid) {
1602 result = 1;
1603 break;
1604 }
1605 };
1606 ALLOCA_FREE(alloca_suppgroups);
1607 #endif
1608
1609 return result;
1610 }
1611
1612 /*
1613 * Create a home directory on demand.
1614 */
1615
create_home_and_chdir(const char * const home)1616 static int create_home_and_chdir(const char * const home)
1617 {
1618 char *pathcomp;
1619 char *z;
1620 size_t len;
1621 const char delim = '/';
1622
1623 if (home == NULL || *home != '/') {
1624 return -1;
1625 }
1626 if (chdir(home) == 0) {
1627 return 0;
1628 }
1629 if (create_home == 0) {
1630 return -1;
1631 }
1632 len = strlen(home) + (size_t) 1U;
1633 if (len < (size_t) 2U || *home != delim) {
1634 return -1;
1635 }
1636 if ((pathcomp = ALLOCA(len)) == NULL) {
1637 return -1;
1638 }
1639 memcpy(pathcomp, home, len); /* safe, no possible overflow */
1640 z = pathcomp;
1641 for (;;) {
1642 z++;
1643 if (*z == 0) {
1644 break;
1645 }
1646 if (*z == delim) {
1647 *z = 0;
1648 if (z[1] == 0) {
1649 break;
1650 }
1651 (void) mkdir(pathcomp, (mode_t) 0755);
1652 *z = delim;
1653 }
1654 }
1655 ALLOCA_FREE(pathcomp);
1656 (void) mkdir(home, (mode_t) 0700);
1657 if (chdir(home) != 0) {
1658 return -1;
1659 }
1660 if (chmod(home, (mode_t) 0777 & ~u_mask_d) < 0 ||
1661 chown(home, authresult.uid, authresult.gid) < 0) {
1662 return -1;
1663 }
1664
1665 return chdir(home);
1666 }
1667
randomsleep(unsigned int t)1668 static void randomsleep(unsigned int t) {
1669 usleep2((unsigned long) (zrand() % PASSWD_FAILURE_DELAY));
1670 usleep2(t * PASSWD_FAILURE_DELAY);
1671 }
1672
dopass(char * password)1673 void dopass(char *password)
1674 {
1675 static unsigned int tapping;
1676 char *hd;
1677 #if !defined(MINIMAL) && defined(HAVE_GETGROUPS) && defined(DISPLAY_GROUPS)
1678 gid_t *groups = NULL;
1679 int ngroups;
1680 # if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
1681 int ngroups_max = NGROUPS_MAX; /* Use the compile time value */
1682 # else
1683 int ngroups_max = 1; /* use a sane default */
1684 # endif
1685 #endif
1686
1687 if (loggedin != 0) {
1688 if (guest != 0) {
1689 addreply_noformat(230, MSG_NO_PASSWORD_NEEDED);
1690 #ifdef LOG_ANON_EMAIL
1691 snprintf(account, sizeof account, "ftp: <%s> ", password);
1692 #endif
1693 } else {
1694 addreply_noformat(530, MSG_CANT_DO_TWICE);
1695 }
1696 return;
1697 }
1698 if (*account == 0) {
1699 addreply_noformat(530, MSG_WHOAREYOU);
1700 return;
1701 }
1702 if (strlen(password) >= MAX_PASSWORD_LEN) {
1703 addreply_noformat(530, MSG_LINE_TOO_LONG);
1704 return;
1705 }
1706 authresult = pw_check(account, password, &ctrlconn, &peer);
1707 pure_memzero(password, strlen(password));
1708 if (authresult.auth_ok != 1) {
1709 tapping++;
1710 randomsleep(tapping);
1711 addreply_noformat(530, MSG_AUTH_FAILED);
1712 doreply();
1713 if (tapping > MAX_PASSWD_TRIES) {
1714 logfile(LOG_ERR, MSG_AUTH_TOOMANY);
1715 _EXIT(EXIT_FAILURE);
1716 }
1717 logfile(LOG_WARNING, MSG_AUTH_FAILED_LOG, account);
1718 return;
1719 }
1720 if (authresult.uid < useruid) {
1721 logfile(LOG_WARNING, MSG_ACCOUNT_DISABLED " (uid < %lu)",
1722 account, (unsigned long) useruid);
1723 randomsleep(tapping);
1724 if (tapping >= MAX_PASSWD_TRIES) {
1725 addreply_noformat(530, MSG_AUTH_FAILED);
1726 doreply();
1727 _EXIT(EXIT_FAILURE);
1728 }
1729 addreply_noformat(530, MSG_NOTRUST);
1730 doreply();
1731 return;
1732 }
1733
1734 #ifdef PER_USER_LIMITS
1735 if (per_user_max > 0U && ftpwho_read_count(account) >= per_user_max) {
1736 addreply(421, MSG_PERUSER_MAX, (unsigned long) per_user_max);
1737 doreply();
1738 _EXIT(1);
1739 }
1740 #endif
1741
1742 /* Add username and primary group to the uid/gid cache */
1743 (void) getname(authresult.uid);
1744 (void) getgroup(authresult.gid);
1745
1746 if (
1747 #if defined(WITH_LDAP) || defined(WITH_MYSQL) || defined(WITH_PGSQL) || defined(WITH_PUREDB) || defined(WITH_EXTAUTH)
1748 doinitsupgroups(NULL, authresult.uid, authresult.gid) != 0
1749 #else
1750 doinitsupgroups(account, (uid_t) -1, authresult.gid) != 0
1751 #endif
1752 ) {
1753 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
1754 (void) 0;
1755 #else
1756 die(421, LOG_WARNING, MSG_NOTRUST);
1757 #endif
1758 }
1759
1760 /* handle /home/user/./public_html form */
1761 if ((root_directory = strdup(authresult.dir)) == NULL) {
1762 die_mem();
1763 }
1764 hd = strstr(root_directory, "/./");
1765 if (hd != NULL) {
1766 if (chrooted != 0) {
1767 die(421, LOG_DEBUG, MSG_CANT_DO_TWICE);
1768 }
1769 if (create_home_and_chdir(root_directory)) {
1770 die(421, LOG_ERR, MSG_NO_HOMEDIR);
1771 }
1772 *++hd = 0;
1773 hd++;
1774 if (chroot(root_directory) || chdir(hd)) {
1775 die(421, LOG_ERR, MSG_NO_HOMEDIR);
1776 }
1777 chrooted = 1;
1778 #ifdef RATIOS
1779 if (ratio_for_non_anon == 0) {
1780 ratio_upload = ratio_download = 0U;
1781 }
1782 if (check_trustedgroup(authresult.uid, authresult.gid) != 0) {
1783 dot_write_ok = dot_read_ok = 1;
1784 ratio_upload = ratio_download = 0U;
1785 keepallfiles = 0;
1786 }
1787 #endif
1788 } else {
1789 (void) free(root_directory);
1790 root_directory = (char *) "/";
1791 if (create_home_and_chdir(authresult.dir)) {
1792 die(421, LOG_ERR, MSG_NO_HOMEDIR);
1793 }
1794 }
1795 if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) {
1796 wd[0] = '/';
1797 wd[1] = 0;
1798 }
1799 #ifndef NON_ROOT_FTP
1800 if (setgid(authresult.gid) || setegid(authresult.gid)) {
1801 _EXIT(EXIT_FAILURE);
1802 }
1803 #endif
1804 if (check_trustedgroup(authresult.uid, authresult.gid) != 0) {
1805 userchroot = 0;
1806 dot_write_ok = dot_read_ok = 1;
1807 keepallfiles = 0;
1808 #ifdef RATIOS
1809 ratio_upload = ratio_download = 0U;
1810 #endif
1811 #ifdef QUOTAS
1812 user_quota_files = user_quota_size = ULONG_LONG_MAX;
1813 #endif
1814 }
1815 #ifdef QUOTAS
1816 if (hasquota() == 0) {
1817 userchroot = 1;
1818 }
1819 #endif
1820 if (loggedin == 0) {
1821 candownload = 1; /* real users can always download */
1822 }
1823 #ifdef THROTTLING
1824 if ((throttling == 2) || (guest != 0 && throttling == 1)) {
1825 addreply_noformat(0, MSG_BANDWIDTH_RESTRICTED);
1826 (void) nice(NICE_VALUE);
1827 } else {
1828 throttling_delay = throttling_bandwidth_dl =
1829 throttling_bandwidth_ul = 0UL;
1830 }
1831 #endif
1832 #if !defined(MINIMAL) && defined(HAVE_GETGROUPS) && defined(DISPLAY_GROUPS)
1833 # ifdef SAFE_GETGROUPS_0
1834 ngroups = getgroups(0, NULL);
1835 if (ngroups > ngroups_max) {
1836 ngroups_max = ngroups;
1837 }
1838 # elif defined(_SC_NGROUPS_MAX)
1839 /* get the run time value */
1840 ngroups = (int) sysconf(_SC_NGROUPS_MAX);
1841 if (ngroups > ngroups_max) {
1842 ngroups_max = ngroups;
1843 }
1844 # endif
1845 if ((groups = malloc(sizeof(GETGROUPS_T) * ngroups_max)) == NULL) {
1846 die_mem();
1847 }
1848 ngroups = getgroups(ngroups_max, groups);
1849 if (guest == 0 && ngroups > 0) {
1850 char reply[80 + MAX_USER_LENGTH];
1851 const char *q;
1852 size_t p;
1853
1854 if (SNCHECK(snprintf(reply, sizeof reply,
1855 MSG_USER_GROUP_ACCESS ": ", account),
1856 sizeof reply)) {
1857 _EXIT(EXIT_FAILURE);
1858 }
1859 p = strlen(reply);
1860 do {
1861 ngroups--;
1862 if ((ngroups != 0 && groups[ngroups] == groups[0]) ||
1863 (q = getgroup(groups[ngroups])) == NULL) {
1864 continue;
1865 }
1866 if (p + strlen(q) > 75) {
1867 reply[p] = 0;
1868 addreply(0, "%s", reply);
1869 *reply = 0;
1870 p = (size_t) 0U;
1871 }
1872 reply[p++] = ' ';
1873 while (*q != 0 && p < sizeof reply - (size_t) 1U) {
1874 reply[p++] = *q++;
1875 }
1876 } while (ngroups > 0);
1877 reply[p] = 0;
1878 addreply(0, "%s", reply);
1879 }
1880 free(groups);
1881 #endif
1882 if (guest == 0 && allowfxp == 1) {
1883 addreply_noformat(0, MSG_FXP_SUPPORT);
1884 }
1885 #ifdef RATIOS
1886 if (ratio_for_non_anon != 0 && ratio_upload > 0) {
1887 addreply(0, MSG_RATIO, ratio_upload, ratio_download);
1888 }
1889 #endif
1890 if (userchroot != 0 && chrooted == 0) {
1891 if (chdir(wd) || chroot(wd)) { /* should never fail */
1892 die(421, LOG_ERR, MSG_CHROOT_FAILED);
1893 }
1894 chrooted = 1;
1895 #ifdef RATIOS
1896 if (ratio_for_non_anon == 0) {
1897 ratio_upload = ratio_download = 0U;
1898 }
1899 #endif
1900 {
1901 const size_t rd_len = strlen(wd) + sizeof "/";
1902
1903 if ((root_directory = malloc(rd_len)) == NULL) {
1904 die_mem();
1905 }
1906 snprintf(root_directory, rd_len, "%s/", wd);
1907 }
1908 wd[0] = '/';
1909 wd[1] = 0;
1910 if (chdir(wd)) {
1911 _EXIT(EXIT_FAILURE);
1912 }
1913 addreply(230, MSG_CURRENT_RESTRICTED_DIR_IS, wd);
1914 } else {
1915 addreply(230, MSG_CURRENT_DIR_IS, wd);
1916 }
1917
1918 #ifndef NON_ROOT_FTP
1919 disablesignals();
1920 # ifndef WITHOUT_PRIVSEP
1921 if (setuid(authresult.uid) != 0 || seteuid(authresult.uid) != 0) {
1922 _EXIT(EXIT_FAILURE);
1923 }
1924 # else
1925 if (seteuid(authresult.uid) != 0) {
1926 _EXIT(EXIT_FAILURE);
1927 }
1928 # ifdef USE_CAPABILITIES
1929 drop_login_caps();
1930 # endif
1931 # endif
1932 enablesignals();
1933 #endif
1934 logfile(LOG_INFO, MSG_IS_NOW_LOGGED_IN, account);
1935 #ifdef FTPWHO
1936 if (shm_data_cur != NULL) {
1937 ftpwho_lock();
1938 strncpy(shm_data_cur->account, account,
1939 sizeof shm_data_cur->account - (size_t) 1U);
1940 shm_data_cur->account[sizeof shm_data_cur->account - 1U] = 0;
1941 ftpwho_unlock();
1942 state_needs_update = 1;
1943 }
1944 #endif
1945 loggedin = 1;
1946 if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) {
1947 wd[0] = '/';
1948 wd[1] = 0;
1949 }
1950 #ifndef MINIMAL
1951 dobanner(0);
1952 #endif
1953 #ifdef QUOTAS
1954 displayquota(NULL);
1955 #endif
1956 #ifdef WITH_BONJOUR
1957 refreshManager();
1958 #endif
1959 }
1960
docwd(const char * dir)1961 void docwd(const char *dir)
1962 {
1963 const char *where;
1964 char buffer[PATH_MAX + 256U];
1965
1966 if (loggedin == 0) {
1967 goto kaboom;
1968 }
1969 /*
1970 * secure and conformant tilde expansion routine. Need to be packaged in
1971 * a function so that it can be called in other commands and avoid
1972 * duplicate code in ls.c -frank.
1973 */
1974 where = dir;
1975 if (dir == NULL || *dir == 0) {
1976 dir = "~";
1977 }
1978 if (*dir == '~') {
1979 const struct passwd *pw;
1980
1981 if (dir[1] == 0) { /* cd ~ */
1982 strncpy(buffer, chrooted != 0 ? "/" : authresult.dir,
1983 sizeof buffer);
1984 buffer[sizeof buffer - (size_t) 1U] = 0;
1985 where = buffer;
1986 } else { /* cd ~user or cd ~user/ */
1987 char *bufpnt = buffer;
1988 size_t s = sizeof buffer;
1989 const char *dirscan = dir + 1;
1990
1991 while (*dirscan != 0 && *dirscan != '/') {
1992 if (--s <= 0) {
1993 goto kaboom; /* script kiddy's playing */
1994 }
1995 *bufpnt++ = *dirscan++;
1996 }
1997 *bufpnt = 0;
1998 if (*buffer == 0) { /* ~/... */
1999 snprintf(buffer, sizeof buffer, "%s%s",
2000 chrooted != 0 ? "/" : authresult.dir, dirscan);
2001 where = buffer;
2002 } else if (authresult.slow_tilde_expansion == 0) {
2003 if (chrooted != 0 || guest != 0 ||
2004 (pw = getpwnam(buffer)) == NULL || pw->pw_dir == NULL) {
2005 /* try with old where = dir */
2006 } else {
2007 snprintf(buffer, sizeof buffer, "%s%s", pw->pw_dir, dirscan);
2008 where = buffer;
2009 }
2010 }
2011 }
2012 }
2013 if (checknamesanity(where, dot_read_ok) != 0) {
2014 addreply(553, MSG_SANITY_FILE_FAILURE, where);
2015 return;
2016 }
2017 if (chdir(where) != 0) {
2018
2019 #ifdef WITH_DIRALIASES
2020 const int real_errno = errno;
2021 const char *where_alias;
2022
2023 if ((where_alias = lookup_alias(where)) == NULL ||
2024 chdir(where_alias) != 0) {
2025 errno = real_errno;
2026 } else {
2027 goto chdir_success;
2028 }
2029 #endif
2030
2031 if (SNCHECK(snprintf(buffer, sizeof buffer,
2032 MSG_CANT_CHANGE_DIR ": %s",
2033 dir, strerror(errno)), sizeof buffer)) {
2034 _EXIT(EXIT_FAILURE);
2035 }
2036 logfile(LOG_INFO, "%s", buffer);
2037 addreply(550, "%s", buffer);
2038
2039 #ifndef MINIMAL
2040 # ifndef NO_DIRSCAN_DELAY
2041 if (cwd_failures >= MAX_DIRSCAN_TRIES) {
2042 _EXIT(EXIT_FAILURE);
2043 }
2044 usleep2(cwd_failures * DIRSCAN_FAILURE_DELAY);
2045 cwd_failures++;
2046 # endif
2047 #endif
2048
2049 return;
2050 }
2051
2052 #ifdef WITH_DIRALIASES
2053 chdir_success:
2054 #endif
2055
2056 #ifndef MINIMAL
2057 cwd_failures = 0UL;
2058 dobanner(1);
2059 #endif
2060 if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) {
2061 if (*dir == '/') {
2062 if (SNCHECK(snprintf(wd, sizeof wd, "%s", dir), sizeof wd)) { /* already checked */
2063 _EXIT(EXIT_FAILURE);
2064 }
2065 } else {
2066 const size_t dir_len = strlen(dir);
2067 const size_t wd_len = strlen(wd);
2068 if (sizeof wd < dir_len + sizeof "/" - 1U + wd_len + 1U) {
2069 kaboom:
2070 die(421, LOG_ERR, MSG_PATH_TOO_LONG);
2071 }
2072 strcat(strcat(wd, "/"), dir); /* safe, see above */
2073 }
2074 }
2075 addreply(250, MSG_CURRENT_DIR_IS, wd);
2076 }
2077
zrand(void)2078 unsigned int zrand(void)
2079 {
2080 return (unsigned int) alt_arc4random();
2081 }
2082
keepalive(const int fd,int keep)2083 static void keepalive(const int fd, int keep)
2084 {
2085 #ifdef SO_KEEPALIVE
2086 {
2087 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &keep, sizeof keep);
2088 }
2089 #endif
2090 }
2091
2092 /* psvtype = 0: PASV */
2093 /* psvtype = 1: EPSV */
2094
dopasv(int psvtype)2095 void dopasv(int psvtype)
2096 {
2097 struct sockaddr_storage dataconn; /* my data connection endpoint */
2098 unsigned long a = 0U;
2099 unsigned int p;
2100 int on;
2101 unsigned int firstporttried;
2102
2103 if (loggedin == 0) {
2104 addreply_noformat(530, MSG_NOT_LOGGED_IN);
2105 return;
2106 }
2107 if (datafd != -1) { /* for buggy clients */
2108 (void) close(datafd);
2109 datafd = -1;
2110 }
2111 fourinsix(&ctrlconn);
2112 if (STORAGE_FAMILY(ctrlconn) == AF_INET6 && psvtype == 0) {
2113 addreply_noformat(425, MSG_CANT_PASV);
2114 return;
2115 }
2116 firstporttried = firstport + zrand() % (lastport - firstport + 1);
2117 p = firstporttried;
2118 datafd = socket(STORAGE_FAMILY(ctrlconn), SOCK_STREAM, IPPROTO_TCP);
2119 if (datafd == -1) {
2120 error(425, MSG_CANT_PASSIVE);
2121 return;
2122 }
2123 on = 1;
2124 if (setsockopt(datafd, SOL_SOCKET, SO_REUSEADDR,
2125 (char *) &on, sizeof on) < 0) {
2126 error(421, "setsockopt");
2127 return;
2128 }
2129 dataconn = ctrlconn;
2130 for (;;) {
2131 if (STORAGE_FAMILY(dataconn) == AF_INET6) {
2132 STORAGE_PORT6(dataconn) = htons(p);
2133 } else {
2134 STORAGE_PORT(dataconn) = htons(p);
2135 }
2136 if (bind(datafd, (struct sockaddr *) &dataconn,
2137 STORAGE_LEN(dataconn)) == 0) {
2138 break;
2139 }
2140 p--;
2141 if (p < firstport) {
2142 p = lastport;
2143 }
2144 if (p == firstporttried) {
2145 (void) close(datafd);
2146 datafd = -1;
2147 addreply_noformat(425, MSG_PORTS_BUSY);
2148 return;
2149 }
2150 }
2151 alarm(idletime);
2152 if (listen(datafd, DEFAULT_BACKLOG_DATA) < 0) {
2153 (void) close(datafd);
2154 datafd = -1;
2155 error(425, MSG_GETSOCKNAME_DATA);
2156 return;
2157 }
2158 switch (psvtype) {
2159 case 0:
2160 if (STORAGE_FAMILY(force_passive_ip) == 0) {
2161 a = ntohl(STORAGE_SIN_ADDR_CONST(dataconn));
2162 } else if (STORAGE_FAMILY(force_passive_ip) == AF_INET6) {
2163 (void) close(datafd);
2164 datafd = -1;
2165 addreply_noformat(425, MSG_NO_EPSV);
2166 return;
2167 } else if (STORAGE_FAMILY(force_passive_ip) == AF_INET) {
2168 a = ntohl(STORAGE_SIN_ADDR_CONST(force_passive_ip));
2169 } else {
2170 _EXIT(EXIT_FAILURE);
2171 }
2172
2173 /* According to RFC, any message can follow 227. But broken NAT gateways
2174 * and connection tracking code rely on this. So don't translate the following
2175 * messages */
2176
2177 addreply(227, "Entering Passive Mode (%lu,%lu,%lu,%lu,%u,%u)",
2178 (a >> 24) & 255UL, (a >> 16) & 255UL, (a >> 8) & 255UL, a & 255UL,
2179 (p >> 8) & 255, p & 255);
2180 break;
2181 case 1:
2182 addreply(229, "Extended Passive mode OK (|||%u|)", p);
2183 break;
2184 default:
2185 _EXIT(EXIT_FAILURE);
2186 }
2187 passive = 1;
2188 }
2189
doport(const char * arg)2190 void doport(const char *arg)
2191 {
2192 unsigned int a1, a2, a3, a4, p1, p2;
2193 struct sockaddr_storage a;
2194
2195 if (sscanf(arg, "%u,%u,%u,%u,%u,%u",
2196 &a1, &a2, &a3, &a4, &p1, &p2) != 6 ||
2197 a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255 ||
2198 p1 > 255 || p2 > 255 || (a1|a2|a3|a4) == 0 ||
2199 (p1 | p2) == 0) {
2200 addreply_noformat(501, MSG_SYNTAX_ERROR_IP);
2201 return;
2202 }
2203 memset(&a, 0, sizeof a);
2204 STORAGE_FAMILY(a) = AF_INET;
2205 STORAGE_SIN_ADDR(a) =
2206 htonl(((uint32_t) a1 << 24) | ((uint32_t) a2 << 16) |
2207 (a3 << 8) | a4);
2208 SET_STORAGE_LEN(a, sizeof(struct sockaddr_in));
2209 doport2(a, (p1 << 8) | p2);
2210 }
2211
2212 #ifdef WITHOUT_PRIVSEP
2213
doport3(const int protocol)2214 static int doport3(const int protocol)
2215 {
2216 struct sockaddr_storage dataconn; /* his endpoint */
2217
2218 # ifndef NON_ROOT_FTP
2219 static const in_port_t portlist[] = FTP_ACTIVE_SOURCE_PORTS;
2220 const in_port_t *portlistpnt = portlist;
2221 # else
2222 static const in_port_t portlist[] = { 0U };
2223 const in_port_t *portlistpnt = portlist;
2224 # endif
2225 int on;
2226
2227 # ifndef NON_ROOT_FTP
2228 disablesignals();
2229 seteuid((uid_t) 0);
2230 # endif
2231 if ((datafd = socket(protocol, SOCK_STREAM, IPPROTO_TCP)) == -1) {
2232 data_socket_error:
2233 # ifndef NON_ROOT_FTP
2234 if (seteuid(authresult.uid) != 0) {
2235 _EXIT(EXIT_FAILURE);
2236 }
2237 enablesignals();
2238 # endif
2239 (void) close(datafd);
2240 datafd = -1;
2241 error(425, MSG_CANT_CREATE_DATA_SOCKET);
2242
2243 return -1;
2244 }
2245 on = 1;
2246 # ifdef SO_REUSEPORT
2247 (void) setsockopt(datafd, SOL_SOCKET, SO_REUSEPORT,
2248 (char *) &on, sizeof on);
2249 # else
2250 (void) setsockopt(datafd, SOL_SOCKET, SO_REUSEADDR,
2251 (char *) &on, sizeof on);
2252 # endif
2253 memcpy(&dataconn, &ctrlconn, sizeof dataconn);
2254 for (;;) {
2255 if (STORAGE_FAMILY(dataconn) == AF_INET6) {
2256 STORAGE_PORT6(dataconn) = htons(*portlistpnt);
2257 } else {
2258 STORAGE_PORT(dataconn) = htons(*portlistpnt);
2259 }
2260 if (bind(datafd, (struct sockaddr *) &dataconn,
2261 STORAGE_LEN(dataconn)) == 0) {
2262 break;
2263 }
2264 # ifdef USE_ONLY_FIXED_DATA_PORT
2265 (void) sleep(1U);
2266 # else
2267 if (*portlistpnt == (in_port_t) 0U) {
2268 goto data_socket_error;
2269 }
2270 portlistpnt++;
2271 # endif
2272 }
2273 # ifndef NON_ROOT_FTP
2274 if (seteuid(authresult.uid) != 0) {
2275 _EXIT(EXIT_FAILURE);
2276 }
2277 enablesignals();
2278 # endif
2279
2280 return 0;
2281 }
2282
2283 #else
2284
2285 /* Privilege-separated version of doport3() */
2286
doport3(const int protocol)2287 static int doport3(const int protocol)
2288 {
2289 if ((datafd = privsep_bindresport(protocol, ctrlconn)) == -1) {
2290 error(425, MSG_CANT_CREATE_DATA_SOCKET);
2291
2292 return -1;
2293 }
2294 return 0;
2295 }
2296
2297 #endif
2298
doport2(struct sockaddr_storage a,unsigned int p)2299 void doport2(struct sockaddr_storage a, unsigned int p)
2300 {
2301 if (loggedin == 0) {
2302 addreply_noformat(530, MSG_NOT_LOGGED_IN);
2303 return;
2304 }
2305 if (epsv_all != 0) {
2306 addreply_noformat(501, MSG_ACTIVE_DISABLED);
2307 return;
2308 }
2309 if (datafd != -1) { /* for buggy clients saying PORT over and over */
2310 (void) close(datafd);
2311 datafd = -1;
2312 }
2313 if (p < 1024U) {
2314 addreply_noformat(501, MSG_BAD_PORT);
2315 return;
2316 }
2317 if (doport3(STORAGE_FAMILY(a) == AF_INET6 ? PF_INET6 : PF_INET) != 0) {
2318 return;
2319 }
2320 peerdataport = (in_port_t) p;
2321 if (addrcmp(&a, &peer) != 0) {
2322 char hbuf[NI_MAXHOST];
2323 char peerbuf[NI_MAXHOST];
2324
2325 if (getnameinfo((struct sockaddr *) &a, STORAGE_LEN(a),
2326 hbuf, sizeof hbuf, NULL,
2327 (size_t) 0U, NI_NUMERICHOST) != 0 ||
2328 getnameinfo((struct sockaddr *) &peer, STORAGE_LEN(peer),
2329 peerbuf, sizeof peerbuf, NULL,
2330 (size_t) 0U, NI_NUMERICHOST) != 0) {
2331 goto hu;
2332 }
2333 if (allowfxp == 0 || (allowfxp == 1 && guest != 0)) {
2334 hu:
2335 (void) close(datafd);
2336 datafd = -1;
2337 addreply(500, MSG_NO_FXP, hbuf, peerbuf);
2338 return;
2339 } else {
2340 addreply(0, MSG_FXP, peerbuf, hbuf);
2341 memcpy(&peer, &a, sizeof a);
2342 }
2343 }
2344 passive = 0;
2345
2346 addreply_noformat(200, MSG_PORT_SUCCESSFUL);
2347 return;
2348 }
2349
closedata(void)2350 void closedata(void)
2351 {
2352 volatile int tmp_xferfd = xferfd; /* do not simplify this... */
2353
2354 #ifdef WITH_TLS
2355 tls_close_session(&tls_data_cnx);
2356 tls_data_cnx = NULL;
2357 #endif
2358 xferfd = -1; /* ...it avoids a race */
2359 (void) close(tmp_xferfd);
2360 }
2361
opendata(void)2362 void opendata(void)
2363 {
2364 struct sockaddr_storage dataconn; /* his data connection endpoint */
2365 int fd;
2366 socklen_t socksize;
2367
2368 if (xferfd != -1) {
2369 closedata();
2370 }
2371 if (datafd == -1) {
2372 addreply_noformat(425, MSG_NO_DATA_CONN);
2373 return;
2374 }
2375 if (passive != 0) {
2376 struct pollfd pfds[2];
2377 struct pollfd *pfd;
2378 int pollret;
2379
2380 pfd = &pfds[0];
2381 pfd->fd = clientfd;
2382 pfd->events = POLLERR | POLLHUP;
2383 pfd->revents = 0;
2384
2385 pfd = &pfds[1];
2386 pfd->fd = datafd;
2387 pfd->events = POLLIN | POLLERR | POLLHUP;
2388 pfd->revents = 0;
2389
2390 alarm(idletime);
2391 for (;;) {
2392 pfds[0].revents = pfds[1].revents = 0;
2393 pollret = poll(pfds, sizeof pfds / sizeof pfds[0], idletime * 1000UL);
2394 if (pollret <= 0) {
2395 die(421, LOG_INFO, MSG_TIMEOUT_DATA, (unsigned long) idletime);
2396 }
2397 if ((pfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0 ||
2398 (pfds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
2399 die(221, LOG_INFO, MSG_LOGOUT);
2400 }
2401 if ((pfds[1].revents & POLLIN) == 0) {
2402 continue;
2403 }
2404 socksize = (socklen_t) sizeof(dataconn);
2405 memset(&dataconn, 0, sizeof dataconn);
2406 if ((fd = accept(datafd, (struct sockaddr *) &dataconn,
2407 &socksize)) == -1) {
2408 nope:
2409 (void) close(datafd);
2410 datafd = -1;
2411 error(421, MSG_ACCEPT_FAILED);
2412 return;
2413 }
2414 if (STORAGE_FAMILY(dataconn) != AF_INET
2415 && STORAGE_FAMILY(dataconn) != AF_INET6) {
2416 (void) close(fd);
2417 goto nope;
2418 }
2419 fourinsix(&dataconn);
2420 if (addrcmp(&peer, &dataconn) == 0) {
2421 break;
2422 }
2423 if (allowfxp == 0 || (allowfxp == 1 && guest != 0)) {
2424 shutdown(fd, 2);
2425 (void) close(fd);
2426 } else {
2427 break;
2428 }
2429 }
2430 addreply_noformat(150, MSG_ACCEPT_SUCCESS);
2431 } else {
2432 struct sockaddr_storage peer2;
2433 unsigned long tries = 1UL + idletime / 2UL;
2434
2435 peer2 = peer;
2436 if (STORAGE_FAMILY(peer) == AF_INET6) {
2437 STORAGE_PORT6(peer2) = htons(peerdataport);
2438 } else {
2439 STORAGE_PORT(peer2) = htons(peerdataport);
2440 }
2441 again:
2442 if (connect(datafd, (struct sockaddr *) &peer2,
2443 STORAGE_LEN(peer2)) != 0) {
2444 if ((errno == EAGAIN || errno == EINTR
2445 #ifdef EADDRINUSE
2446 || errno == EADDRINUSE
2447 #endif
2448 ) && tries > 0UL) {
2449 tries--;
2450 usleep2(1000000UL);
2451 goto again;
2452 }
2453 addreply(425, MSG_CNX_PORT_FAILED ": %s",
2454 peerdataport, strerror(errno));
2455 (void) close(datafd);
2456 datafd = -1;
2457 return;
2458 }
2459 fd = datafd;
2460 datafd = -1;
2461 addreply(150, MSG_CNX_PORT, peerdataport);
2462 }
2463
2464 {
2465 int fodder;
2466 #ifdef IPTOS_THROUGHPUT
2467 fodder = IPTOS_THROUGHPUT;
2468 setsockopt(fd, SOL_IP, IP_TOS, (char *) &fodder, sizeof fodder);
2469 #endif
2470 #ifndef NO_KEEPALIVE
2471 keepalive(fd, 1);
2472 #endif
2473 }
2474 xferfd = fd;
2475 alarm(MAX_SESSION_XFER_IDLE);
2476 }
2477
2478 #ifndef MINIMAL
dochmod(char * name,mode_t mode)2479 void dochmod(char *name, mode_t mode)
2480 {
2481 static dev_t root_st_dev;
2482 static ino_t root_st_ino;
2483 struct stat st2;
2484 int fd = -1;
2485
2486 if (nochmod != 0 && authresult.uid != (uid_t) 0) {
2487 addreply(550, MSG_CHMOD_FAILED, name);
2488 return;
2489 }
2490 # ifndef ANON_CAN_CHANGE_PERMS
2491 if (guest != 0) {
2492 addreply_noformat(550, MSG_ANON_CANT_CHANGE_PERMS);
2493 return;
2494 }
2495 # endif
2496 if (name == NULL || *name == 0) {
2497 addreply_noformat(501, MSG_NO_FILE_NAME);
2498 return;
2499 }
2500 if (checknamesanity(name, dot_write_ok) != 0) {
2501 addreply(553, MSG_SANITY_FILE_FAILURE, name);
2502 return;
2503 }
2504 fd = open(name, O_RDONLY);
2505 if (fd == -1) {
2506 goto failure;
2507 }
2508 if ((root_st_dev | root_st_ino) == 0) {
2509 struct stat st;
2510
2511 if (stat("/", &st) != 0) {
2512 goto failure;
2513 }
2514 root_st_dev = st.st_dev;
2515 root_st_ino = st.st_ino;
2516 }
2517 if (fstat(fd, &st2) != 0) {
2518 goto failure;
2519 }
2520 # ifdef QUOTAS
2521 if (hasquota() == 0 && S_ISDIR(st2.st_mode)) {
2522 mode |= 0500;
2523 }
2524 # endif
2525 if (st2.st_ino == root_st_ino && st2.st_dev == root_st_dev) {
2526 mode |= 0700;
2527 } else if (be_customer_proof != 0) {
2528 mode |= (S_ISDIR(st2.st_mode) ? 0700 : 0600);
2529 }
2530 if (fchmod(fd, mode) < 0 && chmod(name, mode) < 0) {
2531 failure:
2532 if (fd != -1) {
2533 (void) close(fd);
2534 }
2535 addreply(550, MSG_CHMOD_FAILED ": %s", name, strerror(errno));
2536 return;
2537 }
2538 (void) close(fd);
2539 addreply(200, MSG_CHMOD_SUCCESS, name);
2540 }
2541
doutime(char * name,const char * const wanted_time)2542 void doutime(char *name, const char * const wanted_time)
2543 {
2544 struct tm tm;
2545 time_t ts;
2546 struct utimbuf tb;
2547
2548 # ifndef ANON_CAN_CHANGE_UTIME
2549 if (guest != 0) {
2550 addreply_noformat(550, MSG_ANON_CANT_CHANGE_PERMS);
2551 return;
2552 }
2553 # endif
2554 if (name == NULL || *name == 0) {
2555 addreply_noformat(501, MSG_NO_FILE_NAME);
2556 return;
2557 }
2558 if (checknamesanity(name, dot_write_ok) != 0) {
2559 addreply(553, MSG_SANITY_FILE_FAILURE, name);
2560 return;
2561 }
2562 memset(&tm, 0, sizeof tm);
2563 sscanf(wanted_time, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon,
2564 &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
2565 tm.tm_mon--;
2566 tm.tm_year -= 1900;
2567 # ifdef USE_LOCAL_TIME_FOR_SITE_UTIME
2568 ts = mktime(&tm);
2569 # else
2570 # ifdef HAVE_TIMEGM
2571 ts = timegm(&tm);
2572 # elif defined(HAVE_PUTENV)
2573 {
2574 putenv("TZ=UTC+00:00");
2575 # ifdef HAVE_TZSET
2576 tzset();
2577 # endif
2578 ts = mktime(&tm);
2579 putenv(default_tz_for_putenv);
2580 tzset();
2581 }
2582 # else
2583 ts = mktime(&tm);
2584 # endif
2585 # endif
2586 if (tm.tm_mon < 0 || tm.tm_year <= 0 || ts == (time_t) -1) {
2587 addreply_noformat(501, MSG_TIMESTAMP_FAILURE);
2588 return;
2589 }
2590 tb.actime = tb.modtime = ts;
2591 if (utime(name, &tb) < 0) {
2592 addreply(550, "utime(%s): %s", name, strerror(errno));
2593 } else {
2594 addreply_noformat(213, "UTIME OK");
2595 }
2596 }
2597 #endif
2598
dodele(char * name)2599 void dodele(char *name)
2600 {
2601 #ifndef ANON_CAN_DELETE
2602 if (guest != 0) {
2603 addreply_noformat(550, MSG_ANON_CANT_DELETE);
2604 return;
2605 }
2606 #endif
2607 if (name == NULL || *name == 0) {
2608 addreply_noformat(501, MSG_NO_FILE_NAME);
2609 return;
2610 }
2611 if (checknamesanity(name, dot_write_ok) != 0) {
2612 addreply(553, MSG_SANITY_FILE_FAILURE, name);
2613 return;
2614 }
2615 if (keepallfiles != 0) {
2616 #ifdef EPERM
2617 errno = EPERM;
2618 #else
2619 errno = 1;
2620 #endif
2621 goto denied;
2622 }
2623
2624 /*
2625 * What we do here may look a bit strange. It's to defend against
2626 * change-after-stat attacks. If we simply do lstat(name), then unlink(name)
2627 * there's a race. An attacker can rename the file between these two
2628 * system calls, so that a big file is lstat()ed, but a dummy tiny file is
2629 * unlinked. That way, an attacker could easily get extra quota.
2630 * To defend against this attack, we rename the file to an unique dot-file
2631 * (an atomic operation) . People subject to quotas can't access dot-files.
2632 * So we can securely stat it and unlink it. Having the pid in the file
2633 * name should be enough to avoid that two concurrent sessions create the
2634 * same temporary file. But to be paranoid to the extreme, we add some
2635 * random number to that.
2636 */
2637
2638 #ifdef QUOTAS
2639 {
2640 char *p;
2641 struct stat st;
2642 struct stat st2;
2643 size_t dirlen = (size_t) 0U;
2644 char qtfile[PATH_MAX + 1];
2645
2646 if ((p = strrchr(name, '/')) != NULL) {
2647 if ((dirlen = p - name + (size_t) 1U) >= sizeof qtfile) {
2648 goto denied; /* should never happen */
2649 }
2650 memcpy(qtfile, name, dirlen); /* safe, dirlen < sizeof qtfile */
2651 }
2652 if (SNCHECK(snprintf(qtfile + dirlen, sizeof qtfile - dirlen,
2653 PUREFTPD_TMPFILE_PREFIX "rename.%lu.%x",
2654 (unsigned long) getpid(), zrand()),
2655 sizeof qtfile)) {
2656 goto denied;
2657 }
2658 if (lstat(name, &st) != 0) {
2659 goto denied;
2660 }
2661 if (!S_ISREG(st.st_mode)
2662 # ifndef NEVER_DELETE_SYMLINKS
2663 && !S_ISLNK(st.st_mode)
2664 # endif
2665 ) {
2666 # ifdef EINVAL
2667 errno = EINVAL;
2668 # endif
2669 goto denied;
2670 }
2671 if (rename(name, qtfile) != 0) {
2672 goto denied;
2673 }
2674 if (lstat(qtfile, &st2) != 0 ||
2675 st.st_dev != st2.st_dev ||
2676 st.st_ino != st2.st_ino ||
2677 st.st_size != st2.st_size) {
2678 # ifdef EINVAL
2679 errno = EINVAL;
2680 # endif
2681 goto denied;
2682 }
2683 if (unlink(qtfile) < 0) {
2684 /*
2685 * Race if rename() goes to an existing file.
2686 * seems very difficult to exploit, though.
2687 * Does a perfect userland answer exist, after all?
2688 */
2689 (void) rename(qtfile, name);
2690 goto denied;
2691 }
2692 {
2693 Quota quota;
2694
2695 if (quota_update("a, -1LL,
2696 -((long long) st.st_size), NULL) == 0) {
2697 displayquota("a);
2698 }
2699 }
2700 }
2701 #else
2702 if (unlink(name) < 0) {
2703 goto denied;
2704 }
2705 #endif
2706 addreply(250, MSG_DELE_SUCCESS, "", "", "", name);
2707 logfile(LOG_NOTICE, MSG_DELE_SUCCESS, root_directory,
2708 *name == '/' ? "" : wd,
2709 (*name != '/' && (!*wd || wd[strlen(wd) - 1] != '/'))
2710 ? "/" : "", name);
2711 return;
2712
2713 denied:
2714 addreply(550, MSG_DELE_FAILED ": %s", name, strerror(errno));
2715 }
2716
get_usec_time(void)2717 static double get_usec_time(void)
2718 {
2719 struct timeval tv;
2720 struct timezone tz;
2721
2722 if (gettimeofday(&tv, &tz) < 0) {
2723 return 0.0;
2724 }
2725 return (double) tv.tv_sec + ((double) tv.tv_usec) / 1000000.0;
2726 }
2727
displayrate(const char * word,off_t size,const double started,const char * const name,int up)2728 static void displayrate(const char *word, off_t size,
2729 const double started,
2730 const char * const name, int up)
2731 {
2732 double ended;
2733 double t;
2734 double speed;
2735 char speedstring[64];
2736
2737 ended = get_usec_time();
2738
2739 t = ended - started;
2740 if (t > 0.0 && size > (off_t) 0) {
2741 speed = size / t;
2742 } else {
2743 speed = 0.0;
2744 }
2745 if (speed > 524288.0) {
2746 addreply(0, MSG_TRANSFER_RATE_M, t, speed / 1048576.0);
2747 } else if (speed > 512.0) {
2748 addreply(0, MSG_TRANSFER_RATE_K, t, speed / 1024.0);
2749 } else if (speed > 0.1) {
2750 addreply(0, MSG_TRANSFER_RATE_B, t, speed);
2751 }
2752 if (!SNCHECK(snprintf(speedstring, sizeof speedstring,
2753 " (%llu bytes, %.2fKB/sec)",
2754 (unsigned long long) size, speed / 1024.0),
2755 sizeof speedstring)) {
2756 logfile(LOG_NOTICE, "%s%s%s%s %s %s", root_directory,
2757 *name == '/' ? "" : wd,
2758 (*name != '/' && (!*wd || wd[strlen(wd) - 1] != '/'))
2759 ? "/" : "", name, word, speedstring);
2760 }
2761 /* Tons of #ifdef here, but it avoids a pointless call to realpath() */
2762 #if defined(WITH_UPLOAD_SCRIPT) || defined(WITH_ALTLOG)
2763 if (
2764 # ifdef WITH_ALTLOG
2765 altlog_format != ALTLOG_NONE
2766 # endif
2767 # if defined(WITH_UPLOAD_SCRIPT) && defined(WITH_ALTLOG)
2768 ||
2769 # endif
2770 # if (defined(WITH_UPLOAD_SCRIPT))
2771 (do_upload_script != 0 && up != 0)
2772 # endif
2773 )
2774 {
2775 char *alloca_filename_real;
2776 const size_t sizeof_filename_real = PATH_MAX + VHOST_PREFIX_MAX_LEN;
2777 char *resolved_path;
2778 const size_t sizeof_resolved_path = PATH_MAX + 1U;
2779
2780 if ((resolved_path = malloc(sizeof_resolved_path)) == NULL) {
2781 return;
2782 }
2783 resolved_path[sizeof_resolved_path - 1U] = 0;
2784 if (realpath(name, resolved_path) == NULL) {
2785 if (up != 0) {
2786 (void) unlink(name);
2787 }
2788 free(resolved_path);
2789 logfile(LOG_ERR, "realpath() failure : [%s] => [%s]",
2790 name, strerror(errno));
2791 return;
2792 }
2793 if (resolved_path[sizeof_resolved_path - 1U] != 0) {
2794 for (;;) {
2795 *resolved_path++ = 0;
2796 }
2797 }
2798 if ((alloca_filename_real = ALLOCA(sizeof_filename_real)) == NULL) {
2799 free(resolved_path);
2800 return;
2801 }
2802 # ifdef WITH_VIRTUAL_CHROOT
2803 if (SNCHECK(snprintf(alloca_filename_real, sizeof_filename_real,
2804 "\001%s", resolved_path), sizeof_filename_real)) {
2805 goto rp_failure;
2806 }
2807 # else
2808 if (SNCHECK(snprintf(alloca_filename_real, sizeof_filename_real,
2809 "\001%s%s", root_directory,
2810 (*resolved_path == '/' ? resolved_path + 1 :
2811 resolved_path)), sizeof_filename_real)) {
2812 goto rp_failure;
2813 }
2814 # endif
2815 # ifdef WITH_ALTLOG
2816 (void) altlog_writexfer(up, alloca_filename_real + 1, size, t);
2817 # endif
2818 # if defined(WITH_UPLOAD_SCRIPT)
2819 if (do_upload_script != 0 && up != 0) {
2820 upload_pipe_push(account, alloca_filename_real);
2821 }
2822 # endif
2823 rp_failure:
2824 free(resolved_path);
2825 ALLOCA_FREE(alloca_filename_real);
2826 }
2827 #else
2828 (void) up;
2829 #endif
2830 }
2831
displayopenfailure(const char * const name)2832 static void displayopenfailure(const char * const name)
2833 {
2834 char buffer[PATH_MAX + 42U];
2835 const int e = errno;
2836
2837 if (SNCHECK(snprintf(buffer, sizeof buffer, MSG_OPEN_FAILURE, name),
2838 sizeof buffer)) {
2839 _EXIT(EXIT_FAILURE);
2840 }
2841 errno = e;
2842 error(550, buffer);
2843 }
2844
dlhandler_throttle(DLHandler * const dlhandler,const off_t downloaded,const double ts_start,double * required_sleep)2845 static int dlhandler_throttle(DLHandler * const dlhandler,
2846 const off_t downloaded, const double ts_start,
2847 double *required_sleep)
2848 {
2849 double ts_now;
2850 double elapsed;
2851 off_t would_be_downloaded;
2852 double wanted_ts;
2853 off_t previous_chunk_size;
2854
2855 if (dlhandler->bandwidth <= 0UL || downloaded <= (off_t) 0) {
2856 *required_sleep = 0.0;
2857 return 0;
2858 }
2859 if ((ts_now = get_usec_time()) <= 0.0) {
2860 ts_now = ts_start;
2861 }
2862 if (ts_start > ts_now) {
2863 ts_now = ts_start;
2864 }
2865 elapsed = ts_now - ts_start;
2866 would_be_downloaded = dlhandler->total_downloaded + dlhandler->chunk_size;
2867 if (dlhandler->bandwidth > 0UL) {
2868 wanted_ts = (double) would_be_downloaded /
2869 (double) dlhandler->bandwidth;
2870 } else {
2871 wanted_ts = elapsed;
2872 }
2873 *required_sleep = wanted_ts - elapsed;
2874 previous_chunk_size = dlhandler->chunk_size;
2875 if (dlhandler->total_downloaded <= dlhandler->chunk_size) {
2876 return 0;
2877 }
2878 if (*required_sleep < dlhandler->min_sleep) {
2879 dlhandler->chunk_size =
2880 (dlhandler->max_chunk_size + dlhandler->chunk_size) / 2;
2881 } else if (*required_sleep > dlhandler->max_sleep) {
2882 dlhandler->chunk_size =
2883 (dlhandler->min_chunk_size + dlhandler->chunk_size) / 2;
2884 } else {
2885 dlhandler->chunk_size = dlhandler->default_chunk_size;
2886 }
2887 if (dlhandler->chunk_size <= 0 || dlhandler->chunk_size > INT_MAX) {
2888 dlhandler->chunk_size = dlhandler->default_chunk_size;
2889 }
2890 if (previous_chunk_size != dlhandler->default_chunk_size) {
2891 would_be_downloaded =
2892 dlhandler->total_downloaded + dlhandler->chunk_size;
2893 if (dlhandler->bandwidth > 0UL) {
2894 wanted_ts = (double) would_be_downloaded /
2895 (double) dlhandler->bandwidth;
2896 } else {
2897 wanted_ts = elapsed;
2898 }
2899 *required_sleep = wanted_ts - elapsed;
2900 }
2901 return 0;
2902 }
2903
dlhandler_init(DLHandler * const dlhandler,const int clientfd,void * const tls_clientfd,const int xferfd,const char * const name,const int f,void * const tls_fd,const off_t restartat,const int ascii_mode,const unsigned long bandwidth)2904 static int dlhandler_init(DLHandler * const dlhandler,
2905 const int clientfd, void * const tls_clientfd,
2906 const int xferfd,
2907 const char * const name,
2908 const int f, void * const tls_fd,
2909 const off_t restartat,
2910 const int ascii_mode,
2911 const unsigned long bandwidth)
2912 {
2913 struct stat st;
2914 struct pollfd *pfd;
2915
2916 if (fstat(f, &st) < 0 || (S_ISLNK(st.st_mode) && stat(name, &st) < 0)) {
2917 error(451, MSG_STAT_FAILURE);
2918 return -1;
2919 }
2920 if (!S_ISREG(st.st_mode)) {
2921 addreply_noformat(550, MSG_NOT_REGULAR_FILE);
2922 return -1;
2923 }
2924 dlhandler->clientfd = clientfd;
2925 dlhandler->tls_clientfd = tls_clientfd;
2926 dlhandler->xferfd = xferfd;
2927 dlhandler->f = f;
2928 dlhandler->tls_fd = tls_fd;
2929 dlhandler->file_size = st.st_size;
2930 dlhandler->ascii_mode = ascii_mode;
2931 dlhandler->cur_pos = restartat;
2932 dlhandler->total_downloaded = (off_t) 0;
2933 dlhandler->min_sleep = 0.1;
2934 dlhandler->max_sleep = 5.0;
2935 dlhandler->bandwidth = bandwidth;
2936 pfd = &dlhandler->pfds_f_in;
2937 pfd->fd = clientfd;
2938 #ifdef __APPLE_CC__
2939 pfd->events = POLLRDBAND | POLLPRI | POLLERR | POLLHUP;
2940 #else
2941 pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP;
2942 #endif
2943 pfd->revents = 0;
2944
2945 if (restartat > (off_t) 0) {
2946 if (restartat == st.st_size) {
2947 addreply_noformat(226, MSG_NO_MORE_TO_DOWNLOAD);
2948 return -2;
2949 } else if (restartat > st.st_size) {
2950 addreply(554, MSG_REST_TOO_LARGE_FOR_FILE "\n" MSG_REST_RESET,
2951 (long long) restartat, (long long) st.st_size);
2952 return -1;
2953 }
2954 }
2955 if (fcntl(xferfd, F_SETFL, fcntl(xferfd, F_GETFL) | O_NONBLOCK) == -1) {
2956 error(451, "fcntl(F_SETFL, O_NONBLOCK)");
2957 return -1;
2958 }
2959 return 0;
2960 }
2961
dlmap_init(DLHandler * const dlhandler,const int clientfd,void * const tls_clientfd,const int xferfd,const char * const name,const int f,void * const tls_fd,const off_t restartat,const int ascii_mode,const unsigned long bandwidth)2962 static int dlmap_init(DLHandler * const dlhandler, const int clientfd,
2963 void * const tls_clientfd, const int xferfd,
2964 const char * const name, const int f,
2965 void * const tls_fd, const off_t restartat,
2966 const int ascii_mode, const unsigned long bandwidth)
2967 {
2968 if (ascii_mode > 0) {
2969 #ifdef WITHOUT_ASCII
2970 addreply_noformat(450, MSG_ASCII_MODE_UNSUPPORTED);
2971 return -1;
2972 #else
2973 addreply_noformat(0, MSG_ASCII_MODE_WARNING);
2974 #endif
2975 }
2976 if (dlhandler_init(dlhandler, clientfd, tls_clientfd, xferfd, name, f,
2977 tls_fd, restartat, ascii_mode, bandwidth) != 0) {
2978 return -1;
2979 }
2980 dlhandler->min_chunk_size = DL_MIN_CHUNK_SIZE;
2981 if (ascii_mode > 0) {
2982 dlhandler->default_chunk_size = dlhandler->max_chunk_size =
2983 DL_DEFAULT_CHUNK_SIZE_ASCII;
2984 } else {
2985 dlhandler->max_chunk_size = DL_MAX_CHUNK_SIZE;
2986 if (bandwidth <= 0UL) {
2987 dlhandler->default_chunk_size = dlhandler->max_chunk_size;
2988 } else {
2989 dlhandler->default_chunk_size = DL_DEFAULT_CHUNK_SIZE;
2990 }
2991 }
2992 dlhandler->chunk_size = dlhandler->default_chunk_size;
2993 dlhandler->dlmap_size =
2994 (DL_DLMAP_SIZE + page_size - (size_t) 1U) & ~(page_size - (size_t) 1U);
2995 dlhandler->cur_pos = restartat;
2996 dlhandler->dlmap_pos = (off_t) 0;
2997 dlhandler->dlmap_fdpos = (off_t) -1;
2998 dlhandler->sizeof_map = (size_t) 0U;
2999 dlhandler->map_data = NULL;
3000 dlhandler->sizeof_map = dlhandler->dlmap_size;
3001 dlhandler->map = malloc(dlhandler->sizeof_map);
3002 if (dlhandler->map == NULL) {
3003 die_mem();
3004 }
3005 return 0;
3006 }
3007
_dlmap_read(DLHandler * const dlhandler)3008 static int _dlmap_read(DLHandler * const dlhandler)
3009 {
3010 ssize_t readnb;
3011
3012 if (dlhandler->dlmap_size > dlhandler->sizeof_map) {
3013 abort();
3014 }
3015 if (dlhandler->dlmap_size <= (size_t) 0U) {
3016 return 0;
3017 }
3018 if (dlhandler->dlmap_pos != dlhandler->dlmap_fdpos) {
3019 do {
3020 if (lseek(dlhandler->f, dlhandler->dlmap_pos,
3021 SEEK_SET) == (off_t) -1) {
3022 dlhandler->dlmap_fdpos = (off_t) -1;
3023 return -1;
3024 }
3025 dlhandler->dlmap_fdpos = dlhandler->dlmap_pos;
3026 readnb = read(dlhandler->f, dlhandler->map, dlhandler->dlmap_size);
3027 } while (readnb == (ssize_t) -1 && errno == EINTR);
3028 } else {
3029 do {
3030 readnb = read(dlhandler->f, dlhandler->map, dlhandler->dlmap_size);
3031 } while (readnb == (ssize_t) -1 && errno == EINTR);
3032 }
3033 if (readnb <= (ssize_t) 0) {
3034 dlhandler->dlmap_fdpos = (off_t) -1;
3035 return -1;
3036 }
3037 if (readnb != (ssize_t) dlhandler->dlmap_size) {
3038 dlhandler->dlmap_fdpos = (off_t) -1;
3039 } else {
3040 dlhandler->dlmap_fdpos += (off_t) readnb;
3041 }
3042 return 0;
3043 }
3044
_dlmap_remap(DLHandler * const dlhandler)3045 static int _dlmap_remap(DLHandler * const dlhandler)
3046 {
3047 size_t min_dlmap_size;
3048 off_t remaining;
3049
3050 if (dlhandler->map_data != NULL) {
3051 if (dlhandler->cur_pos >= dlhandler->dlmap_pos &&
3052 dlhandler->cur_pos + dlhandler->chunk_size <=
3053 dlhandler->dlmap_pos + (off_t) dlhandler->dlmap_size) {
3054 if (dlhandler->cur_pos < dlhandler->dlmap_pos ||
3055 dlhandler->cur_pos - dlhandler->dlmap_pos >
3056 (off_t) dlhandler->dlmap_size) {
3057 addreply_noformat(451, "remap");
3058 return -1;
3059 }
3060 dlhandler->map_data =
3061 dlhandler->map + dlhandler->cur_pos - dlhandler->dlmap_pos;
3062 return 0;
3063 }
3064 }
3065 if (dlhandler->file_size - dlhandler->cur_pos < dlhandler->chunk_size) {
3066 dlhandler->chunk_size = dlhandler->file_size - dlhandler->cur_pos;
3067 }
3068 if (dlhandler->chunk_size <= 0) {
3069 return 1;
3070 }
3071 dlhandler->dlmap_pos = dlhandler->cur_pos;
3072 min_dlmap_size = dlhandler->chunk_size;
3073 if (dlhandler->dlmap_size < min_dlmap_size) {
3074 dlhandler->dlmap_size = min_dlmap_size;
3075 }
3076 dlhandler->dlmap_size = (dlhandler->dlmap_size + page_size - (size_t) 1U) &
3077 ~(page_size - (size_t) 1U);
3078 if (dlhandler->dlmap_size < page_size) {
3079 dlhandler->dlmap_size = page_size;
3080 }
3081 remaining = dlhandler->file_size - dlhandler->dlmap_pos;
3082 if ((off_t) dlhandler->dlmap_size > remaining) {
3083 dlhandler->dlmap_size = (off_t) remaining;
3084 }
3085 if (_dlmap_read(dlhandler) != 0) {
3086 error(451, MSG_DATA_READ_FAILED);
3087 return -1;
3088 }
3089 dlhandler->map_data = dlhandler->map;
3090
3091 return 0;
3092 }
3093
dl_dowrite(DLHandler * const dlhandler,const unsigned char * buf_,const size_t size_,off_t * const downloaded)3094 static int dl_dowrite(DLHandler * const dlhandler, const unsigned char *buf_,
3095 const size_t size_, off_t * const downloaded)
3096 {
3097 size_t size = size_;
3098 const unsigned char *buf = buf_;
3099 unsigned char *asciibuf = NULL;
3100 int ret = 0;
3101
3102 if (size_ <= (size_t) 0U) {
3103 *downloaded = 0;
3104 return -1;
3105 }
3106 #ifndef WITHOUT_ASCII
3107 if (dlhandler->ascii_mode > 0) {
3108 unsigned char *asciibufpnt;
3109 size_t z = (size_t) 0U;
3110
3111 if (size > (size_t) dlhandler->chunk_size ||
3112 (asciibuf = ALLOCA((size_t) dlhandler->chunk_size * 2U)) == NULL) {
3113 return -1;
3114 }
3115 asciibufpnt = asciibuf;
3116 do {
3117 if (buf_[z] == (unsigned char) '\n') {
3118 *asciibufpnt++ = (unsigned char) '\r';
3119 }
3120 *asciibufpnt++ = buf_[z];
3121 z++;
3122 } while (z < size);
3123 buf = asciibuf;
3124 size = (size_t) (asciibufpnt - asciibuf);
3125 }
3126 #endif
3127 ret = safe_nonblock_write(dlhandler->xferfd, dlhandler->tls_fd, buf, size);
3128 if (asciibuf != NULL) {
3129 ALLOCA_FREE(asciibuf);
3130 }
3131 if (ret < 0) {
3132 *downloaded = 0;
3133 } else {
3134 *downloaded = size;
3135 }
3136 return ret;
3137 }
3138
dlhandler_handle_commands(DLHandler * const dlhandler,const double required_sleep)3139 static int dlhandler_handle_commands(DLHandler * const dlhandler,
3140 const double required_sleep)
3141 {
3142 int pollret;
3143 char buf[100];
3144 char *bufpnt;
3145 ssize_t readnb;
3146
3147 repoll:
3148 dlhandler->pfds_f_in.revents = 0;
3149 pollret = poll(&dlhandler->pfds_f_in, 1U,
3150 required_sleep <= 0.0 ?
3151 0 : (int) (required_sleep * 1000.0));
3152 if (pollret <= 0) {
3153 return pollret;
3154 }
3155 if ((dlhandler->pfds_f_in.revents & (POLLIN | POLLPRI)) != 0) {
3156 if (dlhandler->tls_clientfd != NULL) {
3157 #ifdef WITH_TLS
3158 readnb = SSL_read(dlhandler->tls_clientfd, buf,
3159 sizeof buf - (size_t) 1U);
3160 #else
3161 abort();
3162 #endif
3163 } else {
3164 readnb = read(dlhandler->clientfd, buf, sizeof buf - (size_t) 1U);
3165 }
3166 if (readnb == (ssize_t) 0) {
3167 return -2;
3168 }
3169 if (readnb < (ssize_t) 0) {
3170 if (errno == EAGAIN || errno == EINTR) {
3171 return 0;
3172 }
3173 return -1;
3174 }
3175 buf[readnb] = 0;
3176 bufpnt = skip_telnet_controls(buf);
3177 if (strchr(bufpnt, '\n') != NULL) {
3178 if (strncasecmp(bufpnt, "ABOR", sizeof "ABOR" - 1U) != 0 &&
3179 strncasecmp(bufpnt, "QUIT", sizeof "QUIT" - 1U) != 0) {
3180 addreply_noformat(500, MSG_UNKNOWN_COMMAND);
3181 doreply();
3182 } else {
3183 addreply_noformat(426, "ABORT");
3184 doreply();
3185 addreply_noformat(226, MSG_ABORTED);
3186 return 1;
3187 }
3188 }
3189 if (required_sleep > 0.0) {
3190 goto repoll;
3191 }
3192 } else if ((dlhandler->pfds_f_in.revents &
3193 (POLLERR | POLLHUP | POLLNVAL)) != 0) {
3194 addreply_noformat(451, MSG_DATA_READ_FAILED);
3195 return 1;
3196 }
3197 return 0;
3198 }
3199
dlmap_send(DLHandler * const dlhandler)3200 static int dlmap_send(DLHandler * const dlhandler)
3201 {
3202 int ret;
3203 double ts_start = 0.0;
3204 double required_sleep;
3205 off_t downloaded;
3206
3207 if (dlhandler->bandwidth > 0UL && (ts_start = get_usec_time()) <= 0.0) {
3208 error(451, "gettimeofday()");
3209 return -1;
3210 }
3211 required_sleep = 0.0;
3212 for (;;) {
3213 ret = _dlmap_remap(dlhandler);
3214 if (ret < 0) {
3215 return -1;
3216 }
3217 if (ret == 1) {
3218 break;
3219 }
3220 if (dl_dowrite(dlhandler, dlhandler->map_data, dlhandler->chunk_size,
3221 &downloaded) != 0) {
3222 return -1;
3223 }
3224 dlhandler->cur_pos += dlhandler->chunk_size;
3225 #ifdef FTPWHO
3226 if (shm_data_cur != NULL) {
3227 shm_data_cur->download_current_size = dlhandler->cur_pos;
3228 }
3229 #endif
3230 dlhandler->total_downloaded += downloaded;
3231 required_sleep = 0.0;
3232 if (dlhandler->bandwidth > 0UL) {
3233 dlhandler_throttle(dlhandler, downloaded, ts_start,
3234 &required_sleep);
3235 }
3236 ret = dlhandler_handle_commands(dlhandler, required_sleep);
3237 if (ret != 0) {
3238 return ret;
3239 }
3240 }
3241 return 0;
3242 }
3243
dlmap_exit(DLHandler * const dlhandler)3244 static int dlmap_exit(DLHandler * const dlhandler)
3245 {
3246 if (dlhandler->map != NULL) {
3247 free(dlhandler->map);
3248 dlhandler->map = NULL;
3249 dlhandler->sizeof_map = (size_t) 0U;
3250 dlhandler->dlmap_size = (size_t) 0U;
3251 }
3252 return 0;
3253 }
3254
doretr(char * name)3255 void doretr(char *name)
3256 {
3257 DLHandler dlhandler;
3258 int f;
3259 struct stat st;
3260 double started = 0.0;
3261 int ret;
3262
3263 dlhandler.total_downloaded = 0;
3264 if (!candownload) {
3265 addreply(550, MSG_LOAD_TOO_HIGH, load);
3266 goto end;
3267 }
3268 if (type < 1 || (type == 1 && restartat > (off_t) 1)) {
3269 addreply_noformat(503, MSG_NO_ASCII_RESUME);
3270 goto end;
3271 }
3272 if (checknamesanity(name, dot_read_ok) != 0) {
3273 addreply(553, MSG_SANITY_FILE_FAILURE, name);
3274 goto end;
3275 }
3276 if ((f = open(name, O_RDONLY)) == -1) {
3277 displayopenfailure(name);
3278 goto end;
3279 }
3280 if (fstat(f, &st) < 0) {
3281 stat_failure:
3282 (void) close(f);
3283 error(451, MSG_STAT_FAILURE);
3284 goto end;
3285 }
3286 if (S_ISLNK(st.st_mode)) {
3287 if (stat(name, &st) < 0) {
3288 goto stat_failure;
3289 }
3290 }
3291 if (restartat > st.st_size) {
3292 (void) close(f);
3293 addreply(554, MSG_REST_TOO_LARGE_FOR_FILE "\n" MSG_REST_RESET,
3294 (long long) restartat, (long long) st.st_size);
3295 goto end;
3296 }
3297 if (!S_ISREG(st.st_mode) || ((off_t) st.st_size != st.st_size)) {
3298 (void) close(f);
3299 addreply_noformat(550, MSG_NOT_REGULAR_FILE);
3300 goto end;
3301 }
3302 if (warez != 0 && st.st_uid == warez && guest != 0) {
3303 (void) close(f);
3304 addreply(550, MSG_NOT_MODERATED);
3305 goto end;
3306 }
3307 #ifdef RATIOS
3308 if (ratio_upload > 0U && ratio_download > 0U) {
3309 if ((downloaded + st.st_size - restartat) / ratio_download >
3310 (uploaded / ratio_upload)) {
3311 (void) close(f);
3312 addreply(550, MSG_RATIO_DENIAL, ratio_upload, ratio_download,
3313 (unsigned long long) uploaded / 1024ULL,
3314 (unsigned long long) downloaded / 1024ULL);
3315 goto end;
3316 }
3317 }
3318 #endif
3319 opendata();
3320 if (xferfd == -1) {
3321 (void) close(f);
3322 goto end;
3323 }
3324 #ifndef DISABLE_HUMOR
3325 if ((time(NULL) % 100) == 0) {
3326 addreply_noformat(0, MSG_WINNER);
3327 }
3328 #endif
3329 if (st.st_size - restartat > 4096) {
3330 addreply(0, MSG_KBYTES_LEFT, (double) ((st.st_size - restartat) / 1024.0));
3331 }
3332 doreply();
3333 # ifdef WITH_TLS
3334 if (data_protection_level == CPL_PRIVATE) {
3335 tls_init_data_session(xferfd, passive);
3336 }
3337 # endif
3338 state_needs_update = 1;
3339 setprocessname("pure-ftpd (DOWNLOAD)");
3340
3341 #ifdef FTPWHO
3342 if (shm_data_cur != NULL) {
3343 const size_t sl = strlen(name);
3344
3345 ftpwho_lock();
3346 shm_data_cur->state = FTPWHO_STATE_DOWNLOAD;
3347 shm_data_cur->download_total_size = st.st_size;
3348 shm_data_cur->download_current_size = restartat;
3349 shm_data_cur->restartat = restartat;
3350 (void) time(&shm_data_cur->xfer_date);
3351 if (sl < sizeof shm_data_cur->filename) {
3352 memcpy(shm_data_cur->filename, name, sl);
3353 shm_data_cur->filename[sl] = 0;
3354 } else {
3355 memcpy(shm_data_cur->filename,
3356 &name[sl - sizeof shm_data_cur->filename - 1U],
3357 sizeof shm_data_cur->filename);
3358 }
3359 ftpwho_unlock();
3360 }
3361 #endif
3362 #ifdef HAVE_POSIX_FADVISE
3363 (void) posix_fadvise(f, (off_t) 0, st.st_size, POSIX_FADV_SEQUENTIAL);
3364 #endif
3365
3366 started = get_usec_time();
3367
3368 if (dlmap_init(&dlhandler, clientfd, tls_cnx, xferfd, name, f,
3369 tls_data_cnx, restartat, type == 1,
3370 throttling_bandwidth_dl) == 0) {
3371 ret = dlmap_send(&dlhandler);
3372 dlmap_exit(&dlhandler);
3373 } else {
3374 ret = -1;
3375 }
3376
3377 (void) close(f);
3378 closedata();
3379 if (ret == 0) {
3380 addreply_noformat(226, MSG_TRANSFER_SUCCESSFUL);
3381 }
3382 downloaded += dlhandler.total_downloaded;
3383 displayrate(MSG_DOWNLOADED, dlhandler.total_downloaded, started, name, 0);
3384
3385 end:
3386 restartat = (off_t) 0;
3387 }
3388
dorest(const char * name)3389 void dorest(const char *name)
3390 {
3391 char *endptr;
3392
3393 restartat = (off_t) strtoull(name, &endptr, 10);
3394 if (*endptr != 0 || restartat < (off_t) 0) {
3395 restartat = 0;
3396 addreply(554, MSG_REST_NOT_NUMERIC "\n" MSG_REST_RESET);
3397 } else {
3398 if (type == 1 && restartat != 0) {
3399 #ifdef STRICT_REST
3400 addreply_noformat(504, MSG_REST_ASCII_STRICT);
3401 #else
3402 addreply(350, MSG_REST_ASCII_WORKAROUND,
3403 (long long) restartat);
3404 #endif
3405 } else {
3406 if (restartat != 0) {
3407 logfile(LOG_NOTICE, MSG_REST_SUCCESS, (long long) restartat);
3408 }
3409 addreply(350, MSG_REST_SUCCESS, (long long) restartat);
3410 }
3411 }
3412 }
3413
domkd(char * name)3414 void domkd(char *name)
3415 {
3416 #ifdef QUOTAS
3417 Quota quota;
3418 int overflow;
3419 #endif
3420
3421 if (guest != 0 && allow_anon_mkdir == 0) {
3422 addreply_noformat(550, MSG_ANON_CANT_MKD);
3423 return;
3424 }
3425 if (checknamesanity(name, dot_write_ok) != 0) {
3426 addreply_noformat(553, MSG_SANITY_DIRECTORY_FAILURE);
3427 return;
3428 }
3429 #ifdef QUOTAS
3430 if (quota_update("a, 1LL, 0LL, &overflow) == 0 && overflow != 0) {
3431 (void) quota_update("a, -1LL, 0LL, NULL);
3432 addreply(552, MSG_QUOTA_EXCEEDED, name);
3433 goto end;
3434 }
3435 #endif
3436 if ((mkdir(name, (mode_t) (0777 & ~u_mask_d))) < 0) {
3437 #ifdef QUOTAS
3438 (void) quota_update("a, -1LL, 0LL, NULL);
3439 #endif
3440 error(550, MSG_MKD_FAILURE);
3441 } else {
3442 addreply(257, "\"%s\" : " MSG_MKD_SUCCESS, name);
3443 #ifndef MINIMAL
3444 cwd_failures = 0UL;
3445 #endif
3446 }
3447 #ifdef QUOTAS
3448 end:
3449 displayquota("a);
3450 #endif
3451 }
3452
dormd(char * name)3453 void dormd(char *name)
3454 {
3455 #ifdef QUOTAS
3456 Quota quota;
3457 #endif
3458
3459 #ifndef ANON_CAN_DELETE
3460 if (guest != 0) {
3461 addreply_noformat(550, MSG_ANON_CANT_RMD);
3462 return;
3463 }
3464 #endif
3465 if (checknamesanity(name, dot_write_ok) != 0) {
3466 addreply_noformat(553, MSG_SANITY_DIRECTORY_FAILURE);
3467 return;
3468 }
3469 if ((rmdir(name)) < 0) {
3470 error(550, MSG_RMD_FAILURE);
3471 } else {
3472 #ifdef QUOTAS
3473 if (quota_update("a, -1LL, 0LL, NULL) == 0) {
3474 displayquota("a);
3475 }
3476 #endif
3477 addreply_noformat(250, MSG_RMD_SUCCESS);
3478 }
3479 }
3480
3481 #ifndef MINIMAL
dofeat(void)3482 void dofeat(void)
3483 {
3484 # define FEAT "Extensions supported:" CRLF \
3485 " UTF8" CRLF \
3486 " EPRT" CRLF " IDLE" CRLF " MDTM" CRLF " SIZE" CRLF " MFMT" CRLF \
3487 " REST STREAM" CRLF \
3488 " MLST type*;size*;sizd*;modify*;UNIX.mode*;UNIX.uid*;UNIX.gid*;unique*;" CRLF \
3489 " MLSD" CRLF \
3490 " PRET"
3491
3492 # ifdef WITH_TLS
3493 # define FEAT_TLS CRLF " AUTH TLS" CRLF " PBSZ" CRLF " PROT"
3494 # else
3495 # define FEAT_TLS ""
3496 # endif
3497 # ifdef DEBUG
3498 # define FEAT_DEBUG CRLF " XDBG"
3499 # else
3500 # define FEAT_DEBUG ""
3501 # endif
3502 # ifdef WITH_VIRTUAL_CHROOT
3503 # define FEAT_TVFS ""
3504 # else
3505 # define FEAT_TVFS CRLF " TVFS"
3506 # endif
3507 # define FEAT_PASV CRLF " PASV" CRLF " EPSV"
3508
3509 # ifdef MINIMAL
3510 # define FEAT_ESTA ""
3511 # define FEAT_ESTP ""
3512 # else
3513 # define FEAT_ESTA CRLF " ESTA"
3514 # define FEAT_ESTP CRLF " ESTP"
3515 # endif
3516
3517 char feat[] = FEAT FEAT_DEBUG FEAT_TLS FEAT_TVFS FEAT_ESTA FEAT_PASV FEAT_ESTP;
3518
3519 if (disallow_passive != 0) {
3520 feat[sizeof FEAT FEAT_DEBUG FEAT_TLS FEAT_TVFS FEAT_ESTA - 1U] = 0;
3521 }
3522 # ifndef MINIMAL
3523 else if (STORAGE_FAMILY(force_passive_ip) != 0) {
3524 feat[sizeof FEAT FEAT_DEBUG FEAT_TLS FEAT_TVFS FEAT_ESTA FEAT_PASV - 1U] = 0;
3525 }
3526 # endif
3527 addreply_noformat(0, feat);
3528 addreply_noformat(211, "End.");
3529 }
3530 #endif
3531
3532 #ifndef MINIMAL
dostou(void)3533 void dostou(void)
3534 {
3535 char file[64];
3536 static unsigned int seq = 0U;
3537 struct timeval tv;
3538 struct timezone tz;
3539
3540 if (gettimeofday(&tv, &tz) != 0) {
3541 error(553, MSG_TIMESTAMP_FAILURE);
3542 return;
3543 }
3544 if (SNCHECK(snprintf(file, sizeof file, "pureftpd.%08lx.%02lx.%04x",
3545 (unsigned long) tv.tv_sec,
3546 (unsigned long) tv.tv_usec & 0xff,
3547 seq), sizeof file)) {
3548 _EXIT(EXIT_FAILURE);
3549 }
3550 seq++;
3551 seq &= 0xffff;
3552 addreply(150, "FILE: %s", file);
3553 dostor(file, 0, 1);
3554 }
3555 #endif
3556
tryautorename(const char * const atomic_file,char * const name,const char ** const name2_)3557 static int tryautorename(const char * const atomic_file, char * const name,
3558 const char ** const name2_)
3559 {
3560 static char name2[PATH_MAX];
3561 unsigned int gc = 0U;
3562
3563 if (link(atomic_file, name) == 0) {
3564 *name2_ = NULL;
3565 (void) unlink(atomic_file);
3566 return 0;
3567 }
3568 *name2_ = name2;
3569 for (;;) {
3570 gc++;
3571 if (gc == 0U ||
3572 #ifdef AUTORENAME_REVERSE_ORDER
3573 SNCHECK(snprintf(name2, sizeof name2, "%u.%s", gc, name),
3574 sizeof name2)
3575 #else
3576 SNCHECK(snprintf(name2, sizeof name2, "%s.%u", name, gc),
3577 sizeof name2)
3578 #endif
3579 ) {
3580 break;
3581 }
3582 if (link(atomic_file, name2) == 0) {
3583 (void) unlink(atomic_file);
3584 return 0;
3585 }
3586 switch (errno) {
3587 #ifdef EEXIST
3588 case EEXIST:
3589 #endif
3590 #ifdef EISDIR
3591 case EISDIR:
3592 #endif
3593 #ifdef ETXTBSY
3594 case ETXTBSY:
3595 #endif
3596 continue;
3597 }
3598 break;
3599 }
3600 *name2_ = NULL;
3601
3602 return -1;
3603 }
3604
get_atomic_file(const char * const file)3605 static char *get_atomic_file(const char * const file)
3606 {
3607 static char res[PATH_MAX];
3608 char *z;
3609 size_t orig_len;
3610 size_t slash;
3611 size_t sizeof_atomic_prefix;
3612
3613 if (file == NULL) {
3614 return res;
3615 }
3616 if ((z = strrchr(file, '/')) == NULL) {
3617 *res = 0;
3618 orig_len = (size_t) 0U;
3619 } else {
3620 slash = (size_t) (z - file);
3621 if (slash >= (sizeof res - (size_t) 1U)) {
3622 return NULL;
3623 }
3624 slash++;
3625 if (file[slash] == 0) {
3626 return NULL;
3627 }
3628 strncpy(res, file, slash);
3629 res[slash] = 0;
3630 orig_len = strlen(res);
3631 }
3632 sizeof_atomic_prefix = strlen(atomic_prefix) + (size_t) 1U;
3633 if (sizeof res - orig_len < sizeof_atomic_prefix) {
3634 return NULL;
3635 }
3636 memcpy(res + orig_len, atomic_prefix, sizeof_atomic_prefix);
3637
3638 return res;
3639 }
3640
delete_atomic_file(void)3641 void delete_atomic_file(void)
3642 {
3643 const char *atomic_file;
3644
3645 if ((atomic_file = get_atomic_file(NULL)) == NULL || *atomic_file == 0) {
3646 return;
3647 }
3648 (void) unlink(atomic_file);
3649 atomic_file = NULL;
3650 }
3651
get_file_size(const char * const file)3652 static off_t get_file_size(const char * const file)
3653 {
3654 struct stat st;
3655
3656 if (stat(file, &st) != 0) {
3657 return (off_t) -1;
3658 }
3659 return st.st_size;
3660 }
3661
3662 #ifdef QUOTAS
ul_quota_update(const char * const file_name,const int files_count,const off_t bytes)3663 static int ul_quota_update(const char * const file_name,
3664 const int files_count, const off_t bytes)
3665 {
3666 Quota quota;
3667 off_t file_size = (off_t) -1;
3668 int overflow;
3669 int ret = 0;
3670
3671 if (files_count == 0 && bytes == (off_t) 0) {
3672 return 0;
3673 }
3674 if (quota_update("a, files_count, (long long) bytes, &overflow) != 0) {
3675 return 0;
3676 }
3677 if (overflow != 0) {
3678 ret = 1;
3679 if (file_name != NULL) {
3680 file_size = get_file_size(file_name);
3681 }
3682 if (file_size >= (off_t) 0 && unlink(file_name) == 0) {
3683 (void) quota_update("a, -1, (long long) -file_size, NULL);
3684 }
3685 }
3686 displayquota("a);
3687
3688 return ret;
3689 }
3690 #endif
3691
ulhandler_throttle(ULHandler * const ulhandler,const off_t uploaded,const double ts_start,double * required_sleep)3692 static int ulhandler_throttle(ULHandler * const ulhandler,
3693 const off_t uploaded, const double ts_start,
3694 double *required_sleep)
3695 {
3696 double ts_now;
3697 double elapsed;
3698 off_t would_be_uploaded;
3699 double wanted_ts;
3700 off_t previous_chunk_size;
3701
3702 (void) uploaded;
3703 if (ulhandler->bandwidth <= 0UL) {
3704 *required_sleep = 0.0;
3705 return 0;
3706 }
3707 if ((ts_now = get_usec_time()) <= 0.0) {
3708 ts_now = ts_start;
3709 }
3710 if (ts_start > ts_now) {
3711 ts_now = ts_start;
3712 }
3713 elapsed = ts_now - ts_start;
3714 would_be_uploaded = ulhandler->total_uploaded + ulhandler->chunk_size;
3715 if (ulhandler->bandwidth > 0UL) {
3716 wanted_ts = (double) would_be_uploaded / (double) ulhandler->bandwidth;
3717 } else {
3718 wanted_ts = elapsed;
3719 }
3720 *required_sleep = wanted_ts - elapsed;
3721 previous_chunk_size = ulhandler->chunk_size;
3722 if (ulhandler->total_uploaded > ulhandler->chunk_size) {
3723 if (*required_sleep < ulhandler->min_sleep) {
3724 ulhandler->chunk_size =
3725 (ulhandler->max_chunk_size + ulhandler->chunk_size) / 2;
3726 } else if (*required_sleep > ulhandler->max_sleep) {
3727 ulhandler->chunk_size =
3728 (ulhandler->min_chunk_size + ulhandler->chunk_size) / 2;
3729 } else {
3730 ulhandler->chunk_size = ulhandler->default_chunk_size;
3731 }
3732 if (ulhandler->chunk_size <= 0 ||
3733 ulhandler->chunk_size > (off_t) ulhandler->sizeof_buf) {
3734 ulhandler->chunk_size = ulhandler->default_chunk_size;
3735 }
3736 if (previous_chunk_size != ulhandler->default_chunk_size) {
3737 would_be_uploaded =
3738 ulhandler->total_uploaded + ulhandler->chunk_size;
3739 if (ulhandler->bandwidth > 0UL) {
3740 wanted_ts = (double) would_be_uploaded /
3741 (double) ulhandler->bandwidth;
3742 } else {
3743 wanted_ts = elapsed;
3744 }
3745 *required_sleep = wanted_ts - elapsed;
3746 }
3747 }
3748 return 0;
3749 }
3750
ul_init(ULHandler * const ulhandler,const int clientfd,void * const tls_clientfd,const int xferfd,const char * const name,const int f,void * const tls_fd,const off_t restartat,const int ascii_mode,const unsigned long bandwidth,const off_t max_filesize)3751 static int ul_init(ULHandler * const ulhandler, const int clientfd,
3752 void * const tls_clientfd, const int xferfd,
3753 const char * const name, const int f, void * const tls_fd,
3754 const off_t restartat, const int ascii_mode,
3755 const unsigned long bandwidth, const off_t max_filesize)
3756 {
3757 struct pollfd *pfd;
3758
3759 (void) name;
3760 if (ascii_mode > 0) {
3761 #ifdef WITHOUT_ASCII
3762 addreply_noformat(450, MSG_ASCII_MODE_UNSUPPORTED);
3763 return -1;
3764 #else
3765 addreply_noformat(0, MSG_ASCII_MODE_WARNING);
3766 #endif
3767 }
3768 if (fcntl(xferfd, F_SETFL, fcntl(xferfd, F_GETFL) | O_NONBLOCK) == -1) {
3769 error(451, "fcntl(F_SETFL, O_NONBLOCK)");
3770 return -1;
3771 }
3772 ulhandler->buf = NULL;
3773 ulhandler->sizeof_buf = (size_t) 0UL;
3774 ulhandler->clientfd = clientfd;
3775 ulhandler->tls_clientfd = tls_clientfd;
3776 ulhandler->xferfd = xferfd;
3777 ulhandler->f = f;
3778 ulhandler->tls_fd = tls_fd;
3779 ulhandler->ascii_mode = ascii_mode;
3780 ulhandler->cur_pos = restartat;
3781 ulhandler->total_uploaded = (off_t) 0;
3782 ulhandler->min_sleep = 0.1;
3783 ulhandler->max_sleep = 5.0;
3784 ulhandler->bandwidth = bandwidth;
3785 ulhandler->max_filesize = max_filesize;
3786 ulhandler->idletime = idletime;
3787 pfd = &ulhandler->pfds[PFD_DATA];
3788 pfd->fd = xferfd;
3789 pfd->events = POLLIN | POLLERR | POLLHUP;
3790 pfd->revents = 0;
3791 pfd = &ulhandler->pfds[PFD_COMMANDS];
3792 pfd->fd = clientfd;
3793 #ifdef __APPLE_CC__
3794 pfd->events = POLLRDBAND | POLLPRI | POLLERR | POLLHUP;
3795 #else
3796 pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP;
3797 #endif
3798 pfd->revents = 0;
3799 pfd = &ulhandler->pfds_command;
3800 pfd->fd = clientfd;
3801 #ifdef __APPLE_CC__
3802 pfd->events = POLLRDBAND | POLLPRI | POLLERR | POLLHUP;
3803 #else
3804 pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP;
3805 #endif
3806 pfd->revents = 0;
3807 ulhandler->min_chunk_size = UL_MIN_CHUNK_SIZE;
3808 if (ascii_mode > 0) {
3809 ulhandler->default_chunk_size = ulhandler->max_chunk_size =
3810 UL_DEFAULT_CHUNK_SIZE_ASCII;
3811 } else {
3812 ulhandler->max_chunk_size = UL_MAX_CHUNK_SIZE;
3813 if (bandwidth <= 0UL) {
3814 ulhandler->default_chunk_size = ulhandler->max_chunk_size;
3815 } else {
3816 ulhandler->default_chunk_size = UL_DEFAULT_CHUNK_SIZE;
3817 }
3818 }
3819 ulhandler->chunk_size = ulhandler->default_chunk_size;
3820 ulhandler->cur_pos = restartat;
3821 ulhandler->sizeof_buf = ulhandler->max_chunk_size;
3822 if ((ulhandler->buf = malloc(ulhandler->sizeof_buf)) == NULL) {
3823 ulhandler->buf = NULL;
3824 ulhandler->sizeof_buf = (size_t) 0U;
3825 return -1;
3826 }
3827 return 0;
3828 }
3829
ul_dowrite(ULHandler * const ulhandler,const unsigned char * buf_,const size_t size_,off_t * const uploaded)3830 static int ul_dowrite(ULHandler * const ulhandler, const unsigned char *buf_,
3831 const size_t size_, off_t * const uploaded)
3832 {
3833 size_t size = size_;
3834 ssize_t written;
3835 const unsigned char *buf = buf_;
3836 unsigned char *unasciibuf = NULL;
3837 int ret = 0;
3838
3839 if (size_ <= (size_t) 0U) {
3840 *uploaded = 0;
3841 return -1;
3842 }
3843 #ifndef WITHOUT_ASCII
3844 if (ulhandler->ascii_mode > 0) {
3845 unsigned char *unasciibufpnt;
3846 size_t z = (size_t) 0U;
3847
3848 if (size > (size_t) ulhandler->chunk_size ||
3849 (unasciibuf = ALLOCA((size_t) ulhandler->chunk_size)) == NULL) {
3850 return -1;
3851 }
3852 unasciibufpnt = unasciibuf;
3853 do {
3854 if (buf_[z] != (unsigned char) '\r') {
3855 *unasciibufpnt++ = buf_[z];
3856 }
3857 z++;
3858 } while (z < size);
3859 buf = unasciibuf;
3860 size = (size_t) (unasciibufpnt - unasciibuf);
3861 }
3862 #endif
3863 written = safe_write(ulhandler->f, buf, size, -1);
3864 ret = - (written != (ssize_t) size);
3865 if (unasciibuf != NULL) {
3866 ALLOCA_FREE(unasciibuf);
3867 }
3868 if (ret < 0) {
3869 *uploaded = 0;
3870 } else {
3871 *uploaded = size;
3872 }
3873 return ret;
3874 }
3875
ulhandler_handle_commands(ULHandler * const ulhandler)3876 static int ulhandler_handle_commands(ULHandler * const ulhandler)
3877 {
3878 char buf[100];
3879 char *bufpnt;
3880 ssize_t readnb;
3881
3882 if (ulhandler->tls_clientfd != NULL) {
3883 #ifdef WITH_TLS
3884 readnb = SSL_read(ulhandler->tls_clientfd, buf,
3885 sizeof buf - (size_t) 1U);
3886 #else
3887 abort();
3888 #endif
3889 } else {
3890 readnb = read(ulhandler->clientfd, buf, sizeof buf - (size_t) 1U);
3891 }
3892 if (readnb == (ssize_t) 0) {
3893 return -2;
3894 }
3895 if (readnb < (ssize_t) 0) {
3896 if (errno == EAGAIN || errno == EINTR) {
3897 return 0;
3898 }
3899 return -1;
3900 }
3901 buf[readnb] = 0;
3902 bufpnt = skip_telnet_controls(buf);
3903 if (strchr(buf, '\n') != NULL) {
3904 if (strncasecmp(bufpnt, "ABOR", sizeof "ABOR" - 1U) != 0 &&
3905 strncasecmp(bufpnt, "QUIT", sizeof "QUIT" - 1U) != 0) {
3906 addreply_noformat(500, MSG_UNKNOWN_COMMAND);
3907 doreply();
3908 } else {
3909 addreply_noformat(426, MSG_ABORTED);
3910 doreply();
3911 return 1;
3912 }
3913 }
3914 return 0;
3915 }
3916
ul_handle_data(ULHandler * const ulhandler,off_t * const uploaded,const double ts_start)3917 static int ul_handle_data(ULHandler * const ulhandler, off_t * const uploaded,
3918 const double ts_start)
3919 {
3920 ssize_t readnb;
3921 double required_sleep = 0.0;
3922 int pollret;
3923 int ret;
3924
3925 if (ulhandler->max_filesize >= (off_t) 0 &&
3926 ulhandler->total_uploaded > ulhandler->max_filesize) {
3927 addreply(552, MSG_ABORTED " (quota)");
3928 return -2;
3929 }
3930 if (ulhandler->chunk_size > (off_t) ulhandler->sizeof_buf) {
3931 ulhandler->chunk_size = ulhandler->max_chunk_size =
3932 ulhandler->sizeof_buf;
3933 }
3934 if (ulhandler->tls_fd != NULL) {
3935 #ifdef WITH_TLS
3936 readnb = SSL_read(ulhandler->tls_fd, ulhandler->buf,
3937 ulhandler->chunk_size);
3938 #else
3939 abort();
3940 #endif
3941 } else {
3942 readnb = read(ulhandler->xferfd, ulhandler->buf,
3943 ulhandler->chunk_size);
3944 }
3945 if (readnb == (ssize_t) 0) {
3946 return 2;
3947 }
3948 if (readnb < (ssize_t) 0) {
3949 if (errno == EAGAIN || errno == EINTR) {
3950 return 0;
3951 }
3952 addreply_noformat(451, MSG_DATA_READ_FAILED);
3953 return -1;
3954 }
3955 if (ul_dowrite(ulhandler, ulhandler->buf, readnb, uploaded) != 0) {
3956 addreply_noformat(452, MSG_WRITE_FAILED);
3957 return -1;
3958 }
3959 ulhandler->cur_pos += *uploaded;
3960 #ifdef FTPWHO
3961 if (shm_data_cur != NULL) {
3962 shm_data_cur->download_current_size =
3963 shm_data_cur->download_total_size = ulhandler->cur_pos;
3964 }
3965 #endif
3966 ulhandler->total_uploaded += *uploaded;
3967 if (ulhandler->bandwidth > 0UL) {
3968 ulhandler_throttle(ulhandler, *uploaded, ts_start, &required_sleep);
3969 if (required_sleep > 0.0) {
3970 repoll:
3971 ulhandler->pfds_command.revents = 0;
3972 pollret = poll(&ulhandler->pfds_command, 1, required_sleep * 1000.0);
3973 if (pollret == 0) {
3974 return 0;
3975 }
3976 if (pollret < 0) {
3977 if (errno == EINTR) {
3978 goto repoll;
3979 }
3980 return -1;
3981 }
3982 if ((ulhandler->pfds_command.revents &
3983 (POLLERR | POLLHUP | POLLNVAL)) != 0) {
3984 return -1;
3985 }
3986 if ((ulhandler->pfds_command.revents & (POLLIN | POLLPRI)) != 0) {
3987 ret = ulhandler_handle_commands(ulhandler);
3988 if (ret != 0) {
3989 return ret;
3990 }
3991 goto repoll;
3992 }
3993 }
3994 }
3995 return 0;
3996 }
3997
ul_send(ULHandler * const ulhandler)3998 static int ul_send(ULHandler * const ulhandler)
3999 {
4000 double ts_start = 0.0;
4001 off_t uploaded = (off_t) 0;
4002 int pollret;
4003 int timeout;
4004 int ret;
4005
4006 if (ulhandler->bandwidth > 0UL && (ts_start = get_usec_time()) <= 0.0) {
4007 error(451, "gettimeofday()");
4008 return -1;
4009 }
4010 for (;;) {
4011 if (ulhandler->idletime >= INT_MAX / 1000) {
4012 timeout = INT_MAX;
4013 } else {
4014 timeout = (int) ulhandler->idletime * 1000;
4015 }
4016 ulhandler->pfds[PFD_DATA].revents =
4017 ulhandler->pfds[PFD_COMMANDS].revents = 0;
4018 pollret = poll(ulhandler->pfds,
4019 sizeof ulhandler->pfds / sizeof ulhandler->pfds[0],
4020 timeout);
4021 if (pollret < 0) {
4022 addreply_noformat(451, MSG_DATA_READ_FAILED);
4023 return -1;
4024 }
4025 if (pollret == 0) {
4026 addreply_noformat(421, MSG_TIMEOUT);
4027 return -1;
4028 }
4029 if ((ulhandler->pfds[PFD_DATA].revents & POLLIN) != 0) {
4030 ret = ul_handle_data(ulhandler, &uploaded, ts_start);
4031 switch (ret) {
4032 case 1:
4033 return 1;
4034 case 2:
4035 return 0;
4036 case 0:
4037 break;
4038 default:
4039 if (ret > 2) {
4040 abort();
4041 }
4042 return ret;
4043 }
4044 }
4045 if ((ulhandler->pfds[PFD_COMMANDS].revents & (POLLIN | POLLPRI)) != 0) {
4046 ret = ulhandler_handle_commands(ulhandler);
4047 if (ret != 0) {
4048 return ret;
4049 }
4050 }
4051 if ((ulhandler->pfds[PFD_DATA].revents & (POLLERR | POLLNVAL)) != 0 ||
4052 ((ulhandler->pfds[PFD_DATA].revents & POLLHUP) != 0 &&
4053 (ulhandler->pfds[PFD_DATA].revents & POLLIN) == 0)) {
4054 return -1;
4055 }
4056 if ((ulhandler->pfds[PFD_COMMANDS].revents &
4057 (POLLERR | POLLHUP | POLLNVAL)) != 0) {
4058 addreply_noformat(221, MSG_LOGOUT);
4059 return -1;
4060 }
4061 }
4062 /* NOTREACHED */
4063 return 0;
4064 }
4065
ul_exit(ULHandler * const ulhandler)4066 static int ul_exit(ULHandler * const ulhandler)
4067 {
4068 free(ulhandler->buf);
4069 ulhandler->buf = NULL;
4070
4071 return 0;
4072 }
4073
ul_check_free_space(const char * name,const double min_space)4074 int ul_check_free_space(const char *name, const double min_space)
4075 {
4076 STATFS_STRUCT statfsbuf;
4077 char *z;
4078 char *alloca_namedir;
4079 size_t name_len;
4080 double jam;
4081 double space;
4082
4083 if (maxdiskusagepct <= 0.0 && min_space <= 0.0) {
4084 return 1;
4085 }
4086 #ifdef CHECK_SYMLINKS_DISK_SPACE
4087 if (STATFS(name, &statfsbuf) == 0) {
4088 goto okcheckspace;
4089 }
4090 #endif
4091 name_len = strlen(name) + (size_t) 1U;
4092 if (name_len < (size_t) 2U ||
4093 (alloca_namedir = ALLOCA(name_len)) == NULL) {
4094 return -1;
4095 }
4096 memcpy(alloca_namedir, name, name_len);
4097 if ((z = strrchr(alloca_namedir, '/')) != NULL) {
4098 if (z == alloca_namedir) {
4099 *z++ = '.';
4100 }
4101 *z = 0;
4102 } else {
4103 alloca_namedir[0] = '.';
4104 alloca_namedir[1] = 0;
4105 }
4106 if (STATFS(alloca_namedir, &statfsbuf) != 0) {
4107 ALLOCA_FREE(alloca_namedir);
4108 return -1;
4109 }
4110 ALLOCA_FREE(alloca_namedir);
4111
4112 #ifdef CHECK_SYMLINKS_DISK_SPACE
4113 okcheckspace:
4114 #endif
4115 if ((double) STATFS_BLOCKS(statfsbuf) <= 0.0) {
4116 return 1;
4117 }
4118 if (min_space >= 0.0) {
4119 space = (double) STATFS_BAVAIL(statfsbuf) *
4120 (double) STATFS_FRSIZE(statfsbuf);
4121 if (space < min_space) {
4122 return 0;
4123 }
4124 }
4125 jam = (double) STATFS_BAVAIL(statfsbuf) /
4126 (double) STATFS_BLOCKS(statfsbuf);
4127 if (jam >= maxdiskusagepct) {
4128 return 1;
4129 }
4130 return 0;
4131 }
4132
dostor(char * name,const int append,const int autorename)4133 void dostor(char *name, const int append, const int autorename)
4134 {
4135 ULHandler ulhandler;
4136 int f;
4137 const char *ul_name = NULL;
4138 const char *atomic_file = NULL;
4139 off_t filesize = (off_t) 0U;
4140 struct stat st;
4141 double started = 0.0;
4142 signed char overwrite = 0;
4143 int overflow = 0;
4144 int ret = -1;
4145 off_t max_filesize = (off_t) -1;
4146 #ifdef QUOTAS
4147 Quota quota;
4148 #endif
4149 const char *name2 = NULL;
4150
4151 if (type < 1 || (type == 1 && restartat > (off_t) 1)) {
4152 addreply_noformat(503, MSG_NO_ASCII_RESUME);
4153 goto end;
4154 }
4155 #ifndef ANON_CAN_RESUME
4156 if (guest != 0 && anon_noupload != 0) {
4157 addreply_noformat(550, MSG_ANON_CANT_OVERWRITE);
4158 goto end;
4159 }
4160 #endif
4161 if (ul_check_free_space(name, -1.0) == 0) {
4162 addreply_noformat(552, MSG_NO_DISK_SPACE);
4163 goto end;
4164 }
4165 if (checknamesanity(name, dot_write_ok) != 0) {
4166 addreply(553, MSG_SANITY_FILE_FAILURE, name);
4167 goto end;
4168 }
4169 if (autorename != 0) {
4170 no_truncate = 1;
4171 }
4172 if (restartat > (off_t) 0 || no_truncate != 0) {
4173 if ((atomic_file = get_atomic_file(name)) == NULL) {
4174 addreply(553, MSG_SANITY_FILE_FAILURE, name);
4175 goto end;
4176 }
4177 if (restartat > (off_t) 0 &&
4178 rename(name, atomic_file) != 0 && errno != ENOENT) {
4179 error(553, MSG_RENAME_FAILURE);
4180 atomic_file = NULL;
4181 goto end;
4182 }
4183 }
4184 if (atomic_file != NULL) {
4185 ul_name = atomic_file;
4186 } else {
4187 ul_name = name;
4188 }
4189 if (atomic_file == NULL &&
4190 (f = open(ul_name, O_WRONLY | O_NOFOLLOW)) != -1) {
4191 overwrite++;
4192 } else if ((f = open(ul_name, O_CREAT | O_WRONLY | O_NOFOLLOW,
4193 (mode_t) 0777 & ~u_mask)) == -1) {
4194 error(553, MSG_OPEN_FAILURE2);
4195 goto end;
4196 }
4197 if (fstat(f, &st) < 0) {
4198 (void) close(f);
4199 error(553, MSG_STAT_FAILURE2);
4200 goto end;
4201 }
4202 if (!S_ISREG(st.st_mode)) {
4203 (void) close(f);
4204 addreply_noformat(550, MSG_NOT_REGULAR_FILE);
4205 goto end;
4206 }
4207 alarm(MAX_SESSION_XFER_IDLE);
4208
4209 /* Anonymous users *CAN* overwrite 0-bytes files - This is the right behavior */
4210 if (st.st_size > (off_t) 0) {
4211 #ifndef ANON_CAN_RESUME
4212 if (guest != 0) {
4213 addreply_noformat(550, MSG_ANON_CANT_OVERWRITE);
4214 (void) close(f);
4215 goto end;
4216 }
4217 #endif
4218 if (append != 0) {
4219 restartat = st.st_size;
4220 }
4221 } else {
4222 restartat = (off_t) 0;
4223 }
4224 if (restartat > st.st_size) {
4225 restartat = st.st_size;
4226 }
4227 if (restartat > (off_t) 0 && lseek(f, restartat, SEEK_SET) < (off_t) 0) {
4228 (void) close(f);
4229 error(451, "seek");
4230 goto end;
4231 }
4232 if (restartat < st.st_size) {
4233 if (ftruncate(f, restartat) < 0) {
4234 (void) close(f);
4235 error(451, "ftruncate");
4236 goto end;
4237 }
4238 #ifdef QUOTAS
4239 if (restartat != st.st_size) {
4240 (void) quota_update(NULL, 0LL,
4241 (long long) (restartat - st.st_size),
4242 &overflow);
4243 }
4244 #endif
4245 }
4246 #ifdef QUOTAS
4247 if (quota_update("a, 0LL, 0LL, &overflow) == 0 &&
4248 (overflow > 0 || quota.files >= user_quota_files ||
4249 quota.size > user_quota_size ||
4250 (max_filesize = user_quota_size - quota.size) < (off_t) 0)) {
4251 overflow = 1;
4252 (void) close(f);
4253 goto afterquota;
4254 }
4255 #endif
4256 opendata();
4257 if (xferfd == -1) {
4258 (void) close(f);
4259 goto end;
4260 }
4261 doreply();
4262 # ifdef WITH_TLS
4263 if (data_protection_level == CPL_PRIVATE) {
4264 tls_init_data_session(xferfd, passive);
4265 }
4266 # endif
4267 state_needs_update = 1;
4268 setprocessname("pure-ftpd (UPLOAD)");
4269 filesize = restartat;
4270
4271 #ifdef FTPWHO
4272 if (shm_data_cur != NULL) {
4273 const size_t sl = strlen(name);
4274
4275 ftpwho_lock();
4276 shm_data_cur->state = FTPWHO_STATE_UPLOAD;
4277 shm_data_cur->download_total_size = (off_t) 0U;
4278 shm_data_cur->download_current_size = (off_t) filesize;
4279 shm_data_cur->restartat = restartat;
4280 (void) time(&shm_data_cur->xfer_date);
4281 if (sl < sizeof shm_data_cur->filename) {
4282 memcpy(shm_data_cur->filename, name, sl);
4283 shm_data_cur->filename[sl] = 0;
4284 } else {
4285 memcpy(shm_data_cur->filename,
4286 &name[sl - sizeof shm_data_cur->filename - 1U],
4287 sizeof shm_data_cur->filename);
4288 }
4289 ftpwho_unlock();
4290 }
4291 #else
4292 (void) filesize;
4293 #endif
4294
4295 /* Here starts the real upload code */
4296
4297 started = get_usec_time();
4298
4299 if (ul_init(&ulhandler, clientfd, tls_cnx, xferfd, name, f, tls_data_cnx,
4300 restartat, type == 1, throttling_bandwidth_ul,
4301 max_filesize) == 0) {
4302 ret = ul_send(&ulhandler);
4303 ul_exit(&ulhandler);
4304 } else {
4305 ret = -1;
4306 }
4307 (void) close(f);
4308 closedata();
4309
4310 /* Here ends the real upload code */
4311
4312 #ifdef SHOW_REAL_DISK_SPACE
4313 if (FSTATFS(f, &statfsbuf) == 0) {
4314 double space;
4315
4316 space = (double) STATFS_BAVAIL(statfsbuf) *
4317 (double) STATFS_FRSIZE(statfsbuf);
4318 if (space > 524288.0) {
4319 addreply(0, MSG_SPACE_FREE_M, space / 1048576.0);
4320 } else {
4321 addreply(0, MSG_SPACE_FREE_K, space / 1024.0);
4322 }
4323 }
4324 #endif
4325
4326 uploaded += (unsigned long long) ulhandler.total_uploaded;
4327 {
4328 off_t atomic_file_size;
4329 off_t original_file_size;
4330
4331 #ifdef QUOTAS
4332 int files_count;
4333 #endif
4334
4335 #ifdef QUOTAS
4336 if (overwrite == 0) {
4337 files_count = 1;
4338 } else {
4339 files_count = 0;
4340 }
4341 #endif
4342 if (autorename != 0 && restartat == (off_t) 0) {
4343 if ((atomic_file_size = get_file_size(atomic_file)) < (off_t) 0) {
4344 goto afterquota;
4345 }
4346 if (tryautorename(atomic_file, name, &name2) != 0) {
4347 error(553, MSG_RENAME_FAILURE);
4348 goto afterquota;
4349 } else {
4350 #ifdef QUOTAS
4351 ul_quota_update(name2 ? name2 : name, 1, atomic_file_size);
4352 #endif
4353 atomic_file = NULL;
4354 }
4355 } else if (atomic_file != NULL) {
4356 if ((atomic_file_size = get_file_size(atomic_file)) < (off_t) 0) {
4357 goto afterquota;
4358 }
4359 if ((original_file_size = get_file_size(name)) < (off_t) 0 ||
4360 restartat > original_file_size) {
4361 original_file_size = restartat;
4362 }
4363 if (rename(atomic_file, name) != 0) {
4364 error(553, MSG_RENAME_FAILURE);
4365 goto afterquota;
4366 } else {
4367 #ifdef QUOTAS
4368 overflow = ul_quota_update
4369 (name, files_count, atomic_file_size - original_file_size);
4370 #endif
4371 atomic_file = NULL;
4372 }
4373 } else {
4374 #ifdef QUOTAS
4375 overflow = ul_quota_update
4376 (name, files_count, ulhandler.total_uploaded);
4377 #endif
4378 }
4379 }
4380 afterquota:
4381 if (overflow > 0) {
4382 addreply(552, MSG_QUOTA_EXCEEDED, name);
4383 } else {
4384 if (ret == 0) {
4385 addreply_noformat(226, MSG_TRANSFER_SUCCESSFUL);
4386 } else {
4387 addreply_noformat(451, MSG_ABORTED);
4388 }
4389 displayrate(MSG_UPLOADED, ulhandler.total_uploaded, started,
4390 name2 ? name2 : name, 1);
4391 }
4392 end:
4393 restartat = (off_t) 0;
4394 if (atomic_file != NULL) {
4395 unlink(atomic_file);
4396 atomic_file = NULL;
4397 }
4398 }
4399
domdtm(const char * name)4400 void domdtm(const char *name)
4401 {
4402 struct stat st;
4403 struct tm *t;
4404
4405 if (!name || !*name) {
4406 addreply_noformat(501, MSG_MISSING_ARG);
4407 } else if (stat(name, &st)) {
4408 #ifdef DEBUG
4409 if (debug != 0) {
4410 addreply(0, "arg: %s, wd: %s", name, wd);
4411 }
4412 #endif
4413 addreply_noformat(550, MSG_STAT_FAILURE2);
4414 } else if (!S_ISREG(st.st_mode)) {
4415 addreply_noformat(550, MSG_NOT_REGULAR_FILE);
4416 } else {
4417 t = gmtime((time_t *) &(st.st_mtime));
4418 if (!t) {
4419 addreply_noformat(451, MSG_GMTIME_FAILURE);
4420 } else {
4421 addreply(213, "%04d%02d%02d%02d%02d%02d",
4422 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
4423 t->tm_hour, t->tm_min, t->tm_sec);
4424 }
4425 }
4426 }
4427
dosize(const char * name)4428 void dosize(const char *name)
4429 {
4430 struct stat st;
4431
4432 if (!name || !*name) {
4433 addreply_noformat(501, MSG_MISSING_ARG);
4434 } else if (stat(name, &st)) {
4435 #ifdef DEBUG
4436 if (debug != 0) {
4437 addreply(0, "arg: %s, wd: %s", name, wd);
4438 }
4439 #endif
4440 addreply_noformat(550, MSG_STAT_FAILURE2);
4441 } else if (!S_ISREG(st.st_mode)) {
4442 addreply_noformat(550, MSG_NOT_REGULAR_FILE);
4443 } else {
4444 addreply(213, "%llu", (unsigned long long) st.st_size);
4445 }
4446 }
4447
dotype(const char * arg)4448 void dotype(const char *arg)
4449 {
4450 replycode = 200; /* bloody awful hack */
4451
4452 if (!arg || !*arg) {
4453 addreply(501, MSG_MISSING_ARG "\n" "A(scii) I(mage) L(ocal)");
4454 } else if (tolower((unsigned char) *arg) == 'a')
4455 type = 1;
4456 else if (tolower((unsigned char) *arg) == 'i')
4457 type = 2;
4458 else if (tolower((unsigned char) *arg) == 'l') {
4459 if (arg[1] == '8') {
4460 type = 2;
4461 } else if (isdigit((unsigned char) arg[1])) {
4462 addreply_noformat(504, MSG_TYPE_8BIT_FAILURE);
4463 } else {
4464 addreply_noformat(0, MSG_MISSING_ARG);
4465 type = 2;
4466 }
4467 } else {
4468 addreply(504, MSG_TYPE_UNKNOWN ": %s", arg);
4469 }
4470
4471 addreply(0, MSG_TYPE_SUCCESS " %s", (type > 1) ? "8-bit binary" : "ASCII");
4472 }
4473
dostru(const char * arg)4474 void dostru(const char *arg)
4475 {
4476 if (arg == NULL || !*arg) {
4477 addreply_noformat(501, MSG_MISSING_ARG);
4478 } else if (strcasecmp(arg, "F")) {
4479 addreply_noformat(504, MSG_STRU_FAILURE);
4480 } else {
4481 addreply_noformat(200, "F OK");
4482 }
4483 }
4484
domode(const char * arg)4485 void domode(const char *arg)
4486 {
4487 if (arg == NULL || !*arg) {
4488 addreply_noformat(501, MSG_MISSING_ARG);
4489 } else if (strcasecmp(arg, "S")) {
4490 addreply_noformat(504, MSG_MODE_FAILURE);
4491 } else {
4492 addreply_noformat(200, "S OK");
4493 }
4494 }
4495
dornfr(char * name)4496 void dornfr(char *name)
4497 {
4498 struct stat st;
4499
4500 #ifndef ANON_CAN_RENAME
4501 if (guest != 0) {
4502 addreply_noformat(550, MSG_ANON_CANT_RENAME);
4503 return;
4504 }
4505 #endif
4506 if (disallow_rename != 0) {
4507 addreply_noformat(550, MSG_RENAME_FAILURE);
4508 return;
4509 }
4510 if (checknamesanity(name, dot_write_ok) != 0) {
4511 addreply(553, MSG_SANITY_FILE_FAILURE, name);
4512 return;
4513 }
4514 if ((lstat(name, &st)) == 0) {
4515 if (renamefrom != NULL) {
4516 addreply_noformat(0, MSG_RENAME_ABORT);
4517 (void) free(renamefrom);
4518 }
4519 if ((renamefrom = strdup(name)) == NULL) {
4520 die_mem();
4521 }
4522 addreply_noformat(350, MSG_RENAME_RNFR_SUCCESS);
4523 } else {
4524 addreply_noformat(550, MSG_FILE_DOESNT_EXIST);
4525 }
4526 }
4527
dornto(char * name)4528 void dornto(char *name)
4529 {
4530 #ifdef QUOTAS
4531 off_t target_file_size = (off_t) -1;
4532 int files_count = 0;
4533 long long bytes = 0LL;
4534 #endif
4535
4536 #ifndef ANON_CAN_RENAME
4537 if (guest != 0) {
4538 addreply_noformat(550, MSG_ANON_CANT_RENAME);
4539 goto bye;
4540 }
4541 #endif
4542 if (renamefrom == NULL) {
4543 addreply_noformat(503, MSG_RENAME_NORNFR);
4544 goto bye;
4545 }
4546 if (checknamesanity(name, dot_write_ok) != 0) {
4547 addreply(553, MSG_SANITY_FILE_FAILURE, name);
4548 return; /* don't clear rnfrom buffer */
4549 }
4550 #ifdef QUOTAS
4551 if (hasquota() == 0) {
4552 struct stat st_source, st_target;
4553
4554 if (stat(renamefrom, &st_source) != 0) {
4555 addreply_noformat(550, MSG_RENAME_FAILURE);
4556 goto bye;
4557 }
4558 if (stat(name, &st_target) != 0) {
4559 if (errno == ENOENT) {
4560 target_file_size = (off_t) -1;
4561 } else {
4562 addreply_noformat(550, MSG_RENAME_FAILURE);
4563 goto bye;
4564 }
4565 } else if (st_source.st_ino == st_target.st_ino &&
4566 st_source.st_dev == st_target.st_dev) {
4567 addreply_noformat(250, MSG_RENAME_SUCCESS);
4568 goto bye;
4569 } else {
4570 target_file_size = st_target.st_size;
4571 }
4572 if (target_file_size >= (off_t) 0) {
4573 bytes = - (long long) target_file_size;
4574 files_count = -1;
4575 (void) quota_update(NULL, files_count, bytes, NULL);
4576 } else {
4577 bytes = (off_t) 0;
4578 }
4579 }
4580 #endif
4581 if (rename(renamefrom, name) < 0) {
4582 error(451, MSG_RENAME_FAILURE);
4583 #ifdef QUOTAS
4584 (void) quota_update(NULL, -files_count, -bytes, NULL);
4585 #endif
4586 } else {
4587 addreply_noformat(250, MSG_RENAME_SUCCESS);
4588 logfile(LOG_NOTICE, MSG_RENAME_SUCCESS ": [%s]->[%s]",
4589 renamefrom, name);
4590 }
4591 bye:
4592 (void) free(renamefrom);
4593 renamefrom = NULL;
4594 }
4595
4596 #ifndef MINIMAL
doopts(char * args)4597 void doopts(char *args)
4598 {
4599 char *cmdopts;
4600
4601 if ((cmdopts = strchr(args, ' ')) != NULL) {
4602 cmdopts++;
4603 (void) cmdopts;
4604 }
4605 if (strncasecmp("mlst ", args, 5) == 0) {
4606 addreply_noformat(200, " MLST OPTS "
4607 "type;size;sizd;modify;UNIX.mode;UNIX.uid;"
4608 "UNIX.gid;unique;");
4609 return;
4610 }
4611 addreply_noformat(504, MSG_UNKNOWN_COMMAND);
4612 }
4613 #endif
4614
error(int n,const char * msg)4615 void error(int n, const char *msg)
4616 {
4617 const char *e = strerror(errno);
4618
4619 logfile(LOG_ERR, "%s: %s", msg, e);
4620 addreply(n, "%s: %s", msg, e);
4621 }
4622
fixlimits(void)4623 static void fixlimits(void)
4624 {
4625 #ifdef HAVE_SETRLIMIT
4626 static struct rlimit lim;
4627
4628 lim.rlim_max = lim.rlim_cur = MAX_CPU_TIME;
4629 setrlimit(RLIMIT_CPU, &lim);
4630 lim.rlim_max = lim.rlim_cur = MAX_DATA_SIZE;
4631 setrlimit(RLIMIT_DATA, &lim);
4632 # ifndef DEBUG
4633 lim.rlim_max = lim.rlim_cur = 0;
4634 setrlimit(RLIMIT_CORE, &lim);
4635 # endif
4636 #endif
4637 }
4638
4639 #ifdef COOKIE
fortune(void)4640 static int fortune(void)
4641 {
4642 int fd;
4643 char *buf;
4644 char *bufpnt;
4645 char *bufend;
4646 struct stat st;
4647 off_t gl;
4648 char *fortunepnt;
4649 char fortune[2048];
4650
4651 if (fortunes_file == NULL || *fortunes_file == 0) {
4652 return 0;
4653 }
4654 if ((fd = open(fortunes_file, O_RDONLY)) == -1) {
4655 logfile(LOG_ERR, MSG_OPEN_FAILURE, fortunes_file);
4656 return -1;
4657 }
4658 if (fstat(fd, &st) < 0 ||
4659 (((S_IRUSR | S_IRGRP | S_IROTH) & st.st_mode) !=
4660 (S_IRUSR | S_IRGRP | S_IROTH)) ||
4661 !(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) || st.st_size < 2 ||
4662 (buf = mmap(NULL, (size_t) st.st_size,
4663 PROT_READ, MAP_FILE | MAP_SHARED, fd,
4664 (off_t) 0)) == (void *) MAP_FAILED) {
4665 (void) close(fd);
4666 logfile(LOG_ERR, MSG_OPEN_FAILURE, fortunes_file);
4667 return -1;
4668 }
4669 # ifdef HAVE_RANDOM
4670 gl = (off_t) (random() % (st.st_size - 1U));
4671 # else
4672 gl = (off_t) (rand() % (st.st_size - 1U));
4673 # endif
4674 bufpnt = buf + gl;
4675 bufend = buf + st.st_size;
4676 while (bufpnt != buf) {
4677 if (bufpnt[0] == '\n') {
4678 if (&bufpnt[-1] != buf && bufpnt[-1] == '%') {
4679 if (&bufpnt[-2] != buf && bufpnt[-2] == '\n') {
4680 break;
4681 }
4682 }
4683 }
4684 bufpnt--;
4685 }
4686 if (bufpnt != buf) {
4687 while (bufpnt != bufend && *bufpnt == '\n') {
4688 bufpnt++;
4689 }
4690 }
4691 fortunepnt = fortune;
4692 while (*bufpnt != 0 && bufpnt != bufend &&
4693 fortunepnt != &fortune[sizeof fortune - 1U]) {
4694 if (bufpnt[0] == '\n') {
4695 if (&bufpnt[1] != bufend && bufpnt[1] == '%') {
4696 if (&bufpnt[2] != bufend && bufpnt[2] == '\n') {
4697 break;
4698 }
4699 }
4700 }
4701 *fortunepnt++ = *bufpnt++;
4702 }
4703 if (fortunepnt == fortune) {
4704 goto bye;
4705 }
4706 do {
4707 fortunepnt--;
4708 } while (fortunepnt != fortune && (*fortunepnt == '\n' ||
4709 isspace((unsigned char) *fortunepnt)));
4710 fortunepnt[1] = 0;
4711 fortunepnt = fortune;
4712 while (*fortunepnt == '\n') {
4713 fortunepnt++;
4714 }
4715 if (*fortunepnt == 0) {
4716 goto bye;
4717 }
4718 addreply(220, "%s", fortunepnt);
4719 bye:
4720 (void) munmap(buf, st.st_size);
4721 (void) close(fd);
4722
4723 return 1;
4724 }
4725 #endif
4726
4727 #if !defined(NO_STANDALONE) && !defined(NO_INETD)
check_standalone(void)4728 static int check_standalone(void)
4729 {
4730 socklen_t socksize = (socklen_t) sizeof ctrlconn;
4731 if (getsockname(0, (struct sockaddr *) &ctrlconn, &socksize) != 0) {
4732 clientfd = -1;
4733 return 1;
4734 }
4735 if (dup2(0, 1) == -1) {
4736 _EXIT(EXIT_FAILURE);
4737 }
4738 clientfd = 0;
4739
4740 return 0;
4741 }
4742 #endif
4743
set_signals_client(void)4744 static void set_signals_client(void)
4745 {
4746 sigset_t sigs;
4747 struct sigaction sa;
4748
4749 sigfillset(&sigs);
4750 sigemptyset(&sa.sa_mask);
4751
4752 sa.sa_flags = SA_RESTART;
4753
4754 sa.sa_handler = SIG_IGN;
4755 (void) sigaction(SIGPIPE, &sa, NULL);
4756 (void) sigaction(SIGURG, &sa, NULL);
4757 #ifdef SIGIO
4758 (void) sigaction(SIGIO, &sa, NULL);
4759 #endif
4760
4761 sa.sa_handler = SIG_DFL;
4762 sigdelset(&sigs, SIGCHLD);
4763 (void) sigaction(SIGCHLD, &sa, NULL);
4764 #ifdef SIGFPE
4765 (void) sigaction(SIGFPE, &sa, NULL);
4766 sigdelset(&sigs, SIGFPE);
4767 #endif
4768 sa.sa_flags = 0;
4769
4770 sa.sa_handler = sigalarm;
4771 sigdelset(&sigs, SIGALRM);
4772 (void) sigaction(SIGALRM, &sa, NULL);
4773
4774 sa.sa_handler = sigterm_client;
4775 sigdelset(&sigs, SIGTERM);
4776 (void) sigaction(SIGTERM, &sa, NULL);
4777 sigdelset(&sigs, SIGHUP);
4778 (void) sigaction(SIGHUP, &sa, NULL);
4779 sigdelset(&sigs, SIGQUIT);
4780 (void) sigaction(SIGQUIT, &sa, NULL);
4781 sigdelset(&sigs, SIGINT);
4782 (void) sigaction(SIGINT, &sa, NULL);
4783 #ifdef SIGXCPU
4784 sigdelset(&sigs, SIGXCPU);
4785 (void) sigaction(SIGXCPU, &sa, NULL);
4786 #endif
4787 (void) sigprocmask(SIG_SETMASK, &sigs, NULL);
4788 }
4789
set_signals(void)4790 static void set_signals(void)
4791 {
4792 #ifndef NO_STANDALONE
4793 sigset_t sigs;
4794 struct sigaction sa;
4795
4796 sigfillset(&sigs);
4797 sigemptyset(&sa.sa_mask);
4798
4799 sa.sa_flags = SA_RESTART;
4800 sa.sa_handler = sigchild;
4801 sigdelset(&sigs, SIGCHLD);
4802 (void) sigaction(SIGCHLD, &sa, NULL);
4803
4804 sa.sa_handler = SIG_IGN;
4805 (void) sigaction(SIGPIPE, &sa, NULL);
4806 (void) sigaction(SIGALRM, &sa, NULL);
4807 (void) sigaction(SIGURG, &sa, NULL);
4808 #ifdef SIGIO
4809 (void) sigaction(SIGIO, &sa, NULL);
4810 #endif
4811
4812 sa.sa_flags = 0;
4813 sa.sa_handler = sigterm;
4814 sigdelset(&sigs, SIGTERM);
4815 (void) sigaction(SIGTERM, &sa, NULL);
4816 sigdelset(&sigs, SIGHUP);
4817 (void) sigaction(SIGHUP, &sa, NULL);
4818 sigdelset(&sigs, SIGQUIT);
4819 (void) sigaction(SIGQUIT, &sa, NULL);
4820 sigdelset(&sigs, SIGINT);
4821 (void) sigaction(SIGINT, &sa, NULL);
4822 # ifdef SIGXCPU
4823 sigdelset(&sigs, SIGXCPU);
4824 (void) sigaction(SIGXCPU, &sa, NULL);
4825 # endif
4826 (void) sigprocmask(SIG_SETMASK, &sigs, NULL);
4827 #endif
4828 }
4829
dns_sanitize(char * z)4830 static void dns_sanitize(char *z)
4831 {
4832 while (*z != 0) {
4833 if ((*z >= 'a' && *z <= 'z') ||
4834 (*z >= '0' && *z <= '9') ||
4835 *z == '.' || *z == '-' || *z == ':' ||
4836 (*z >= 'A' && *z <= 'Z')) {
4837 /* unless */
4838 } else {
4839 *z = '_';
4840 }
4841 z++;
4842 }
4843 }
4844
fill_atomic_prefix(void)4845 static void fill_atomic_prefix(void)
4846 {
4847 char tmp_atomic_prefix[PATH_MAX];
4848
4849 snprintf(tmp_atomic_prefix, sizeof tmp_atomic_prefix,
4850 "%s%lx.%x.%lx.%x",
4851 ATOMIC_PREFIX_PREFIX,
4852 (unsigned long) session_start_time,
4853 (unsigned int) serverport,
4854 (unsigned long) getpid(),
4855 zrand());
4856 if ((atomic_prefix = strdup(tmp_atomic_prefix)) == NULL) {
4857 die_mem();
4858 }
4859 }
4860
doit(void)4861 static void doit(void)
4862 {
4863 socklen_t socksize;
4864 unsigned int users = 0U;
4865 int display_banner = 1;
4866
4867 client_init_reply_buf();
4868 session_start_time = time(NULL);
4869 fixlimits();
4870 #ifdef F_SETOWN
4871 fcntl(clientfd, F_SETOWN, getpid());
4872 #endif
4873 set_signals_client();
4874 alt_arc4random_stir();
4875 (void) umask((mode_t) 0);
4876 socksize = (socklen_t) sizeof ctrlconn;
4877 if (getsockname(clientfd, (struct sockaddr *) &ctrlconn, &socksize) != 0) {
4878 die(421, LOG_ERR, MSG_NO_SUPERSERVER);
4879 }
4880 fourinsix(&ctrlconn);
4881 if (checkvalidaddr(&ctrlconn) == 0) {
4882 die(425, LOG_ERR, MSG_INVALID_IP);
4883 }
4884 if (STORAGE_FAMILY(ctrlconn) == AF_INET6) {
4885 serverport = ntohs((in_port_t) STORAGE_PORT6_CONST(ctrlconn));
4886 } else {
4887 serverport = ntohs((in_port_t) STORAGE_PORT_CONST(ctrlconn));
4888 }
4889 if (trustedip != NULL && addrcmp(&ctrlconn, trustedip) != 0) {
4890 anon_only = 1;
4891 }
4892 socksize = (socklen_t) sizeof peer;
4893 if (getpeername(clientfd, (struct sockaddr *) &peer, &socksize)) {
4894 die(421, LOG_ERR, MSG_GETPEERNAME ": %s" , strerror(errno));
4895 }
4896 fourinsix(&peer);
4897 if (checkvalidaddr(&peer) == 0) {
4898 die(425, LOG_ERR, MSG_INVALID_IP);
4899 }
4900 #ifndef DONT_LOG_IP
4901 for (;;) {
4902 int eai;
4903
4904 if ((eai = getnameinfo
4905 ((struct sockaddr *) &peer, STORAGE_LEN(peer), host,
4906 sizeof host, NULL, (size_t) 0U,
4907 resolve_hostnames != 0 ? 0 : NI_NUMERICHOST)) == 0) {
4908 break;
4909 }
4910 if (resolve_hostnames != 0 &&
4911 getnameinfo
4912 ((struct sockaddr *) &peer, STORAGE_LEN(peer), host,
4913 sizeof host, NULL, (size_t) 0U, NI_NUMERICHOST) == 0) {
4914 break;
4915 }
4916 die(425, LOG_ERR, MSG_INVALID_IP);
4917 }
4918 #endif
4919 #ifndef DONT_LOG_IP
4920 dns_sanitize(host);
4921 #else
4922 *host = '?';
4923 host[1] = 0;
4924 #endif
4925 logfile(LOG_INFO, MSG_NEW_CONNECTION, host);
4926
4927 replycode = 220;
4928
4929 fill_atomic_prefix();
4930
4931 if (maxusers > 0U) {
4932 #ifdef NO_STANDALONE
4933 users = daemons(serverport);
4934 #else
4935 # ifdef NO_INETD
4936 users = nb_children;
4937 # else
4938 if (standalone) {
4939 users = nb_children;
4940 } else {
4941 users = daemons(serverport);
4942 }
4943 # endif
4944 #endif
4945 if (users > maxusers) {
4946 addreply(421, MSG_MAX_USERS, (unsigned long) maxusers);
4947 doreply();
4948 _EXIT(1);
4949 }
4950 }
4951 /* It's time to add a new entry to the ftpwho list */
4952 #ifdef FTPWHO
4953 {
4954 ftpwho_initwho();
4955 if (shm_data_cur != NULL) {
4956 ftpwho_lock();
4957 shm_data_cur->pid = getpid();
4958 shm_data_cur->state = FTPWHO_STATE_IDLE;
4959 shm_data_cur->addr = peer;
4960 shm_data_cur->local_addr = ctrlconn;
4961 shm_data_cur->date = session_start_time;
4962 shm_data_cur->xfer_date = shm_data_cur->date;
4963 (shm_data_cur->account)[0] = '?';
4964 (shm_data_cur->account)[1] = 0;
4965 shm_data_cur->download_total_size = (off_t) 0;
4966 shm_data_cur->download_current_size = (off_t) 0;
4967 ftpwho_unlock();
4968 }
4969 }
4970 #endif
4971
4972 #ifdef WITH_ALTLOG
4973 if (altlog_format != ALTLOG_NONE) {
4974 if (altlog_format == ALTLOG_W3C) {
4975 if ((altlog_fd = open(altlog_filename,
4976 O_CREAT | O_WRONLY | O_NOFOLLOW | O_EXCL,
4977 (mode_t) 0600)) != -1) {
4978 altlog_write_w3c_header();
4979 } else if (errno == EEXIST) {
4980 altlog_fd = open(altlog_filename, O_WRONLY | O_NOFOLLOW);
4981 }
4982 } else {
4983 altlog_fd = open(altlog_filename,
4984 O_CREAT | O_WRONLY | O_NOFOLLOW, (mode_t) 0600);
4985 }
4986 if (altlog_fd == -1) {
4987 logfile(LOG_ERR, "altlog %s: %s", altlog_filename, strerror(errno));
4988 }
4989 }
4990 #endif
4991 /* Back to the client - Get the 5 min load average */
4992 {
4993 double load_[2];
4994
4995 if (getloadavg(load_, sizeof load_ / sizeof load_[0]) < 0) {
4996 load = 0.0;
4997 } else {
4998 load = load_[1];
4999 }
5000 }
5001 #ifndef NON_ROOT_FTP
5002 wd[0] = '/';
5003 wd[1] = 0;
5004 if (chdir(wd)) {
5005 _EXIT(EXIT_FAILURE);
5006 }
5007 #endif
5008 {
5009 int fodder;
5010 #ifdef IPTOS_LOWDELAY
5011 fodder = IPTOS_LOWDELAY;
5012 setsockopt(clientfd, SOL_IP, IP_TOS, (char *) &fodder, sizeof fodder);
5013 #endif
5014 #ifdef SO_OOBINLINE
5015 fodder = 1;
5016 setsockopt(clientfd, SOL_SOCKET, SO_OOBINLINE,
5017 (char *) &fodder, sizeof fodder);
5018 #endif
5019 #ifdef TCP_NODELAY
5020 fodder = 1;
5021 setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY,
5022 (char *) &fodder, sizeof fodder);
5023 #endif
5024 keepalive(clientfd, 0);
5025 }
5026 #ifdef HAVE_SRANDOMDEV
5027 srandomdev();
5028 #elif defined (HAVE_RANDOM)
5029 srandom((unsigned int) session_start_time ^ (unsigned int) zrand());
5030 #else
5031 srand((unsigned int) session_start_time ^ (unsigned int) zrand());
5032 #endif
5033 #ifdef COOKIE
5034 if (fortune() > 0) {
5035 display_banner = 0;
5036 }
5037 #endif
5038 if (display_banner) {
5039 #ifdef BORING_MODE
5040 addreply_noformat(0, MSG_WELCOME_TO " Pure-FTPd.");
5041 #else
5042 # ifdef DEBUG
5043 addreply_noformat(0, "--------- " MSG_WELCOME_TO
5044 " Pure-FTPd " PACKAGE_VERSION VERSION_PRIVSEP VERSION_TLS " ----------");
5045 # else
5046 addreply_noformat(0, "--------- " MSG_WELCOME_TO
5047 " Pure-FTPd" VERSION_PRIVSEP VERSION_TLS " ----------");
5048 # endif
5049 #endif
5050 if (users > 0U) {
5051 addreply(0, MSG_NB_USERS, users, maxusers);
5052 }
5053 {
5054 struct tm *t;
5055
5056 if ((t = localtime(&session_start_time)) != NULL) {
5057 addreply(220, MSG_WELCOME_TIME,
5058 t->tm_hour, t->tm_min, (unsigned int) serverport);
5059 }
5060 }
5061 }
5062 if (anon_only > 0) {
5063 addreply_noformat(220, MSG_ANONYMOUS_FTP_ONLY);
5064 } else if (anon_only < 0) {
5065 addreply_noformat(220, MSG_NO_ANONYMOUS_LOGIN);
5066 }
5067 if (allowfxp == 2) {
5068 addreply_noformat(220, MSG_FXP_SUPPORT);
5069 }
5070 #ifdef RATIOS
5071 if (ratio_upload > 0) {
5072 if (ratio_for_non_anon != 0) {
5073 addreply_noformat(0, MSG_RATIOS_EVERYONE);
5074 } else {
5075 addreply_noformat(0, MSG_RATIOS_ANONYMOUS);
5076 }
5077 addreply(0, MSG_RATIOS_RULE, ratio_download, ratio_upload);
5078 }
5079 #endif
5080 if (display_banner) {
5081 if (v6ready != 0 && STORAGE_FAMILY(peer) != AF_INET6) {
5082 addreply(0, MSG_IPV6_OK);
5083 }
5084 if (idletime >= 120UL) {
5085 addreply(220, MSG_INFO_IDLE_M, idletime / 60UL);
5086 } else {
5087 addreply(220, MSG_INFO_IDLE_S, (unsigned long) idletime);
5088 }
5089 }
5090 candownload = (signed char) ((maxload <= 0.0) || (load < maxload));
5091
5092 if (force_passive_ip_s != NULL) {
5093 struct addrinfo hints, *res;
5094
5095 memset(&hints, 0, sizeof hints);
5096 hints.ai_family = AF_INET;
5097 hints.ai_addr = NULL;
5098 if (getaddrinfo(force_passive_ip_s, NULL, &hints, &res) != 0 ||
5099 res->ai_family != AF_INET ||
5100 res->ai_addrlen > sizeof force_passive_ip) {
5101 die(421, LOG_ERR, MSG_ILLEGAL_FORCE_PASSIVE);
5102 }
5103 memcpy(&force_passive_ip, res->ai_addr, res->ai_addrlen);
5104 freeaddrinfo(res);
5105 }
5106
5107 #ifndef WITHOUT_PRIVSEP
5108 if (privsep_init() != 0) {
5109 die(421, LOG_ERR, "privsep_init");
5110 }
5111 #endif
5112
5113 parser();
5114
5115 addreply(0, MSG_LOGOUT);
5116 logfile(LOG_INFO, MSG_LOGOUT);
5117 doreply();
5118 #ifdef WITH_BONJOUR
5119 refreshManager();
5120 #endif
5121 }
5122
check_ipv6_support(void)5123 static void check_ipv6_support(void) /* check for ipv6 support in kernel */
5124 {
5125 #ifndef OLD_IP_STACK
5126 int p;
5127
5128 if ((p = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) != -1) {
5129 (void) close(p);
5130 v6ready++;
5131 }
5132 #endif
5133 }
5134
5135 #ifndef NO_STANDALONE
updatepidfile(void)5136 static void updatepidfile(void)
5137 {
5138 int fd;
5139 char buf[42];
5140 size_t buf_len;
5141
5142 if (SNCHECK(snprintf(buf, sizeof buf, "%lu\n",
5143 (unsigned long) getpid()), sizeof buf)) {
5144 return;
5145 }
5146 if (unlink(pid_file) != 0 && errno != ENOENT) {
5147 return;
5148 }
5149 if ((fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC |
5150 O_NOFOLLOW, (mode_t) 0644)) == -1) {
5151 return;
5152 }
5153 buf_len = strlen(buf);
5154 if (safe_write(fd, buf, buf_len, -1) != (ssize_t) buf_len) {
5155 (void) ftruncate(fd, (off_t) 0);
5156 }
5157 (void) close(fd);
5158 }
5159
5160 #ifndef NO_STANDALONE
closedesc_all(const int closestdin)5161 static int closedesc_all(const int closestdin)
5162 {
5163 int fodder;
5164
5165 if (closestdin != 0) {
5166 (void) close(0);
5167 if ((fodder = open("/dev/null", O_RDONLY)) == -1) {
5168 return -1;
5169 }
5170 (void) dup2(fodder, 0);
5171 if (fodder > 0) {
5172 (void) close(fodder);
5173 }
5174 }
5175 if ((fodder = open("/dev/null", O_WRONLY)) == -1) {
5176 return -1;
5177 }
5178 (void) dup2(fodder, 1);
5179 (void) dup2(1, 2);
5180 if (fodder > 2) {
5181 (void) close(fodder);
5182 }
5183
5184 return 0;
5185 }
5186
dodaemonize(void)5187 static void dodaemonize(void)
5188 {
5189 pid_t child;
5190 unsigned int i;
5191
5192 /* Contributed by Jason Lunz - also based on APUI code, see open_max() */
5193 if (daemonize != 0) {
5194 if ((child = fork()) == (pid_t) -1) {
5195 perror(MSG_STANDALONE_FAILED " - fork");
5196 logfile(LOG_ERR, MSG_STANDALONE_FAILED ": [fork: %s]", strerror(errno));
5197 return;
5198 } else if (child != (pid_t) 0) {
5199 _EXIT(EXIT_SUCCESS); /* parent exits */
5200 }
5201 if (setsid() == (pid_t) -1) {
5202 perror(MSG_STANDALONE_FAILED " - setsid"); /* continue anyway */
5203 }
5204 # ifndef NON_ROOT_FTP
5205 if (chdir("/") != 0) {
5206 perror("chdir");
5207 _EXIT(EXIT_FAILURE);
5208 }
5209 # endif
5210 i = open_max();
5211 do {
5212 if (isatty((int) i)) {
5213 (void) close((int) i);
5214 }
5215 i--;
5216 } while (i > 2U);
5217 if (closedesc_all(1) != 0) {
5218 perror(MSG_STANDALONE_FAILED " - /dev/null duplication");
5219 _EXIT(EXIT_FAILURE);
5220 }
5221 }
5222 }
5223 #endif
5224
accept_client(const int active_listen_fd)5225 static void accept_client(const int active_listen_fd) {
5226 sigset_t set;
5227 struct sockaddr_storage sa;
5228 socklen_t dummy;
5229 pid_t child;
5230
5231 memset(&sa, 0, sizeof sa);
5232 dummy = (socklen_t) sizeof sa;
5233 if ((clientfd = accept
5234 (active_listen_fd, (struct sockaddr *) &sa, &dummy)) == -1) {
5235 return;
5236 }
5237 if (STORAGE_FAMILY(sa) != AF_INET && STORAGE_FAMILY(sa) != AF_INET6) {
5238 (void) close(clientfd);
5239 clientfd = -1;
5240 return;
5241 }
5242 if (maxusers > 0U && nb_children >= maxusers) {
5243 char line[1024];
5244
5245 snprintf(line, sizeof line, "421 " MSG_MAX_USERS "\r\n",
5246 (unsigned long) maxusers);
5247 /* No need to check a return value to say 'f*ck' */
5248 (void) fcntl(clientfd, F_SETFL, fcntl(clientfd, F_GETFL) | O_NONBLOCK);
5249 (void) write(clientfd, line, strlen(line));
5250 (void) close(clientfd);
5251 clientfd = -1;
5252 return;
5253 }
5254 if (maxip > 0U) {
5255 fourinsix(&sa);
5256 if (iptrack_get(&sa) >= maxip) {
5257 char line[1024];
5258 char hbuf[NI_MAXHOST];
5259 static struct sockaddr_storage old_sa;
5260
5261 (void) fcntl(clientfd, F_SETFL, fcntl(clientfd, F_GETFL) | O_NONBLOCK);
5262 if (!SNCHECK(snprintf(line, sizeof line,
5263 "421 " MSG_MAX_USERS_IP "\r\n",
5264 (unsigned long) maxip), sizeof line)) {
5265 (void) write(clientfd, line, strlen(line));
5266 }
5267 if (addrcmp(&old_sa, &sa) != 0) {
5268 old_sa = sa;
5269 if (getnameinfo((struct sockaddr *) &sa,
5270 STORAGE_LEN(sa), hbuf,
5271 sizeof hbuf, NULL, (size_t) 0U,
5272 NI_NUMERICHOST) == 0) {
5273 logfile(LOG_WARNING, MSG_MAX_USERS_IP ": [%s]",
5274 (unsigned long) maxip, hbuf);
5275 }
5276 }
5277 (void) close(clientfd);
5278 clientfd = -1;
5279 return;
5280 }
5281 }
5282 sigemptyset(&set);
5283 sigaddset(&set, SIGCHLD);
5284 sigprocmask(SIG_BLOCK, &set, NULL);
5285 nb_children++;
5286 child = fork();
5287 if (child == (pid_t) 0) {
5288 if (isatty(2)) {
5289 (void) close(2);
5290 }
5291 #ifndef SAVE_DESCRIPTORS
5292 if (no_syslog == 0) {
5293 closelog();
5294 openlog("pure-ftpd", LOG_NDELAY | log_pid, syslog_facility);
5295 }
5296 #endif
5297 doit();
5298 _EXIT(EXIT_SUCCESS);
5299 } else if (child == (pid_t) -1) {
5300 if (nb_children > 0U) {
5301 nb_children--;
5302 }
5303 } else {
5304 if (maxip > 0U) {
5305 iptrack_add(&sa, child);
5306 }
5307 }
5308 (void) close(clientfd);
5309 clientfd = -1;
5310 sigprocmask(SIG_UNBLOCK, &set, NULL);
5311 }
5312
standalone_server(void)5313 static void standalone_server(void)
5314 {
5315 int on;
5316 struct addrinfo hints, *res, *res6;
5317 fd_set rs;
5318 int max_fd;
5319
5320 # ifndef NO_INETD
5321 standalone = 1;
5322 # endif
5323 memset(&hints, 0, sizeof hints);
5324 hints.ai_flags = AI_PASSIVE;
5325 hints.ai_family = AF_INET;
5326 hints.ai_socktype = SOCK_STREAM;
5327 hints.ai_addr = NULL;
5328 on = 1;
5329 if (listenfd == -1 && no_ipv4 == 0 &&
5330 getaddrinfo(standalone_ip, standalone_port, &hints, &res) == 0) {
5331 if ((listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ||
5332 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
5333 (char *) &on, sizeof on) != 0) {
5334 int old_errno;
5335
5336 freeaddrinfo(res);
5337 cant_bind:
5338 old_errno = errno;
5339 perror(MSG_STANDALONE_FAILED);
5340 logfile(LOG_ERR, MSG_STANDALONE_FAILED ": [%s]",
5341 strerror(old_errno));
5342 return;
5343 }
5344 # ifdef TCP_FASTOPEN
5345 {
5346 # ifdef __APPLE__
5347 int tfo = 1;
5348 # else
5349 int tfo = 5;
5350 # endif
5351 setsockopt(listenfd, IPPROTO_TCP, TCP_FASTOPEN,
5352 (void *) &tfo, sizeof tfo);
5353 }
5354 # endif
5355 if (bind(listenfd, res->ai_addr, (socklen_t) res->ai_addrlen) != 0 ||
5356 listen(listenfd, maxusers > 0U ?
5357 3U + maxusers / 8U : DEFAULT_BACKLOG) != 0) {
5358 freeaddrinfo(res);
5359 goto cant_bind;
5360 }
5361 freeaddrinfo(res);
5362 set_cloexec_flag(listenfd);
5363 }
5364 if (listenfd6 == -1 && v6ready != 0) {
5365 hints.ai_family = AF_INET6;
5366 if (getaddrinfo(standalone_ip, standalone_port, &hints, &res6) == 0) {
5367 if ((listenfd6 = socket(AF_INET6,
5368 SOCK_STREAM, IPPROTO_TCP)) == -1 ||
5369 setsockopt(listenfd6, SOL_SOCKET, SO_REUSEADDR,
5370 (char *) &on, sizeof on) != 0) {
5371 freeaddrinfo(res6);
5372 goto cant_bind;
5373 }
5374 # if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
5375 (void) setsockopt(listenfd6, IPPROTO_IPV6, IPV6_V6ONLY,
5376 (char *) &on, sizeof on);
5377 # endif
5378 # ifdef TCP_FASTOPEN
5379 {
5380 int tfo = maxusers > 0U ? 3U + maxusers / 8U : DEFAULT_BACKLOG;
5381 setsockopt(listenfd6, IPPROTO_TCP, TCP_FASTOPEN,
5382 (void *) &tfo, sizeof tfo);
5383 }
5384 # endif
5385 if (bind(listenfd6, res6->ai_addr,
5386 (socklen_t) res6->ai_addrlen) != 0 ||
5387 listen(listenfd6, maxusers > 0U ?
5388 3U + maxusers / 8U : DEFAULT_BACKLOG) != 0) {
5389 freeaddrinfo(res6);
5390 goto cant_bind;
5391 }
5392 freeaddrinfo(res6);
5393 set_cloexec_flag(listenfd6);
5394 }
5395 }
5396 if (listenfd == -1 && listenfd6 == -1) {
5397 # ifdef EADDRNOTAVAIL
5398 errno = EADDRNOTAVAIL;
5399 # endif
5400 goto cant_bind;
5401 }
5402 updatepidfile();
5403 setprocessname("pure-ftpd (SERVER)");
5404 FD_ZERO(&rs);
5405 if (listenfd > listenfd6) {
5406 max_fd = listenfd;
5407 } else {
5408 max_fd = listenfd6;
5409 }
5410 max_fd++;
5411 while (stop_server == 0) {
5412 safe_fd_set(listenfd, &rs);
5413 safe_fd_set(listenfd6, &rs);
5414 if (select(max_fd, &rs, NULL, NULL, NULL) <= 0) {
5415 if (errno != EINTR) {
5416 (void) sleep(1);
5417 }
5418 continue;
5419 }
5420 if (safe_fd_isset(listenfd, &rs)) {
5421 accept_client(listenfd);
5422 }
5423 if (safe_fd_isset(listenfd6, &rs)) {
5424 accept_client(listenfd6);
5425 }
5426 }
5427 }
5428 #endif
5429
5430 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
fakegetpwnam(const char * const name)5431 static struct passwd *fakegetpwnam(const char * const name)
5432 {
5433 static struct passwd pwd;
5434
5435 (void) name;
5436 pwd.pw_name = pwd.pw_gecos = pwd.pw_shell = "ftp";
5437 pwd.pw_passwd = "*";
5438 pwd.pw_uid = (uid_t) 42U;
5439 pwd.pw_gid = (gid_t) 42U;
5440 pwd.pw_dir = WIN32_ANON_DIR;
5441
5442 return &pwd;
5443 }
5444 #endif
5445
5446 #ifndef MINIMAL
sc_special_handler(void ** output_p,const char * arg,void * user_data)5447 static SimpleConfSpecialHandlerResult sc_special_handler(void **output_p,
5448 const char *arg,
5449 void *user_data)
5450 {
5451 struct stat st;
5452 (void) user_data;
5453
5454 if (stat(arg, &st) != 0) {
5455 return SC_SPECIAL_HANDLER_RESULT_NEXT;
5456 }
5457 if ((*output_p = strdup(arg)) == NULL) {
5458 return SC_SPECIAL_HANDLER_RESULT_ERROR;
5459 }
5460 return SC_SPECIAL_HANDLER_RESULT_INCLUDE;
5461 }
5462 #endif
5463
pureftpd_start(int argc,char * argv[],const char * home_directory_)5464 int pureftpd_start(int argc, char *argv[], const char *home_directory_)
5465 {
5466 #ifndef NO_GETOPT_LONG
5467 int option_index = 0;
5468 #endif
5469 int fodder;
5470 int bypass_ipv6 = 0;
5471 struct passwd *pw;
5472
5473 (void) home_directory_;
5474 #ifdef NON_ROOT_FTP
5475 home_directory = home_directory_;
5476 #endif
5477 client_init_reply_buf();
5478
5479 #ifdef HAVE_GETPAGESIZE
5480 page_size = (size_t) getpagesize();
5481 #elif defined(_SC_PAGESIZE)
5482 page_size = (size_t) sysconf(_SC_PAGESIZE);
5483 #elif defined(_SC_PAGE_SIZE)
5484 page_size = (size_t) sysconf(_SC_PAGE_SIZE);
5485 #else
5486 page_size = (size_t) 4096U;
5487 #endif
5488
5489 #ifdef HAVE_SETLOCALE
5490 # ifdef LC_MESSAGES
5491 (void) setlocale(LC_MESSAGES, MESSAGES_LOCALE);
5492 # endif
5493 # ifdef LC_CTYPE
5494 (void) setlocale(LC_CTYPE, "C");
5495 # endif
5496 # ifdef LC_COLLATE
5497 (void) setlocale(LC_COLLATE, "C");
5498 # endif
5499 #endif
5500
5501 init_tz();
5502 (void) strerror(ENOENT);
5503
5504 #ifndef SAVE_DESCRIPTORS
5505 openlog("pure-ftpd", LOG_NDELAY | log_pid, DEFAULT_FACILITY);
5506 #endif
5507
5508 #ifdef USE_CAPABILITIES
5509 set_initial_caps();
5510 #endif
5511 set_signals();
5512
5513 loggedin = 0;
5514
5515 #ifdef BANNER_ENVIRON
5516 # ifdef COOKIE
5517 {
5518 const char *a;
5519
5520 if ((a = getenv("BANNER")) != NULL && *a != 0) {
5521 fortunes_file = strdup(a);
5522 }
5523 }
5524 # endif
5525 #endif
5526
5527 #ifndef MINIMAL
5528 {
5529 static SimpleConfConfig config = { NULL, sc_special_handler };
5530
5531 if (argc == 2 && *argv[1] != '-' &&
5532 sc_build_command_line_from_file(argv[1], &config,
5533 simpleconf_options,
5534 (sizeof simpleconf_options) /
5535 (sizeof simpleconf_options[0]),
5536 argv[0], &argc, &argv) != 0) {
5537 die(421, LOG_ERR, MSG_CONF_ERR);
5538 }
5539 }
5540 #endif
5541
5542 while ((fodder =
5543 #ifndef NO_GETOPT_LONG
5544 getopt_long(argc, argv, GETOPT_OPTIONS, long_options, &option_index)
5545 #else
5546 getopt(argc, argv, GETOPT_OPTIONS)
5547 #endif
5548 ) != -1) {
5549 switch (fodder) {
5550 case 's': {
5551 if ((pw = getpwnam("ftp")) != NULL ||
5552 (pw = getpwnam("_ftp")) != NULL) {
5553 warez = pw->pw_uid;
5554 } else {
5555 logfile(LOG_ERR, MSG_NO_FTP_ACCOUNT);
5556 }
5557 break;
5558 }
5559 case '0': {
5560 no_truncate = 1;
5561 break;
5562 }
5563 case '4': {
5564 bypass_ipv6 = 1;
5565 break;
5566 }
5567 case '6': {
5568 no_ipv4 = 1;
5569 break;
5570 }
5571 case '1': {
5572 log_pid = LOG_PID;
5573 break;
5574 }
5575 #ifndef NO_STANDALONE
5576 case 'S': {
5577 char *struck;
5578
5579 if ((struck = strchr(optarg, ',')) != NULL) {
5580 *struck = 0;
5581 if (*optarg != 0) {
5582 if (standalone_ip == NULL &&
5583 (standalone_ip = strdup(optarg)) == NULL) {
5584 die_mem();
5585 }
5586 }
5587 *struck = ',';
5588 if (struck[1] != 0) {
5589 if ((standalone_port = strdup(struck + 1)) == NULL) {
5590 die_mem();
5591 }
5592 }
5593 } else {
5594 if ((standalone_port = strdup(optarg)) == NULL) {
5595 die_mem();
5596 }
5597 }
5598 break;
5599 }
5600 #endif
5601 case 'D': {
5602 force_ls_a = 1;
5603 break;
5604 }
5605 #ifdef THROTTLING
5606 case 't':
5607 case 'T': {
5608 char *struck;
5609 const char *tr_bw_ul = NULL;
5610 const char *tr_bw_dl = NULL;
5611
5612 if ((struck = strchr(optarg, ':')) != NULL) {
5613 *struck = 0;
5614 if (*optarg != 0) {
5615 tr_bw_ul = optarg;
5616 }
5617 if (struck[1] != 0) {
5618 tr_bw_dl = &struck[1];
5619 }
5620 } else {
5621 tr_bw_ul = tr_bw_dl = optarg;
5622 }
5623 if ((tr_bw_ul == NULL || *tr_bw_ul == 0) &&
5624 (tr_bw_dl == NULL || *tr_bw_dl == 0)) {
5625 bad_bw:
5626 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_THROTTLING ": %s" , optarg);
5627 }
5628 if (tr_bw_dl != NULL) {
5629 if ((throttling_bandwidth_dl =
5630 strtoul(tr_bw_dl, NULL, 0) * 1024UL) == 0UL) {
5631 goto bad_bw;
5632 }
5633 }
5634 if (tr_bw_ul != NULL) {
5635 if ((throttling_bandwidth_ul =
5636 strtoul(tr_bw_ul, NULL, 0) * 1024UL) == 0UL) {
5637 goto bad_bw;
5638 }
5639 }
5640 throttling_delay = 1000000 /
5641 (throttling_bandwidth_dl | throttling_bandwidth_ul);
5642 if (fodder == 't') {
5643 throttling = 1;
5644 } else {
5645 throttling = 2;
5646 }
5647 break;
5648 }
5649 #endif
5650 case 'a': {
5651 const char *nptr;
5652 char *endptr;
5653
5654 nptr = optarg;
5655 endptr = NULL;
5656 chroot_trustedgid = strtoul(nptr, &endptr, 0);
5657 if (!nptr || !*nptr || !endptr || *endptr) {
5658 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_TRUSTED_GID ": %s" , optarg);
5659 }
5660 userchroot = 1;
5661 break;
5662 }
5663 case 'x': {
5664 dot_write_ok = 0;
5665 break;
5666 }
5667 case 'X': {
5668 dot_write_ok = dot_read_ok = 0;
5669 break;
5670 }
5671 case 'z': {
5672 dot_read_anon_ok = 1;
5673 break;
5674 }
5675 case 'Z': {
5676 be_customer_proof = 1;
5677 break;
5678 }
5679 case 'A': {
5680 userchroot = 2;
5681 break;
5682 }
5683 case 'w': {
5684 allowfxp = 1;
5685 break;
5686 }
5687 case 'W': {
5688 allowfxp = 2;
5689 break;
5690 }
5691 case 'd': {
5692 if (logging < 2) {
5693 logging++;
5694 }
5695 break;
5696 }
5697 case 'b': {
5698 broken_client_compat = 1;
5699 break;
5700 }
5701 case 'c': {
5702 const char *nptr;
5703 char *endptr;
5704
5705 nptr = optarg;
5706 endptr = NULL;
5707 maxusers = (unsigned int) strtoul(nptr, &endptr, 0);
5708 if (!nptr || !*nptr || !endptr || *endptr || !maxusers) {
5709 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_USER_LIMIT ": %s" , optarg);
5710 }
5711 break;
5712 }
5713 #ifndef NO_STANDALONE
5714 case 'B': {
5715 daemonize = 1;
5716 break;
5717 }
5718 case 'C': {
5719 const char *nptr;
5720 char *endptr;
5721
5722 nptr = optarg;
5723 endptr = NULL;
5724 maxip = (unsigned int) strtoul(nptr, &endptr, 0);
5725 if (!nptr || !*nptr || !endptr || *endptr || !maxip) {
5726 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_USER_LIMIT ": %s" , optarg);
5727 }
5728 break;
5729 }
5730 #endif
5731 #ifdef PER_USER_LIMITS
5732 case 'y': {
5733 int ret;
5734
5735 ret = sscanf(optarg, "%u:%u", &per_user_max, &per_anon_max);
5736 if (ret != 2) {
5737 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_USER_LIMIT ": %s" , optarg);
5738 }
5739 break;
5740 }
5741 #endif
5742 #ifdef WITH_TLS
5743 case '2': {
5744 char *struck;
5745 char *key_file_;
5746
5747 if ((struck = strchr(optarg, ',')) != NULL) {
5748 *struck = 0;
5749 key_file_ = struck + 1;
5750 } else {
5751 key_file_ = optarg;
5752 }
5753 if (*optarg == 0 || *key_file_ == 0) {
5754 die(421, LOG_ERR, MSG_CONF_ERR ": TLS");
5755 }
5756 if ((cert_file = strdup(optarg)) == NULL) {
5757 die_mem();
5758 }
5759 if ((key_file = strdup(key_file_)) == NULL) {
5760 die_mem();
5761 }
5762 break;
5763 }
5764 case '3':
5765 tls_extcert_parse(optarg);
5766 use_extcert++;
5767 break;
5768 case 'Y': {
5769 if ((enforce_tls_auth = atoi(optarg)) < 0 || enforce_tls_auth > 3) {
5770 die(421, LOG_ERR, MSG_CONF_ERR ": TLS");
5771 }
5772 break;
5773 }
5774 case 'J': {
5775 while (*optarg == '-') {
5776 if (strncmp(optarg, "-S:", sizeof "-S:" - (size_t) 1U) == 0) {
5777 optarg += sizeof "-S:" - (size_t) 1U;
5778 } else if (strncmp(optarg, "-C:", sizeof "-C:" - (size_t) 1U) == 0) {
5779 optarg += sizeof "-C:" - (size_t) 1U;
5780 ssl_verify_client_cert = 1;
5781 }
5782 }
5783 if ((tlsciphersuite = strdup(optarg)) == NULL) {
5784 die_mem();
5785 }
5786 break;
5787 }
5788 #endif
5789 case 'e': {
5790 anon_only = 1;
5791 break;
5792 }
5793 case 'E': {
5794 anon_only = -1;
5795 break;
5796 }
5797 #ifdef COOKIE
5798 case 'F': {
5799 # ifdef BANNER_ENVIRON
5800 free(fortunes_file);
5801 # endif
5802 fortunes_file = strdup(optarg);
5803 break;
5804 }
5805 #endif
5806 case 'f': {
5807 int n = 0;
5808
5809 if (strcasecmp(optarg, "none") == 0) {
5810 no_syslog = 1;
5811 break;
5812 }
5813 while (facilitynames[n].c_name &&
5814 strcasecmp(facilitynames[n].c_name, optarg) != 0) {
5815 n++;
5816 }
5817 if (facilitynames[n].c_name) {
5818 syslog_facility = facilitynames[n].c_val;
5819 } else {
5820 logfile(LOG_ERR,
5821 MSG_CONF_ERR ": " MSG_ILLEGAL_FACILITY ": %s", optarg);
5822 }
5823 break;
5824 }
5825 case 'l': {
5826 const Authentication *auth_list_pnt = auth_list;
5827 const char *opt = optarg;
5828 Authentications *new_auth;
5829 size_t auth_name_len;
5830
5831 for (;;) {
5832 auth_name_len = strlen(auth_list_pnt->name);
5833 if (strncasecmp(opt, auth_list_pnt->name,
5834 auth_name_len) == 0) {
5835 char *file = NULL;
5836
5837 opt += auth_name_len;
5838 if (*opt == ':') {
5839 opt++;
5840 if (*opt != 0) {
5841 if ((file = strdup(opt)) == NULL) {
5842 die_mem();
5843 }
5844 }
5845 }
5846 if (auth_list_pnt->parse != NULL) {
5847 auth_list_pnt->parse(file);
5848 }
5849 if ((new_auth = malloc(sizeof *new_auth)) == NULL) {
5850 die_mem();
5851 }
5852 new_auth->auth = auth_list_pnt;
5853 new_auth->conf_file = file;
5854 new_auth->next = NULL;
5855 if (last_authentications == NULL) {
5856 first_authentications = new_auth;
5857 } else {
5858 last_authentications->next = new_auth;
5859 }
5860 last_authentications = new_auth;
5861
5862 break;
5863 }
5864 auth_list_pnt++;
5865 if (auth_list_pnt->name == NULL) {
5866 die(421, LOG_ERR, MSG_AUTH_UNKNOWN ": %s", opt);
5867 }
5868 }
5869
5870 break;
5871 }
5872 case 'm': {
5873 const char *nptr;
5874 char *endptr;
5875
5876 nptr = optarg;
5877 endptr = NULL;
5878 maxload = strtod(nptr, &endptr);
5879 if (!nptr || !*nptr || !endptr || *endptr || maxload <= 0.0) {
5880 die(421, LOG_ERR, MSG_CONF_ERR ": "
5881 MSG_ILLEGAL_LOAD_LIMIT ": %s" , optarg);
5882 }
5883 break;
5884 }
5885 case 'M': {
5886 allow_anon_mkdir = 1;
5887 break;
5888 }
5889 case 'N': {
5890 disallow_passive = 1;
5891 break;
5892 }
5893 #if defined(WITH_UPLOAD_SCRIPT)
5894 case 'o': {
5895 do_upload_script = 1;
5896 break;
5897 }
5898 #endif
5899 #ifdef WITH_ALTLOG
5900 case 'O': {
5901 char *optarg_copy;
5902 char *delpoint;
5903
5904 if ((optarg_copy = strdup(optarg)) == NULL) {
5905 die_mem();
5906 }
5907 if ((delpoint = strchr(optarg_copy, ALTLOG_DELIMITER)) == NULL) {
5908 altlog_format = ALTLOG_DEFAULT;
5909 delpoint = optarg_copy;
5910 } else {
5911 const AltLogPrefixes *altlogprefixes_pnt = altlogprefixes;
5912
5913 *delpoint++ = 0;
5914 do {
5915 if (strcasecmp(optarg_copy,
5916 altlogprefixes_pnt->prefix) == 0) {
5917 altlog_format = altlogprefixes_pnt->format;
5918 break;
5919 }
5920 altlogprefixes_pnt++;
5921 } while (altlogprefixes_pnt->prefix != NULL);
5922 if (altlog_format == ALTLOG_NONE) {
5923 die(421, LOG_ERR,
5924 MSG_CONF_ERR ": " MSG_UNKNOWN_ALTLOG ": %s",
5925 optarg_copy);
5926 }
5927 }
5928 if (*delpoint != '/') {
5929 die(421, LOG_ERR,
5930 MSG_CONF_ERR ": " MSG_SANITY_FILE_FAILURE,
5931 delpoint);
5932 }
5933 if (altlog_filename == NULL &&
5934 (altlog_filename = strdup(delpoint)) == NULL) {
5935 die_mem();
5936 }
5937 (void) free(optarg_copy);
5938 break;
5939 }
5940 #endif
5941 case 'p': {
5942 int ret;
5943
5944 ret = sscanf(optarg, "%u:%u", &firstport, &lastport);
5945 if (ret != 2 ||
5946 firstport < 1024U || lastport > 65535U
5947 || lastport < firstport) {
5948 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_PORTS_RANGE ": %s" , optarg);
5949 }
5950 break;
5951 }
5952 case 'L': {
5953 int ret;
5954
5955 ret = sscanf(optarg, "%u:%u", &max_ls_files, &max_ls_depth);
5956 if (ret != 2 ||
5957 max_ls_files < 1U || max_ls_depth < 1U) {
5958 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_LS_LIMITS ": %s" , optarg);
5959 }
5960 break;
5961 }
5962 #ifdef QUOTAS
5963 case 'n': {
5964 int ret;
5965
5966 ret = sscanf(optarg, "%llu:%llu",
5967 &user_quota_files, &user_quota_size);
5968 if (ret != 2) {
5969 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_QUOTA ": %s" , optarg);
5970 }
5971 user_quota_size *= (1024ULL * 1024ULL);
5972 break;
5973 }
5974 #endif
5975 case 'P': {
5976 if (force_passive_ip_s == NULL &&
5977 (force_passive_ip_s = strdup(optarg)) == NULL) {
5978 die_mem();
5979 }
5980 break;
5981 }
5982 #ifdef RATIOS
5983 case 'q':
5984 case 'Q': {
5985 int ret;
5986
5987 ret = sscanf(optarg, "%u:%u", &ratio_upload, &ratio_download);
5988 if (ret != 2 ||
5989 ratio_upload < 1U || ratio_download < 1U) {
5990 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_RATIO ": %s" , optarg);
5991 }
5992 if (fodder == 'Q') {
5993 ratio_for_non_anon = 1;
5994 }
5995 break;
5996 }
5997 #endif
5998 case 'r': {
5999 autorename = 1;
6000 break;
6001 }
6002 case 'R': {
6003 nochmod = 1;
6004 break;
6005 }
6006 case 'K': {
6007 keepallfiles = 1;
6008 break;
6009 }
6010 #ifndef NO_STANDALONE
6011 case 'g': {
6012 if ((pid_file = strdup(optarg)) == NULL) {
6013 die_mem();
6014 }
6015 break;
6016 }
6017 #endif
6018 case 'G': {
6019 disallow_rename = 1;
6020 break;
6021 }
6022 case 'H': {
6023 resolve_hostnames = 0;
6024 break;
6025 }
6026 case 'I': {
6027 const char *nptr;
6028 char *endptr;
6029
6030 nptr = optarg;
6031 endptr = NULL;
6032 idletime = strtoul(nptr, &endptr, 0) * 60UL;
6033 if (idletime <= 0) {
6034 idletime = DEFAULT_IDLE;
6035 }
6036 break;
6037 }
6038 case 'i': {
6039 anon_noupload = 1;
6040 break;
6041 }
6042 case 'j': {
6043 create_home = 1;
6044 break;
6045 }
6046 case 'k': {
6047 const char *nptr;
6048 char *endptr;
6049
6050 nptr = optarg;
6051 endptr = NULL;
6052 maxdiskusagepct = 1.0 - (strtod(nptr, &endptr) / 100.0);
6053 if (maxdiskusagepct >= 1.0 || maxdiskusagepct < 0.0) {
6054 maxdiskusagepct = 0.0;
6055 }
6056 break;
6057 }
6058 case 'u': {
6059 const char *nptr;
6060 char *endptr;
6061 long tmp;
6062
6063 nptr = optarg;
6064 endptr = NULL;
6065 tmp = strtol(nptr, &endptr, 10);
6066 if (!nptr || !*nptr || !endptr || *endptr || tmp < 0) {
6067 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_UID_LIMIT ": %s" , optarg);
6068 }
6069 useruid = (uid_t) tmp;
6070 break;
6071 }
6072 case 'U': {
6073 char *optarg_copy;
6074 char *struck;
6075 const char *tr_umask = NULL;
6076 const char *tr_umask_d = NULL;
6077
6078 if ((optarg_copy = strdup(optarg)) == NULL) {
6079 die_mem();
6080 }
6081 if ((struck = strchr(optarg_copy, ':')) != NULL) {
6082 *struck = 0;
6083 if (*optarg_copy != 0) {
6084 tr_umask = optarg_copy;
6085 }
6086 if (struck[1] != 0) {
6087 tr_umask_d = &struck[1];
6088 }
6089 } else {
6090 tr_umask = tr_umask_d = optarg_copy;
6091 }
6092 if ((tr_umask == NULL || *tr_umask == 0) &&
6093 (tr_umask_d == NULL || *tr_umask_d == 0)) {
6094 bad_umask:
6095 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_UMASK ": %s",
6096 optarg_copy);
6097 }
6098 if (tr_umask != NULL) {
6099 if ((u_mask =
6100 strtoul(tr_umask, NULL, 8)) > 0777) {
6101 goto bad_umask;
6102 }
6103 }
6104 if (tr_umask_d != NULL) {
6105 if ((u_mask_d =
6106 strtoul(tr_umask_d, NULL, 8)) > 0777) {
6107 goto bad_umask;
6108 }
6109 }
6110 (void) free(optarg_copy);
6111 break;
6112 }
6113 #ifdef WITH_VIRTUAL_HOSTS
6114 case 'V': {
6115 if (trustedip == NULL &&
6116 (trustedip = malloc(sizeof *trustedip)) == NULL) {
6117 die_mem();
6118 }
6119 if (generic_aton(optarg, trustedip) != 0) {
6120 die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_TRUSTED_IP);
6121 }
6122 break;
6123 }
6124 #endif
6125 #ifdef WITH_BONJOUR
6126 case 'v': {
6127 char *rdvname;
6128 char *end;
6129
6130 if ((rdvname = strdup(optarg)) == NULL) {
6131 die_mem();
6132 }
6133 doregistration(rdvname, strtoul(standalone_port, &end, 10));
6134 break;
6135 }
6136 #endif
6137 case 'h': {
6138 #ifndef NON_ROOT_FTP
6139 if (geteuid() == (uid_t) 0)
6140 #endif
6141 {
6142 puts(PACKAGE " v" VERSION VERSION_PRIVSEP "\n");
6143 }
6144 #ifndef NO_GETOPT_LONG
6145 {
6146 const struct option *options = long_options;
6147
6148 do {
6149 printf("-%c\t--%s\t%s\n", options->val, options->name,
6150 options->has_arg ? "<opt>" : "");
6151 options++;
6152 } while (options->name != NULL);
6153 }
6154 #endif
6155 exit(EXIT_SUCCESS);
6156 }
6157 default:
6158 die(421, LOG_ERR, MSG_ILLEGAL_OPTION);
6159 }
6160 }
6161 if (optind < argc) {
6162 die(421, LOG_ERR, MSG_INVALID_ARGUMENT, argv[optind]);
6163 }
6164 if (first_authentications == NULL) {
6165 if ((first_authentications =
6166 malloc(sizeof *first_authentications)) == NULL) {
6167 die_mem();
6168 }
6169 first_authentications->auth = DEFAULT_AUTHENTICATION;
6170 first_authentications->conf_file = NULL;
6171 first_authentications->next = NULL;
6172 }
6173 #ifndef NO_STANDALONE
6174 dodaemonize();
6175 #endif
6176 #ifndef SAVE_DESCRIPTORS
6177 if (no_syslog == 0 && (log_pid || syslog_facility != DEFAULT_FACILITY)) {
6178 closelog();
6179 openlog("pure-ftpd", LOG_NDELAY | log_pid, syslog_facility);
6180 }
6181 #endif
6182 (void) umask((mode_t) 0);
6183 clearargs(argc, argv);
6184 idletime_noop = (double) idletime * 2.0;
6185 if (firstport) {
6186 unsigned int portmax;
6187
6188 portmax = (lastport - firstport + 1) / 2;
6189 if (!maxusers || maxusers > portmax) {
6190 maxusers = portmax; /* ... so we don't run out of ports */
6191 }
6192 }
6193 if (bypass_ipv6 == 0) {
6194 check_ipv6_support();
6195 }
6196 #if defined(WITH_UPLOAD_SCRIPT)
6197 if (do_upload_script != 0) {
6198 upload_pipe_open();
6199 }
6200 #endif
6201 #ifdef WITH_DIRALIASES
6202 if (init_aliases() != 0) {
6203 logfile(LOG_ERR, MSG_ALIASES_BROKEN_FILE);
6204 }
6205 #endif
6206 #ifdef WITH_TLS
6207 if (enforce_tls_auth > 0) {
6208 (void) tls_init_library();
6209 }
6210 #endif
6211 #if !defined(NO_STANDALONE) && !defined(NO_INETD)
6212 if (check_standalone() != 0) {
6213 standalone_server();
6214 } else {
6215 doit();
6216 }
6217 #elif !defined(NO_STANDALONE) && defined(NO_INETD)
6218 standalone_server();
6219 #elif defined(NO_STANDALONE) && !defined(NO_INETD)
6220 doit();
6221 #else
6222 # error Configuration error
6223 #endif
6224
6225 #ifdef WITH_UPLOAD_SCRIPT
6226 upload_pipe_close();
6227 #endif
6228 {
6229 Authentications *auth_scan = first_authentications;
6230 Authentications *previous;
6231
6232 while (auth_scan != NULL) {
6233 if (auth_scan->auth->exit != NULL) {
6234 auth_scan->auth->exit();
6235 }
6236 free(auth_scan->conf_file);
6237 previous = auth_scan;
6238 auth_scan = auth_scan->next;
6239 free(previous);
6240 }
6241 }
6242 first_authentications = last_authentications = NULL;
6243 free(trustedip);
6244 #ifndef NO_STANDALONE
6245 iptrack_free();
6246 unlink(pid_file);
6247 #endif
6248 closelog();
6249 #ifdef WITH_TLS
6250 tls_free_library();
6251 tls_extcert_exit();
6252 free((void *) client_sni_name);
6253 #endif
6254 alt_arc4random_close();
6255
6256 _EXIT(EXIT_SUCCESS);
6257
6258 return 0;
6259 }
6260