1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 1997, 1998 Public Flood Software
4  * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver@tos.net>
5  * Copyright (c) 2001-2020 The ProFTPD Project team
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
20  *
21  * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
22  * and other respective copyright holders give permission to link this program
23  * with OpenSSL, and distribute the resulting executable, without including
24  * the source code for OpenSSL in the source distribution.
25  */
26 
27 /* Various basic support routines for ProFTPD, used by all modules
28  * and not specific to one or another.
29  */
30 
31 #include "conf.h"
32 
33 #ifdef PR_USE_OPENSSL
34 # include <openssl/crypto.h>
35 #endif /* PR_USE_OPENSSL */
36 
37 /* Keep a counter of the number of times signals_block()/signals_unblock()
38  * have been called, to handle nesting of calls.
39  */
40 static unsigned int sigs_nblocked = 0;
41 
42 typedef struct sched_obj {
43   struct sched_obj *next, *prev;
44 
45   pool *pool;
46   void (*cb)(void *, void *, void *, void *);
47   int nloops;
48   void *arg1, *arg2, *arg3, *arg4;
49 } sched_t;
50 
51 static xaset_t *scheds = NULL;
52 
53 /* Masks/unmasks all important signals (as opposed to blocking alarms)
54  */
mask_signals(unsigned char block)55 static void mask_signals(unsigned char block) {
56   static sigset_t mask_sigset;
57 
58   if (block) {
59     sigemptyset(&mask_sigset);
60 
61     sigaddset(&mask_sigset, SIGTERM);
62     sigaddset(&mask_sigset, SIGCHLD);
63     sigaddset(&mask_sigset, SIGUSR1);
64     sigaddset(&mask_sigset, SIGINT);
65     sigaddset(&mask_sigset, SIGQUIT);
66     sigaddset(&mask_sigset, SIGALRM);
67 #ifdef SIGIO
68     sigaddset(&mask_sigset, SIGIO);
69 #endif
70 #ifdef SIGBUS
71     sigaddset(&mask_sigset, SIGBUS);
72 #endif
73     sigaddset(&mask_sigset, SIGHUP);
74 
75     if (sigprocmask(SIG_BLOCK, &mask_sigset, NULL) < 0) {
76       pr_log_pri(PR_LOG_NOTICE,
77         "unable to block signal set: %s", strerror(errno));
78     }
79 
80   } else {
81     if (sigprocmask(SIG_UNBLOCK, &mask_sigset, NULL) < 0) {
82       pr_log_pri(PR_LOG_NOTICE,
83         "unable to unblock signal set: %s", strerror(errno));
84     }
85   }
86 }
87 
pr_signals_block(void)88 void pr_signals_block(void) {
89   if (sigs_nblocked == 0) {
90     mask_signals(TRUE);
91     pr_trace_msg("signal", 5, "signals blocked");
92 
93   } else {
94     pr_trace_msg("signal", 9, "signals already blocked (block count = %u)",
95       sigs_nblocked);
96   }
97 
98   sigs_nblocked++;
99 }
100 
pr_signals_unblock(void)101 void pr_signals_unblock(void) {
102   if (sigs_nblocked == 0) {
103     pr_trace_msg("signal", 5, "signals already unblocked");
104     return;
105   }
106 
107   if (sigs_nblocked == 1) {
108     mask_signals(FALSE);
109     pr_trace_msg("signal", 5, "signals unblocked");
110 
111   } else {
112     pr_trace_msg("signal", 9, "signals already unblocked (block count = %u)",
113       sigs_nblocked);
114   }
115 
116   sigs_nblocked--;
117 }
118 
schedule(void (* cb)(void *,void *,void *,void *),int nloops,void * arg1,void * arg2,void * arg3,void * arg4)119 void schedule(void (*cb)(void *, void *, void *, void *), int nloops,
120     void *arg1, void *arg2, void *arg3, void *arg4) {
121   pool *p, *sub_pool;
122   sched_t *s;
123 
124   if (cb == NULL ||
125       nloops < 0) {
126     return;
127   }
128 
129   if (scheds == NULL) {
130     p = make_sub_pool(permanent_pool);
131     pr_pool_tag(p, "Schedules Pool");
132     scheds = xaset_create(p, NULL);
133 
134   } else {
135     p = scheds->pool;
136   }
137 
138   sub_pool = make_sub_pool(p);
139   pr_pool_tag(sub_pool, "schedule pool");
140 
141   s = pcalloc(sub_pool, sizeof(sched_t));
142   s->pool = sub_pool;
143   s->cb = cb;
144   s->arg1 = arg1;
145   s->arg2 = arg2;
146   s->arg3 = arg3;
147   s->arg4 = arg4;
148   s->nloops = nloops;
149   xaset_insert(scheds, (xasetmember_t *) s);
150 }
151 
run_schedule(void)152 void run_schedule(void) {
153   sched_t *s, *snext;
154 
155   if (scheds == NULL ||
156       scheds->xas_list == NULL) {
157     return;
158   }
159 
160   for (s = (sched_t *) scheds->xas_list; s; s = snext) {
161     snext = s->next;
162 
163     pr_signals_handle();
164 
165     if (s->nloops-- <= 0) {
166       s->cb(s->arg1, s->arg2, s->arg3, s->arg4);
167       xaset_remove(scheds, (xasetmember_t *) s);
168       destroy_pool(s->pool);
169     }
170   }
171 }
172 
173 /* Get the maximum size of a file name (pathname component).
174  * If a directory file descriptor, e.g. the d_fd DIR structure element,
175  * is not available, the second argument should be 0.
176  *
177  * Note: a POSIX compliant system typically should NOT define NAME_MAX,
178  * since the value almost certainly varies across different file system types.
179  * Refer to POSIX 1003.1a, Section 2.9.5, Table 2-5.
180  * Alas, current (Jul 2000) Linux systems define NAME_MAX anyway.
181  * NB: NAME_MAX_GUESS is defined in support.h.
182  */
183 
get_fpathconf_name_max(int fd,long * name_max)184 static int get_fpathconf_name_max(int fd, long *name_max) {
185 #if defined(HAVE_FPATHCONF)
186   *name_max = fpathconf(fd, _PC_NAME_MAX);
187   return 0;
188 #else
189   errno = ENOSYS;
190   return -1;
191 #endif /* HAVE_FPATHCONF */
192 }
193 
get_pathconf_name_max(char * dir,long * name_max)194 static int get_pathconf_name_max(char *dir, long *name_max) {
195 #if defined(HAVE_PATHCONF)
196   *name_max = pathconf(dir, _PC_NAME_MAX);
197   return 0;
198 #else
199   errno = ENOSYS;
200   return -1;
201 #endif /* HAVE_PATHCONF */
202 }
203 
get_name_max(char * dir_name,int dir_fd)204 long get_name_max(char *dir_name, int dir_fd) {
205   int res;
206   long name_max = 0;
207 
208   if (dir_name == NULL &&
209       dir_fd < 0) {
210     errno = EINVAL;
211     return -1;
212   }
213 
214   /* Try the fd first. */
215   if (dir_fd >= 0) {
216     res = get_fpathconf_name_max(dir_fd, &name_max);
217     if (res == 0) {
218       if (name_max < 0) {
219         int xerrno = errno;
220 
221         pr_log_debug(DEBUG5, "fpathconf() error for fd %d: %s", dir_fd,
222           strerror(xerrno));
223 
224         errno = xerrno;
225         return -1;
226       }
227 
228       return name_max;
229     }
230   }
231 
232   /* Name, then. */
233   if (dir_name != NULL) {
234     res = get_pathconf_name_max(dir_name, &name_max);
235     if (res == 0) {
236       if (name_max < 0) {
237         int xerrno = errno;
238 
239         pr_log_debug(DEBUG5, "pathconf() error for name '%s': %s", dir_name,
240           strerror(xerrno));
241 
242         errno = xerrno;
243         return -1;
244       }
245 
246       return name_max;
247     }
248   }
249 
250   errno = ENOSYS;
251   return -1;
252 }
253 
254 /* Interpolates a pathname, expanding ~ notation if necessary
255  */
dir_interpolate(pool * p,const char * path)256 char *dir_interpolate(pool *p, const char *path) {
257   char *res = NULL;
258 
259   if (p == NULL ||
260       path == NULL) {
261     errno = EINVAL;
262     return NULL;
263   }
264 
265   if (*path == '~') {
266     char *ptr, *user;
267     struct passwd *pw;
268 
269     user = pstrdup(p, path + 1);
270     ptr = strchr(user, '/');
271     if (ptr != NULL) {
272       *ptr++ = '\0';
273     }
274 
275     if (!*user) {
276       user = (char *) session.user;
277     }
278 
279     pw = pr_auth_getpwnam(p, user);
280     if (pw == NULL) {
281       errno = ENOENT;
282       return NULL;
283     }
284 
285     res = pdircat(p, pw->pw_dir, ptr, NULL);
286 
287   } else {
288     res = pstrdup(p, path);
289   }
290 
291   return res;
292 }
293 
294 /* dir_best_path() creates the "most" fully canonicalized path possible
295  * (i.e. if path components at the end don't exist, they are ignored).
296  */
dir_best_path(pool * p,const char * path)297 char *dir_best_path(pool *p, const char *path) {
298   char workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
299   char realpath_buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
300   char *target = NULL, *ntarget;
301   int fini = 0;
302 
303   if (p == NULL ||
304       path == NULL) {
305     errno = EINVAL;
306     return NULL;
307   }
308 
309   if (*path == '~') {
310     if (pr_fs_interpolate(path, workpath, sizeof(workpath)-1) != 1) {
311       if (pr_fs_dircat(workpath, sizeof(workpath), pr_fs_getcwd(), path) < 0) {
312         return NULL;
313       }
314     }
315 
316   } else {
317     if (pr_fs_dircat(workpath, sizeof(workpath), pr_fs_getcwd(), path) < 0) {
318       return NULL;
319     }
320   }
321 
322   pr_fs_clean_path(pstrdup(p, workpath), workpath, sizeof(workpath)-1);
323 
324   while (!fini && *workpath) {
325     if (pr_fs_resolve_path(workpath, realpath_buf,
326         sizeof(realpath_buf)-1, 0) != -1) {
327       break;
328     }
329 
330     ntarget = strrchr(workpath, '/');
331     if (ntarget) {
332       if (target) {
333         if (pr_fs_dircat(workpath, sizeof(workpath), workpath, target) < 0) {
334           return NULL;
335         }
336       }
337 
338       target = ntarget;
339       *target++ = '\0';
340 
341     } else {
342       fini++;
343     }
344   }
345 
346   if (!fini && *workpath) {
347     if (target) {
348       if (pr_fs_dircat(workpath, sizeof(workpath), realpath_buf, target) < 0) {
349         return NULL;
350       }
351 
352     } else {
353       sstrncpy(workpath, realpath_buf, sizeof(workpath));
354     }
355 
356   } else {
357     if (pr_fs_dircat(workpath, sizeof(workpath), "/", target) < 0) {
358       return NULL;
359     }
360   }
361 
362   return pstrdup(p, workpath);
363 }
364 
dir_canonical_path(pool * p,const char * path)365 char *dir_canonical_path(pool *p, const char *path) {
366   char buf[PR_TUNABLE_PATH_MAX + 1]  = {'\0'};
367   char work[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
368 
369   if (p == NULL ||
370       path == NULL) {
371     errno = EINVAL;
372     return NULL;
373   }
374 
375   if (*path == '~') {
376     if (pr_fs_interpolate(path, work, sizeof(work)-1) != 1) {
377       if (pr_fs_dircat(work, sizeof(work), pr_fs_getcwd(), path) < 0) {
378         return NULL;
379       }
380     }
381 
382   } else {
383     if (pr_fs_dircat(work, sizeof(work), pr_fs_getcwd(), path) < 0) {
384       return NULL;
385     }
386   }
387 
388   pr_fs_clean_path(work, buf, sizeof(buf)-1);
389   return pstrdup(p, buf);
390 }
391 
dir_canonical_vpath(pool * p,const char * path)392 char *dir_canonical_vpath(pool *p, const char *path) {
393   char buf[PR_TUNABLE_PATH_MAX + 1]  = {'\0'};
394   char work[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
395 
396   if (p == NULL ||
397       path == NULL) {
398     errno = EINVAL;
399     return NULL;
400   }
401 
402   if (*path == '~') {
403     if (pr_fs_interpolate(path, work, sizeof(work)-1) != 1) {
404       if (pr_fs_dircat(work, sizeof(work), pr_fs_getvwd(), path) < 0) {
405         return NULL;
406       }
407     }
408 
409   } else {
410     if (pr_fs_dircat(work, sizeof(work), pr_fs_getvwd(), path) < 0) {
411       return NULL;
412     }
413   }
414 
415   pr_fs_clean_path(work, buf, sizeof(buf)-1);
416   return pstrdup(p, buf);
417 }
418 
419 /* Performs chroot-aware handling of symlinks. */
dir_readlink(pool * p,const char * path,char * buf,size_t bufsz,int flags)420 int dir_readlink(pool *p, const char *path, char *buf, size_t bufsz,
421     int flags) {
422   int is_abs_dst, clean_flags, len, res = -1;
423   size_t chroot_pathlen = 0, adj_pathlen = 0;
424   char *dst_path, *adj_path;
425   pool *tmp_pool;
426 
427   if (p == NULL ||
428       path == NULL ||
429       buf == NULL) {
430     errno = EINVAL;
431     return -1;
432   }
433 
434   if (bufsz == 0) {
435     return 0;
436   }
437 
438   len = pr_fsio_readlink(path, buf, bufsz);
439   if (len < 0) {
440     return -1;
441   }
442 
443   pr_trace_msg("fsio", 9,
444     "dir_readlink() read link '%.*s' for path '%s'", (int) len, buf, path);
445 
446   if (len == 0 ||
447       (size_t) len == bufsz) {
448     /* If we read nothing in, OR if the given buffer was completely
449      * filled WITHOUT terminating NUL, there's really nothing we can/should
450      * be doing.
451      */
452     return len;
453   }
454 
455   is_abs_dst = FALSE;
456   if (*buf == '/') {
457     is_abs_dst = TRUE;
458   }
459 
460   if (session.chroot_path != NULL) {
461     chroot_pathlen = strlen(session.chroot_path);
462   }
463 
464   if (chroot_pathlen <= 1) {
465     char *ptr;
466 
467     if (is_abs_dst == TRUE ||
468         !(flags & PR_DIR_READLINK_FL_HANDLE_REL_PATH)) {
469       return len;
470     }
471 
472     /* Since we have a relative destination path, we will concat it
473      * with the source path's directory, then clean up that path.
474      */
475     ptr = strrchr(path, '/');
476     if (ptr != NULL &&
477         ptr != path) {
478       char *parent_dir;
479 
480       tmp_pool = make_sub_pool(p);
481       pr_pool_tag(tmp_pool, "dir_readlink pool");
482 
483       parent_dir = pstrndup(tmp_pool, path, (ptr - path));
484       dst_path = pdircat(tmp_pool, parent_dir, buf, NULL);
485 
486       adj_pathlen = bufsz + 1;
487       adj_path = pcalloc(tmp_pool, adj_pathlen);
488 
489       res = pr_fs_clean_path2(dst_path, adj_path, adj_pathlen-1, 0);
490       if (res == 0) {
491         pr_trace_msg("fsio", 19,
492           "cleaned symlink path '%s', yielding '%s'", dst_path, adj_path);
493         dst_path = adj_path;
494       }
495 
496       pr_trace_msg("fsio", 19,
497         "adjusted relative symlink path '%s', yielding '%s'", buf, dst_path);
498 
499       memset(buf, '\0', bufsz);
500       sstrncpy(buf, dst_path, bufsz);
501       len = strlen(buf);
502       destroy_pool(tmp_pool);
503     }
504 
505     return len;
506   }
507 
508   if (is_abs_dst == FALSE) {
509     /* If we are to ignore relative destination paths, return now. */
510     if (!(flags & PR_DIR_READLINK_FL_HANDLE_REL_PATH)) {
511       return len;
512     }
513   }
514 
515   if (is_abs_dst == TRUE &&
516       (size_t) len < chroot_pathlen) {
517     /* If the destination path length is shorter than the chroot path,
518      * AND the destination path is absolute, then by definition it CANNOT
519      * point within the chroot.
520      */
521     return len;
522   }
523 
524   tmp_pool = make_sub_pool(p);
525   pr_pool_tag(tmp_pool, "dir_readlink pool");
526 
527   dst_path = pstrdup(tmp_pool, buf);
528   if (is_abs_dst == FALSE) {
529     char *ptr;
530 
531     /* Since we have a relative destination path, we will concat it
532      * with the source path's directory, then clean up that path.
533      */
534 
535     ptr = strrchr(path, '/');
536     if (ptr != NULL) {
537       if (ptr != path) {
538         char *parent_dir;
539 
540         parent_dir = pstrndup(tmp_pool, path, (ptr - path));
541         dst_path = pdircat(tmp_pool, parent_dir, dst_path, NULL);
542 
543       } else {
544         dst_path = pdircat(tmp_pool, "/", dst_path, NULL);
545       }
546     }
547   }
548 
549   adj_pathlen = bufsz + 1;
550   adj_path = pcalloc(tmp_pool, adj_pathlen);
551 
552   clean_flags = PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH;
553   res = pr_fs_clean_path2(dst_path, adj_path, adj_pathlen-1, clean_flags);
554   if (res == 0) {
555     pr_trace_msg("fsio", 19,
556       "cleaned symlink path '%s', yielding '%s'", dst_path, adj_path);
557     dst_path = adj_path;
558 
559     memset(buf, '\0', bufsz);
560     sstrncpy(buf, dst_path, bufsz);
561     len = strlen(dst_path);
562   }
563 
564   if (strncmp(dst_path, session.chroot_path, chroot_pathlen) == 0 &&
565       *(dst_path + chroot_pathlen) == '/') {
566     char *ptr;
567 
568     ptr = dst_path + chroot_pathlen;
569 
570     if (is_abs_dst == FALSE &&
571         res == 0) {
572       /* If we originally had a relative destination path, AND we cleaned
573        * that adjusted path, then we should try to re-adjust the path
574        * back to being a relative path.  Within reason.
575        */
576       ptr = pstrcat(tmp_pool, ".", ptr, NULL);
577     }
578 
579     /* Since we are making the destination path shorter, the given buffer
580      * (which was big enough for the original destination path) should
581      * always be large enough for this adjusted, shorter version.  Right?
582      */
583     pr_trace_msg("fsio", 19,
584       "adjusted symlink path '%s' for chroot '%s', yielding '%s'",
585       dst_path, session.chroot_path, ptr);
586 
587     memset(buf, '\0', bufsz);
588     sstrncpy(buf, ptr, bufsz);
589     len = strlen(buf);
590   }
591 
592   destroy_pool(tmp_pool);
593   return len;
594 }
595 
596 /* dir_realpath() is needed to properly dereference symlinks (getcwd() may
597  * not work if permissions cause problems somewhere up the tree).
598  */
dir_realpath(pool * p,const char * path)599 char *dir_realpath(pool *p, const char *path) {
600   char buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
601 
602   if (p == NULL ||
603       path == NULL) {
604     errno = EINVAL;
605     return NULL;
606   }
607 
608   if (pr_fs_resolve_partial(path, buf, sizeof(buf)-1, 0) < 0) {
609     return NULL;
610   }
611 
612   return pstrdup(p, buf);
613 }
614 
615 /* Takes a directory and returns its absolute version.  ~username references
616  * are appropriately interpolated.  "Absolute" includes a _full_ reference
617  * based on the root directory, not upon a chrooted dir.
618  */
dir_abs_path(pool * p,const char * path,int interpolate)619 char *dir_abs_path(pool *p, const char *path, int interpolate) {
620   char *res = NULL;
621 
622   if (p == NULL ||
623       path == NULL) {
624     errno = EINVAL;
625     return NULL;
626   }
627 
628   if (interpolate) {
629     char buf[PR_TUNABLE_PATH_MAX+1];
630 
631     memset(buf, '\0', sizeof(buf));
632     switch (pr_fs_interpolate(path, buf, sizeof(buf)-1)) {
633       case -1:
634         return NULL;
635 
636       case 0:
637         /* Do nothing; path exists */
638         break;
639 
640       case 1:
641         /* Interpolation occurred; make a copy of the interpolated path. */
642         path = pstrdup(p, buf);
643         break;
644     }
645   }
646 
647   if (*path != '/') {
648     if (session.chroot_path) {
649       res = pdircat(p, session.chroot_path, pr_fs_getcwd(), path, NULL);
650 
651     } else {
652       res = pdircat(p, pr_fs_getcwd(), path, NULL);
653     }
654 
655   } else {
656     if (session.chroot_path) {
657       if (strncmp(path, session.chroot_path,
658           strlen(session.chroot_path)) != 0) {
659         res = pdircat(p, session.chroot_path, path, NULL);
660 
661       } else {
662         res = pstrdup(p, path);
663       }
664 
665     } else {
666       res = pstrdup(p, path);
667     }
668   }
669 
670   return res;
671 }
672 
673 /* Return the mode (including the file type) of the file pointed to by symlink
674  * PATH, or 0 if it doesn't exist. Catch symlink loops using LAST_INODE and
675  * RCOUNT.
676  */
_symlink(pool * p,const char * path,ino_t last_inode,int rcount)677 static mode_t _symlink(pool *p, const char *path, ino_t last_inode,
678     int rcount) {
679   char buf[PR_TUNABLE_PATH_MAX + 1];
680   struct stat st;
681   int i;
682 
683   if (++rcount >= PR_FSIO_MAX_LINK_COUNT) {
684     errno = ELOOP;
685     return 0;
686   }
687 
688   memset(buf, '\0', sizeof(buf));
689 
690   if (p != NULL) {
691     i = dir_readlink(p, path, buf, sizeof(buf)-1,
692       PR_DIR_READLINK_FL_HANDLE_REL_PATH);
693   } else {
694     i = pr_fsio_readlink(path, buf, sizeof(buf)-1);
695   }
696 
697   if (i < 0) {
698     return (mode_t) 0;
699   }
700   buf[i] = '\0';
701 
702   pr_fs_clear_cache2(buf);
703   if (pr_fsio_lstat(buf, &st) >= 0) {
704     if (st.st_ino > 0 &&
705         (ino_t) st.st_ino == last_inode) {
706       errno = ELOOP;
707       return 0;
708     }
709 
710     if (S_ISLNK(st.st_mode)) {
711       return _symlink(p, buf, (ino_t) st.st_ino, rcount);
712     }
713 
714     return st.st_mode;
715   }
716 
717   return 0;
718 }
719 
symlink_mode2(pool * p,const char * path)720 mode_t symlink_mode2(pool *p, const char *path) {
721   if (path == NULL) {
722     errno = EINVAL;
723     return 0;
724   }
725 
726   return _symlink(p, path, (ino_t) 0, 0);
727 }
728 
symlink_mode(const char * path)729 mode_t symlink_mode(const char *path) {
730   return symlink_mode2(NULL, path);
731 }
732 
file_mode2(pool * p,const char * path)733 mode_t file_mode2(pool *p, const char *path) {
734   struct stat st;
735   mode_t mode = 0;
736 
737   if (path == NULL) {
738     errno = EINVAL;
739     return mode;
740   }
741 
742   pr_fs_clear_cache2(path);
743   if (pr_fsio_lstat(path, &st) >= 0) {
744     if (S_ISLNK(st.st_mode)) {
745       mode = _symlink(p, path, (ino_t) 0, 0);
746       if (mode == 0) {
747 	/* a dangling symlink, but it exists to rename or delete. */
748 	mode = st.st_mode;
749       }
750 
751     } else {
752       mode = st.st_mode;
753     }
754   }
755 
756   return mode;
757 }
758 
file_mode(const char * path)759 mode_t file_mode(const char *path) {
760   return file_mode2(NULL, path);
761 }
762 
763 /* If flags == 1, fail unless PATH is an existing directory.
764  * If flags == 0, fail unless PATH is an existing non-directory.
765  * If flags == -1, fail unless PATH exists; the caller doesn't care whether
766  * PATH is a file or a directory.
767  */
_exists(pool * p,const char * path,int flags)768 static int _exists(pool *p, const char *path, int flags) {
769   mode_t mode;
770 
771   mode = file_mode2(p, path);
772   if (mode != 0) {
773     switch (flags) {
774       case 1:
775         if (!S_ISDIR(mode)) {
776           return FALSE;
777         }
778         break;
779 
780       case 0:
781         if (S_ISDIR(mode)) {
782           return FALSE;
783         }
784         break;
785 
786       default:
787         break;
788     }
789 
790     return TRUE;
791   }
792 
793   return FALSE;
794 }
795 
file_exists2(pool * p,const char * path)796 int file_exists2(pool *p, const char *path) {
797   return _exists(p, path, 0);
798 }
799 
file_exists(const char * path)800 int file_exists(const char *path) {
801   return file_exists2(NULL, path);
802 }
803 
dir_exists2(pool * p,const char * path)804 int dir_exists2(pool *p, const char *path) {
805   return _exists(p, path, 1);
806 }
807 
dir_exists(const char * path)808 int dir_exists(const char *path) {
809   return dir_exists2(NULL, path);
810 }
811 
exists2(pool * p,const char * path)812 int exists2(pool *p, const char *path) {
813   return _exists(p, path, -1);
814 }
815 
exists(const char * path)816 int exists(const char *path) {
817   return exists2(NULL, path);
818 }
819 
820 /* safe_token tokenizes a string, and increments the pointer to
821  * the next non-white space character.  It's "safe" because it
822  * never returns NULL, only an empty string if no token remains
823  * in the source string.
824  */
safe_token(char ** s)825 char *safe_token(char **s) {
826   char *res = "";
827 
828   if (s == NULL ||
829       !*s) {
830     return res;
831   }
832 
833   while (PR_ISSPACE(**s) && **s) {
834     (*s)++;
835   }
836 
837   if (**s) {
838     res = *s;
839 
840     while (!PR_ISSPACE(**s) && **s) {
841       (*s)++;
842     }
843 
844     if (**s) {
845       *(*s)++ = '\0';
846     }
847 
848     while (PR_ISSPACE(**s) && **s) {
849       (*s)++;
850     }
851   }
852 
853   return res;
854 }
855 
856 /* Checks for the existence of PR_SHUTMSG_PATH.  deny and disc are
857  * filled with the times to deny new connections and disconnect
858  * existing ones.
859  */
check_shutmsg(pool * p,const char * path,time_t * shut,time_t * deny,time_t * disc,char * msg,size_t msg_size)860 int check_shutmsg(pool *p, const char *path, time_t *shut, time_t *deny,
861     time_t *disc, char *msg, size_t msg_size) {
862   FILE *fp;
863   char *deny_str, *disc_str, *cp, buf[PR_TUNABLE_BUFFER_SIZE+1] = {'\0'};
864   char hr[3] = {'\0'}, mn[3] = {'\0'};
865   time_t now, shuttime = (time_t) 0;
866   struct stat st;
867   struct tm *tm;
868 
869   if (path == NULL) {
870     errno = EINVAL;
871     return -1;
872   }
873 
874   fp = fopen(path, "r");
875   if (fp == NULL) {
876     return -1;
877   }
878 
879   if (fstat(fileno(fp), &st) == 0) {
880     if (S_ISDIR(st.st_mode)) {
881       fclose(fp);
882       errno = EISDIR;
883       return -1;
884     }
885   }
886 
887   cp = fgets(buf, sizeof(buf), fp);
888   if (cp != NULL) {
889     buf[sizeof(buf)-1] = '\0'; CHOP(cp);
890 
891     /* We use this to fill in dst, timezone, etc */
892     time(&now);
893     tm = pr_localtime(p, &now);
894     if (tm == NULL) {
895       fclose(fp);
896       return 0;
897     }
898 
899     tm->tm_year = atoi(safe_token(&cp)) - 1900;
900     tm->tm_mon = atoi(safe_token(&cp)) - 1;
901     tm->tm_mday = atoi(safe_token(&cp));
902     tm->tm_hour = atoi(safe_token(&cp));
903     tm->tm_min = atoi(safe_token(&cp));
904     tm->tm_sec = atoi(safe_token(&cp));
905 
906     deny_str = safe_token(&cp);
907     disc_str = safe_token(&cp);
908 
909     shuttime = mktime(tm);
910     if (shuttime == (time_t) -1) {
911       fclose(fp);
912       return 0;
913     }
914 
915     if (deny != NULL) {
916       if (strlen(deny_str) == 4) {
917         sstrncpy(hr, deny_str, sizeof(hr));
918         hr[2] = '\0';
919         deny_str += 2;
920 
921         sstrncpy(mn, deny_str, sizeof(mn));
922         mn[2] = '\0';
923 
924         *deny = shuttime - ((atoi(hr) * 3600) + (atoi(mn) * 60));
925 
926       } else {
927         *deny = shuttime;
928       }
929     }
930 
931     if (disc != NULL) {
932       if (strlen(disc_str) == 4) {
933         sstrncpy(hr, disc_str, sizeof(hr));
934         hr[2] = '\0';
935         disc_str += 2;
936 
937         sstrncpy(mn, disc_str, sizeof(mn));
938         mn[2] = '\0';
939 
940         *disc = shuttime - ((atoi(hr) * 3600) + (atoi(mn) * 60));
941 
942       } else {
943         *disc = shuttime;
944       }
945     }
946 
947     if (fgets(buf, sizeof(buf), fp) && msg) {
948       buf[sizeof(buf)-1] = '\0';
949       CHOP(buf);
950       sstrncpy(msg, buf, msg_size-1);
951     }
952   }
953 
954   fclose(fp);
955 
956   if (shut != NULL) {
957     *shut = shuttime;
958   }
959 
960   return 1;
961 }
962 
963 #if !defined(PR_USE_OPENSSL) || OPENSSL_VERSION_NUMBER <= 0x000907000L
964 /* "safe" memset() (code borrowed from OpenSSL).  This function should be
965  * used to clear/scrub sensitive memory areas instead of memset() for the
966  * reasons mentioned in this BugTraq thread:
967  *
968  *  http://online.securityfocus.com/archive/1/298598
969  */
970 
971 static unsigned char memscrub_ctr = 0;
972 #endif
973 
pr_memscrub(void * ptr,size_t ptrlen)974 void pr_memscrub(void *ptr, size_t ptrlen) {
975 #if defined(PR_USE_OPENSSL) && OPENSSL_VERSION_NUMBER > 0x000907000L
976   if (ptr == NULL ||
977       ptrlen == 0) {
978     return;
979   }
980 
981   /* Just use OpenSSL's function for this.  They have optimized it for
982    * performance in later OpenSSL releases.
983    */
984   OPENSSL_cleanse(ptr, ptrlen);
985 
986 #else
987   unsigned char *p;
988   size_t loop;
989 
990   if (ptr == NULL ||
991       ptrlen == 0) {
992     return;
993   }
994 
995   p = ptr;
996   loop = ptrlen;
997 
998   while (loop--) {
999     *(p++) = memscrub_ctr++;
1000     memscrub_ctr += (17 + (unsigned char)((intptr_t) p & 0xF));
1001   }
1002 
1003   if (memchr(ptr, memscrub_ctr, ptrlen)) {
1004     memscrub_ctr += 63;
1005   }
1006 #endif
1007 }
1008 
pr_getopt_reset(void)1009 void pr_getopt_reset(void) {
1010 #if defined(FREEBSD4) || defined(FREEBSD5) || defined(FREEBSD6) || \
1011     defined(FREEBSD7) || defined(FREEBSD8) || defined(FREEBSD9) || \
1012     defined(FREEBSD10) || defined(FREEBSD11) || \
1013     defined(DARWIN7) || defined(DARWIN8) || defined(DARWIN9) || \
1014     defined(DARWIN10) || defined(DARWIN11) || defined(DARWIN12) || \
1015     defined(DARWIN13) || defined(DARWIN14) || defined(DARWIN15) || \
1016     defined(DARWIN16) || defined(DARWIN17) || defined(DARWIN18)
1017   optreset = 1;
1018   opterr = 1;
1019   optind = 1;
1020 
1021 #elif defined(SOLARIS2) || defined(HPUX11)
1022   opterr = 0;
1023   optind = 1;
1024 
1025 #else
1026   opterr = 0;
1027   optind = 0;
1028 #endif /* !FreeBSD, !Mac OSX and !Solaris2 */
1029 
1030   if (pr_env_get(permanent_pool, "POSIXLY_CORRECT") == NULL) {
1031     pr_env_set(permanent_pool, "POSIXLY_CORRECT", "1");
1032   }
1033 }
1034 
pr_gmtime(pool * p,const time_t * now)1035 struct tm *pr_gmtime(pool *p, const time_t *now) {
1036   struct tm *sys_tm, *dup_tm;
1037 
1038   if (now == NULL) {
1039     errno = EINVAL;
1040     return NULL;
1041   }
1042 
1043 #if defined(HAVE_GMTIME_R)
1044   if (p == NULL) {
1045     errno = EINVAL;
1046     return NULL;
1047   }
1048 
1049   sys_tm = gmtime_r(now, pcalloc(p, sizeof(struct tm)));
1050 #else
1051   sys_tm = gmtime(now);
1052 #endif /* HAVE_GMTIME_R */
1053   if (sys_tm == NULL) {
1054     return NULL;
1055   }
1056 
1057   /* If the caller provided a pool, make a copy of the struct tm using that
1058    * pool.  Otherwise, return the struct tm as is.
1059    */
1060   if (p != NULL) {
1061     dup_tm = pcalloc(p, sizeof(struct tm));
1062     memcpy(dup_tm, sys_tm, sizeof(struct tm));
1063 
1064   } else {
1065     dup_tm = sys_tm;
1066   }
1067 
1068   return dup_tm;
1069 }
1070 
pr_localtime(pool * p,const time_t * now)1071 struct tm *pr_localtime(pool *p, const time_t *now) {
1072   struct tm *sys_tm, *dup_tm;
1073 
1074 #ifdef HAVE_TZNAME
1075   char *tzname_dup[2];
1076 
1077   /* The localtime(3) function has a nasty habit of changing the tzname
1078    * global variable as a side-effect.  This can cause problems, as when
1079    * the process has become chrooted, and localtime(3) sets/changes
1080    * tzname wrong.  (For more information on the tzname global variable,
1081    * see the tzset(3) man page.)
1082    *
1083    * The best way to deal with this issue (which is especially prominent
1084    * on systems running glibc-2.3 or later, which is particularly ill-behaved
1085    * in a chrooted environment, as it assumes the ability to find system
1086    * timezone files at paths which are no longer valid within the chroot)
1087    * is to set the TZ environment variable explicitly, before starting
1088    * proftpd.  You can also use the SetEnv configuration directive within
1089    * the proftpd.conf to set the TZ environment variable, e.g.:
1090    *
1091    *  SetEnv TZ PST
1092    *
1093    * To try to help sites which fail to do this, the tzname global variable
1094    * will be copied prior to the localtime(3) call, and the copy restored
1095    * after the call.  (Note that calling the ctime(3) and mktime(3)
1096    * functions also causes a similar overwriting/setting of the tzname
1097    * environment variable.)
1098    *
1099    * This hack is also used in the lib/pr-syslog.c code, to work around
1100    * mktime(3) antics.
1101    */
1102   memcpy(&tzname_dup, tzname, sizeof(tzname_dup));
1103 #endif /* HAVE_TZNAME */
1104 
1105   if (now == NULL) {
1106     errno = EINVAL;
1107     return NULL;
1108   }
1109 
1110 #if defined(HAVE_LOCALTIME_R)
1111   if (p == NULL) {
1112     errno = EINVAL;
1113     return NULL;
1114   }
1115 
1116   sys_tm = localtime_r(now, pcalloc(p, sizeof(struct tm)));
1117 #else
1118   sys_tm = localtime(now);
1119 #endif /* HAVE_LOCALTIME_R */
1120   if (sys_tm == NULL) {
1121     return NULL;
1122   }
1123 
1124   if (p != NULL) {
1125     /* If the caller provided a pool, make a copy of the returned
1126      * struct tm, allocated out of that pool.
1127      */
1128     dup_tm = pcalloc(p, sizeof(struct tm));
1129     memcpy(dup_tm, sys_tm, sizeof(struct tm));
1130 
1131   } else {
1132 
1133     /* Other callers do not require pool-allocated copies, and instead
1134      * are happy with the struct tm as is.
1135      */
1136     dup_tm = sys_tm;
1137   }
1138 
1139 #if defined(HAVE_TZNAME)
1140   /* Restore the old tzname values prior to returning. */
1141   memcpy(tzname, tzname_dup, sizeof(tzname_dup));
1142 #endif /* HAVE_TZNAME */
1143 
1144   return dup_tm;
1145 }
1146 
pr_strtime(time_t t)1147 const char *pr_strtime(time_t t) {
1148   return pr_strtime2(t, FALSE);
1149 }
1150 
pr_strtime2(time_t t,int use_gmtime)1151 const char *pr_strtime2(time_t t, int use_gmtime) {
1152   return pr_strtime3(NULL, t, use_gmtime);
1153 }
1154 
pr_strtime3(pool * p,time_t t,int use_gmtime)1155 const char *pr_strtime3(pool *p, time_t t, int use_gmtime) {
1156   static char buf[64];
1157   static char *mons[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
1158     "Aug", "Sep", "Oct", "Nov", "Dec" };
1159   static char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1160   struct tm *tr;
1161 
1162   memset(buf, '\0', sizeof(buf));
1163 
1164   if (use_gmtime) {
1165     tr = pr_gmtime(p, &t);
1166 
1167   } else {
1168     tr = pr_localtime(p, &t);
1169   }
1170 
1171   if (tr == NULL) {
1172     return NULL;
1173   }
1174 
1175   pr_snprintfl(__FILE__, __LINE__, buf, sizeof(buf),
1176     "%s %s %02d %02d:%02d:%02d %d", days[tr->tm_wday], mons[tr->tm_mon],
1177     tr->tm_mday, tr->tm_hour, tr->tm_min, tr->tm_sec, tr->tm_year + 1900);
1178   buf[sizeof(buf)-1] = '\0';
1179 
1180   if (p != NULL) {
1181     return pstrdup(p, buf);
1182   }
1183 
1184   return buf;
1185 }
1186 
pr_timeval2millis(struct timeval * tv,uint64_t * millis)1187 int pr_timeval2millis(struct timeval *tv, uint64_t *millis) {
1188   if (tv == NULL ||
1189       millis == NULL) {
1190     errno = EINVAL;
1191     return -1;
1192   }
1193 
1194   /* Make sure to use 64-bit multiplication to avoid overflow errors,
1195    * as much as we can.
1196    */
1197   *millis = (tv->tv_sec * (uint64_t) 1000) + (tv->tv_usec / (uint64_t) 1000);
1198   return 0;
1199 }
1200 
pr_gettimeofday_millis(uint64_t * millis)1201 int pr_gettimeofday_millis(uint64_t *millis) {
1202   struct timeval tv;
1203 
1204   if (gettimeofday(&tv, NULL) < 0) {
1205     return -1;
1206   }
1207 
1208   if (pr_timeval2millis(&tv, millis) < 0) {
1209     return -1;
1210   }
1211 
1212   return 0;
1213 }
1214 
pr_vsnprintfl(const char * file,int lineno,char * buf,size_t bufsz,const char * fmt,va_list msg)1215 int pr_vsnprintfl(const char *file, int lineno, char *buf, size_t bufsz,
1216     const char *fmt, va_list msg) {
1217   int res, xerrno = 0;
1218 
1219   if (buf == NULL ||
1220       fmt == NULL) {
1221     errno = EINVAL;
1222     return -1;
1223   }
1224 
1225   if (bufsz == 0) {
1226     return 0;
1227   }
1228 
1229   res = vsnprintf(buf, bufsz, fmt, msg);
1230   xerrno = errno;
1231 
1232   if (res < 0) {
1233     /* Unexpected error. */
1234 
1235 #ifdef EOVERFLOW
1236     if (xerrno == EOVERFLOW) {
1237       xerrno = ENOSPC;
1238     }
1239 #endif /* EOVERFLOW */
1240 
1241   } else if ((size_t) res >= bufsz) {
1242     /* Buffer too small. */
1243     xerrno = ENOSPC;
1244     res = -1;
1245   }
1246 
1247   /* We are mostly concerned with tracking down the locations of truncated
1248    * buffers, hence the stacktrace logging only for these conditions.
1249    */
1250   if (res < 0 &&
1251       xerrno == ENOSPC) {
1252     if (file != NULL &&
1253         lineno > 0) {
1254       pr_log_pri(PR_LOG_WARNING,
1255         "%s:%d: error writing format string '%s' into %lu-byte buffer: %s",
1256         file, lineno, fmt, (unsigned long) bufsz, strerror(xerrno));
1257 
1258     } else {
1259       pr_log_pri(PR_LOG_WARNING,
1260         "error writing format string '%s' into %lu-byte buffer: %s", fmt,
1261         (unsigned long) bufsz, strerror(xerrno));
1262     }
1263 
1264     pr_log_stacktrace(-1, NULL);
1265   }
1266 
1267   errno = xerrno;
1268   return res;
1269 }
1270 
pr_vsnprintf(char * buf,size_t bufsz,const char * fmt,va_list msg)1271 int pr_vsnprintf(char *buf, size_t bufsz, const char *fmt, va_list msg) {
1272   return pr_vsnprintfl(NULL, -1, buf, bufsz, fmt, msg);
1273 }
1274 
pr_snprintfl(const char * file,int lineno,char * buf,size_t bufsz,const char * fmt,...)1275 int pr_snprintfl(const char *file, int lineno, char *buf, size_t bufsz,
1276     const char *fmt, ...) {
1277   va_list msg;
1278   int res;
1279 
1280   va_start(msg, fmt);
1281   res = pr_vsnprintfl(file, lineno, buf, bufsz, fmt, msg);
1282   va_end(msg);
1283 
1284   return res;
1285 }
1286 
pr_snprintf(char * buf,size_t bufsz,const char * fmt,...)1287 int pr_snprintf(char *buf, size_t bufsz, const char *fmt, ...) {
1288   va_list msg;
1289   int res;
1290 
1291   va_start(msg, fmt);
1292   res = pr_vsnprintfl(NULL, -1, buf, bufsz, fmt, msg);
1293   va_end(msg);
1294 
1295   return res;
1296 }
1297 
1298 /* Substitute any appearance of the %u variable in the given string with
1299  * the value.
1300  */
path_subst_uservar(pool * path_pool,const char ** path)1301 const char *path_subst_uservar(pool *path_pool, const char **path) {
1302   const char *new_path = NULL, *substr_path = NULL;
1303   char *substr = NULL;
1304   size_t user_len = 0;
1305 
1306   /* Sanity check. */
1307   if (path_pool == NULL ||
1308       path == NULL ||
1309       !*path) {
1310     errno = EINVAL;
1311     return NULL;
1312   }
1313 
1314   /* If no %u string present, do nothing. */
1315   if (strstr(*path, "%u") == NULL) {
1316     return *path;
1317   }
1318 
1319   /* Same if there is no user set yet. */
1320   if (session.user == NULL) {
1321     return *path;
1322   }
1323 
1324   user_len = strlen(session.user);
1325 
1326   /* First, deal with occurrences of "%u[index]" strings.  Note that
1327    * with this syntax, the '[' and ']' characters become invalid in paths,
1328    * but only if that '[' appears after a "%u" string -- certainly not
1329    * a common phenomenon (I hope).  This means that in the future, an escape
1330    * mechanism may be needed in this function.  Caveat emptor.
1331    */
1332 
1333   substr_path = *path;
1334   substr = substr_path ? strstr(substr_path, "%u[") : NULL;
1335   while (substr != NULL) {
1336     long i = 0;
1337     char *substr_end = NULL, *substr_dup = NULL, *endp = NULL;
1338     char ref_char[2] = {'\0', '\0'};
1339 
1340     pr_signals_handle();
1341 
1342     /* Now, find the closing ']'. If not found, it is a syntax error;
1343      * continue on without processing this occurrence.
1344      */
1345     substr_end = strchr(substr, ']');
1346     if (substr_end == NULL) {
1347       /* Just end here. */
1348       break;
1349     }
1350 
1351     /* Make a copy of the entire substring. */
1352     substr_dup = pstrdup(path_pool, substr);
1353 
1354     /* The substr_end variable (used as an index) should work here, too
1355      * (trying to obtain the entire substring).
1356      */
1357     substr_dup[substr_end - substr + 1] = '\0';
1358 
1359     /* Advance the substring pointer by three characters, so that it is
1360      * pointing at the character after the '['.
1361      */
1362     substr += 3;
1363 
1364     /* If the closing ']' is the next character after the opening '[', it
1365      * is a syntax error.
1366      */
1367     if (*substr == ']') {
1368       substr_path = *path;
1369       break;
1370     }
1371 
1372     /* Temporarily set the ']' to '\0', to make it easy for the string
1373      * scanning below.
1374      */
1375     *substr_end = '\0';
1376 
1377     /* Scan the index string into a number, watching for bad strings. */
1378     i = strtol(substr, &endp, 10);
1379     if (endp && *endp) {
1380       *substr_end = ']';
1381       pr_trace_msg("auth", 3,
1382         "invalid index number syntax found in '%s', ignoring", substr);
1383       return *path;
1384     }
1385 
1386     /* Make sure that index is within bounds. */
1387     if (i < 0 ||
1388         (size_t) i > user_len - 1) {
1389 
1390       /* Put the closing ']' back. */
1391       *substr_end = ']';
1392 
1393       if (i < 0) {
1394         pr_trace_msg("auth", 3,
1395           "out-of-bounds index number (%ld) found in '%s', ignoring", i,
1396           substr);
1397 
1398       } else {
1399         pr_trace_msg("auth", 3,
1400           "out-of-bounds index number (%ld > %lu) found in '%s', ignoring", i,
1401           (unsigned long) user_len-1, substr);
1402       }
1403 
1404       return *path;
1405     }
1406 
1407     ref_char[0] = session.user[i];
1408 
1409     /* Put the closing ']' back. */
1410     *substr_end = ']';
1411 
1412     /* Now, to substitute the whole "%u[index]" substring with the
1413      * referenced character/string.
1414      */
1415     substr_path = sreplace(path_pool, substr_path, substr_dup, ref_char, NULL);
1416     substr = substr_path ? strstr(substr_path, "%u[") : NULL;
1417   }
1418 
1419   /* Check for any bare "%u", and handle those if present. */
1420   if (substr_path &&
1421       strstr(substr_path, "%u") != NULL) {
1422     new_path = sreplace(path_pool, substr_path, "%u", session.user, NULL);
1423 
1424   } else {
1425     new_path = substr_path;
1426   }
1427 
1428   return new_path;
1429 }
1430 
1431