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(&quota, 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(&quota, -1LL,
2696                              -((long long) st.st_size), NULL) == 0) {
2697                 displayquota(&quota);
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(&quota, 1LL, 0LL, &overflow) == 0 && overflow != 0) {
3431         (void) quota_update(&quota, -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(&quota, -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(&quota);
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(&quota, -1LL, 0LL, NULL) == 0) {
3474             displayquota(&quota);
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(&quota, 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(&quota, -1, (long long) -file_size, NULL);
3684         }
3685     }
3686     displayquota(&quota);
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(&quota, 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