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