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
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 /* ProFTPD virtual/modular file-system support */
28
29 #include "error.h"
30 #include "conf.h"
31 #include "privs.h"
32
33 #ifdef HAVE_SYS_STATVFS_H
34 # include <sys/statvfs.h>
35 #endif
36
37 #ifdef HAVE_SYS_VFS_H
38 # include <sys/vfs.h>
39 #endif
40
41 #ifdef HAVE_SYS_PARAM_H
42 # include <sys/param.h>
43 #endif
44
45 #ifdef HAVE_SYS_MOUNT_H
46 # include <sys/mount.h>
47 #endif
48
49 #ifdef AIX3
50 # include <sys/statfs.h>
51 #endif
52
53 #ifdef HAVE_ACL_LIBACL_H
54 # include <acl/libacl.h>
55 #endif
56
57 /* We will reset timers in the progress callback every Nth iteration of the
58 * callback when copying a file.
59 */
60 static size_t copy_iter_count = 0;
61
62 #ifndef COPY_PROGRESS_NTH_ITER
63 # define COPY_PROGRESS_NTH_ITER 50000
64 #endif
65
66 /* For determining whether a file is on an NFS filesystem. Note that
67 * this value is Linux specific. See Bug#3874 for details.
68 */
69 #ifndef NFS_SUPER_MAGIC
70 # define NFS_SUPER_MAGIC 0x6969
71 #endif
72
73 #if defined(__FreeBSD__)
74 #include <dlfcn.h>
75 #endif
76
77 typedef struct fsopendir fsopendir_t;
78
79 struct fsopendir {
80 fsopendir_t *next,*prev;
81
82 /* pool for this object's use */
83 pool *pool;
84
85 pr_fs_t *fsdir;
86 DIR *dir;
87 };
88
89 static pr_fs_t *root_fs = NULL, *fs_cwd = NULL;
90 static array_header *fs_map = NULL;
91
92 static fsopendir_t *fsopendir_list;
93
94 static void *fs_cache_dir = NULL;
95 static pr_fs_t *fs_cache_fsdir = NULL;
96
97 /* Internal flag set whenever a new pr_fs_t has been added or removed, and
98 * cleared once the fs_map has been scanned
99 */
100 static unsigned char chk_fs_map = FALSE;
101
102 /* Virtual working directory */
103 static char vwd[PR_TUNABLE_PATH_MAX + 1] = "/";
104
105 static char cwd[PR_TUNABLE_PATH_MAX + 1] = "/";
106 static size_t cwd_len = 1;
107
108 static int fsio_guard_chroot = FALSE;
109 static unsigned long fsio_opts = 0UL;
110
111 /* Runtime enabling/disabling of mkdtemp(3) use. */
112 #ifdef HAVE_MKDTEMP
113 static int fsio_use_mkdtemp = TRUE;
114 #else
115 static int fsio_use_mkdtemp = FALSE;
116 #endif /* HAVE_MKDTEMP */
117
118 /* Runtime enabling/disabling of encoding of paths. */
119 static int use_encoding = TRUE;
120
121 static const char *trace_channel = "fsio";
122
123 /* Guard against attacks like "Roaring Beast" when we are chrooted. See:
124 *
125 * https://auscert.org.au/15286
126 * https://auscert.org.au/15526
127 *
128 * Currently, we guard the /etc and /lib directories.
129 */
chroot_allow_path(const char * path)130 static int chroot_allow_path(const char *path) {
131 size_t path_len;
132 int res = 0;
133
134 /* Note: we expect to get (and DO get) the absolute path here. Should that
135 * ever not be the case, this check will not work.
136 */
137
138 path_len = strlen(path);
139 if (path_len < 4) {
140 /* Path is not long enough to include one of the guarded directories. */
141 return 0;
142 }
143
144 if (path_len == 4) {
145 if (strcmp(path, "/etc") == 0 ||
146 strcmp(path, "/lib") == 0) {
147 res = -1;
148 }
149
150 } else {
151 if (strncmp(path, "/etc/", 5) == 0 ||
152 strncmp(path, "/lib/", 5) == 0) {
153 res = -1;
154 }
155 }
156
157 if (res < 0) {
158 pr_trace_msg(trace_channel, 1, "rejecting path '%s' within chroot '%s'",
159 path, session.chroot_path);
160 pr_log_debug(DEBUG2,
161 "WARNING: attempt to use sensitive path '%s' within chroot '%s', "
162 "rejecting", path, session.chroot_path);
163
164 errno = EACCES;
165 }
166
167 return res;
168 }
169
170 /* Builtin/default "progress" callback for long-running file copies. */
copy_progress_cb(int nwritten)171 static void copy_progress_cb(int nwritten) {
172 int res;
173
174 copy_iter_count++;
175 if ((copy_iter_count % COPY_PROGRESS_NTH_ITER) != 0) {
176 return;
177 }
178
179 /* Reset some of the Timeouts which might interfere, i.e. TimeoutIdle and
180 * TimeoutNoDataTransfer.
181 */
182
183 res = pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
184 if (res < 0) {
185 pr_trace_msg(trace_channel, 14, "error resetting TimeoutIdle timer: %s",
186 strerror(errno));
187 }
188
189 res = pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
190 if (res < 0) {
191 pr_trace_msg(trace_channel, 14,
192 "error resetting TimeoutNoTransfer timer: %s", strerror(errno));
193 }
194
195 res = pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
196 if (res < 0) {
197 pr_trace_msg(trace_channel, 14,
198 "error resetting TimeoutStalled timer: %s", strerror(errno));
199 }
200 }
201
202 /* The following static functions are simply wrappers for system functions
203 */
204
sys_stat(pr_fs_t * fs,const char * path,struct stat * sbuf)205 static int sys_stat(pr_fs_t *fs, const char *path, struct stat *sbuf) {
206 return stat(path, sbuf);
207 }
208
sys_fstat(pr_fh_t * fh,int fd,struct stat * sbuf)209 static int sys_fstat(pr_fh_t *fh, int fd, struct stat *sbuf) {
210 return fstat(fd, sbuf);
211 }
212
sys_lstat(pr_fs_t * fs,const char * path,struct stat * sbuf)213 static int sys_lstat(pr_fs_t *fs, const char *path, struct stat *sbuf) {
214 return lstat(path, sbuf);
215 }
216
sys_rename(pr_fs_t * fs,const char * rnfm,const char * rnto)217 static int sys_rename(pr_fs_t *fs, const char *rnfm, const char *rnto) {
218 int res;
219
220 if (fsio_guard_chroot) {
221 res = chroot_allow_path(rnfm);
222 if (res < 0) {
223 return -1;
224 }
225
226 res = chroot_allow_path(rnto);
227 if (res < 0) {
228 return -1;
229 }
230 }
231
232 res = rename(rnfm, rnto);
233 return res;
234 }
235
sys_unlink(pr_fs_t * fs,const char * path)236 static int sys_unlink(pr_fs_t *fs, const char *path) {
237 int res;
238
239 if (fsio_guard_chroot) {
240 res = chroot_allow_path(path);
241 if (res < 0) {
242 return -1;
243 }
244 }
245
246 res = unlink(path);
247 return res;
248 }
249
sys_open(pr_fh_t * fh,const char * path,int flags)250 static int sys_open(pr_fh_t *fh, const char *path, int flags) {
251 int res;
252
253 #ifdef O_BINARY
254 /* On Cygwin systems, we need the open(2) equivalent of fopen(3)'s "b"
255 * option. Cygwin defines an O_BINARY flag for this purpose.
256 */
257 flags |= O_BINARY;
258 #endif
259
260 if (fsio_guard_chroot) {
261 /* If we are creating (or truncating) a file, then we need to check.
262 * Note: should O_RDWR be added to this list?
263 */
264 if (flags & (O_APPEND|O_CREAT|O_TRUNC|O_WRONLY)) {
265 res = chroot_allow_path(path);
266 if (res < 0) {
267 return -1;
268 }
269 }
270 }
271
272 res = open(path, flags, PR_OPEN_MODE);
273 return res;
274 }
275
sys_close(pr_fh_t * fh,int fd)276 static int sys_close(pr_fh_t *fh, int fd) {
277 return close(fd);
278 }
279
sys_pread(pr_fh_t * fh,int fd,void * buf,size_t sz,off_t offset)280 static ssize_t sys_pread(pr_fh_t *fh, int fd, void *buf, size_t sz,
281 off_t offset) {
282 #if defined(HAVE_PREAD)
283 return pread(fd, buf, sz, offset);
284 #else
285 /* XXX Provide an implementation using lseek+read+lseek */
286 errno = ENOSYS;
287 return -1;
288 #endif /* HAVE_PREAD */
289 }
290
sys_read(pr_fh_t * fh,int fd,char * buf,size_t size)291 static int sys_read(pr_fh_t *fh, int fd, char *buf, size_t size) {
292 return read(fd, buf, size);
293 }
294
sys_pwrite(pr_fh_t * fh,int fd,const void * buf,size_t sz,off_t offset)295 static ssize_t sys_pwrite(pr_fh_t *fh, int fd, const void *buf, size_t sz,
296 off_t offset) {
297 #if defined(HAVE_PWRITE)
298 return pwrite(fd, buf, sz, offset);
299 #else
300 /* XXX Provide an implementation using lseek+write+lseek */
301 errno = ENOSYS;
302 return -1;
303 #endif /* HAVE_PWRITE */
304 }
305
sys_write(pr_fh_t * fh,int fd,const char * buf,size_t size)306 static int sys_write(pr_fh_t *fh, int fd, const char *buf, size_t size) {
307 return write(fd, buf, size);
308 }
309
sys_lseek(pr_fh_t * fh,int fd,off_t offset,int whence)310 static off_t sys_lseek(pr_fh_t *fh, int fd, off_t offset, int whence) {
311 return lseek(fd, offset, whence);
312 }
313
sys_link(pr_fs_t * fs,const char * target_path,const char * link_path)314 static int sys_link(pr_fs_t *fs, const char *target_path,
315 const char *link_path) {
316 int res;
317
318 if (fsio_guard_chroot) {
319 res = chroot_allow_path(link_path);
320 if (res < 0) {
321 return -1;
322 }
323 }
324
325 res = link(target_path, link_path);
326 return res;
327 }
328
sys_symlink(pr_fs_t * fs,const char * target_path,const char * link_path)329 static int sys_symlink(pr_fs_t *fs, const char *target_path,
330 const char *link_path) {
331 int res;
332
333 if (fsio_guard_chroot) {
334 res = chroot_allow_path(link_path);
335 if (res < 0) {
336 return -1;
337 }
338 }
339
340 res = symlink(target_path, link_path);
341 return res;
342 }
343
sys_readlink(pr_fs_t * fs,const char * path,char * buf,size_t buflen)344 static int sys_readlink(pr_fs_t *fs, const char *path, char *buf,
345 size_t buflen) {
346 return readlink(path, buf, buflen);
347 }
348
sys_ftruncate(pr_fh_t * fh,int fd,off_t len)349 static int sys_ftruncate(pr_fh_t *fh, int fd, off_t len) {
350 return ftruncate(fd, len);
351 }
352
sys_truncate(pr_fs_t * fs,const char * path,off_t len)353 static int sys_truncate(pr_fs_t *fs, const char *path, off_t len) {
354 int res;
355
356 if (fsio_guard_chroot) {
357 res = chroot_allow_path(path);
358 if (res < 0) {
359 return -1;
360 }
361 }
362
363 res = truncate(path, len);
364 return res;
365 }
366
sys_chmod(pr_fs_t * fs,const char * path,mode_t mode)367 static int sys_chmod(pr_fs_t *fs, const char *path, mode_t mode) {
368 int res;
369
370 if (fsio_guard_chroot) {
371 res = chroot_allow_path(path);
372 if (res < 0) {
373 return -1;
374 }
375 }
376
377 res = chmod(path, mode);
378 return res;
379 }
380
sys_fchmod(pr_fh_t * fh,int fd,mode_t mode)381 static int sys_fchmod(pr_fh_t *fh, int fd, mode_t mode) {
382 return fchmod(fd, mode);
383 }
384
sys_chown(pr_fs_t * fs,const char * path,uid_t uid,gid_t gid)385 static int sys_chown(pr_fs_t *fs, const char *path, uid_t uid, gid_t gid) {
386 int res;
387
388 if (fsio_guard_chroot) {
389 res = chroot_allow_path(path);
390 if (res < 0) {
391 return -1;
392 }
393 }
394
395 res = chown(path, uid, gid);
396 return res;
397 }
398
sys_fchown(pr_fh_t * fh,int fd,uid_t uid,gid_t gid)399 static int sys_fchown(pr_fh_t *fh, int fd, uid_t uid, gid_t gid) {
400 return fchown(fd, uid, gid);
401 }
402
sys_lchown(pr_fs_t * fs,const char * path,uid_t uid,gid_t gid)403 static int sys_lchown(pr_fs_t *fs, const char *path, uid_t uid, gid_t gid) {
404 int res;
405
406 if (fsio_guard_chroot) {
407 res = chroot_allow_path(path);
408 if (res < 0) {
409 return -1;
410 }
411 }
412
413 res = lchown(path, uid, gid);
414 return res;
415 }
416
417 /* We provide our own equivalent of access(2) here, rather than using
418 * access(2) directly, because access(2) uses the real IDs, rather than
419 * the effective IDs, of the process.
420 */
sys_access(pr_fs_t * fs,const char * path,int mode,uid_t uid,gid_t gid,array_header * suppl_gids)421 static int sys_access(pr_fs_t *fs, const char *path, int mode, uid_t uid,
422 gid_t gid, array_header *suppl_gids) {
423 struct stat st;
424
425 if (pr_fsio_stat(path, &st) < 0) {
426 return -1;
427 }
428
429 return pr_fs_have_access(&st, mode, uid, gid, suppl_gids);
430 }
431
sys_faccess(pr_fh_t * fh,int mode,uid_t uid,gid_t gid,array_header * suppl_gids)432 static int sys_faccess(pr_fh_t *fh, int mode, uid_t uid, gid_t gid,
433 array_header *suppl_gids) {
434 return sys_access(fh->fh_fs, fh->fh_path, mode, uid, gid, suppl_gids);
435 }
436
sys_utimes(pr_fs_t * fs,const char * path,struct timeval * tvs)437 static int sys_utimes(pr_fs_t *fs, const char *path, struct timeval *tvs) {
438 int res;
439
440 if (fsio_guard_chroot) {
441 res = chroot_allow_path(path);
442 if (res < 0) {
443 return -1;
444 }
445 }
446
447 res = utimes(path, tvs);
448 return res;
449 }
450
sys_futimes(pr_fh_t * fh,int fd,struct timeval * tvs)451 static int sys_futimes(pr_fh_t *fh, int fd, struct timeval *tvs) {
452 #ifdef HAVE_FUTIMES
453 int res;
454
455 /* Check for an ENOSYS errno; if so, fallback to using sys_utimes. Some
456 * platforms will provide a futimes(2) stub which does not actually do
457 * anything.
458 */
459 res = futimes(fd, tvs);
460 if (res < 0 &&
461 errno == ENOSYS) {
462 return sys_utimes(fh->fh_fs, fh->fh_path, tvs);
463 }
464
465 return res;
466 #else
467 return sys_utimes(fh->fh_fs, fh->fh_path, tvs);
468 #endif
469 }
470
sys_fsync(pr_fh_t * fh,int fd)471 static int sys_fsync(pr_fh_t *fh, int fd) {
472 int res;
473
474 #ifdef HAVE_FSYNC
475 res = fsync(fd);
476 #else
477 errno = ENOSYS;
478 res = -1;
479 #endif /* HAVE_FSYNC */
480
481 return res;
482 }
483
sys_getxattr(pool * p,pr_fs_t * fs,const char * path,const char * name,void * val,size_t valsz)484 static ssize_t sys_getxattr(pool *p, pr_fs_t *fs, const char *path,
485 const char *name, void *val, size_t valsz) {
486 ssize_t res = -1;
487
488 (void) p;
489
490 #if defined(PR_USE_XATTR)
491 # if defined(HAVE_SYS_EXTATTR_H)
492 res = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, val, valsz);
493 # elif defined(HAVE_SYS_XATTR_H)
494 # if defined(XATTR_NOFOLLOW)
495 res = getxattr(path, name, val, valsz, 0, 0);
496 # else
497 res = getxattr(path, name, val, valsz);
498 # endif /* XATTR_NOFOLLOW */
499 # else
500 errno = NOSYS;
501 res = -1;
502 # endif /* HAVE_SYS_XATTR_H */
503 #else
504 (void) fs;
505 (void) path;
506 (void) name;
507 (void) val;
508 (void) valsz;
509
510 errno = ENOSYS;
511 res = -1;
512 #endif /* PR_USE_XATTR */
513
514 return res;
515 }
516
sys_lgetxattr(pool * p,pr_fs_t * fs,const char * path,const char * name,void * val,size_t valsz)517 static ssize_t sys_lgetxattr(pool *p, pr_fs_t *fs, const char *path,
518 const char *name, void *val, size_t valsz) {
519 ssize_t res = -1;
520
521 (void) p;
522
523 #if defined(PR_USE_XATTR)
524 # if defined(HAVE_SYS_EXTATTR_H)
525 # if defined(HAVE_EXTATTR_GET_LINK)
526 res = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, val, valsz);
527 # else
528 res = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, val, valsz);
529 # endif /* HAVE_EXTATTR_GET_LINK */
530 # elif defined(HAVE_SYS_XATTR_H)
531 # if defined(HAVE_LGETXATTR)
532 res = lgetxattr(path, name, val, valsz);
533 # elif defined(XATTR_NOFOLLOW)
534 res = getxattr(path, name, val, valsz, 0, XATTR_NOFOLLOW);
535 # else
536 res = getxattr(path, name, val, valsz);
537 # endif /* HAVE_LGETXATTR */
538 # else
539 errno = ENOSYS;
540 res = -1;
541 # endif /* HAVE_SYS_XATTR_H */
542 #else
543 (void) fs;
544 (void) path;
545 (void) name;
546 (void) val;
547 (void) valsz;
548
549 errno = ENOSYS;
550 res = -1;
551 #endif /* PR_USE_XATTR */
552
553 return res;
554 }
555
sys_fgetxattr(pool * p,pr_fh_t * fh,int fd,const char * name,void * val,size_t valsz)556 static ssize_t sys_fgetxattr(pool *p, pr_fh_t *fh, int fd, const char *name,
557 void *val, size_t valsz) {
558 ssize_t res = -1;
559
560 (void) p;
561
562 #if defined(PR_USE_XATTR)
563 # if defined(HAVE_SYS_EXTATTR_H)
564 res = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, val, valsz);
565 # elif defined(HAVE_SYS_XATTR_H)
566 # if defined(XATTR_NOFOLLOW)
567 res = fgetxattr(fd, name, val, valsz, 0, 0);
568 # else
569 res = fgetxattr(fd, name, val, valsz);
570 # endif /* XATTR_NOFOLLOW */
571 # else
572 errno = ENOSYS;
573 res = -1;
574 # endif /* HAVE_SYS_XATTR_H */
575 #else
576 (void) fh;
577 (void) fd;
578 (void) name;
579 (void) val;
580 (void) valsz;
581
582 errno = ENOSYS;
583 res = -1;
584 #endif /* PR_USE_XATTR */
585
586 return res;
587 }
588
589 #if defined(PR_USE_XATTR)
parse_xattr_namelist(pool * p,char * namelist,size_t sz)590 static array_header *parse_xattr_namelist(pool *p, char *namelist, size_t sz) {
591 array_header *names;
592 char *ptr;
593
594 names = make_array(p, 0, sizeof(char *));
595 ptr = namelist;
596
597 # if defined(HAVE_SYS_EXTATTR_H)
598 /* BSD style name lists use a one-byte length prefix (limiting xattr names
599 * to a maximum length of 255 bytes), followed by the name, without any
600 * terminating NUL.
601 */
602 while (sz > 0) {
603 unsigned char len;
604
605 pr_signals_handle();
606
607 len = (unsigned char) *ptr;
608 ptr++;
609 sz--;
610
611 *((char **) push_array(names)) = pstrndup(p, ptr, len);
612
613 ptr += len;
614 sz -= len;
615 }
616
617 # elif defined(HAVE_SYS_XATTR_H)
618 /* Linux/MacOSX style name lists use NUL-terminated xattr names. */
619 while (sz > 0) {
620 char *ptr2;
621 size_t len;
622
623 pr_signals_handle();
624
625 for (ptr2 = ptr; *ptr2; ptr2++);
626 len = ptr2 - ptr;
627 *((char **) push_array(names)) = pstrndup(p, ptr, len);
628
629 ptr = ptr2 + 1;
630 sz -= (len + 1);
631 }
632 # endif /* HAVE_SYS_XATTR_H */
633
634 return names;
635 }
636
unix_listxattr(const char * path,char * namelist,size_t len)637 static ssize_t unix_listxattr(const char *path, char *namelist, size_t len) {
638 ssize_t res = -1;
639
640 #if defined(HAVE_SYS_EXTATTR_H)
641 res = extattr_list_file(path, EXTATTR_NAMESPACE_USER, namelist, len);
642 #elif defined(HAVE_SYS_XATTR_H)
643 # if defined(XATTR_NOFOLLOW)
644 res = listxattr(path, namelist, len, 0);
645 # else
646 res = listxattr(path, namelist, len);
647 # endif /* XATTR_NOFOLLOW */
648 #else
649 errno = ENOSYS;
650 res = -1;
651 #endif /* HAVE_SYS_XATTR_H */
652
653 return res;
654 }
655
unix_llistxattr(const char * path,char * namelist,size_t len)656 static ssize_t unix_llistxattr(const char *path, char *namelist, size_t len) {
657 ssize_t res = -1;
658
659 # if defined(HAVE_SYS_EXTATTR_H)
660 # if defined(HAVE_EXTATTR_LIST_LINK)
661 res = extattr_list_link(path, EXTATTR_NAMESPACE_USER, namelist, len);
662 # else
663 res = extattr_list_file(path, EXTATTR_NAMESPACE_USER, namelist, len);
664 # endif /* HAVE_EXTATTR_LIST_LINK */
665 # elif defined(HAVE_SYS_XATTR_H)
666 # if defined(HAVE_LLISTXATTR)
667 res = llistxattr(path, namelist, len);
668 # elif defined(XATTR_NOFOLLOW)
669 res = listxattr(path, namelist, len, XATTR_NOFOLLOW);
670 # else
671 res = listxattr(path, namelist, len);
672 # endif /* XATTR_NOFOLLOW */
673 # else
674 errno = ENOSYS;
675 res = -1;
676 # endif /* HAVE_SYS_XATTR_H */
677
678 return res;
679 }
680
unix_flistxattr(int fd,char * namelist,size_t len)681 static ssize_t unix_flistxattr(int fd, char *namelist, size_t len) {
682 ssize_t res = -1;
683
684 # if defined(HAVE_SYS_EXTATTR_H)
685 res = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, namelist, len);
686 # elif defined(HAVE_SYS_XATTR_H)
687 # if defined(XATTR_NOFOLLOW)
688 res = flistxattr(fd, namelist, len, 0);
689 # else
690 res = flistxattr(fd, namelist, len);
691 # endif /* XATTR_NOFOLLOW */
692 # else
693 errno = ENOSYS;
694 res = -1;
695 # endif /* HAVE_SYS_XATTR_H */
696
697 return res;
698 }
699 #endif /* PR_USE_XATTR */
700
sys_listxattr(pool * p,pr_fs_t * fs,const char * path,array_header ** names)701 static int sys_listxattr(pool *p, pr_fs_t *fs, const char *path,
702 array_header **names) {
703 ssize_t res;
704 char *namelist = NULL;
705 size_t len = 0;
706
707 #ifdef PR_USE_XATTR
708 /* We need to handle the different formats of namelists that listxattr et al
709 * can provide. On *BSDs, the namelist buffer uses length prefixes and no
710 * terminating NULs; on Linux/Mac, the namelist buffer uses ONLY
711 * NUL-terminated names.
712 *
713 * Thus we ALWAYS provide all the available attribute names, by first
714 * querying for the full namelist buffer size, allocating that out of
715 * given pool, querying for the names (using the buffer), and then parsing
716 * them into an array.
717 */
718
719 res = unix_listxattr(path, NULL, 0);
720 if (res < 0) {
721 return -1;
722 }
723
724 len = res;
725 namelist = palloc(p, len);
726
727 res = unix_listxattr(path, namelist, len);
728 if (res < 0) {
729 return -1;
730 }
731
732 *names = parse_xattr_namelist(p, namelist, len);
733 if (pr_trace_get_level(trace_channel) >= 15) {
734 register unsigned int i;
735 unsigned int count;
736 const char **attr_names;
737
738 count = (*names)->nelts;
739 attr_names = (*names)->elts;
740
741 pr_trace_msg(trace_channel, 15, "listxattr: found %d xattr names for '%s'",
742 count, path);
743 for (i = 0; i < count; i++) {
744 pr_trace_msg(trace_channel, 15, " [%u]: '%s'", i, attr_names[i]);
745 }
746 }
747
748 res = (*names)->nelts;
749
750 #else
751 (void) fs;
752 (void) path;
753 (void) names;
754 (void) namelist;
755 (void) len;
756 errno = ENOSYS;
757 res = -1;
758 #endif /* PR_USE_XATTR */
759
760 return (int) res;
761 }
762
sys_llistxattr(pool * p,pr_fs_t * fs,const char * path,array_header ** names)763 static int sys_llistxattr(pool *p, pr_fs_t *fs, const char *path,
764 array_header **names) {
765 ssize_t res;
766 char *namelist = NULL;
767 size_t len = 0;
768
769 #ifdef PR_USE_XATTR
770 /* See sys_listxattr for a description of why we use this approach. */
771 res = unix_llistxattr(path, NULL, 0);
772 if (res < 0) {
773 return -1;
774 }
775
776 len = res;
777 namelist = palloc(p, len);
778
779 res = unix_llistxattr(path, namelist, len);
780 if (res < 0) {
781 return -1;
782 }
783
784 *names = parse_xattr_namelist(p, namelist, len);
785 if (pr_trace_get_level(trace_channel) >= 15) {
786 register unsigned int i;
787 unsigned int count;
788 const char **attr_names;
789
790 count = (*names)->nelts;
791 attr_names = (*names)->elts;
792
793 pr_trace_msg(trace_channel, 15, "llistxattr: found %d xattr names for '%s'",
794 count, path);
795 for (i = 0; i < count; i++) {
796 pr_trace_msg(trace_channel, 15, " [%u]: '%s'", i, attr_names[i]);
797 }
798 }
799
800 res = (*names)->nelts;
801
802 #else
803 (void) fs;
804 (void) path;
805 (void) names;
806 (void) namelist;
807 (void) len;
808 errno = ENOSYS;
809 res = -1;
810 #endif /* PR_USE_XATTR */
811
812 return (int) res;
813 }
814
sys_flistxattr(pool * p,pr_fh_t * fh,int fd,array_header ** names)815 static int sys_flistxattr(pool *p, pr_fh_t *fh, int fd, array_header **names) {
816 ssize_t res;
817 char *namelist = NULL;
818 size_t len = 0;
819
820 #ifdef PR_USE_XATTR
821 /* See sys_listxattr for a description of why we use this approach. */
822 res = unix_flistxattr(fd, NULL, 0);
823 if (res < 0) {
824 return -1;
825 }
826
827 len = res;
828 namelist = palloc(p, len);
829
830 res = unix_flistxattr(fd, namelist, len);
831 if (res < 0) {
832 return -1;
833 }
834
835 *names = parse_xattr_namelist(p, namelist, len);
836 if (pr_trace_get_level(trace_channel) >= 15) {
837 register unsigned int i;
838 unsigned int count;
839 const char **attr_names;
840
841 count = (*names)->nelts;
842 attr_names = (*names)->elts;
843
844 pr_trace_msg(trace_channel, 15, "flistxattr: found %d xattr names for '%s'",
845 count, fh->fh_path);
846 for (i = 0; i < count; i++) {
847 pr_trace_msg(trace_channel, 15, " [%u]: '%s'", i, attr_names[i]);
848 }
849 }
850
851 res = (*names)->nelts;
852
853 #else
854 (void) fh;
855 (void) fd;
856 (void) names;
857 (void) namelist;
858 (void) len;
859 errno = ENOSYS;
860 res = -1;
861 #endif /* PR_USE_XATTR */
862
863 return (int) res;
864 }
865
sys_removexattr(pool * p,pr_fs_t * fs,const char * path,const char * name)866 static int sys_removexattr(pool *p, pr_fs_t *fs, const char *path,
867 const char *name) {
868 int res = -1;
869
870 (void) p;
871
872 #if defined(PR_USE_XATTR)
873 # if defined(HAVE_SYS_EXTATTR_H)
874 res = extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name);
875 # elif defined(HAVE_SYS_XATTR_H)
876 # if defined(XATTR_NOFOLLOW)
877 res = removexattr(path, name, 0);
878 # else
879 res = removexattr(path, name);
880 # endif /* XATTR_NOFOLLOW */
881 # else
882 errno = ENOSYS;
883 res = -1;
884 # endif /* HAVE_SYS_XATTR_H */
885 #else
886 (void) fs;
887 (void) path;
888 (void) name;
889
890 errno = ENOSYS;
891 res = -1;
892 #endif /* PR_USE_XATTR */
893
894 return res;
895 }
896
sys_lremovexattr(pool * p,pr_fs_t * fs,const char * path,const char * name)897 static int sys_lremovexattr(pool *p, pr_fs_t *fs, const char *path,
898 const char *name) {
899 int res;
900
901 (void) p;
902
903 #if defined(PR_USE_XATTR)
904 # if defined(HAVE_SYS_EXTATTR_H)
905 # if defined(HAVE_EXTATTR_DELETE_LINK)
906 res = extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name);
907 # else
908 res = extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name);
909 # endif /* HAVE_EXTATTR_DELETE_LINK */
910 # elif defined(HAVE_SYS_XATTR_H)
911 # if defined(HAVE_LREMOVEXATTR)
912 res = lremovexattr(path, name);
913 # elif defined(XATTR_NOFOLLOW)
914 res = removexattr(path, name, XATTR_NOFOLLOW);
915 # else
916 res = removexattr(path, name);
917 # endif /* XATTR_NOFOLLOW */
918 # else
919 errno = ENOSYS;
920 res = -1;
921 # endif /* HAVE_SYS_XATTR_H */
922 #else
923 (void) fs;
924 (void) path;
925 (void) name;
926
927 errno = ENOSYS;
928 res = -1;
929 #endif /* PR_USE_XATTR */
930
931 return res;
932 }
933
sys_fremovexattr(pool * p,pr_fh_t * fh,int fd,const char * name)934 static int sys_fremovexattr(pool *p, pr_fh_t *fh, int fd, const char *name) {
935 int res;
936
937 (void) p;
938
939 #if defined(PR_USE_XATTR)
940 # if defined(HAVE_SYS_EXTATTR_H)
941 res = extattr_delete_fd(fd, EXTATTR_NAMESPACE_USER, name);
942 # elif defined(HAVE_SYS_XATTR_H)
943 # if defined(XATTR_NOFOLLOW)
944 res = fremovexattr(fd, name, 0);
945 # else
946 res = fremovexattr(fd, name);
947 # endif /* XATTR_NOFOLLOW */
948 # else
949 errno = ENOSYS;
950 res = -1;
951 # endif /* HAVE_SYS_XATTR_H */
952 #else
953 (void) fh;
954 (void) fd;
955 (void) name;
956
957 errno = ENOSYS;
958 res = -1;
959 #endif /* PR_USE_XATTR */
960
961 return res;
962 }
963
964 #if defined(PR_USE_XATTR) && defined(HAVE_SYS_XATTR_H)
965 /* Map the given flags onto the sys/xattr.h flags */
get_setxattr_flags(int fsio_flags)966 static int get_setxattr_flags(int fsio_flags) {
967 int xattr_flags = 0;
968
969 /* If both CREATE and REPLACE are set, use a value of zero; per the
970 * man pages, this value gives the desired "create or replace" semantics.
971 * Right?
972 */
973
974 if (fsio_flags & PR_FSIO_XATTR_FL_CREATE) {
975 #if defined(XATTR_CREATE)
976 xattr_flags = XATTR_CREATE;
977 #endif /* XATTR_CREATE */
978
979 if (fsio_flags & PR_FSIO_XATTR_FL_REPLACE) {
980 xattr_flags = 0;
981 }
982
983 } else if (fsio_flags & PR_FSIO_XATTR_FL_REPLACE) {
984 #if defined(XATTR_REPLACE)
985 xattr_flags = XATTR_REPLACE;
986 #endif /* XATTR_REPLACE */
987 }
988
989 return xattr_flags;
990 }
991 #endif /* PR_USE_XATTR and <sys/xattr.h> */
992
sys_setxattr(pool * p,pr_fs_t * fs,const char * path,const char * name,void * val,size_t valsz,int flags)993 static int sys_setxattr(pool *p, pr_fs_t *fs, const char *path,
994 const char *name, void *val, size_t valsz, int flags) {
995 int res, xattr_flags = 0;
996
997 (void) p;
998
999 #if defined(PR_USE_XATTR)
1000 # if defined(HAVE_SYS_EXTATTR_H)
1001 (void) xattr_flags;
1002 res = extattr_set_file(path, EXTATTR_NAMESPACE_USER, name, val, valsz);
1003
1004 # elif defined(HAVE_SYS_XATTR_H)
1005 xattr_flags = get_setxattr_flags(flags);
1006
1007 # if defined(XATTR_NOFOLLOW)
1008 res = setxattr(path, name, val, valsz, 0, xattr_flags);
1009 # else
1010 res = setxattr(path, name, val, valsz, xattr_flags);
1011 # endif /* XATTR_NOFOLLOW */
1012 # else
1013 errno = NOSYS;
1014 res = -1;
1015 # endif /* HAVE_SYS_XATTR_H */
1016 #else
1017 (void) fs;
1018 (void) path;
1019 (void) name;
1020 (void) val;
1021 (void) valsz;
1022 (void) flags;
1023 (void) xattr_flags;
1024
1025 errno = ENOSYS;
1026 res = -1;
1027 #endif /* PR_USE_XATTR */
1028
1029 return res;
1030 }
1031
sys_lsetxattr(pool * p,pr_fs_t * fs,const char * path,const char * name,void * val,size_t valsz,int flags)1032 static int sys_lsetxattr(pool *p, pr_fs_t *fs, const char *path,
1033 const char *name, void *val, size_t valsz, int flags) {
1034 int res, xattr_flags = 0;
1035
1036 (void) p;
1037
1038 #if defined(PR_USE_XATTR)
1039 # if defined(HAVE_SYS_EXTATTR_H)
1040 (void) xattr_flags;
1041 # if defined(HAVE_EXTATTR_SET_LINK)
1042 res = extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, val, valsz);
1043 # else
1044 res = extattr_set_file(path, EXTATTR_NAMESPACE_USER, name, val, valsz);
1045 # endif /* HAVE_EXTATTR_SET_LINK */
1046 # elif defined(HAVE_SYS_XATTR_H)
1047 xattr_flags = get_setxattr_flags(flags);
1048
1049 # if defined(HAVE_LSETXATTR)
1050 res = lsetxattr(path, name, val, valsz, xattr_flags);
1051 # elif defined(XATTR_NOFOLLOW)
1052 xattr_flags |= XATTR_NOFOLLOW;
1053 res = setxattr(path, name, val, valsz, 0, xattr_flags);
1054 # else
1055 res = setxattr(path, name, val, valsz, xattr_flags);
1056 # endif /* XATTR_NOFOLLOW */
1057 # else
1058 errno = ENOSYS;
1059 res = -1;
1060 # endif /* HAVE_SYS_XATTR_H */
1061 #else
1062 (void) fs;
1063 (void) path;
1064 (void) name;
1065 (void) val;
1066 (void) valsz;
1067 (void) flags;
1068 (void) xattr_flags;
1069
1070 errno = ENOSYS;
1071 res = -1;
1072 #endif /* PR_USE_XATTR */
1073
1074 return res;
1075 }
1076
sys_fsetxattr(pool * p,pr_fh_t * fh,int fd,const char * name,void * val,size_t valsz,int flags)1077 static int sys_fsetxattr(pool *p, pr_fh_t *fh, int fd, const char *name,
1078 void *val, size_t valsz, int flags) {
1079 int res, xattr_flags = 0;
1080
1081 (void) p;
1082
1083 #if defined(PR_USE_XATTR)
1084 # if defined(HAVE_SYS_EXTATTR_H)
1085 (void) xattr_flags;
1086 res = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, name, val, valsz);
1087
1088 # elif defined(HAVE_SYS_XATTR_H)
1089 xattr_flags = get_setxattr_flags(flags);
1090
1091 # if defined(XATTR_NOFOLLOW)
1092 res = fsetxattr(fd, name, val, valsz, 0, xattr_flags);
1093 # else
1094 res = fsetxattr(fd, name, val, valsz, xattr_flags);
1095 # endif /* XATTR_NOFOLLOW */
1096 # else
1097 errno = ENOSYS;
1098 res = -1;
1099 # endif /* HAVE_SYS_XATTR_H */
1100 #else
1101 (void) fh;
1102 (void) fd;
1103 (void) name;
1104 (void) val;
1105 (void) valsz;
1106 (void) flags;
1107 (void) xattr_flags;
1108
1109 errno = ENOSYS;
1110 res = -1;
1111 #endif /* PR_USE_XATTR */
1112
1113 return res;
1114 }
1115
1116 #if defined(__FreeBSD__)
1117 static int
enter_freebsd_restricted_mode()1118 enter_freebsd_restricted_mode()
1119 {
1120 typedef void frmode_t();
1121 frmode_t *frmode;
1122
1123 frmode = (frmode_t *)dlfunc(
1124 RTLD_NEXT, "__FreeBSD_libc_enter_restricted_mode");
1125 if (frmode == NULL) {
1126 pr_log_pri(PR_LOG_ERR,
1127 "error: FreeBSD with vulnerable chroot (FreeBSD-SA-11:07.chroot)");
1128 return 1;
1129 }
1130 frmode();
1131 return 0;
1132 }
1133 #endif
1134
sys_chroot(pr_fs_t * fs,const char * path)1135 static int sys_chroot(pr_fs_t *fs, const char *path) {
1136 #if defined(__FreeBSD__)
1137 if (enter_freebsd_restricted_mode() != 0)
1138 return -1;
1139 #endif
1140 if (chroot(path) < 0) {
1141 return -1;
1142 }
1143
1144 session.chroot_path = (char *) path;
1145 return 0;
1146 }
1147
sys_chdir(pr_fs_t * fs,const char * path)1148 static int sys_chdir(pr_fs_t *fs, const char *path) {
1149 if (chdir(path) < 0) {
1150 return -1;
1151 }
1152
1153 pr_fs_setcwd(path);
1154 return 0;
1155 }
1156
sys_opendir(pr_fs_t * fs,const char * path)1157 static void *sys_opendir(pr_fs_t *fs, const char *path) {
1158 return opendir(path);
1159 }
1160
sys_closedir(pr_fs_t * fs,void * dir)1161 static int sys_closedir(pr_fs_t *fs, void *dir) {
1162 return closedir((DIR *) dir);
1163 }
1164
sys_readdir(pr_fs_t * fs,void * dir)1165 static struct dirent *sys_readdir(pr_fs_t *fs, void *dir) {
1166 return readdir((DIR *) dir);
1167 }
1168
sys_mkdir(pr_fs_t * fs,const char * path,mode_t mode)1169 static int sys_mkdir(pr_fs_t *fs, const char *path, mode_t mode) {
1170 int res;
1171
1172 if (fsio_guard_chroot) {
1173 res = chroot_allow_path(path);
1174 if (res < 0) {
1175 return -1;
1176 }
1177 }
1178
1179 res = mkdir(path, mode);
1180 return res;
1181 }
1182
sys_rmdir(pr_fs_t * fs,const char * path)1183 static int sys_rmdir(pr_fs_t *fs, const char *path) {
1184 int res;
1185
1186 if (fsio_guard_chroot) {
1187 res = chroot_allow_path(path);
1188 if (res < 0) {
1189 return -1;
1190 }
1191 }
1192
1193 res = rmdir(path);
1194 return res;
1195 }
1196
fs_cmp(const void * a,const void * b)1197 static int fs_cmp(const void *a, const void *b) {
1198 pr_fs_t *fsa, *fsb;
1199
1200 if (a == NULL) {
1201 if (b == NULL) {
1202 return 0;
1203 }
1204
1205 return 1;
1206
1207 } else {
1208 if (b == NULL) {
1209 return -1;
1210 }
1211 }
1212
1213 fsa = *((pr_fs_t **) a);
1214 fsb = *((pr_fs_t **) b);
1215
1216 return strcmp(fsa->fs_path, fsb->fs_path);
1217 }
1218
1219 /* Statcache stuff */
1220 struct fs_statcache {
1221 xasetmember_t *next, *prev;
1222 pool *sc_pool;
1223 const char *sc_path;
1224 struct stat sc_stat;
1225 int sc_errno;
1226 int sc_retval;
1227 time_t sc_cached_ts;
1228 };
1229
1230 static const char *statcache_channel = "fs.statcache";
1231 static pool *statcache_pool = NULL;
1232 static unsigned int statcache_size = 0;
1233 static unsigned int statcache_max_age = 0;
1234 static unsigned int statcache_flags = 0;
1235
1236 /* We need to maintain two different caches: one for stat(2) data, and one
1237 * for lstat(2) data. For some files (e.g. symlinks), the struct stat data
1238 * for the same path will be different for the two system calls.
1239 */
1240 static pr_table_t *stat_statcache_tab = NULL;
1241 static xaset_t *stat_statcache_set = NULL;
1242 static pr_table_t *lstat_statcache_tab = NULL;
1243 static xaset_t *lstat_statcache_set = NULL;
1244
1245 #define fs_cache_lstat(f, p, s) cache_stat((f), (p), (s), FSIO_FILE_LSTAT)
1246 #define fs_cache_stat(f, p, s) cache_stat((f), (p), (s), FSIO_FILE_STAT)
1247
fs_statcache_get(pr_table_t * cache_tab,xaset_t * cache_set,const char * path,size_t path_len,time_t now)1248 static const struct fs_statcache *fs_statcache_get(pr_table_t *cache_tab,
1249 xaset_t *cache_set, const char *path, size_t path_len, time_t now) {
1250 const struct fs_statcache *sc = NULL;
1251
1252 if (pr_table_count(cache_tab) == 0) {
1253 errno = EPERM;
1254 return NULL;
1255 }
1256
1257 sc = pr_table_get(cache_tab, path, NULL);
1258 if (sc != NULL) {
1259 time_t age;
1260
1261 /* If this item hasn't expired yet, return it, otherwise, remove it. */
1262 age = now - sc->sc_cached_ts;
1263 if (age <= statcache_max_age) {
1264 pr_trace_msg(statcache_channel, 19,
1265 "using cached entry for '%s' (age %lu %s)", path,
1266 (unsigned long) age, age != 1 ? "secs" : "sec");
1267 return sc;
1268 }
1269
1270 pr_trace_msg(statcache_channel, 14,
1271 "entry for '%s' expired (age %lu %s > max age %lu), removing", path,
1272 (unsigned long) age, age != 1 ? "secs" : "sec",
1273 (unsigned long) statcache_max_age);
1274 (void) pr_table_remove(cache_tab, path, NULL);
1275 (void) xaset_remove(cache_set, (xasetmember_t *) sc);
1276 destroy_pool(sc->sc_pool);
1277 }
1278
1279 errno = ENOENT;
1280 return NULL;
1281 }
1282
fs_statcache_evict(pr_table_t * cache_tab,xaset_t * cache_set,time_t now)1283 static int fs_statcache_evict(pr_table_t *cache_tab, xaset_t *cache_set,
1284 time_t now) {
1285 time_t age;
1286 xasetmember_t *item;
1287 struct fs_statcache *sc;
1288
1289 if (cache_set->xas_list == NULL) {
1290 /* Should never happen. */
1291 errno = EPERM;
1292 return -1;
1293 }
1294
1295 /* We only need to remove the FIRST expired item; it should be the first
1296 * item in the list, since we keep the list in insert (and thus expiry)
1297 * order.
1298 */
1299
1300 item = cache_set->xas_list;
1301 sc = (struct fs_statcache *) item;
1302 age = now - sc->sc_cached_ts;
1303
1304 if (age < statcache_max_age) {
1305 errno = ENOENT;
1306 return -1;
1307 }
1308
1309 pr_trace_msg(statcache_channel, 14,
1310 "entry for '%s' expired (age %lu %s > max age %lu), evicting",
1311 sc->sc_path, (unsigned long) age, age != 1 ? "secs" : "sec",
1312 (unsigned long) statcache_max_age);
1313
1314 (void) pr_table_remove(cache_tab, sc->sc_path, NULL);
1315 (void) xaset_remove(cache_set, (xasetmember_t *) sc);
1316 destroy_pool(sc->sc_pool);
1317 return 0;
1318 }
1319
1320 /* Returns 1 if we successfully added a cache entry, 0 if not, and -1 if
1321 * there was an error.
1322 */
fs_statcache_add(pr_table_t * cache_tab,xaset_t * cache_set,const char * path,size_t path_len,struct stat * st,int xerrno,int retval,time_t now)1323 static int fs_statcache_add(pr_table_t *cache_tab, xaset_t *cache_set,
1324 const char *path, size_t path_len, struct stat *st, int xerrno,
1325 int retval, time_t now) {
1326 int res, table_count;
1327 pool *sc_pool;
1328 struct fs_statcache *sc;
1329
1330 if (statcache_size == 0 ||
1331 statcache_max_age == 0) {
1332 /* Caching disabled; nothing to do here. */
1333 return 0;
1334 }
1335
1336 table_count = pr_table_count(cache_tab);
1337 if (table_count > 0 &&
1338 (unsigned int) table_count >= statcache_size) {
1339 /* We've reached capacity, and need to evict an item to make room. */
1340 if (fs_statcache_evict(cache_tab, cache_set, now) < 0) {
1341 pr_trace_msg(statcache_channel, 8,
1342 "unable to evict enough items from the cache: %s", strerror(errno));
1343 }
1344
1345 /* We did not evict any items, and so are at capacity. */
1346 return 0;
1347 }
1348
1349 sc_pool = make_sub_pool(statcache_pool);
1350 pr_pool_tag(sc_pool, "FS statcache entry pool");
1351 sc = pcalloc(sc_pool, sizeof(struct fs_statcache));
1352 sc->sc_pool = sc_pool;
1353 sc->sc_path = pstrndup(sc_pool, path, path_len);
1354 memcpy(&(sc->sc_stat), st, sizeof(struct stat));
1355 sc->sc_errno = xerrno;
1356 sc->sc_retval = retval;
1357 sc->sc_cached_ts = now;
1358
1359 res = pr_table_add(cache_tab, sc->sc_path, sc, sizeof(struct fs_statcache *));
1360 if (res < 0) {
1361 int tmp_errno = errno;
1362
1363 if (tmp_errno == EEXIST) {
1364 res = 0;
1365 }
1366
1367 destroy_pool(sc->sc_pool);
1368 errno = tmp_errno;
1369
1370 } else {
1371 xaset_insert_end(cache_set, (xasetmember_t *) sc);
1372 }
1373
1374 return (res == 0 ? 1 : res);
1375 }
1376
cache_stat(pr_fs_t * fs,const char * path,struct stat * st,unsigned int op)1377 static int cache_stat(pr_fs_t *fs, const char *path, struct stat *st,
1378 unsigned int op) {
1379 int res = -1, retval, xerrno = 0;
1380 char cleaned_path[PR_TUNABLE_PATH_MAX+1], pathbuf[PR_TUNABLE_PATH_MAX+1];
1381 int (*mystat)(pr_fs_t *, const char *, struct stat *) = NULL;
1382 size_t path_len;
1383 pr_table_t *cache_tab = NULL;
1384 xaset_t *cache_set = NULL;
1385 const struct fs_statcache *sc = NULL;
1386 time_t now;
1387
1388 now = time(NULL);
1389 memset(cleaned_path, '\0', sizeof(cleaned_path));
1390 memset(pathbuf, '\0', sizeof(pathbuf));
1391
1392 if (fs->non_std_path == FALSE) {
1393 /* Use only absolute path names. Construct them, if given a relative
1394 * path, based on cwd. This obviates the need for something like
1395 * realpath(3), which only introduces more stat(2) system calls.
1396 */
1397 if (*path != '/') {
1398 size_t pathbuf_len;
1399
1400 sstrcat(pathbuf, cwd, sizeof(pathbuf)-1);
1401 pathbuf_len = cwd_len;
1402
1403 /* If the cwd is "/", we don't need to duplicate the path separator.
1404 * On some systems (e.g. Cygwin), this duplication can cause problems,
1405 * as the path may then have different semantics.
1406 */
1407 if (strncmp(cwd, "/", 2) != 0) {
1408 sstrcat(pathbuf + pathbuf_len, "/", sizeof(pathbuf) - pathbuf_len - 1);
1409 pathbuf_len++;
1410 }
1411
1412 /* If the given directory is ".", then we don't need to append it. */
1413 if (strncmp(path, ".", 2) != 0) {
1414 sstrcat(pathbuf + pathbuf_len, path, sizeof(pathbuf)- pathbuf_len - 1);
1415 }
1416
1417 } else {
1418 sstrncpy(pathbuf, path, sizeof(pathbuf)-1);
1419 }
1420
1421 pr_fs_clean_path2(pathbuf, cleaned_path, sizeof(cleaned_path)-1, 0);
1422
1423 } else {
1424 sstrncpy(cleaned_path, path, sizeof(cleaned_path)-1);
1425 }
1426
1427 /* Determine which filesystem function to use, stat() or lstat() */
1428 if (op == FSIO_FILE_STAT) {
1429 mystat = fs->stat ? fs->stat : sys_stat;
1430 cache_tab = stat_statcache_tab;
1431 cache_set = stat_statcache_set;
1432
1433 } else {
1434 mystat = fs->lstat ? fs->lstat : sys_lstat;
1435 cache_tab = lstat_statcache_tab;
1436 cache_set = lstat_statcache_set;
1437 }
1438
1439 path_len = strlen(cleaned_path);
1440
1441 sc = fs_statcache_get(cache_tab, cache_set, cleaned_path, path_len, now);
1442 if (sc != NULL) {
1443
1444 /* Update the given struct stat pointer with the cached info */
1445 memcpy(st, &(sc->sc_stat), sizeof(struct stat));
1446
1447 pr_trace_msg(trace_channel, 18,
1448 "using cached stat for %s for path '%s' (retval %d, errno %s)",
1449 op == FSIO_FILE_STAT ? "stat()" : "lstat()", path, sc->sc_retval,
1450 strerror(sc->sc_errno));
1451
1452 /* Use the cached errno as well */
1453 errno = sc->sc_errno;
1454
1455 return sc->sc_retval;
1456 }
1457
1458 pr_trace_msg(trace_channel, 8, "using %s %s for path '%s'",
1459 fs->fs_name, op == FSIO_FILE_STAT ? "stat()" : "lstat()", path);
1460 retval = mystat(fs, cleaned_path, st);
1461 xerrno = errno;
1462
1463 if (retval == 0) {
1464 xerrno = 0;
1465 }
1466
1467 /* Update the cache */
1468 res = fs_statcache_add(cache_tab, cache_set, cleaned_path, path_len, st,
1469 xerrno, retval, now);
1470 if (res < 0) {
1471 pr_trace_msg(trace_channel, 8,
1472 "error adding cached stat for '%s': %s", cleaned_path, strerror(errno));
1473
1474 } else if (res > 0) {
1475 pr_trace_msg(trace_channel, 18,
1476 "added cached stat for path '%s' (retval %d, errno %s)", path,
1477 retval, strerror(xerrno));
1478 }
1479
1480 if (retval < 0) {
1481 errno = xerrno;
1482 }
1483
1484 return retval;
1485 }
1486
1487 /* Lookup routines */
1488
1489 /* Necessary prototype for static function */
1490 static pr_fs_t *lookup_file_canon_fs(const char *, char **, int);
1491
1492 /* lookup_dir_fs() is called when we want to perform some sort of directory
1493 * operation on a directory or file. A "closest" match algorithm is used. If
1494 * the lookup fails or is not "close enough" (i.e. the final target does not
1495 * exactly match an existing filesystem handle) scan the list of fs_matches for
1496 * matchable targets and call any callback functions, then rescan the pr_fs_t
1497 * list. The rescan is performed in case any modules registered pr_fs_ts
1498 * during the hit.
1499 */
lookup_dir_fs(const char * path,int op)1500 static pr_fs_t *lookup_dir_fs(const char *path, int op) {
1501 char buf[PR_TUNABLE_PATH_MAX + 1], tmp_path[PR_TUNABLE_PATH_MAX + 1];
1502 pr_fs_t *fs = NULL;
1503 int exact = FALSE;
1504 size_t tmp_pathlen = 0;
1505
1506 memset(buf, '\0', sizeof(buf));
1507 memset(tmp_path, '\0', sizeof(tmp_path));
1508 sstrncpy(buf, path, sizeof(buf));
1509
1510 /* Check if the given path is an absolute path. Since there may be
1511 * alternate fs roots, this is not a simple check. If the path is
1512 * not absolute, prepend the current location.
1513 */
1514 if (pr_fs_valid_path(path) < 0) {
1515 if (pr_fs_dircat(tmp_path, sizeof(tmp_path), cwd, buf) < 0) {
1516 return NULL;
1517 }
1518
1519 } else {
1520 sstrncpy(tmp_path, buf, sizeof(tmp_path));
1521 }
1522
1523 /* Make sure that if this is a directory operation, the path being
1524 * search ends in a trailing slash -- this is how files and directories
1525 * are differentiated in the fs_map.
1526 */
1527 tmp_pathlen = strlen(tmp_path);
1528 if ((FSIO_DIR_COMMON & op) &&
1529 tmp_pathlen > 0 &&
1530 tmp_pathlen < sizeof(tmp_path) &&
1531 tmp_path[tmp_pathlen - 1] != '/') {
1532 sstrcat(tmp_path, "/", sizeof(tmp_path));
1533 }
1534
1535 fs = pr_get_fs(tmp_path, &exact);
1536 if (fs == NULL) {
1537 fs = root_fs;
1538 }
1539
1540 return fs;
1541 }
1542
1543 /* lookup_file_fs() performs the same function as lookup_dir_fs, however
1544 * because we are performing a file lookup, the target is the subdirectory
1545 * _containing_ the actual target. A basic optimization is used here,
1546 * if the path contains no '/' characters, fs_cwd is returned.
1547 */
lookup_file_fs(const char * path,char ** deref,int op)1548 static pr_fs_t *lookup_file_fs(const char *path, char **deref, int op) {
1549 pr_fs_t *fs = fs_cwd;
1550 struct stat st;
1551 int (*mystat)(pr_fs_t *, const char *, struct stat *) = NULL, res;
1552 char linkbuf[PR_TUNABLE_PATH_MAX + 1];
1553
1554 if (strchr(path, '/') != NULL) {
1555 return lookup_dir_fs(path, op);
1556 }
1557
1558 /* Determine which function to use, stat() or lstat(). */
1559 if (op == FSIO_FILE_STAT) {
1560 while (fs && fs->fs_next && !fs->stat) {
1561 fs = fs->fs_next;
1562 }
1563
1564 mystat = fs->stat;
1565
1566 } else {
1567 while (fs && fs->fs_next && !fs->lstat) {
1568 fs = fs->fs_next;
1569 }
1570
1571 mystat = fs->lstat;
1572 }
1573
1574 res = mystat(fs, path, &st);
1575 if (res < 0) {
1576 return fs;
1577 }
1578
1579 if (!S_ISLNK(st.st_mode)) {
1580 return fs;
1581 }
1582
1583 /* The given path is a symbolic link, in which case we need to find
1584 * the actual path referenced, and return an pr_fs_t for _that_ path
1585 */
1586
1587 /* Three characters are reserved at the end of linkbuf for some path
1588 * characters (and a trailing NUL).
1589 */
1590 if (fs->readlink != NULL) {
1591 res = (fs->readlink)(fs, path, &linkbuf[2], sizeof(linkbuf)-3);
1592
1593 } else {
1594 errno = ENOSYS;
1595 res = -1;
1596 }
1597
1598 if (res != -1) {
1599 linkbuf[res] = '\0';
1600
1601 if (strchr(linkbuf, '/') == NULL) {
1602 if (res + 3 > PR_TUNABLE_PATH_MAX) {
1603 res = PR_TUNABLE_PATH_MAX - 3;
1604 }
1605
1606 memmove(&linkbuf[2], linkbuf, res + 1);
1607
1608 linkbuf[res+2] = '\0';
1609 linkbuf[0] = '.';
1610 linkbuf[1] = '/';
1611 return lookup_file_canon_fs(linkbuf, deref, op);
1612 }
1613 }
1614
1615 /* What happens if fs_cwd->readlink is NULL, or readlink() returns -1?
1616 * I guess, for now, we punt, and return fs_cwd.
1617 */
1618 return fs_cwd;
1619 }
1620
lookup_file_canon_fs(const char * path,char ** deref,int op)1621 static pr_fs_t *lookup_file_canon_fs(const char *path, char **deref, int op) {
1622 static char workpath[PR_TUNABLE_PATH_MAX + 1];
1623
1624 memset(workpath,'\0',sizeof(workpath));
1625
1626 if (pr_fs_resolve_partial(path, workpath, sizeof(workpath)-1,
1627 FSIO_FILE_OPEN) == -1) {
1628 if (*path == '/' || *path == '~') {
1629 if (pr_fs_interpolate(path, workpath, sizeof(workpath)-1) != -1) {
1630 sstrncpy(workpath, path, sizeof(workpath));
1631 }
1632
1633 } else {
1634 if (pr_fs_dircat(workpath, sizeof(workpath), cwd, path) < 0) {
1635 return NULL;
1636 }
1637 }
1638 }
1639
1640 if (deref) {
1641 *deref = workpath;
1642 }
1643
1644 return lookup_file_fs(workpath, deref, op);
1645 }
1646
1647 /* FS Statcache API */
1648
statcache_dumpf(const char * fmt,...)1649 static void statcache_dumpf(const char *fmt, ...) {
1650 char buf[PR_TUNABLE_BUFFER_SIZE];
1651 va_list msg;
1652
1653 memset(buf, '\0', sizeof(buf));
1654
1655 va_start(msg, fmt);
1656 pr_vsnprintf(buf, sizeof(buf), fmt, msg);
1657 va_end(msg);
1658
1659 buf[sizeof(buf)-1] = '\0';
1660 (void) pr_trace_msg(statcache_channel, 9, "%s", buf);
1661 }
1662
pr_fs_statcache_dump(void)1663 void pr_fs_statcache_dump(void) {
1664 pr_table_dump(statcache_dumpf, stat_statcache_tab);
1665 pr_table_dump(statcache_dumpf, lstat_statcache_tab);
1666 }
1667
pr_fs_statcache_free(void)1668 void pr_fs_statcache_free(void) {
1669 if (stat_statcache_tab != NULL) {
1670 int size;
1671
1672 size = pr_table_count(stat_statcache_tab);
1673 pr_trace_msg(statcache_channel, 11,
1674 "resetting stat(2) statcache (clearing %d %s)", size,
1675 size != 1 ? "entries" : "entry");
1676 pr_table_empty(stat_statcache_tab);
1677 pr_table_free(stat_statcache_tab);
1678 stat_statcache_tab = NULL;
1679 stat_statcache_set = NULL;
1680 }
1681
1682 if (lstat_statcache_tab != NULL) {
1683 int size;
1684
1685 size = pr_table_count(lstat_statcache_tab);
1686 pr_trace_msg(statcache_channel, 11,
1687 "resetting lstat(2) statcache (clearing %d %s)", size,
1688 size != 1 ? "entries" : "entry");
1689 pr_table_empty(lstat_statcache_tab);
1690 pr_table_free(lstat_statcache_tab);
1691 lstat_statcache_tab = NULL;
1692 lstat_statcache_set = NULL;
1693 }
1694
1695 /* Note: we do not need to explicitly destroy each entry in the statcache
1696 * tables, since ALL entries are allocated out of this statcache_pool.
1697 * And we destroy this pool here. Much easier cleanup that way.
1698 */
1699 if (statcache_pool != NULL) {
1700 destroy_pool(statcache_pool);
1701 statcache_pool = NULL;
1702 }
1703 }
1704
pr_fs_statcache_reset(void)1705 void pr_fs_statcache_reset(void) {
1706 pr_fs_statcache_free();
1707
1708 if (statcache_pool == NULL) {
1709 statcache_pool = make_sub_pool(permanent_pool);
1710 pr_pool_tag(statcache_pool, "FS Statcache Pool");
1711 }
1712
1713 stat_statcache_tab = pr_table_alloc(statcache_pool, 0);
1714 stat_statcache_set = xaset_create(statcache_pool, NULL);
1715
1716 lstat_statcache_tab = pr_table_alloc(statcache_pool, 0);
1717 lstat_statcache_set = xaset_create(statcache_pool, NULL);
1718 }
1719
pr_fs_statcache_set_policy(unsigned int size,unsigned int max_age,unsigned int flags)1720 int pr_fs_statcache_set_policy(unsigned int size, unsigned int max_age,
1721 unsigned int flags) {
1722
1723 statcache_size = size;
1724 statcache_max_age = max_age;
1725 statcache_flags = flags;
1726
1727 return 0;
1728 }
1729
pr_fs_clear_cache2(const char * path)1730 int pr_fs_clear_cache2(const char *path) {
1731 int res;
1732
1733 (void) pr_event_generate("fs.statcache.clear", path);
1734
1735 if (pr_table_count(stat_statcache_tab) == 0 &&
1736 pr_table_count(lstat_statcache_tab) == 0) {
1737 return 0;
1738 }
1739
1740 if (path != NULL) {
1741 char cleaned_path[PR_TUNABLE_PATH_MAX+1], pathbuf[PR_TUNABLE_PATH_MAX+1];
1742 int lstat_count, stat_count;
1743
1744 if (*path != '/') {
1745 size_t pathbuf_len;
1746
1747 memset(cleaned_path, '\0', sizeof(cleaned_path));
1748 memset(pathbuf, '\0', sizeof(pathbuf));
1749
1750 sstrcat(pathbuf, cwd, sizeof(pathbuf)-1);
1751 pathbuf_len = cwd_len;
1752
1753 if (strncmp(cwd, "/", 2) != 0) {
1754 sstrcat(pathbuf + pathbuf_len, "/", sizeof(pathbuf) - pathbuf_len - 1);
1755 pathbuf_len++;
1756 }
1757
1758 if (strncmp(path, ".", 2) != 0) {
1759 sstrcat(pathbuf + pathbuf_len, path, sizeof(pathbuf)- pathbuf_len - 1);
1760 }
1761
1762 } else {
1763 sstrncpy(pathbuf, path, sizeof(pathbuf)-1);
1764 }
1765
1766 pr_fs_clean_path2(pathbuf, cleaned_path, sizeof(cleaned_path)-1, 0);
1767
1768 res = 0;
1769
1770 stat_count = pr_table_exists(stat_statcache_tab, cleaned_path);
1771 if (stat_count > 0) {
1772 const struct fs_statcache *sc;
1773
1774 sc = pr_table_remove(stat_statcache_tab, cleaned_path, NULL);
1775 if (sc != NULL) {
1776 (void) xaset_remove(stat_statcache_set, (xasetmember_t *) sc);
1777 destroy_pool(sc->sc_pool);
1778 }
1779
1780 pr_trace_msg(statcache_channel, 17, "cleared stat(2) entry for '%s'",
1781 path);
1782 res += stat_count;
1783 }
1784
1785 lstat_count = pr_table_exists(lstat_statcache_tab, cleaned_path);
1786 if (lstat_count > 0) {
1787 const struct fs_statcache *sc;
1788
1789 sc = pr_table_remove(lstat_statcache_tab, cleaned_path, NULL);
1790 if (sc != NULL) {
1791 (void) xaset_remove(lstat_statcache_set, (xasetmember_t *) sc);
1792 destroy_pool(sc->sc_pool);
1793 }
1794
1795 pr_trace_msg(statcache_channel, 17, "cleared lstat(2) entry for '%s'",
1796 path);
1797 res += lstat_count;
1798 }
1799
1800 } else {
1801 /* Caller is requesting that we empty the entire cache. */
1802 pr_fs_statcache_reset();
1803 res = 0;
1804 }
1805
1806 return res;
1807 }
1808
pr_fs_clear_cache(void)1809 void pr_fs_clear_cache(void) {
1810 (void) pr_fs_clear_cache2(NULL);
1811 }
1812
1813 /* FS functions proper */
1814
pr_fs_copy_file2(const char * src,const char * dst,int flags,void (* progress_cb)(int))1815 int pr_fs_copy_file2(const char *src, const char *dst, int flags,
1816 void (*progress_cb)(int)) {
1817 pr_fh_t *src_fh, *dst_fh;
1818 struct stat src_st, dst_st;
1819 char *buf;
1820 size_t bufsz;
1821 int dst_existed = FALSE, res;
1822 #ifdef PR_USE_XATTR
1823 array_header *xattrs = NULL;
1824 #endif /* PR_USE_XATTR */
1825
1826 if (src == NULL ||
1827 dst == NULL) {
1828 errno = EINVAL;
1829 return -1;
1830 }
1831
1832 copy_iter_count = 0;
1833
1834 /* Use a nonblocking open() for the path; it could be a FIFO, and we don't
1835 * want to block forever if the other end of the FIFO is not running.
1836 */
1837 src_fh = pr_fsio_open(src, O_RDONLY|O_NONBLOCK);
1838 if (src_fh == NULL) {
1839 int xerrno = errno;
1840
1841 pr_log_pri(PR_LOG_WARNING, "error opening source file '%s' "
1842 "for copying: %s", src, strerror(xerrno));
1843
1844 errno = xerrno;
1845 return -1;
1846 }
1847
1848 /* Do not allow copying of directories. open(2) may not fail when
1849 * opening the source path, since it is only doing a read-only open,
1850 * which does work on directories.
1851 */
1852
1853 /* This should never fail. */
1854 if (pr_fsio_fstat(src_fh, &src_st) < 0) {
1855 pr_trace_msg(trace_channel, 3,
1856 "error fstat'ing '%s': %s", src, strerror(errno));
1857 }
1858
1859 if (S_ISDIR(src_st.st_mode)) {
1860 int xerrno = EISDIR;
1861
1862 pr_fsio_close(src_fh);
1863
1864 pr_log_pri(PR_LOG_WARNING, "warning: cannot copy source '%s': %s", src,
1865 strerror(xerrno));
1866
1867 errno = xerrno;
1868 return -1;
1869 }
1870
1871 if (pr_fsio_set_block(src_fh) < 0) {
1872 pr_trace_msg(trace_channel, 3,
1873 "error putting '%s' into blocking mode: %s", src, strerror(errno));
1874 }
1875
1876 /* We use stat() here, not lstat(), since open() would follow a symlink
1877 * to its target, and what we really want to know here is whether the
1878 * ultimate destination file exists or not.
1879 */
1880 pr_fs_clear_cache2(dst);
1881 if (pr_fsio_stat(dst, &dst_st) == 0) {
1882 if (S_ISDIR(dst_st.st_mode)) {
1883 int xerrno = EISDIR;
1884
1885 (void) pr_fsio_close(src_fh);
1886
1887 pr_log_pri(PR_LOG_WARNING,
1888 "warning: cannot copy to destination '%s': %s", dst, strerror(xerrno));
1889
1890 errno = xerrno;
1891 return -1;
1892 }
1893
1894 dst_existed = TRUE;
1895 pr_fs_clear_cache2(dst);
1896 }
1897
1898 /* Use a nonblocking open() for the path; it could be a FIFO, and we don't
1899 * want to block forever if the other end of the FIFO is not running.
1900 */
1901 dst_fh = pr_fsio_open(dst, O_WRONLY|O_CREAT|O_NONBLOCK);
1902 if (dst_fh == NULL) {
1903 int xerrno = errno;
1904
1905 (void) pr_fsio_close(src_fh);
1906
1907 pr_log_pri(PR_LOG_WARNING, "error opening destination file '%s' "
1908 "for copying: %s", dst, strerror(xerrno));
1909
1910 errno = xerrno;
1911 return -1;
1912 }
1913
1914 if (pr_fsio_set_block(dst_fh) < 0) {
1915 pr_trace_msg(trace_channel, 3,
1916 "error putting '%s' into blocking mode: %s", dst, strerror(errno));
1917 }
1918
1919 /* Stat the source file to find its optimal copy block size. */
1920 if (pr_fsio_fstat(src_fh, &src_st) < 0) {
1921 int xerrno = errno;
1922
1923 pr_log_pri(PR_LOG_WARNING, "error checking source file '%s' "
1924 "for copying: %s", src, strerror(xerrno));
1925
1926 (void) pr_fsio_close(src_fh);
1927 (void) pr_fsio_close(dst_fh);
1928
1929 /* Don't unlink the destination file if it already existed. */
1930 if (!dst_existed) {
1931 if (!(flags & PR_FSIO_COPY_FILE_FL_NO_DELETE_ON_FAILURE)) {
1932 if (pr_fsio_unlink(dst) < 0) {
1933 pr_trace_msg(trace_channel, 12,
1934 "error deleting failed copy of '%s': %s", dst, strerror(errno));
1935 }
1936 }
1937 }
1938
1939 errno = xerrno;
1940 return -1;
1941 }
1942
1943 if (pr_fsio_fstat(dst_fh, &dst_st) == 0) {
1944
1945 /* Check to see if the source and destination paths are identical.
1946 * We wait until now, rather than simply comparing the path strings
1947 * earlier, in order to do stats on the paths and compare things like
1948 * file size, mtime, inode, etc.
1949 */
1950
1951 if (strcmp(src, dst) == 0 &&
1952 src_st.st_dev == dst_st.st_dev &&
1953 src_st.st_ino == dst_st.st_ino &&
1954 src_st.st_size == dst_st.st_size &&
1955 src_st.st_mtime == dst_st.st_mtime) {
1956
1957 (void) pr_fsio_close(src_fh);
1958 (void) pr_fsio_close(dst_fh);
1959
1960 /* No need to copy the same file. */
1961 return 0;
1962 }
1963 }
1964
1965 bufsz = src_st.st_blksize;
1966 buf = malloc(bufsz);
1967 if (buf == NULL) {
1968 pr_log_pri(PR_LOG_ALERT, "Out of memory!");
1969 exit(1);
1970 }
1971
1972 #ifdef S_ISFIFO
1973 if (!S_ISFIFO(dst_st.st_mode)) {
1974 /* Make sure the destination file starts with a zero size. */
1975 pr_fsio_truncate(dst, 0);
1976 }
1977 #endif
1978
1979 while ((res = pr_fsio_read(src_fh, buf, bufsz)) > 0) {
1980 size_t datalen;
1981 off_t offset;
1982
1983 pr_signals_handle();
1984
1985 /* Be sure to handle short writes. */
1986 datalen = res;
1987 offset = 0;
1988
1989 while (datalen > 0) {
1990 res = pr_fsio_write(dst_fh, buf + offset, datalen);
1991 if (res < 0) {
1992 int xerrno = errno;
1993
1994 if (xerrno == EINTR ||
1995 xerrno == EAGAIN) {
1996 pr_signals_handle();
1997 continue;
1998 }
1999
2000 (void) pr_fsio_close(src_fh);
2001 (void) pr_fsio_close(dst_fh);
2002
2003 /* Don't unlink the destination file if it already existed. */
2004 if (!dst_existed) {
2005 if (!(flags & PR_FSIO_COPY_FILE_FL_NO_DELETE_ON_FAILURE)) {
2006 if (pr_fsio_unlink(dst) < 0) {
2007 pr_trace_msg(trace_channel, 12,
2008 "error deleting failed copy of '%s': %s", dst, strerror(errno));
2009 }
2010 }
2011 }
2012
2013 pr_log_pri(PR_LOG_WARNING, "error copying to '%s': %s", dst,
2014 strerror(xerrno));
2015 free(buf);
2016
2017 errno = xerrno;
2018 return -1;
2019 }
2020
2021 if (progress_cb != NULL) {
2022 (progress_cb)(res);
2023
2024 } else {
2025 copy_progress_cb(res);
2026 }
2027
2028 if ((size_t) res == datalen) {
2029 break;
2030 }
2031
2032 offset += res;
2033 datalen -= res;
2034 }
2035 }
2036
2037 free(buf);
2038
2039 #if defined(HAVE_POSIX_ACL) && defined(PR_USE_FACL)
2040 {
2041 /* Copy any ACLs from the source file to the destination file as well. */
2042 # if defined(HAVE_BSD_POSIX_ACL)
2043 acl_t facl, facl_dup = NULL;
2044 int have_facl = FALSE, have_dup = FALSE;
2045
2046 facl = acl_get_fd(PR_FH_FD(src_fh));
2047 if (facl) {
2048 have_facl = TRUE;
2049 }
2050
2051 if (have_facl) {
2052 facl_dup = acl_dup(facl);
2053 }
2054
2055 if (facl_dup) {
2056 have_dup = TRUE;
2057 }
2058
2059 if (have_dup &&
2060 acl_set_fd(PR_FH_FD(dst_fh), facl_dup) < 0) {
2061 pr_log_debug(DEBUG3, "error applying ACL to destination file: %s",
2062 strerror(errno));
2063 }
2064
2065 if (have_dup) {
2066 acl_free(facl_dup);
2067 }
2068 # elif defined(HAVE_LINUX_POSIX_ACL)
2069
2070 # if defined(HAVE_PERM_COPY_FD)
2071 /* Linux provides the handy perm_copy_fd(3) function in its libacl
2072 * library just for this purpose.
2073 */
2074 if (perm_copy_fd(src, PR_FH_FD(src_fh), dst, PR_FH_FD(dst_fh), NULL) < 0) {
2075 pr_log_debug(DEBUG3, "error copying ACL to destination file: %s",
2076 strerror(errno));
2077 }
2078
2079 # else
2080 acl_t src_acl = acl_get_fd(PR_FH_FD(src_fh));
2081 if (src_acl == NULL) {
2082 pr_log_debug(DEBUG3, "error obtaining ACL for fd %d: %s",
2083 PR_FH_FD(src_fh), strerror(errno));
2084
2085 } else {
2086 if (acl_set_fd(PR_FH_FD(dst_fh), src_acl) < 0) {
2087 pr_log_debug(DEBUG3, "error setting ACL on fd %d: %s",
2088 PR_FH_FD(dst_fh), strerror(errno));
2089
2090 } else {
2091 acl_free(src_acl);
2092 }
2093 }
2094
2095 # endif /* !HAVE_PERM_COPY_FD */
2096
2097 # elif defined(HAVE_SOLARIS_POSIX_ACL)
2098 int nents;
2099
2100 nents = facl(PR_FH_FD(src_fh), GETACLCNT, 0, NULL);
2101 if (nents < 0) {
2102 pr_log_debug(DEBUG3, "error getting source file ACL count: %s",
2103 strerror(errno));
2104
2105 } else {
2106 aclent_t *acls;
2107
2108 acls = malloc(sizeof(aclent_t) * nents);
2109 if (!acls) {
2110 pr_log_pri(PR_LOG_ALERT, "Out of memory!");
2111 exit(1);
2112 }
2113
2114 if (facl(PR_FH_FD(src_fh), GETACL, nents, acls) < 0) {
2115 pr_log_debug(DEBUG3, "error getting source file ACLs: %s",
2116 strerror(errno));
2117
2118 } else {
2119 if (facl(PR_FH_FD(dst_fh), SETACL, nents, acls) < 0) {
2120 pr_log_debug(DEBUG3, "error setting dest file ACLs: %s",
2121 strerror(errno));
2122 }
2123 }
2124
2125 free(acls);
2126 }
2127 # endif /* HAVE_SOLARIS_POSIX_ACL && PR_USE_FACL */
2128 }
2129 #endif /* HAVE_POSIX_ACL */
2130
2131 #ifdef PR_USE_XATTR
2132 /* Copy any xattrs that the source file may have. We'll use the
2133 * destination file handle's pool for our xattr allocations.
2134 */
2135 if (pr_fsio_flistxattr(dst_fh->fh_pool, src_fh, &xattrs) > 0) {
2136 register unsigned int i;
2137 const char **names;
2138
2139 names = xattrs->elts;
2140 for (i = 0; i < xattrs->nelts; i++) {
2141 ssize_t valsz;
2142
2143 /* First, find out how much memory we need for this attribute's
2144 * value.
2145 */
2146 valsz = pr_fsio_fgetxattr(dst_fh->fh_pool, src_fh, names[i], NULL, 0);
2147 if (valsz > 0) {
2148 void *val;
2149 ssize_t sz;
2150
2151 val = palloc(dst_fh->fh_pool, valsz);
2152 sz = pr_fsio_fgetxattr(dst_fh->fh_pool, src_fh, names[i], val, valsz);
2153 if (sz > 0) {
2154 sz = pr_fsio_fsetxattr(dst_fh->fh_pool, dst_fh, names[i], val,
2155 valsz, 0);
2156 if (sz < 0 &&
2157 errno != ENOSYS) {
2158 pr_trace_msg(trace_channel, 7,
2159 "error copying xattr '%s' (%lu bytes) from '%s' to '%s': %s",
2160 names[i], (unsigned long) valsz, src, dst, strerror(errno));
2161 }
2162 }
2163 }
2164 }
2165 }
2166 #endif /* PR_USE_XATTR */
2167
2168 (void) pr_fsio_close(src_fh);
2169
2170 if (progress_cb != NULL) {
2171 (progress_cb)(0);
2172
2173 } else {
2174 copy_progress_cb(0);
2175 }
2176
2177 res = pr_fsio_close(dst_fh);
2178 if (res < 0) {
2179 int xerrno = errno;
2180
2181 /* Don't unlink the destination file if it already existed. */
2182 if (!dst_existed) {
2183 if (!(flags & PR_FSIO_COPY_FILE_FL_NO_DELETE_ON_FAILURE)) {
2184 if (pr_fsio_unlink(dst) < 0) {
2185 pr_trace_msg(trace_channel, 12,
2186 "error deleting failed copy of '%s': %s", dst, strerror(errno));
2187 }
2188 }
2189 }
2190
2191 pr_log_pri(PR_LOG_WARNING, "error closing '%s': %s", dst,
2192 strerror(xerrno));
2193
2194 errno = xerrno;
2195 }
2196
2197 return res;
2198 }
2199
pr_fs_copy_file(const char * src,const char * dst)2200 int pr_fs_copy_file(const char *src, const char *dst) {
2201 return pr_fs_copy_file2(src, dst, 0, NULL);
2202 }
2203
pr_register_fs(pool * p,const char * name,const char * path)2204 pr_fs_t *pr_register_fs(pool *p, const char *name, const char *path) {
2205 pr_fs_t *fs = NULL;
2206 int xerrno = 0;
2207
2208 /* Sanity check */
2209 if (p == NULL ||
2210 name == NULL ||
2211 path == NULL) {
2212 errno = EINVAL;
2213 return NULL;
2214 }
2215
2216 /* Instantiate an pr_fs_t */
2217 fs = pr_create_fs(p, name);
2218 xerrno = errno;
2219
2220 if (fs != NULL) {
2221 if (pr_insert_fs(fs, path) == FALSE) {
2222 xerrno = errno;
2223
2224 pr_trace_msg(trace_channel, 4, "error inserting FS '%s' at path '%s'",
2225 name, path);
2226
2227 destroy_pool(fs->fs_pool);
2228 fs->fs_pool = NULL;
2229
2230 errno = xerrno;
2231 return NULL;
2232 }
2233
2234 } else {
2235 pr_trace_msg(trace_channel, 6, "error creating FS '%s': %s", name,
2236 strerror(errno));
2237 }
2238
2239 errno = xerrno;
2240 return fs;
2241 }
2242
pr_create_fs(pool * p,const char * name)2243 pr_fs_t *pr_create_fs(pool *p, const char *name) {
2244 pr_fs_t *fs = NULL;
2245 pool *fs_pool = NULL;
2246
2247 /* Sanity check */
2248 if (p == NULL ||
2249 name == NULL) {
2250 errno = EINVAL;
2251 return NULL;
2252 }
2253
2254 /* Allocate a subpool, then allocate an pr_fs_t object from that subpool */
2255 fs_pool = make_sub_pool(p);
2256 pr_pool_tag(fs_pool, "FS Pool");
2257
2258 fs = pcalloc(fs_pool, sizeof(pr_fs_t));
2259 fs->fs_pool = fs_pool;
2260 fs->fs_next = fs->fs_prev = NULL;
2261 fs->fs_name = pstrdup(fs->fs_pool, name);
2262 fs->fs_next = root_fs;
2263 fs->allow_xdev_link = TRUE;
2264 fs->allow_xdev_rename = TRUE;
2265
2266 /* This is NULL until set by pr_insert_fs() */
2267 fs->fs_path = NULL;
2268
2269 return fs;
2270 }
2271
pr_insert_fs(pr_fs_t * fs,const char * path)2272 int pr_insert_fs(pr_fs_t *fs, const char *path) {
2273 char cleaned_path[PR_TUNABLE_PATH_MAX] = {'\0'};
2274
2275 if (fs == NULL ||
2276 path == NULL) {
2277 errno = EINVAL;
2278 return -1;
2279 }
2280
2281 if (fs_map == NULL) {
2282 pool *map_pool = make_sub_pool(permanent_pool);
2283 pr_pool_tag(map_pool, "FSIO Map Pool");
2284
2285 fs_map = make_array(map_pool, 0, sizeof(pr_fs_t *));
2286 }
2287
2288 /* Clean the path, but only if it starts with a '/'. Non-local-filesystem
2289 * paths may not want/need to be cleaned.
2290 */
2291 if (*path == '/') {
2292 pr_fs_clean_path(path, cleaned_path, sizeof(cleaned_path));
2293
2294 /* Cleaning the path may have removed a trailing slash, which the
2295 * caller may actually have wanted. Make sure one is present in
2296 * the cleaned version, if it was present in the original version and
2297 * is not present in the cleaned version.
2298 */
2299 if (path[strlen(path)-1] == '/') {
2300 size_t len = strlen(cleaned_path);
2301
2302 if (len > 1 &&
2303 len < (PR_TUNABLE_PATH_MAX-3) &&
2304 cleaned_path[len-1] != '/') {
2305 cleaned_path[len] = '/';
2306 cleaned_path[len+1] = '\0';
2307 }
2308 }
2309
2310 } else {
2311 sstrncpy(cleaned_path, path, sizeof(cleaned_path));
2312 }
2313
2314 if (fs->fs_path == NULL) {
2315 fs->fs_path = pstrdup(fs->fs_pool, cleaned_path);
2316 }
2317
2318 /* Check for duplicates. */
2319 if (fs_map->nelts > 0) {
2320 pr_fs_t *fsi = NULL, **fs_objs = (pr_fs_t **) fs_map->elts;
2321 register unsigned int i;
2322
2323 for (i = 0; i < fs_map->nelts; i++) {
2324 fsi = fs_objs[i];
2325
2326 if (strcmp(fsi->fs_path, cleaned_path) == 0) {
2327 /* An entry for this path already exists. Make sure the FS being
2328 * mounted is not the same as the one already present.
2329 */
2330 if (strcmp(fsi->fs_name, fs->fs_name) == 0) {
2331 pr_log_pri(PR_LOG_NOTICE,
2332 "error: duplicate fs paths not allowed: '%s'", cleaned_path);
2333 errno = EEXIST;
2334 return FALSE;
2335 }
2336
2337 /* "Push" the given FS on top of the existing one. */
2338 fs->fs_next = fsi;
2339 fsi->fs_prev = fs;
2340 fs_objs[i] = fs;
2341
2342 chk_fs_map = TRUE;
2343 return TRUE;
2344 }
2345 }
2346 }
2347
2348 /* Push the new FS into the container, then resort the contents. */
2349 *((pr_fs_t **) push_array(fs_map)) = fs;
2350
2351 /* Sort the FSs in the map according to their paths, but only if there
2352 * are more than one element in the array_header.
2353 */
2354 if (fs_map->nelts > 1) {
2355 qsort(fs_map->elts, fs_map->nelts, sizeof(pr_fs_t *), fs_cmp);
2356 }
2357
2358 /* Set the flag so that the fs wrapper functions know that a new FS
2359 * has been registered.
2360 */
2361 chk_fs_map = TRUE;
2362
2363 return TRUE;
2364 }
2365
pr_unmount_fs(const char * path,const char * name)2366 pr_fs_t *pr_unmount_fs(const char *path, const char *name) {
2367 pr_fs_t *fsi = NULL, **fs_objs = NULL;
2368 register unsigned int i = 0;
2369
2370 /* Sanity check */
2371 if (path == NULL) {
2372 errno = EINVAL;
2373 return NULL;
2374 }
2375
2376 /* This should never be called before pr_register_fs(), but, just in case...*/
2377 if (fs_map == NULL) {
2378 errno = EACCES;
2379 return NULL;
2380 }
2381
2382 fs_objs = (pr_fs_t **) fs_map->elts;
2383
2384 for (i = 0; i < fs_map->nelts; i++) {
2385 fsi = fs_objs[i];
2386
2387 if (strcmp(fsi->fs_path, path) == 0 &&
2388 (name ? strcmp(fsi->fs_name, name) == 0 : TRUE)) {
2389
2390 /* Exact match -- remove this FS. If there is an FS underneath, pop
2391 * the top FS off the stack. Otherwise, allocate a new map. Then
2392 * iterate through the old map, pushing all other FSs into the new map.
2393 * Destroy the old map. Move the new map into place.
2394 */
2395
2396 if (fsi->fs_next == NULL) {
2397 register unsigned int j = 0;
2398 pr_fs_t *tmp_fs, **old_objs = NULL;
2399 pool *map_pool;
2400 array_header *new_map;
2401
2402 /* If removing this FS would leave an empty map, don't bother
2403 * allocating a new one.
2404 */
2405 if (fs_map->nelts == 1) {
2406 destroy_pool(fs_map->pool);
2407 fs_map = NULL;
2408 fs_cwd = root_fs;
2409
2410 chk_fs_map = TRUE;
2411 return NULL;
2412 }
2413
2414 map_pool = make_sub_pool(permanent_pool);
2415 new_map = make_array(map_pool, 0, sizeof(pr_fs_t *));
2416
2417 pr_pool_tag(map_pool, "FSIO Map Pool");
2418 old_objs = (pr_fs_t **) fs_map->elts;
2419
2420 for (j = 0; j < fs_map->nelts; j++) {
2421 tmp_fs = old_objs[j];
2422
2423 if (strcmp(tmp_fs->fs_path, path) != 0) {
2424 *((pr_fs_t **) push_array(new_map)) = old_objs[j];
2425 }
2426 }
2427
2428 destroy_pool(fs_map->pool);
2429 fs_map = new_map;
2430
2431 /* Don't forget to set the flag so that wrapper functions scan the
2432 * new map.
2433 */
2434 chk_fs_map = TRUE;
2435
2436 return fsi;
2437 }
2438
2439 /* "Pop" this FS off the stack. */
2440 if (fsi->fs_next) {
2441 fsi->fs_next->fs_prev = NULL;
2442 }
2443 fs_objs[i] = fsi->fs_next;
2444 fsi->fs_next = fsi->fs_prev = NULL;
2445
2446 chk_fs_map = TRUE;
2447 return fsi;
2448 }
2449 }
2450
2451 errno = ENOENT;
2452 return NULL;
2453 }
2454
pr_remove_fs(const char * path)2455 pr_fs_t *pr_remove_fs(const char *path) {
2456 return pr_unmount_fs(path, NULL);
2457 }
2458
pr_unregister_fs(const char * path)2459 int pr_unregister_fs(const char *path) {
2460 pr_fs_t *fs = NULL;
2461
2462 if (path == NULL) {
2463 errno = EINVAL;
2464 return -1;
2465 }
2466
2467 /* Call pr_remove_fs() to get the fs for this path removed from the map. */
2468 fs = pr_remove_fs(path);
2469 if (fs != NULL) {
2470 destroy_pool(fs->fs_pool);
2471 fs->fs_pool = NULL;
2472 return 0;
2473 }
2474
2475 errno = ENOENT;
2476 return -1;
2477 }
2478
2479 /* This function returns the best pr_fs_t to handle the given path. It will
2480 * return NULL if there are no registered pr_fs_ts to handle the given path,
2481 * in which case the default root_fs should be used. This is so that
2482 * functions can look to see if an pr_fs_t, other than the default, for a
2483 * given path has been registered, if necessary. If the return value is
2484 * non-NULL, that will be a registered pr_fs_t to handle the given path. In
2485 * this case, if the exact argument is not NULL, it will either be TRUE,
2486 * signifying that the returned pr_fs_t is an exact match for the given
2487 * path, or FALSE, meaning the returned pr_fs_t is a "best match" -- most
2488 * likely the pr_fs_t that handles the directory in which the given path
2489 * occurs.
2490 */
pr_get_fs(const char * path,int * exact)2491 pr_fs_t *pr_get_fs(const char *path, int *exact) {
2492 pr_fs_t *fs = NULL, **fs_objs = NULL, *best_match_fs = NULL;
2493 register unsigned int i = 0;
2494
2495 /* Sanity check */
2496 if (path == NULL) {
2497 errno = EINVAL;
2498 return NULL;
2499 }
2500
2501 /* Basic optimization -- if there're no elements in the fs_map,
2502 * return the root_fs.
2503 */
2504 if (fs_map == NULL ||
2505 fs_map->nelts == 0) {
2506 return root_fs;
2507 }
2508
2509 fs_objs = (pr_fs_t **) fs_map->elts;
2510 best_match_fs = root_fs;
2511
2512 /* In order to handle deferred-resolution paths (eg "~" paths), the given
2513 * path will need to be passed through dir_realpath(), if necessary.
2514 *
2515 * The chk_fs_map flag, if TRUE, should be cleared on return of this
2516 * function -- all that flag says is, if TRUE, that this function _might_
2517 * return something different than it did on a previous call.
2518 */
2519
2520 for (i = 0; i < fs_map->nelts; i++) {
2521 int res = 0;
2522
2523 fs = fs_objs[i];
2524
2525 /* If the current pr_fs_t's path ends in a slash (meaning it is a
2526 * directory, and it matches the first part of the given path,
2527 * assume it to be the best pr_fs_t found so far.
2528 */
2529 if ((fs->fs_path)[strlen(fs->fs_path) - 1] == '/' &&
2530 !strncmp(path, fs->fs_path, strlen(fs->fs_path))) {
2531 best_match_fs = fs;
2532 }
2533
2534 res = strcmp(fs->fs_path, path);
2535 if (res == 0) {
2536 /* Exact match */
2537 if (exact) {
2538 *exact = TRUE;
2539 }
2540
2541 chk_fs_map = FALSE;
2542 return fs;
2543
2544 } else if (res > 0) {
2545 if (exact != NULL) {
2546 *exact = FALSE;
2547 }
2548
2549 chk_fs_map = FALSE;
2550
2551 /* Gone too far - return the best-match pr_fs_t */
2552 return best_match_fs;
2553 }
2554 }
2555
2556 chk_fs_map = FALSE;
2557
2558 if (exact != NULL) {
2559 *exact = FALSE;
2560 }
2561
2562 /* Return best-match by default */
2563 return best_match_fs;
2564 }
2565
pr_fs_setcwd(const char * dir)2566 int pr_fs_setcwd(const char *dir) {
2567 if (pr_fs_resolve_path(dir, cwd, sizeof(cwd)-1, FSIO_DIR_CHDIR) < 0) {
2568 return -1;
2569 }
2570
2571 if (sstrncpy(cwd, dir, sizeof(cwd)) < 0) {
2572 return -1;
2573 }
2574
2575 fs_cwd = lookup_dir_fs(cwd, FSIO_DIR_CHDIR);
2576 cwd[sizeof(cwd) - 1] = '\0';
2577 cwd_len = strlen(cwd);
2578
2579 return 0;
2580 }
2581
pr_fs_getcwd(void)2582 const char *pr_fs_getcwd(void) {
2583 return cwd;
2584 }
2585
pr_fs_getvwd(void)2586 const char *pr_fs_getvwd(void) {
2587 return vwd;
2588 }
2589
pr_fs_dircat(char * buf,int buflen,const char * dir1,const char * dir2)2590 int pr_fs_dircat(char *buf, int buflen, const char *dir1, const char *dir2) {
2591 /* Make temporary copies so that memory areas can overlap */
2592 char *_dir1 = NULL, *_dir2 = NULL, *ptr = NULL;
2593 size_t dir1len = 0, dir2len = 0;
2594
2595 /* The shortest possible path is "/", which requires 2 bytes. */
2596
2597 if (buf == NULL ||
2598 buflen < 2 ||
2599 dir1 == NULL ||
2600 dir2 == NULL) {
2601 errno = EINVAL;
2602 return -1;
2603 }
2604
2605 /* This is a test to see if we've got reasonable directories to concatenate.
2606 */
2607 dir1len = strlen(dir1);
2608 dir2len = strlen(dir2);
2609
2610 /* If both strings are empty, then the "concatenation" becomes trivial. */
2611 if (dir1len == 0 &&
2612 dir2len == 0) {
2613 buf[0] = '/';
2614 buf[1] = '\0';
2615 return 0;
2616 }
2617
2618 /* If dir2 is non-empty, but dir1 IS empty... */
2619 if (dir1len == 0) {
2620 sstrncpy(buf, dir2, buflen);
2621 buflen -= dir2len;
2622 sstrcat(buf, "/", buflen);
2623 return 0;
2624 }
2625
2626 /* Likewise, if dir1 is non-empty, but dir2 IS empty... */
2627 if (dir2len == 0) {
2628 sstrncpy(buf, dir1, buflen);
2629 buflen -= dir1len;
2630 sstrcat(buf, "/", buflen);
2631 return 0;
2632 }
2633
2634 if ((dir1len + dir2len + 1) >= PR_TUNABLE_PATH_MAX) {
2635 errno = ENAMETOOLONG;
2636 buf[0] = '\0';
2637 return -1;
2638 }
2639
2640 _dir1 = strdup(dir1);
2641 if (_dir1 == NULL) {
2642 return -1;
2643 }
2644
2645 _dir2 = strdup(dir2);
2646 if (_dir2 == NULL) {
2647 int xerrno = errno;
2648
2649 free(_dir1);
2650
2651 errno = xerrno;
2652 return -1;
2653 }
2654
2655 if (*_dir2 == '/') {
2656 sstrncpy(buf, _dir2, buflen);
2657 free(_dir1);
2658 free(_dir2);
2659 return 0;
2660 }
2661
2662 ptr = buf;
2663 sstrncpy(ptr, _dir1, buflen);
2664 ptr += dir1len;
2665 buflen -= dir1len;
2666
2667 if (buflen > 0 &&
2668 dir1len >= 1 &&
2669 *(_dir1 + (dir1len-1)) != '/') {
2670 sstrcat(ptr, "/", buflen);
2671 ptr += 1;
2672 buflen -= 1;
2673 }
2674
2675 sstrcat(ptr, _dir2, buflen);
2676
2677 if (*buf == '\0') {
2678 *buf++ = '/';
2679 *buf = '\0';
2680 }
2681
2682 free(_dir1);
2683 free(_dir2);
2684
2685 return 0;
2686 }
2687
2688 /* This function performs any tilde expansion needed and then returns the
2689 * resolved path, if any.
2690 *
2691 * Returns: -1 (errno = ENOENT): user does not exist
2692 * 0 : no interpolation done (path exists)
2693 * 1 : interpolation done
2694 */
pr_fs_interpolate(const char * path,char * buf,size_t buflen)2695 int pr_fs_interpolate(const char *path, char *buf, size_t buflen) {
2696 char *ptr = NULL;
2697 size_t currlen, pathlen;
2698 char user[PR_TUNABLE_LOGIN_MAX+1];
2699
2700 if (path == NULL ||
2701 buf == NULL ||
2702 buflen == 0) {
2703 errno = EINVAL;
2704 return -1;
2705 }
2706
2707 if (path[0] != '~') {
2708 sstrncpy(buf, path, buflen);
2709 return 1;
2710 }
2711
2712 memset(user, '\0', sizeof(user));
2713
2714 /* The first character of the given path is '~'.
2715 *
2716 * We next need to see what the rest of the path looks like. Could be:
2717 *
2718 * "~"
2719 * "~user"
2720 * "~/"
2721 * "~/path"
2722 * "~user/path"
2723 */
2724
2725 pathlen = strlen(path);
2726 if (pathlen == 1) {
2727 /* If the path is just "~", AND we're chrooted, then the interpolation
2728 * is easy.
2729 */
2730 if (session.chroot_path != NULL) {
2731 sstrncpy(buf, session.chroot_path, buflen);
2732 return 1;
2733 }
2734 }
2735
2736 ptr = strchr(path, '/');
2737 if (ptr == NULL) {
2738 struct stat st;
2739
2740 /* No path separator present, which means path must be "~user".
2741 *
2742 * This means that a path of "~foo" could be a file with that exact
2743 * name, or it could be that user's home directory. Let's find out
2744 * which it is.
2745 */
2746
2747 if (pr_fsio_stat(path, &st) < 0) {
2748 /* Must be a user, if anything...otherwise it's probably a typo.
2749 *
2750 * The user name, then, is everything just past the '~' character.
2751 */
2752 sstrncpy(user, path+1,
2753 pathlen-1 > sizeof(user)-1 ? sizeof(user)-1 : pathlen-1);
2754
2755 } else {
2756 /* This IS the file in question, perform no interpolation. */
2757 return 0;
2758 }
2759
2760 } else {
2761 currlen = ptr - path;
2762 if (currlen > 1) {
2763 /* Copy over the username. */
2764 sstrncpy(user, path+1,
2765 currlen > sizeof(user)-1 ? sizeof(user)-1 : currlen);
2766 }
2767
2768 /* Advance past the '/'. */
2769 ptr++;
2770 }
2771
2772 if (user[0] == '\0') {
2773 /* No user name provided. If we are chrooted, we leave it that way.
2774 * Otherwise, we're not chrooted, and we can assume the current user.
2775 */
2776 if (session.chroot_path == NULL) {
2777 sstrncpy(user, session.user, sizeof(user)-1);
2778 }
2779 }
2780
2781 if (user[0] != '\0') {
2782 struct passwd *pw = NULL;
2783 pool *p = NULL;
2784
2785 /* We need to look up the info for the given username, and add it
2786 * into the buffer.
2787 *
2788 * The permanent pool is used here, rather than session.pool, as path
2789 * interpolation can occur during startup parsing, when session.pool does
2790 * not exist. It does not really matter, since the allocated sub pool
2791 * is destroyed shortly.
2792 */
2793 p = make_sub_pool(permanent_pool);
2794 pr_pool_tag(p, "pr_fs_interpolate() pool");
2795
2796 pw = pr_auth_getpwnam(p, user);
2797 if (pw == NULL) {
2798 destroy_pool(p);
2799 errno = ENOENT;
2800 return -1;
2801 }
2802
2803 sstrncpy(buf, pw->pw_dir, buflen);
2804
2805 /* Done with pw, which means we can destroy the temporary pool now. */
2806 destroy_pool(p);
2807
2808 } else {
2809 /* We're chrooted. */
2810 sstrncpy(buf, "/", buflen);
2811 }
2812
2813 currlen = strlen(buf);
2814
2815 if (ptr != NULL &&
2816 currlen < buflen &&
2817 buf[currlen-1] != '/') {
2818 buf[currlen++] = '/';
2819 }
2820
2821 if (ptr != NULL) {
2822 sstrncpy(&buf[currlen], ptr, buflen - currlen);
2823 }
2824
2825 return 1;
2826 }
2827
pr_fs_resolve_partial(const char * path,char * buf,size_t buflen,int op)2828 int pr_fs_resolve_partial(const char *path, char *buf, size_t buflen, int op) {
2829 char curpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
2830 workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
2831 namebuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
2832 *where = NULL, *ptr = NULL, *last = NULL;
2833 pr_fs_t *fs = NULL;
2834 int len = 0, fini = 1, link_cnt = 0;
2835 ino_t prev_inode = 0;
2836 dev_t prev_device = 0;
2837 struct stat sbuf;
2838
2839 if (path == NULL ||
2840 buf == NULL ||
2841 buflen == 0) {
2842 errno = EINVAL;
2843 return -1;
2844 }
2845
2846 if (*path != '/') {
2847 if (*path == '~') {
2848 switch (pr_fs_interpolate(path, curpath, sizeof(curpath)-1)) {
2849 case -1:
2850 return -1;
2851
2852 case 0:
2853 sstrncpy(curpath, path, sizeof(curpath));
2854 sstrncpy(workpath, cwd, sizeof(workpath));
2855 break;
2856 }
2857
2858 } else {
2859 sstrncpy(curpath, path, sizeof(curpath));
2860 sstrncpy(workpath, cwd, sizeof(workpath));
2861 }
2862
2863 } else {
2864 sstrncpy(curpath, path, sizeof(curpath));
2865 }
2866
2867 while (fini--) {
2868 where = curpath;
2869
2870 while (*where != '\0') {
2871 pr_signals_handle();
2872
2873 /* Handle "." */
2874 if (strncmp(where, ".", 2) == 0) {
2875 where++;
2876 continue;
2877 }
2878
2879 /* Handle ".." */
2880 if (strncmp(where, "..", 3) == 0) {
2881 where += 2;
2882 ptr = last = workpath;
2883
2884 while (*ptr) {
2885 if (*ptr == '/') {
2886 last = ptr;
2887 }
2888 ptr++;
2889 }
2890
2891 *last = '\0';
2892 continue;
2893 }
2894
2895 /* Handle "./" */
2896 if (strncmp(where, "./", 2) == 0) {
2897 where += 2;
2898 continue;
2899 }
2900
2901 /* Handle "../" */
2902 if (strncmp(where, "../", 3) == 0) {
2903 where += 3;
2904 ptr = last = workpath;
2905
2906 while (*ptr) {
2907 if (*ptr == '/') {
2908 last = ptr;
2909 }
2910 ptr++;
2911 }
2912
2913 *last = '\0';
2914 continue;
2915 }
2916
2917 ptr = strchr(where, '/');
2918 if (ptr == NULL) {
2919 size_t wherelen = strlen(where);
2920
2921 ptr = where;
2922 if (wherelen >= 1) {
2923 ptr += (wherelen - 1);
2924 }
2925
2926 } else {
2927 *ptr = '\0';
2928 }
2929
2930 sstrncpy(namebuf, workpath, sizeof(namebuf));
2931
2932 if (*namebuf) {
2933 for (last = namebuf; *last; last++);
2934 if (*--last != '/') {
2935 sstrcat(namebuf, "/", sizeof(namebuf)-1);
2936 }
2937
2938 } else {
2939 sstrcat(namebuf, "/", sizeof(namebuf)-1);
2940 }
2941
2942 sstrcat(namebuf, where, sizeof(namebuf)-1);
2943
2944 where = ++ptr;
2945
2946 fs = lookup_dir_fs(namebuf, op);
2947
2948 if (fs_cache_lstat(fs, namebuf, &sbuf) == -1) {
2949 return -1;
2950 }
2951
2952 if (S_ISLNK(sbuf.st_mode)) {
2953 char linkpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
2954
2955 /* Detect an obvious recursive symlink */
2956 if (sbuf.st_ino && (ino_t) sbuf.st_ino == prev_inode &&
2957 sbuf.st_dev && (dev_t) sbuf.st_dev == prev_device) {
2958 errno = ELOOP;
2959 return -1;
2960 }
2961
2962 prev_inode = (ino_t) sbuf.st_ino;
2963 prev_device = (dev_t) sbuf.st_dev;
2964
2965 if (++link_cnt > PR_FSIO_MAX_LINK_COUNT) {
2966 errno = ELOOP;
2967 return -1;
2968 }
2969
2970 len = pr_fsio_readlink(namebuf, linkpath, sizeof(linkpath)-1);
2971 if (len <= 0) {
2972 errno = ENOENT;
2973 return -1;
2974 }
2975
2976 *(linkpath + len) = '\0';
2977 if (*linkpath == '/') {
2978 *workpath = '\0';
2979 }
2980
2981 /* Trim any trailing slash. */
2982 if (linkpath[len-1] == '/') {
2983 linkpath[len-1] = '\0';
2984 }
2985
2986 if (*linkpath == '~') {
2987 char tmpbuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
2988
2989 *workpath = '\0';
2990 sstrncpy(tmpbuf, linkpath, sizeof(tmpbuf));
2991
2992 if (pr_fs_interpolate(tmpbuf, linkpath, sizeof(linkpath)-1) < 0) {
2993 return -1;
2994 }
2995 }
2996
2997 if (*where) {
2998 sstrcat(linkpath, "/", sizeof(linkpath)-1);
2999 sstrcat(linkpath, where, sizeof(linkpath)-1);
3000 }
3001
3002 sstrncpy(curpath, linkpath, sizeof(curpath));
3003 fini++;
3004 break; /* continue main loop */
3005 }
3006
3007 if (S_ISDIR(sbuf.st_mode)) {
3008 sstrncpy(workpath, namebuf, sizeof(workpath));
3009 continue;
3010 }
3011
3012 if (*where) {
3013 errno = ENOENT;
3014 return -1; /* path/notadir/morepath */
3015 }
3016
3017 sstrncpy(workpath, namebuf, sizeof(workpath));
3018 }
3019 }
3020
3021 if (!workpath[0]) {
3022 sstrncpy(workpath, "/", sizeof(workpath));
3023 }
3024
3025 sstrncpy(buf, workpath, buflen);
3026 return 0;
3027 }
3028
pr_fs_resolve_path(const char * path,char * buf,size_t buflen,int op)3029 int pr_fs_resolve_path(const char *path, char *buf, size_t buflen, int op) {
3030 char curpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
3031 workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
3032 namebuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
3033 *where = NULL, *ptr = NULL, *last = NULL;
3034 pr_fs_t *fs = NULL;
3035 int len = 0, fini = 1, link_cnt = 0;
3036 ino_t prev_inode = 0;
3037 dev_t prev_device = 0;
3038 struct stat sbuf;
3039
3040 if (path == NULL ||
3041 buf == NULL ||
3042 buflen == 0) {
3043 errno = EINVAL;
3044 return -1;
3045 }
3046
3047 if (pr_fs_interpolate(path, curpath, sizeof(curpath)-1) != -1) {
3048 sstrncpy(curpath, path, sizeof(curpath));
3049 }
3050
3051 if (curpath[0] != '/') {
3052 sstrncpy(workpath, cwd, sizeof(workpath));
3053
3054 } else {
3055 workpath[0] = '\0';
3056 }
3057
3058 while (fini--) {
3059 where = curpath;
3060
3061 while (*where != '\0') {
3062 pr_signals_handle();
3063
3064 if (strncmp(where, ".", 2) == 0) {
3065 where++;
3066 continue;
3067 }
3068
3069 /* handle "./" */
3070 if (strncmp(where, "./", 2) == 0) {
3071 where += 2;
3072 continue;
3073 }
3074
3075 /* handle "../" */
3076 if (strncmp(where, "../", 3) == 0) {
3077 where += 3;
3078 ptr = last = workpath;
3079 while (*ptr) {
3080 if (*ptr == '/') {
3081 last = ptr;
3082 }
3083 ptr++;
3084 }
3085
3086 *last = '\0';
3087 continue;
3088 }
3089
3090 ptr = strchr(where, '/');
3091 if (ptr == NULL) {
3092 size_t wherelen = strlen(where);
3093
3094 ptr = where;
3095 if (wherelen >= 1) {
3096 ptr += (wherelen - 1);
3097 }
3098
3099 } else {
3100 *ptr = '\0';
3101 }
3102
3103 sstrncpy(namebuf, workpath, sizeof(namebuf));
3104
3105 if (*namebuf) {
3106 for (last = namebuf; *last; last++);
3107 if (*--last != '/') {
3108 sstrcat(namebuf, "/", sizeof(namebuf)-1);
3109 }
3110
3111 } else {
3112 sstrcat(namebuf, "/", sizeof(namebuf)-1);
3113 }
3114
3115 sstrcat(namebuf, where, sizeof(namebuf)-1);
3116
3117 where = ++ptr;
3118
3119 fs = lookup_dir_fs(namebuf, op);
3120
3121 if (fs_cache_lstat(fs, namebuf, &sbuf) == -1) {
3122 errno = ENOENT;
3123 return -1;
3124 }
3125
3126 if (S_ISLNK(sbuf.st_mode)) {
3127 char linkpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3128
3129 /* Detect an obvious recursive symlink */
3130 if (sbuf.st_ino && (ino_t) sbuf.st_ino == prev_inode &&
3131 sbuf.st_dev && (dev_t) sbuf.st_dev == prev_device) {
3132 errno = ELOOP;
3133 return -1;
3134 }
3135
3136 prev_inode = (ino_t) sbuf.st_ino;
3137 prev_device = (dev_t) sbuf.st_dev;
3138
3139 if (++link_cnt > PR_FSIO_MAX_LINK_COUNT) {
3140 errno = ELOOP;
3141 return -1;
3142 }
3143
3144 len = pr_fsio_readlink(namebuf, linkpath, sizeof(linkpath)-1);
3145 if (len <= 0) {
3146 errno = ENOENT;
3147 return -1;
3148 }
3149
3150 *(linkpath+len) = '\0';
3151
3152 if (*linkpath == '/') {
3153 *workpath = '\0';
3154 }
3155
3156 /* Trim any trailing slash. */
3157 if (linkpath[len-1] == '/') {
3158 linkpath[len-1] = '\0';
3159 }
3160
3161 if (*linkpath == '~') {
3162 char tmpbuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3163 *workpath = '\0';
3164
3165 sstrncpy(tmpbuf, linkpath, sizeof(tmpbuf));
3166
3167 if (pr_fs_interpolate(tmpbuf, linkpath, sizeof(linkpath)-1) < 0) {
3168 return -1;
3169 }
3170 }
3171
3172 if (*where) {
3173 sstrcat(linkpath, "/", sizeof(linkpath)-1);
3174 sstrcat(linkpath, where, sizeof(linkpath)-1);
3175 }
3176
3177 sstrncpy(curpath, linkpath, sizeof(curpath));
3178 fini++;
3179 break; /* continue main loop */
3180 }
3181
3182 if (S_ISDIR(sbuf.st_mode)) {
3183 sstrncpy(workpath, namebuf, sizeof(workpath));
3184 continue;
3185 }
3186
3187 if (*where) {
3188 errno = ENOENT;
3189 return -1; /* path/notadir/morepath */
3190 }
3191
3192 sstrncpy(workpath, namebuf, sizeof(workpath));
3193 }
3194 }
3195
3196 if (!workpath[0]) {
3197 sstrncpy(workpath, "/", sizeof(workpath));
3198 }
3199
3200 sstrncpy(buf, workpath, buflen);
3201 return 0;
3202 }
3203
pr_fs_clean_path2(const char * path,char * buf,size_t buflen,int flags)3204 int pr_fs_clean_path2(const char *path, char *buf, size_t buflen, int flags) {
3205 char workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3206 char curpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3207 char namebuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3208 int fini = 1, have_abs_path = FALSE;
3209
3210 if (path == NULL ||
3211 buf == NULL) {
3212 errno = EINVAL;
3213 return -1;
3214 }
3215
3216 if (buflen == 0) {
3217 return 0;
3218 }
3219
3220 sstrncpy(curpath, path, sizeof(curpath));
3221
3222 if (*curpath == '/') {
3223 have_abs_path = TRUE;
3224 }
3225
3226 /* main loop */
3227 while (fini--) {
3228 char *where = NULL, *ptr = NULL, *last = NULL;
3229
3230 where = curpath;
3231 while (*where != '\0') {
3232 pr_signals_handle();
3233
3234 if (strncmp(where, ".", 2) == 0) {
3235 where++;
3236 continue;
3237 }
3238
3239 /* handle "./" */
3240 if (strncmp(where, "./", 2) == 0) {
3241 where += 2;
3242 continue;
3243 }
3244
3245 /* handle ".." */
3246 if (strncmp(where, "..", 3) == 0) {
3247 where += 2;
3248 ptr = last = workpath;
3249
3250 while (*ptr) {
3251 pr_signals_handle();
3252
3253 if (*ptr == '/') {
3254 last = ptr;
3255 }
3256
3257 ptr++;
3258 }
3259
3260 *last = '\0';
3261 continue;
3262 }
3263
3264 /* handle "../" */
3265 if (strncmp(where, "../", 3) == 0) {
3266 where += 3;
3267 ptr = last = workpath;
3268
3269 while (*ptr) {
3270 pr_signals_handle();
3271
3272 if (*ptr == '/') {
3273 last = ptr;
3274 }
3275 ptr++;
3276 }
3277
3278 *last = '\0';
3279 continue;
3280 }
3281
3282 ptr = strchr(where, '/');
3283 if (ptr == NULL) {
3284 size_t wherelen = strlen(where);
3285
3286 ptr = where;
3287 if (wherelen >= 1) {
3288 ptr += (wherelen - 1);
3289 }
3290
3291 } else {
3292 *ptr = '\0';
3293 }
3294
3295 sstrncpy(namebuf, workpath, sizeof(namebuf));
3296
3297 if (*namebuf) {
3298 for (last = namebuf; *last; last++);
3299 if (*--last != '/') {
3300 sstrcat(namebuf, "/", sizeof(namebuf)-1);
3301 }
3302
3303 } else {
3304 if (have_abs_path ||
3305 (flags & PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH)) {
3306 sstrcat(namebuf, "/", sizeof(namebuf)-1);
3307 have_abs_path = FALSE;
3308 }
3309 }
3310
3311 sstrcat(namebuf, where, sizeof(namebuf)-1);
3312 namebuf[sizeof(namebuf)-1] = '\0';
3313
3314 where = ++ptr;
3315
3316 sstrncpy(workpath, namebuf, sizeof(workpath));
3317 }
3318 }
3319
3320 if (!workpath[0]) {
3321 sstrncpy(workpath, "/", sizeof(workpath));
3322 }
3323
3324 sstrncpy(buf, workpath, buflen);
3325 return 0;
3326 }
3327
pr_fs_clean_path(const char * path,char * buf,size_t buflen)3328 void pr_fs_clean_path(const char *path, char *buf, size_t buflen) {
3329 pr_fs_clean_path2(path, buf, buflen, PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH);
3330 }
3331
pr_fs_use_encoding(int bool)3332 int pr_fs_use_encoding(int bool) {
3333 int curr_setting = use_encoding;
3334
3335 if (bool != TRUE &&
3336 bool != FALSE) {
3337 errno = EINVAL;
3338 return -1;
3339 }
3340
3341 use_encoding = bool;
3342 return curr_setting;
3343 }
3344
pr_fs_decode_path2(pool * p,const char * path,int flags)3345 char *pr_fs_decode_path2(pool *p, const char *path, int flags) {
3346 #ifdef PR_USE_NLS
3347 size_t outlen;
3348 char *res;
3349
3350 if (p == NULL ||
3351 path == NULL) {
3352 errno = EINVAL;
3353 return NULL;
3354 }
3355
3356 if (!use_encoding) {
3357 return (char *) path;
3358 }
3359
3360 res = pr_decode_str(p, path, strlen(path), &outlen);
3361 if (res == NULL) {
3362 int xerrno = errno;
3363
3364 pr_trace_msg("encode", 1, "error decoding path '%s': %s", path,
3365 strerror(xerrno));
3366
3367 if (pr_trace_get_level("encode") >= 14) {
3368 /* Write out the path we tried (and failed) to decode, in hex. */
3369 register unsigned int i;
3370 unsigned char *raw_path;
3371 size_t pathlen, raw_pathlen;
3372
3373 pathlen = strlen(path);
3374 raw_pathlen = (pathlen * 5) + 1;
3375 raw_path = pcalloc(p, raw_pathlen + 1);
3376
3377 for (i = 0; i < pathlen; i++) {
3378 pr_snprintf((char *) (raw_path + (i * 5)), (raw_pathlen - 1) - (i * 5),
3379 "0x%02x ", (unsigned char) path[i]);
3380 }
3381
3382 pr_trace_msg("encode", 14, "unable to decode path (raw bytes): %s",
3383 raw_path);
3384 }
3385
3386 if (flags & FSIO_DECODE_FL_TELL_ERRORS) {
3387 unsigned long policy;
3388
3389 policy = pr_encode_get_policy();
3390 if (policy & PR_ENCODE_POLICY_FL_REQUIRE_VALID_ENCODING) {
3391 /* Note: At present, we DO return null here to callers, to indicate
3392 * the illegal encoding (Bug#4125), if configured to do so via
3393 * e.g. the RequireValidEncoding LangOption.
3394 */
3395 errno = xerrno;
3396 return NULL;
3397 }
3398 }
3399
3400 return (char *) path;
3401 }
3402
3403 pr_trace_msg("encode", 5, "decoded '%s' into '%s'", path, res);
3404 return res;
3405 #else
3406 if (p == NULL ||
3407 path == NULL) {
3408 errno = EINVAL;
3409 return NULL;
3410 }
3411
3412 return (char *) path;
3413 #endif /* PR_USE_NLS */
3414 }
3415
pr_fs_decode_path(pool * p,const char * path)3416 char *pr_fs_decode_path(pool *p, const char *path) {
3417 return pr_fs_decode_path2(p, path, 0);
3418 }
3419
pr_fs_encode_path(pool * p,const char * path)3420 char *pr_fs_encode_path(pool *p, const char *path) {
3421 #ifdef PR_USE_NLS
3422 size_t outlen;
3423 char *res;
3424
3425 if (p == NULL ||
3426 path == NULL) {
3427 errno = EINVAL;
3428 return NULL;
3429 }
3430
3431 if (!use_encoding) {
3432 return (char *) path;
3433 }
3434
3435 res = pr_encode_str(p, path, strlen(path), &outlen);
3436 if (res == NULL) {
3437 int xerrno = errno;
3438
3439 pr_trace_msg("encode", 1, "error encoding path '%s': %s", path,
3440 strerror(xerrno));
3441
3442 if (pr_trace_get_level("encode") >= 14) {
3443 /* Write out the path we tried (and failed) to encode, in hex. */
3444 register unsigned int i;
3445 unsigned char *raw_path;
3446 size_t pathlen, raw_pathlen;
3447
3448 pathlen = strlen(path);
3449 raw_pathlen = (pathlen * 5) + 1;
3450 raw_path = pcalloc(p, raw_pathlen + 1);
3451
3452 for (i = 0; i < pathlen; i++) {
3453 pr_snprintf((char *) (raw_path + (i * 5)), (raw_pathlen - 1) - (i * 5),
3454 "0x%02x ", (unsigned char) path[i]);
3455 }
3456
3457 pr_trace_msg("encode", 14, "unable to encode path (raw bytes): %s",
3458 raw_path);
3459 }
3460
3461 /* Note: At present, we do NOT return null here to callers; we assume
3462 * that all local names, being encoded for the remote client, are OK.
3463 * Revisit this assumption if necessary (Bug#4125).
3464 */
3465
3466 return (char *) path;
3467 }
3468
3469 pr_trace_msg("encode", 5, "encoded '%s' into '%s'", path, res);
3470 return res;
3471 #else
3472 if (p == NULL ||
3473 path == NULL) {
3474 errno = EINVAL;
3475 return NULL;
3476 }
3477
3478 return (char *) path;
3479 #endif /* PR_USE_NLS */
3480 }
3481
pr_fs_split_path(pool * p,const char * path)3482 array_header *pr_fs_split_path(pool *p, const char *path) {
3483 int res, have_abs_path = FALSE;
3484 char *buf;
3485 size_t buflen, bufsz, pathlen;
3486 array_header *components;
3487
3488 if (p == NULL ||
3489 path == NULL) {
3490 errno = EINVAL;
3491 return NULL;
3492 }
3493
3494 pathlen = strlen(path);
3495 if (pathlen == 0) {
3496 errno = EINVAL;
3497 return NULL;
3498 }
3499
3500 if (*path == '/') {
3501 have_abs_path = TRUE;
3502 }
3503
3504 /* Clean the path first */
3505 bufsz = PR_TUNABLE_PATH_MAX;
3506 buf = pcalloc(p, bufsz + 1);
3507
3508 res = pr_fs_clean_path2(path, buf, bufsz,
3509 PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH);
3510 if (res < 0) {
3511 int xerrno = errno;
3512
3513 pr_trace_msg(trace_channel, 7, "error cleaning path '%s': %s", path,
3514 strerror(xerrno));
3515 errno = xerrno;
3516 return NULL;
3517 }
3518
3519 buflen = strlen(buf);
3520
3521 /* Special-case handling of just "/", since pr_str_text_to_array() will
3522 * "eat" that delimiter.
3523 */
3524 if (buflen == 1 &&
3525 buf[0] == '/') {
3526 pr_trace_msg(trace_channel, 18, "split path '%s' into 1 component", path);
3527
3528 components = make_array(p, 1, sizeof(char *));
3529 *((char **) push_array(components)) = pstrdup(p, "/");
3530
3531 return components;
3532 }
3533
3534 components = pr_str_text_to_array(p, buf, '/');
3535 if (components != NULL) {
3536 pr_trace_msg(trace_channel, 17, "split path '%s' into %u %s", path,
3537 components->nelts, components->nelts != 1 ? "components" : "component");
3538
3539 if (pr_trace_get_level(trace_channel) >= 18) {
3540 register unsigned int i;
3541
3542 for (i = 0; i < components->nelts; i++) {
3543 char *component;
3544
3545 component = ((char **) components->elts)[i];
3546 if (component == NULL) {
3547 component = "NULL";
3548 }
3549
3550 pr_trace_msg(trace_channel, 18, "path '%s' component #%u: '%s'",
3551 path, i + 1, component);
3552 }
3553 }
3554 }
3555
3556 if (have_abs_path == TRUE) {
3557 array_header *root_component;
3558
3559 /* Since pr_str_text_to_array() will treat the leading '/' as a delimiter,
3560 * it will be stripped and not included as a path component. But it
3561 * DOES need to be there.
3562 */
3563 root_component = make_array(p, 1, sizeof(char *));
3564 *((char **) push_array(root_component)) = pstrdup(p, "/");
3565
3566 array_cat(root_component, components);
3567 components = root_component;
3568 }
3569
3570 return components;
3571 }
3572
pr_fs_join_path(pool * p,array_header * components,size_t count)3573 char *pr_fs_join_path(pool *p, array_header *components, size_t count) {
3574 register unsigned int i;
3575 char *path = NULL;
3576
3577 if (p == NULL ||
3578 components == NULL ||
3579 components->nelts == 0 ||
3580 count == 0) {
3581 errno = EINVAL;
3582 return NULL;
3583 }
3584
3585 /* Can't join more components than we have. */
3586 if (count > components->nelts) {
3587 errno = EINVAL;
3588 return NULL;
3589 }
3590
3591 path = ((char **) components->elts)[0];
3592
3593 for (i = 1; i < count; i++) {
3594 char *elt;
3595
3596 elt = ((char **) components->elts)[i];
3597 path = pdircat(p, path, elt, NULL);
3598 }
3599
3600 return path;
3601 }
3602
3603 /* This function checks the given path's prefix against the paths that
3604 * have been registered. If no matching path prefix has been registered,
3605 * the path is considered invalid.
3606 */
pr_fs_valid_path(const char * path)3607 int pr_fs_valid_path(const char *path) {
3608 if (path == NULL) {
3609 errno = EINVAL;
3610 return -1;
3611 }
3612
3613 if (fs_map != NULL &&
3614 fs_map->nelts > 0) {
3615 pr_fs_t *fsi = NULL, **fs_objs = (pr_fs_t **) fs_map->elts;
3616 register unsigned int i;
3617
3618 for (i = 0; i < fs_map->nelts; i++) {
3619 fsi = fs_objs[i];
3620
3621 if (strncmp(fsi->fs_path, path, strlen(fsi->fs_path)) == 0) {
3622 return 0;
3623 }
3624 }
3625 }
3626
3627 /* Also check the path against the default '/' path. */
3628 if (*path == '/') {
3629 return 0;
3630 }
3631
3632 errno = ENOENT;
3633 return -1;
3634 }
3635
pr_fs_virtual_path(const char * path,char * buf,size_t buflen)3636 void pr_fs_virtual_path(const char *path, char *buf, size_t buflen) {
3637 char curpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
3638 workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
3639 namebuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'},
3640 *where = NULL, *ptr = NULL, *last = NULL;
3641 int fini = 1;
3642
3643 if (path == NULL) {
3644 return;
3645 }
3646
3647 if (pr_fs_interpolate(path, curpath, sizeof(curpath)-1) != -1) {
3648 sstrncpy(curpath, path, sizeof(curpath));
3649 }
3650
3651 if (curpath[0] != '/') {
3652 sstrncpy(workpath, vwd, sizeof(workpath));
3653
3654 } else {
3655 workpath[0] = '\0';
3656 }
3657
3658 /* curpath is path resolving */
3659 /* linkpath is path a symlink pointed to */
3660 /* workpath is the path we've resolved */
3661
3662 /* main loop */
3663 while (fini--) {
3664 where = curpath;
3665 while (*where != '\0') {
3666 if (strncmp(where, ".", 2) == 0) {
3667 where++;
3668 continue;
3669 }
3670
3671 /* handle "./" */
3672 if (strncmp(where, "./", 2) == 0) {
3673 where += 2;
3674 continue;
3675 }
3676
3677 /* handle ".." */
3678 if (strncmp(where, "..", 3) == 0) {
3679 where += 2;
3680 ptr = last = workpath;
3681 while (*ptr) {
3682 if (*ptr == '/') {
3683 last = ptr;
3684 }
3685 ptr++;
3686 }
3687
3688 *last = '\0';
3689 continue;
3690 }
3691
3692 /* handle "../" */
3693 if (strncmp(where, "../", 3) == 0) {
3694 where += 3;
3695 ptr = last = workpath;
3696 while (*ptr) {
3697 if (*ptr == '/') {
3698 last = ptr;
3699 }
3700 ptr++;
3701 }
3702
3703 *last = '\0';
3704 continue;
3705 }
3706
3707 ptr = strchr(where, '/');
3708 if (ptr == NULL) {
3709 size_t wherelen = strlen(where);
3710
3711 ptr = where;
3712 if (wherelen >= 1) {
3713 ptr += (wherelen - 1);
3714 }
3715
3716 } else {
3717 *ptr = '\0';
3718 }
3719
3720 sstrncpy(namebuf, workpath, sizeof(namebuf));
3721
3722 if (*namebuf) {
3723 for (last = namebuf; *last; last++);
3724 if (*--last != '/') {
3725 sstrcat(namebuf, "/", sizeof(namebuf)-1);
3726 }
3727
3728 } else {
3729 sstrcat(namebuf, "/", sizeof(namebuf)-1);
3730 }
3731
3732 sstrcat(namebuf, where, sizeof(namebuf)-1);
3733
3734 where = ++ptr;
3735
3736 sstrncpy(workpath, namebuf, sizeof(workpath));
3737 }
3738 }
3739
3740 if (!workpath[0]) {
3741 sstrncpy(workpath, "/", sizeof(workpath));
3742 }
3743
3744 sstrncpy(buf, workpath, buflen);
3745 }
3746
pr_fsio_chdir_canon(const char * path,int hidesymlink)3747 int pr_fsio_chdir_canon(const char *path, int hidesymlink) {
3748 char resbuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3749 pr_fs_t *fs = NULL;
3750 int res = 0;
3751
3752 if (path == NULL) {
3753 errno = EINVAL;
3754 return -1;
3755 }
3756
3757 if (pr_fs_resolve_partial(path, resbuf, sizeof(resbuf)-1,
3758 FSIO_DIR_CHDIR) < 0) {
3759 return -1;
3760 }
3761
3762 fs = lookup_dir_fs(resbuf, FSIO_DIR_CHDIR);
3763 if (fs == NULL) {
3764 return -1;
3765 }
3766
3767 /* Find the first non-NULL custom chdir handler. If there are none,
3768 * use the system chdir.
3769 */
3770 while (fs && fs->fs_next && !fs->chdir) {
3771 fs = fs->fs_next;
3772 }
3773
3774 pr_trace_msg(trace_channel, 8, "using %s chdir() for path '%s'", fs->fs_name,
3775 path);
3776 res = (fs->chdir)(fs, resbuf);
3777
3778 if (res == 0) {
3779 /* chdir succeeded, so we set fs_cwd for future references. */
3780 fs_cwd = fs;
3781
3782 if (hidesymlink) {
3783 pr_fs_virtual_path(path, vwd, sizeof(vwd)-1);
3784
3785 } else {
3786 sstrncpy(vwd, resbuf, sizeof(vwd));
3787 }
3788 }
3789
3790 return res;
3791 }
3792
pr_fsio_chdir(const char * path,int hidesymlink)3793 int pr_fsio_chdir(const char *path, int hidesymlink) {
3794 char resbuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3795 pr_fs_t *fs = NULL;
3796 int res;
3797
3798 if (path == NULL) {
3799 errno = EINVAL;
3800 return -1;
3801 }
3802
3803 pr_fs_clean_path(path, resbuf, sizeof(resbuf)-1);
3804
3805 fs = lookup_dir_fs(path, FSIO_DIR_CHDIR);
3806 if (fs == NULL) {
3807 return -1;
3808 }
3809
3810 /* Find the first non-NULL custom chdir handler. If there are none,
3811 * use the system chdir.
3812 */
3813 while (fs && fs->fs_next && !fs->chdir) {
3814 fs = fs->fs_next;
3815 }
3816
3817 pr_trace_msg(trace_channel, 8, "using %s chdir() for path '%s'", fs->fs_name,
3818 path);
3819 res = (fs->chdir)(fs, resbuf);
3820 if (res == 0) {
3821 /* chdir succeeded, so we set fs_cwd for future references. */
3822 fs_cwd = fs;
3823
3824 if (hidesymlink) {
3825 pr_fs_virtual_path(path, vwd, sizeof(vwd)-1);
3826
3827 } else {
3828 sstrncpy(vwd, resbuf, sizeof(vwd));
3829 }
3830 }
3831
3832 return res;
3833 }
3834
3835 /* fs_opendir, fs_closedir and fs_readdir all use a nifty
3836 * optimization, caching the last-recently-used pr_fs_t, and
3837 * avoid future pr_fs_t lookups when iterating via readdir.
3838 */
pr_fsio_opendir(const char * path)3839 void *pr_fsio_opendir(const char *path) {
3840 pr_fs_t *fs = NULL;
3841 fsopendir_t *fsod = NULL, *fsodi = NULL;
3842 pool *fsod_pool = NULL;
3843 DIR *res = NULL;
3844
3845 if (path == NULL) {
3846 errno = EINVAL;
3847 return NULL;
3848 }
3849
3850 if (strchr(path, '/') == NULL) {
3851 pr_fs_setcwd(pr_fs_getcwd());
3852 fs = fs_cwd;
3853
3854 } else {
3855 char buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
3856
3857 if (pr_fs_resolve_partial(path, buf, sizeof(buf)-1, FSIO_DIR_OPENDIR) < 0) {
3858 return NULL;
3859 }
3860
3861 fs = lookup_dir_fs(buf, FSIO_DIR_OPENDIR);
3862 }
3863
3864 /* Find the first non-NULL custom opendir handler. If there are none,
3865 * use the system opendir.
3866 */
3867 while (fs && fs->fs_next && !fs->opendir) {
3868 fs = fs->fs_next;
3869 }
3870
3871 pr_trace_msg(trace_channel, 8, "using %s opendir() for path '%s'",
3872 fs->fs_name, path);
3873 res = (fs->opendir)(fs, path);
3874 if (res == NULL) {
3875 return NULL;
3876 }
3877
3878 /* Cache it here */
3879 fs_cache_dir = res;
3880 fs_cache_fsdir = fs;
3881
3882 fsod_pool = make_sub_pool(permanent_pool);
3883 pr_pool_tag(fsod_pool, "fsod subpool");
3884
3885 fsod = pcalloc(fsod_pool, sizeof(fsopendir_t));
3886 if (fsod == NULL) {
3887 if (fs->closedir) {
3888 (fs->closedir)(fs, res);
3889 errno = ENOMEM;
3890 return NULL;
3891 }
3892
3893 sys_closedir(fs, res);
3894 errno = ENOMEM;
3895 return NULL;
3896 }
3897
3898 fsod->pool = fsod_pool;
3899 fsod->dir = res;
3900 fsod->fsdir = fs;
3901 fsod->next = NULL;
3902 fsod->prev = NULL;
3903
3904 if (fsopendir_list) {
3905
3906 /* find the end of the fsopendir list */
3907 fsodi = fsopendir_list;
3908 while (fsodi->next) {
3909 pr_signals_handle();
3910 fsodi = fsodi->next;
3911 }
3912
3913 fsod->next = NULL;
3914 fsod->prev = fsodi;
3915 fsodi->next = fsod;
3916
3917 } else {
3918 /* This fsopendir _becomes_ the start of the fsopendir list */
3919 fsopendir_list = fsod;
3920 }
3921
3922 return res;
3923 }
3924
find_opendir(void * dir,int closing)3925 static pr_fs_t *find_opendir(void *dir, int closing) {
3926 pr_fs_t *fs = NULL;
3927
3928 if (fsopendir_list) {
3929 fsopendir_t *fsod;
3930
3931 for (fsod = fsopendir_list; fsod; fsod = fsod->next) {
3932 if (fsod->dir != NULL &&
3933 fsod->dir == dir) {
3934 fs = fsod->fsdir;
3935 break;
3936 }
3937 }
3938
3939 if (closing && fsod) {
3940 if (fsod->prev) {
3941 fsod->prev->next = fsod->next;
3942 }
3943
3944 if (fsod->next) {
3945 fsod->next->prev = fsod->prev;
3946 }
3947
3948 if (fsod == fsopendir_list) {
3949 fsopendir_list = fsod->next;
3950 }
3951
3952 destroy_pool(fsod->pool);
3953 fsod->pool = NULL;
3954 }
3955 }
3956
3957 if (dir == fs_cache_dir) {
3958 fs = fs_cache_fsdir;
3959
3960 if (closing) {
3961 fs_cache_dir = NULL;
3962 fs_cache_fsdir = NULL;
3963 }
3964 }
3965
3966 if (fs == NULL) {
3967 errno = ENOTDIR;
3968 }
3969
3970 return fs;
3971 }
3972
pr_fsio_closedir(void * dir)3973 int pr_fsio_closedir(void *dir) {
3974 int res;
3975 pr_fs_t *fs;
3976
3977 if (dir == NULL) {
3978 errno = EINVAL;
3979 return -1;
3980 }
3981
3982 fs = find_opendir(dir, TRUE);
3983 if (fs == NULL) {
3984 return -1;
3985 }
3986
3987 /* Find the first non-NULL custom closedir handler. If there are none,
3988 * use the system closedir.
3989 */
3990 while (fs && fs->fs_next && !fs->closedir) {
3991 fs = fs->fs_next;
3992 }
3993
3994 pr_trace_msg(trace_channel, 8, "using %s closedir()", fs->fs_name);
3995 res = (fs->closedir)(fs, dir);
3996
3997 return res;
3998 }
3999
pr_fsio_readdir(void * dir)4000 struct dirent *pr_fsio_readdir(void *dir) {
4001 struct dirent *res;
4002 pr_fs_t *fs;
4003
4004 if (dir == NULL) {
4005 errno = EINVAL;
4006 return NULL;
4007 }
4008
4009 fs = find_opendir(dir, FALSE);
4010 if (fs == NULL) {
4011 return NULL;
4012 }
4013
4014 /* Find the first non-NULL custom readdir handler. If there are none,
4015 * use the system readdir.
4016 */
4017 while (fs && fs->fs_next && !fs->readdir) {
4018 fs = fs->fs_next;
4019 }
4020
4021 pr_trace_msg(trace_channel, 8, "using %s readdir()", fs->fs_name);
4022 res = (fs->readdir)(fs, dir);
4023
4024 return res;
4025 }
4026
pr_fsio_mkdir(const char * path,mode_t mode)4027 int pr_fsio_mkdir(const char *path, mode_t mode) {
4028 int res, xerrno;
4029 pr_fs_t *fs;
4030 mode_t dir_umask = -1, prev_umask = -1, *umask_ptr = NULL;
4031
4032 if (path == NULL) {
4033 errno = EINVAL;
4034 return -1;
4035 }
4036
4037 fs = lookup_dir_fs(path, FSIO_DIR_MKDIR);
4038 if (fs == NULL) {
4039 return -1;
4040 }
4041
4042 /* Find the first non-NULL custom mkdir handler. If there are none,
4043 * use the system mkdir.
4044 */
4045 while (fs && fs->fs_next && !fs->mkdir) {
4046 fs = fs->fs_next;
4047 }
4048
4049 /* Make sure we honor the directory Umask, if any (Bug#4311). */
4050 umask_ptr = get_param_ptr(CURRENT_CONF, "DirUmask", FALSE);
4051 if (umask_ptr == NULL) {
4052 /* If Umask was configured with a single parameter, then DirUmask
4053 * would not be present; we still should check for Umask.
4054 */
4055 umask_ptr = get_param_ptr(CURRENT_CONF, "Umask", FALSE);
4056 }
4057
4058 if (umask_ptr != NULL) {
4059 dir_umask = *umask_ptr;
4060
4061 if (dir_umask != (mode_t) -1) {
4062 prev_umask = umask(dir_umask);
4063 }
4064 }
4065
4066 pr_trace_msg(trace_channel, 8, "using %s mkdir() for path '%s'", fs->fs_name,
4067 path);
4068 res = (fs->mkdir)(fs, path, mode);
4069 xerrno = errno;
4070
4071 if (res == 0) {
4072 pr_fs_clear_cache2(path);
4073 }
4074
4075 if (dir_umask != (mode_t) -1) {
4076 (void) umask(prev_umask);
4077 }
4078
4079 errno = xerrno;
4080 return res;
4081 }
4082
pr_fsio_mkdir_with_error(pool * p,const char * path,mode_t mode,pr_error_t ** err)4083 int pr_fsio_mkdir_with_error(pool *p, const char *path, mode_t mode,
4084 pr_error_t **err) {
4085 int res;
4086
4087 res = pr_fsio_mkdir(path, mode);
4088 if (res < 0) {
4089 int xerrno = errno;
4090
4091 if (p != NULL &&
4092 err != NULL) {
4093 *err = pr_error_create(p, xerrno);
4094 if (pr_error_explain_mkdir(*err, path, mode) < 0) {
4095 pr_error_destroy(*err);
4096 *err = NULL;
4097 }
4098 }
4099
4100 errno = xerrno;
4101 }
4102
4103 return res;
4104 }
4105
pr_fsio_guard_chroot(int guard)4106 int pr_fsio_guard_chroot(int guard) {
4107 int prev;
4108
4109 prev = fsio_guard_chroot;
4110 fsio_guard_chroot = guard;
4111
4112 return prev;
4113 }
4114
pr_fsio_set_options(unsigned long opts)4115 unsigned long pr_fsio_set_options(unsigned long opts) {
4116 unsigned long prev;
4117
4118 prev = fsio_opts;
4119 fsio_opts = opts;
4120
4121 return prev;
4122 }
4123
pr_fsio_set_use_mkdtemp(int value)4124 int pr_fsio_set_use_mkdtemp(int value) {
4125 int prev_value;
4126
4127 if (value != TRUE &&
4128 value != FALSE) {
4129 errno = EINVAL;
4130 return -1;
4131 }
4132
4133 prev_value = fsio_use_mkdtemp;
4134
4135 #ifdef HAVE_MKDTEMP
4136 fsio_use_mkdtemp = value;
4137 #endif /* HAVE_MKDTEMP */
4138
4139 return prev_value;
4140 }
4141
4142 /* Directory-specific "safe" chmod(2) which attempts to avoid/mitigate
4143 * symlink attacks.
4144 *
4145 * To do this, we first open a file descriptor on the given path, using
4146 * O_NOFOLLOW to avoid symlinks. If the fd is not to a directory, it's
4147 * an error. Then we use fchmod(2) to set the perms. There is still a
4148 * race condition here, between the time the directory is created and
4149 * when we call open(2). But hopefully the ensuing checks on the fd
4150 * (i.e. that it IS a directory) can mitigate that race.
4151 *
4152 * The fun part is ensuring that the OS/filesystem will give us an fd
4153 * on a directory path (using O_RDONLY to avoid getting an EISDIR error),
4154 * whilst being able to do a write (effectively) on the fd by changing
4155 * its permissions.
4156 */
schmod_dir(pool * p,const char * path,mode_t perms,int use_root)4157 static int schmod_dir(pool *p, const char *path, mode_t perms, int use_root) {
4158 int flags, fd, ignore_eacces = FALSE, ignore_eperm = FALSE, res, xerrno = 0;
4159 struct stat st;
4160 mode_t dir_mode;
4161
4162 /* We're not using the pool at the moment. */
4163 (void) p;
4164
4165 /* Open an fd on the path using O_RDONLY|O_NOFOLLOW, so that we a)
4166 * avoid symlinks, and b) get an fd on the (hopefully) directory.
4167 */
4168 flags = O_RDONLY;
4169 #ifdef O_NOFOLLOW
4170 flags |= O_NOFOLLOW;
4171 #endif
4172 fd = open(path, flags);
4173 xerrno = errno;
4174
4175 if (fd < 0) {
4176 pr_trace_msg(trace_channel, 3,
4177 "schmod: unable to open path '%s': %s", path, strerror(xerrno));
4178 errno = xerrno;
4179 return -1;
4180 }
4181
4182 res = fstat(fd, &st);
4183 if (res < 0) {
4184 xerrno = errno;
4185
4186 (void) close(fd);
4187
4188 pr_trace_msg(trace_channel, 3,
4189 "schmod: unable to fstat path '%s': %s", path, strerror(xerrno));
4190 errno = xerrno;
4191 return -1;
4192 }
4193
4194 /* We expect only directories. */
4195 if (!S_ISDIR(st.st_mode)) {
4196 xerrno = ENOTDIR;
4197
4198 (void) close(fd);
4199
4200 pr_trace_msg(trace_channel, 3,
4201 "schmod: unable to use path '%s': %s", path, strerror(xerrno));
4202
4203 /* This is such an unexpected (and possibly malicious) situation that
4204 * it warrants louder logging.
4205 */
4206 pr_log_pri(PR_LOG_WARNING,
4207 "WARNING: detected non-directory '%s' during directory creation: "
4208 "possible symlink attack", path);
4209
4210 errno = xerrno;
4211 return -1;
4212 }
4213
4214 /* Note that some filesystems (e.g. CIFS) may not actually create a
4215 * directory with the expected 0700 mode. If that is the case, then a
4216 * subsequence chmod(2) on that directory will likely fail. Thus we also
4217 * double-check the mode of the directory created via mkdtemp(3), and
4218 * attempt to mitigate Bug#4063.
4219 */
4220 dir_mode = (st.st_mode & ~S_IFMT);
4221 if (dir_mode != 0700) {
4222 ignore_eacces = ignore_eperm = TRUE;
4223
4224 pr_trace_msg(trace_channel, 3,
4225 "schmod: path '%s' has mode %04o, expected 0700", path, dir_mode);
4226
4227 /* This is such an unexpected situation that it warrants some logging. */
4228 pr_log_pri(PR_LOG_DEBUG,
4229 "NOTICE: directory '%s' has unexpected mode %04o (expected 0700)", path,
4230 dir_mode);
4231 }
4232
4233 if (use_root) {
4234 PRIVS_ROOT
4235 }
4236
4237 res = fchmod(fd, perms);
4238 xerrno = errno;
4239
4240 /* Using fchmod(2) on a directory descriptor is not really kosher
4241 * behavior, but appears to work on most filesystems. Still, if we
4242 * get an ENOENT back (as seen on some CIFS mounts, per Bug#4134), try
4243 * using chmod(2) on the path.
4244 */
4245 if (res < 0 &&
4246 xerrno == ENOENT) {
4247 ignore_eacces = TRUE;
4248 res = chmod(path, perms);
4249 xerrno = errno;
4250 }
4251
4252 if (use_root) {
4253 PRIVS_RELINQUISH
4254 }
4255
4256 /* At this point, succeed or fail, we're done with the fd. */
4257 (void) close(fd);
4258
4259 if (res < 0) {
4260 /* Note: Some filesystem implementations, particularly via FUSE,
4261 * may not actually implement ownership/permissions (e.g. FAT-based
4262 * filesystems). In such cases, chmod(2) et al will return ENOSYS
4263 * (see Bug#3986).
4264 *
4265 * Other filesystem implementations (e.g. CIFS, depending on the mount
4266 * options) will a chmod(2) that returns ENOENT (see Bug#4134).
4267 *
4268 * Should this fail the entire operation? I'm of two minds about this.
4269 * On the one hand, such filesystem behavior can undermine wider site
4270 * security policies; on the other, prohibiting a MKD/MKDIR operation
4271 * on such filesystems, deliberately used by the site admin, is not
4272 * useful/friendly behavior.
4273 *
4274 * Maybe these exceptions for ENOSYS/ENOENT here should be made
4275 * configurable?
4276 */
4277
4278 if (xerrno == ENOSYS ||
4279 xerrno == ENOENT ||
4280 (xerrno == EACCES && ignore_eacces == TRUE) ||
4281 (xerrno == EPERM && ignore_eperm == TRUE)) {
4282 pr_log_debug(DEBUG0, "schmod: unable to set perms %04o on "
4283 "path '%s': %s (chmod(2) not supported by underlying filesystem?)",
4284 perms, path, strerror(xerrno));
4285 return 0;
4286 }
4287
4288 pr_trace_msg(trace_channel, 3,
4289 "schmod: unable to set perms %04o on path '%s': %s", perms, path,
4290 strerror(xerrno));
4291 errno = xerrno;
4292 return -1;
4293 }
4294
4295 return 0;
4296 }
4297
4298 /* "safe mkdir" variant of mkdir(2), uses mkdtemp(3), lchown(2), and
4299 * rename(2) to create a directory which cannot be hijacked by a symlink
4300 * race (hopefully) before the UserOwner/GroupOwner ownership changes are
4301 * applied.
4302 */
pr_fsio_smkdir(pool * p,const char * path,mode_t mode,uid_t uid,gid_t gid)4303 int pr_fsio_smkdir(pool *p, const char *path, mode_t mode, uid_t uid,
4304 gid_t gid) {
4305 int res, set_sgid = FALSE, use_mkdtemp, use_root_chown = FALSE, xerrno = 0;
4306 char *tmpl_path;
4307 char *dst_dir, *tmpl;
4308 size_t dst_dirlen, tmpl_len;
4309
4310 if (p == NULL ||
4311 path == NULL) {
4312 errno = EINVAL;
4313 return -1;
4314 }
4315
4316 pr_trace_msg(trace_channel, 9,
4317 "smkdir: path '%s', mode %04o, UID %s, GID %s", path, (unsigned int) mode,
4318 pr_uid2str(p, uid), pr_gid2str(p, gid));
4319
4320 if (fsio_guard_chroot) {
4321 res = chroot_allow_path(path);
4322 if (res < 0) {
4323 return -1;
4324 }
4325 }
4326
4327 use_mkdtemp = fsio_use_mkdtemp;
4328 if (use_mkdtemp == TRUE) {
4329
4330 /* Note that using mkdtemp(3) is a way of dealing with Bug#3841. The
4331 * problem in question, though, only applies if root privs are used
4332 * to set the ownership. Thus if root privs are NOT needed, then there
4333 * is no need to use mkdtemp(3).
4334 */
4335
4336 if (uid != (uid_t) -1) {
4337 use_root_chown = TRUE;
4338
4339 } else if (gid != (gid_t) -1) {
4340 register unsigned int i;
4341
4342 use_root_chown = TRUE;
4343
4344 /* Check if session.fsgid is in session.gids. If not, use root privs. */
4345 for (i = 0; i < session.gids->nelts; i++) {
4346 gid_t *group_ids = session.gids->elts;
4347
4348 if (group_ids[i] == gid) {
4349 use_root_chown = FALSE;
4350 break;
4351 }
4352 }
4353 }
4354
4355 if (use_root_chown == FALSE) {
4356 use_mkdtemp = FALSE;
4357 }
4358 }
4359
4360 #ifdef HAVE_MKDTEMP
4361 if (use_mkdtemp == TRUE) {
4362 char *ptr;
4363 struct stat st;
4364
4365 ptr = strrchr(path, '/');
4366 if (ptr == NULL) {
4367 errno = EINVAL;
4368 return -1;
4369 }
4370
4371 if (ptr != path) {
4372 dst_dirlen = (ptr - path);
4373 dst_dir = pstrndup(p, path, dst_dirlen);
4374
4375 } else {
4376 dst_dirlen = 1;
4377 dst_dir = "/";
4378 }
4379
4380 res = lstat(dst_dir, &st);
4381 if (res < 0) {
4382 xerrno = errno;
4383
4384 pr_log_pri(PR_LOG_WARNING,
4385 "smkdir: unable to lstat(2) parent directory '%s': %s", dst_dir,
4386 strerror(xerrno));
4387 pr_trace_msg(trace_channel, 1,
4388 "smkdir: unable to lstat(2) parent directory '%s': %s", dst_dir,
4389 strerror(xerrno));
4390
4391 errno = xerrno;
4392 return -1;
4393 }
4394
4395 if (!S_ISDIR(st.st_mode) &&
4396 !S_ISLNK(st.st_mode)) {
4397 errno = EPERM;
4398 return -1;
4399 }
4400
4401 if (st.st_mode & S_ISGID) {
4402 set_sgid = TRUE;
4403 }
4404
4405 /* Allocate enough space for the temporary name: the length of the
4406 * destination directory, a slash, 9 X's, 3 for the prefix, and 1 for the
4407 * trailing NUL.
4408 */
4409 tmpl_len = dst_dirlen + 15;
4410 tmpl = pcalloc(p, tmpl_len);
4411 pr_snprintf(tmpl, tmpl_len-1, "%s/.dstXXXXXXXXX",
4412 dst_dirlen > 1 ? dst_dir : "");
4413
4414 /* Use mkdtemp(3) to create the temporary directory (in the same destination
4415 * directory as the target path).
4416 */
4417 tmpl_path = mkdtemp(tmpl);
4418 if (tmpl_path == NULL) {
4419 xerrno = errno;
4420
4421 pr_log_pri(PR_LOG_WARNING,
4422 "smkdir: mkdtemp(3) failed to create directory using '%s': %s", tmpl,
4423 strerror(xerrno));
4424 pr_trace_msg(trace_channel, 1,
4425 "smkdir: mkdtemp(3) failed to create directory using '%s': %s", tmpl,
4426 strerror(xerrno));
4427
4428 errno = xerrno;
4429 return -1;
4430 }
4431
4432 } else {
4433 res = pr_fsio_mkdir(path, mode);
4434 if (res < 0) {
4435 xerrno = errno;
4436
4437 pr_trace_msg(trace_channel, 1,
4438 "mkdir(2) failed to create directory '%s' with perms %04o: %s", path,
4439 mode, strerror(xerrno));
4440
4441 errno = xerrno;
4442 return -1;
4443 }
4444
4445 tmpl_path = pstrdup(p, path);
4446 }
4447 #else
4448
4449 res = pr_fsio_mkdir(path, mode);
4450 if (res < 0) {
4451 xerrno = errno;
4452
4453 pr_trace_msg(trace_channel, 1,
4454 "mkdir(2) failed to create directory '%s' with perms %04o: %s", path,
4455 mode, strerror(xerrno));
4456
4457 errno = xerrno;
4458 return -1;
4459 }
4460
4461 tmpl_path = pstrdup(p, path);
4462 #endif /* HAVE_MKDTEMP */
4463
4464 if (use_mkdtemp == TRUE) {
4465 mode_t mask, *dir_umask, perms;
4466
4467 /* mkdtemp(3) creates a directory with 0700 perms; we are given the
4468 * target mode (modulo the configured Umask).
4469 */
4470 dir_umask = get_param_ptr(CURRENT_CONF, "DirUmask", FALSE);
4471 if (dir_umask == NULL) {
4472 /* If Umask was configured with a single parameter, then DirUmask
4473 * would not be present; we still should check for Umask.
4474 */
4475 dir_umask = get_param_ptr(CURRENT_CONF, "Umask", FALSE);
4476 }
4477
4478 if (dir_umask) {
4479 mask = *dir_umask;
4480
4481 } else {
4482 mask = (mode_t) 0022;
4483 }
4484
4485 perms = (mode & ~mask);
4486
4487 if (set_sgid) {
4488 perms |= S_ISGID;
4489 }
4490
4491 /* If we're setting the SGID bit, we need to use root privs, in order
4492 * to reliably set the SGID bit. Sigh.
4493 */
4494 res = schmod_dir(p, tmpl_path, perms, set_sgid);
4495 xerrno = errno;
4496
4497 if (set_sgid) {
4498 if (res < 0 &&
4499 xerrno == EPERM) {
4500 /* Try again, this time without root privs. NFS situations which
4501 * squash root privs could cause the above chmod(2) to fail; it
4502 * might succeed now that we've dropped root privs (Bug#3962).
4503 */
4504 res = schmod_dir(p, tmpl_path, perms, FALSE);
4505 xerrno = errno;
4506 }
4507 }
4508
4509 if (res < 0) {
4510 pr_log_pri(PR_LOG_WARNING, "chmod(%s) failed: %s", tmpl_path,
4511 strerror(xerrno));
4512
4513 (void) rmdir(tmpl_path);
4514
4515 errno = xerrno;
4516 return -1;
4517 }
4518 }
4519
4520 if (uid != (uid_t) -1) {
4521 if (use_root_chown) {
4522 PRIVS_ROOT
4523 }
4524
4525 res = pr_fsio_lchown(tmpl_path, uid, gid);
4526 xerrno = errno;
4527
4528 if (use_root_chown) {
4529 PRIVS_RELINQUISH
4530 }
4531
4532 if (res < 0) {
4533 pr_log_pri(PR_LOG_WARNING, "lchown(%s) as root failed: %s", tmpl_path,
4534 strerror(xerrno));
4535
4536 } else {
4537 if (gid != (gid_t) -1) {
4538 pr_log_debug(DEBUG2, "root lchown(%s) to UID %s, GID %s successful",
4539 tmpl_path, pr_uid2str(p, uid), pr_gid2str(p, gid));
4540
4541 } else {
4542 pr_log_debug(DEBUG2, "root lchown(%s) to UID %s successful",
4543 tmpl_path, pr_uid2str(NULL, uid));
4544 }
4545 }
4546
4547 } else if (gid != (gid_t) -1) {
4548 if (use_root_chown) {
4549 PRIVS_ROOT
4550 }
4551
4552 res = pr_fsio_lchown(tmpl_path, (uid_t) -1, gid);
4553 xerrno = errno;
4554
4555 if (use_root_chown) {
4556 PRIVS_RELINQUISH
4557 }
4558
4559 if (res < 0) {
4560 pr_log_pri(PR_LOG_WARNING, "%slchown(%s) failed: %s",
4561 use_root_chown ? "root " : "", tmpl_path, strerror(xerrno));
4562
4563 } else {
4564 pr_log_debug(DEBUG2, "%slchown(%s) to GID %s successful",
4565 use_root_chown ? "root " : "", tmpl_path, pr_gid2str(p, gid));
4566 }
4567 }
4568
4569 if (use_mkdtemp == TRUE) {
4570 /* Use rename(2) to move the temporary directory into place at the
4571 * target path.
4572 */
4573 res = rename(tmpl_path, path);
4574 if (res < 0) {
4575 xerrno = errno;
4576
4577 pr_log_pri(PR_LOG_INFO, "renaming '%s' to '%s' failed: %s", tmpl_path,
4578 path, strerror(xerrno));
4579
4580 (void) rmdir(tmpl_path);
4581
4582 #ifdef ENOTEMPTY
4583 if (xerrno == ENOTEMPTY) {
4584 /* If the rename(2) failed with "Directory not empty" (ENOTEMPTY),
4585 * then change the errno to "File exists" (EEXIST), so that the
4586 * error reported to the client is more indicative of the actual
4587 * cause.
4588 */
4589 xerrno = EEXIST;
4590 }
4591 #endif /* ENOTEMPTY */
4592
4593 errno = xerrno;
4594 return -1;
4595 }
4596 }
4597
4598 pr_fs_clear_cache2(path);
4599 return 0;
4600 }
4601
pr_fsio_rmdir(const char * path)4602 int pr_fsio_rmdir(const char *path) {
4603 int res;
4604 pr_fs_t *fs;
4605
4606 if (path == NULL) {
4607 errno = EINVAL;
4608 return -1;
4609 }
4610
4611 fs = lookup_dir_fs(path, FSIO_DIR_RMDIR);
4612 if (fs == NULL) {
4613 return -1;
4614 }
4615
4616 /* Find the first non-NULL custom rmdir handler. If there are none,
4617 * use the system rmdir.
4618 */
4619 while (fs && fs->fs_next && !fs->rmdir) {
4620 fs = fs->fs_next;
4621 }
4622
4623 pr_trace_msg(trace_channel, 8, "using %s rmdir() for path '%s'", fs->fs_name,
4624 path);
4625 res = (fs->rmdir)(fs, path);
4626 if (res == 0) {
4627 pr_fs_clear_cache2(path);
4628 }
4629
4630 return res;
4631 }
4632
pr_fsio_rmdir_with_error(pool * p,const char * path,pr_error_t ** err)4633 int pr_fsio_rmdir_with_error(pool *p, const char *path, pr_error_t **err) {
4634 int res;
4635
4636 res = pr_fsio_rmdir(path);
4637 if (res < 0) {
4638 int xerrno = errno;
4639
4640 if (p != NULL &&
4641 err != NULL) {
4642 *err = pr_error_create(p, xerrno);
4643 if (pr_error_explain_rmdir(*err, path) < 0) {
4644 pr_error_destroy(*err);
4645 *err = NULL;
4646 }
4647 }
4648
4649 errno = xerrno;
4650 }
4651
4652 return res;
4653 }
4654
pr_fsio_stat(const char * path,struct stat * st)4655 int pr_fsio_stat(const char *path, struct stat *st) {
4656 pr_fs_t *fs = NULL;
4657
4658 if (path == NULL ||
4659 st == NULL) {
4660 errno = EINVAL;
4661 return -1;
4662 }
4663
4664 fs = lookup_file_fs(path, NULL, FSIO_FILE_STAT);
4665 if (fs == NULL) {
4666 return -1;
4667 }
4668
4669 /* Find the first non-NULL custom stat handler. If there are none,
4670 * use the system stat.
4671 */
4672 while (fs && fs->fs_next && !fs->stat) {
4673 fs = fs->fs_next;
4674 }
4675
4676 pr_trace_msg(trace_channel, 8, "using %s stat() for path '%s'", fs->fs_name,
4677 path);
4678 return fs_cache_stat(fs ? fs : root_fs, path, st);
4679 }
4680
pr_fsio_stat_with_error(pool * p,const char * path,struct stat * st,pr_error_t ** err)4681 int pr_fsio_stat_with_error(pool *p, const char *path, struct stat *st,
4682 pr_error_t **err) {
4683 int res;
4684
4685 res = pr_fsio_stat(path, st);
4686 if (res < 0) {
4687 int xerrno = errno;
4688
4689 if (p != NULL &&
4690 err != NULL) {
4691 *err = pr_error_create(p, xerrno);
4692 if (pr_error_explain_stat(*err, path, st) < 0) {
4693 pr_error_destroy(*err);
4694 *err = NULL;
4695 }
4696 }
4697
4698 errno = xerrno;
4699 }
4700
4701 return res;
4702 }
4703
pr_fsio_fstat(pr_fh_t * fh,struct stat * st)4704 int pr_fsio_fstat(pr_fh_t *fh, struct stat *st) {
4705 int res;
4706 pr_fs_t *fs;
4707
4708 if (fh == NULL ||
4709 st == NULL) {
4710 errno = EINVAL;
4711 return -1;
4712 }
4713
4714 /* Find the first non-NULL custom fstat handler. If there are none,
4715 * use the system fstat.
4716 */
4717 fs = fh->fh_fs;
4718 while (fs && fs->fs_next && !fs->fstat) {
4719 fs = fs->fs_next;
4720 }
4721
4722 pr_trace_msg(trace_channel, 8, "using %s fstat() for path '%s'", fs->fs_name,
4723 fh->fh_path);
4724 res = (fs->fstat)(fh, fh->fh_fd, st);
4725
4726 return res;
4727 }
4728
pr_fsio_lstat(const char * path,struct stat * st)4729 int pr_fsio_lstat(const char *path, struct stat *st) {
4730 pr_fs_t *fs;
4731
4732 if (path == NULL ||
4733 st == NULL) {
4734 errno = EINVAL;
4735 return -1;
4736 }
4737
4738 fs = lookup_file_fs(path, NULL, FSIO_FILE_LSTAT);
4739 if (fs == NULL) {
4740 return -1;
4741 }
4742
4743 /* Find the first non-NULL custom lstat handler. If there are none,
4744 * use the system lstat.
4745 */
4746 while (fs && fs->fs_next && !fs->lstat) {
4747 fs = fs->fs_next;
4748 }
4749
4750 pr_trace_msg(trace_channel, 8, "using %s lstat() for path '%s'", fs->fs_name,
4751 path);
4752 return fs_cache_lstat(fs ? fs : root_fs, path, st);
4753 }
4754
pr_fsio_lstat_with_error(pool * p,const char * path,struct stat * st,pr_error_t ** err)4755 int pr_fsio_lstat_with_error(pool *p, const char *path, struct stat *st,
4756 pr_error_t **err) {
4757 int res;
4758
4759 res = pr_fsio_lstat(path, st);
4760 if (res < 0) {
4761 int xerrno = errno;
4762
4763 if (p != NULL &&
4764 err != NULL) {
4765 *err = pr_error_create(p, xerrno);
4766 if (pr_error_explain_lstat(*err, path, st) < 0) {
4767 pr_error_destroy(*err);
4768 *err = NULL;
4769 }
4770 }
4771
4772 errno = xerrno;
4773 }
4774
4775 return res;
4776 }
4777
pr_fsio_readlink(const char * path,char * buf,size_t buflen)4778 int pr_fsio_readlink(const char *path, char *buf, size_t buflen) {
4779 int res;
4780 pr_fs_t *fs;
4781
4782 if (path == NULL ||
4783 buf == NULL) {
4784 errno = EINVAL;
4785 return -1;
4786 }
4787
4788 fs = lookup_file_fs(path, NULL, FSIO_FILE_READLINK);
4789 if (fs == NULL) {
4790 return -1;
4791 }
4792
4793 /* Find the first non-NULL custom readlink handler. If there are none,
4794 * use the system readlink.
4795 */
4796 while (fs && fs->fs_next && !fs->readlink) {
4797 fs = fs->fs_next;
4798 }
4799
4800 pr_trace_msg(trace_channel, 8, "using %s readlink() for path '%s'",
4801 fs->fs_name, path);
4802 res = (fs->readlink)(fs, path, buf, buflen);
4803
4804 return res;
4805 }
4806
4807 /* pr_fs_glob() is just a wrapper for glob(3), setting the various gl_
4808 * callbacks to our fs functions.
4809 */
pr_fs_glob(const char * pattern,int flags,int (* errfunc)(const char *,int),glob_t * pglob)4810 int pr_fs_glob(const char *pattern, int flags,
4811 int (*errfunc)(const char *, int), glob_t *pglob) {
4812
4813 if (pattern == NULL ||
4814 pglob == NULL) {
4815 errno = EINVAL;
4816 return -1;
4817 }
4818
4819 flags |= GLOB_ALTDIRFUNC;
4820
4821 pglob->gl_closedir = (void (*)(void *)) pr_fsio_closedir;
4822 pglob->gl_readdir = pr_fsio_readdir;
4823 pglob->gl_opendir = pr_fsio_opendir;
4824 pglob->gl_lstat = pr_fsio_lstat;
4825 pglob->gl_stat = pr_fsio_stat;
4826
4827 return glob(pattern, flags, errfunc, pglob);
4828 }
4829
pr_fs_globfree(glob_t * pglob)4830 void pr_fs_globfree(glob_t *pglob) {
4831 if (pglob != NULL) {
4832 globfree(pglob);
4833 }
4834 }
4835
pr_fsio_rename(const char * rnfr,const char * rnto)4836 int pr_fsio_rename(const char *rnfr, const char *rnto) {
4837 int res;
4838 pr_fs_t *from_fs, *to_fs, *fs;
4839
4840 if (rnfr == NULL ||
4841 rnto == NULL) {
4842 errno = EINVAL;
4843 return -1;
4844 }
4845
4846 from_fs = lookup_file_fs(rnfr, NULL, FSIO_FILE_RENAME);
4847 if (from_fs == NULL) {
4848 return -1;
4849 }
4850
4851 to_fs = lookup_file_fs(rnto, NULL, FSIO_FILE_RENAME);
4852 if (to_fs == NULL) {
4853 return -1;
4854 }
4855
4856 if (from_fs->allow_xdev_rename == FALSE ||
4857 to_fs->allow_xdev_rename == FALSE) {
4858 if (from_fs != to_fs) {
4859 errno = EXDEV;
4860 return -1;
4861 }
4862 }
4863
4864 fs = to_fs;
4865
4866 /* Find the first non-NULL custom rename handler. If there are none,
4867 * use the system rename.
4868 */
4869 while (fs && fs->fs_next && !fs->rename) {
4870 fs = fs->fs_next;
4871 }
4872
4873 pr_trace_msg(trace_channel, 8, "using %s rename() for paths '%s', '%s'",
4874 fs->fs_name, rnfr, rnto);
4875 res = (fs->rename)(fs, rnfr, rnto);
4876 if (res == 0) {
4877 pr_fs_clear_cache2(rnfr);
4878 pr_fs_clear_cache2(rnto);
4879 }
4880
4881 return res;
4882 }
4883
pr_fsio_rename_with_error(pool * p,const char * rnfr,const char * rnto,pr_error_t ** err)4884 int pr_fsio_rename_with_error(pool *p, const char *rnfr, const char *rnto,
4885 pr_error_t **err) {
4886 int res;
4887
4888 res = pr_fsio_rename(rnfr, rnto);
4889 if (res < 0) {
4890 int xerrno = errno;
4891
4892 if (p != NULL &&
4893 err != NULL) {
4894 *err = pr_error_create(p, xerrno);
4895 if (pr_error_explain_rename(*err, rnfr, rnto) < 0) {
4896 pr_error_destroy(*err);
4897 *err = NULL;
4898 }
4899 }
4900
4901 errno = xerrno;
4902 }
4903
4904 return res;
4905 }
4906
pr_fsio_unlink(const char * name)4907 int pr_fsio_unlink(const char *name) {
4908 int res;
4909 pr_fs_t *fs;
4910
4911 if (name == NULL) {
4912 errno = EINVAL;
4913 return -1;
4914 }
4915
4916 fs = lookup_file_fs(name, NULL, FSIO_FILE_UNLINK);
4917 if (fs == NULL) {
4918 return -1;
4919 }
4920
4921 /* Find the first non-NULL custom unlink handler. If there are none,
4922 * use the system unlink.
4923 */
4924 while (fs && fs->fs_next && !fs->unlink) {
4925 fs = fs->fs_next;
4926 }
4927
4928 pr_trace_msg(trace_channel, 8, "using %s unlink() for path '%s'",
4929 fs->fs_name, name);
4930 res = (fs->unlink)(fs, name);
4931 if (res == 0) {
4932 pr_fs_clear_cache2(name);
4933 }
4934
4935 return res;
4936 }
4937
pr_fsio_unlink_with_error(pool * p,const char * path,pr_error_t ** err)4938 int pr_fsio_unlink_with_error(pool *p, const char *path, pr_error_t **err) {
4939 int res;
4940
4941 res = pr_fsio_unlink(path);
4942 if (res < 0) {
4943 int xerrno = errno;
4944
4945 if (p != NULL &&
4946 err != NULL) {
4947 *err = pr_error_create(p, xerrno);
4948 if (pr_error_explain_unlink(*err, path) < 0) {
4949 pr_error_destroy(*err);
4950 *err = NULL;
4951 }
4952 }
4953
4954 errno = xerrno;
4955 }
4956
4957 return res;
4958 }
4959
pr_fsio_open_canon(const char * name,int flags)4960 pr_fh_t *pr_fsio_open_canon(const char *name, int flags) {
4961 char *deref = NULL;
4962 pool *tmp_pool = NULL;
4963 pr_fh_t *fh = NULL;
4964 pr_fs_t *fs = NULL;
4965
4966 if (name == NULL) {
4967 errno = EINVAL;
4968 return NULL;
4969 }
4970
4971 fs = lookup_file_canon_fs(name, &deref, FSIO_FILE_OPEN);
4972 if (fs == NULL) {
4973 return NULL;
4974 }
4975
4976 /* Allocate a filehandle. */
4977 tmp_pool = make_sub_pool(fs->fs_pool);
4978 pr_pool_tag(tmp_pool, "pr_fsio_open_canon() subpool");
4979
4980 fh = pcalloc(tmp_pool, sizeof(pr_fh_t));
4981 fh->fh_pool = tmp_pool;
4982 fh->fh_path = pstrdup(fh->fh_pool, name);
4983 fh->fh_fd = -1;
4984 fh->fh_buf = NULL;
4985 fh->fh_fs = fs;
4986
4987 /* Find the first non-NULL custom open handler. If there are none,
4988 * use the system open.
4989 */
4990 while (fs && fs->fs_next && !fs->open) {
4991 fs = fs->fs_next;
4992 }
4993
4994 pr_trace_msg(trace_channel, 8, "using %s open() for path '%s'", fs->fs_name,
4995 name);
4996 fh->fh_fd = (fs->open)(fh, deref, flags);
4997 if (fh->fh_fd < 0) {
4998 int xerrno = errno;
4999
5000 destroy_pool(fh->fh_pool);
5001 fh->fh_pool = NULL;
5002
5003 errno = xerrno;
5004 return NULL;
5005 }
5006
5007 if ((flags & O_CREAT) ||
5008 (flags & O_TRUNC)) {
5009 pr_fs_clear_cache2(name);
5010 }
5011
5012 if (fcntl(fh->fh_fd, F_SETFD, FD_CLOEXEC) < 0) {
5013 if (errno != EBADF) {
5014 pr_trace_msg(trace_channel, 1, "error setting CLOEXEC on file fd %d: %s",
5015 fh->fh_fd, strerror(errno));
5016 }
5017 }
5018
5019 return fh;
5020 }
5021
pr_fsio_open(const char * name,int flags)5022 pr_fh_t *pr_fsio_open(const char *name, int flags) {
5023 pool *tmp_pool = NULL;
5024 pr_fh_t *fh = NULL;
5025 pr_fs_t *fs = NULL;
5026
5027 if (name == NULL) {
5028 errno = EINVAL;
5029 return NULL;
5030 }
5031
5032 fs = lookup_file_fs(name, NULL, FSIO_FILE_OPEN);
5033 if (fs == NULL) {
5034 return NULL;
5035 }
5036
5037 /* Allocate a filehandle. */
5038 tmp_pool = make_sub_pool(fs->fs_pool);
5039 pr_pool_tag(tmp_pool, "pr_fsio_open() subpool");
5040
5041 fh = pcalloc(tmp_pool, sizeof(pr_fh_t));
5042 fh->fh_pool = tmp_pool;
5043 fh->fh_path = pstrdup(fh->fh_pool, name);
5044 fh->fh_fd = -1;
5045 fh->fh_buf = NULL;
5046 fh->fh_fs = fs;
5047
5048 /* Find the first non-NULL custom open handler. If there are none,
5049 * use the system open.
5050 */
5051 while (fs && fs->fs_next && !fs->open) {
5052 fs = fs->fs_next;
5053 }
5054
5055 pr_trace_msg(trace_channel, 8, "using %s open() for path '%s'", fs->fs_name,
5056 name);
5057 fh->fh_fd = (fs->open)(fh, name, flags);
5058 if (fh->fh_fd < 0) {
5059 int xerrno = errno;
5060
5061 destroy_pool(fh->fh_pool);
5062 fh->fh_pool = NULL;
5063
5064 errno = xerrno;
5065 return NULL;
5066 }
5067
5068 if ((flags & O_CREAT) ||
5069 (flags & O_TRUNC)) {
5070 pr_fs_clear_cache2(name);
5071 }
5072
5073 if (fcntl(fh->fh_fd, F_SETFD, FD_CLOEXEC) < 0) {
5074 if (errno != EBADF) {
5075 pr_trace_msg(trace_channel, 1, "error setting CLOEXEC on file fd %d: %s",
5076 fh->fh_fd, strerror(errno));
5077 }
5078 }
5079
5080 return fh;
5081 }
5082
pr_fsio_open_with_error(pool * p,const char * name,int flags,pr_error_t ** err)5083 pr_fh_t *pr_fsio_open_with_error(pool *p, const char *name, int flags,
5084 pr_error_t **err) {
5085 pr_fh_t *fh;
5086
5087 fh = pr_fsio_open(name, flags);
5088 if (fh == NULL) {
5089 int xerrno = errno;
5090
5091 if (p != NULL &&
5092 err != NULL) {
5093 *err = pr_error_create(p, xerrno);
5094 if (pr_error_explain_open(*err, name, flags, PR_OPEN_MODE) < 0) {
5095 pr_error_destroy(*err);
5096 *err = NULL;
5097 }
5098 }
5099
5100 errno = xerrno;
5101 }
5102
5103 return fh;
5104 }
5105
pr_fsio_close(pr_fh_t * fh)5106 int pr_fsio_close(pr_fh_t *fh) {
5107 int res = 0, xerrno = 0;
5108 pr_fs_t *fs;
5109
5110 if (fh == NULL) {
5111 errno = EINVAL;
5112 return -1;
5113 }
5114
5115 /* Find the first non-NULL custom close handler. If there are none,
5116 * use the system close.
5117 */
5118 fs = fh->fh_fs;
5119 while (fs && fs->fs_next && !fs->close) {
5120 fs = fs->fs_next;
5121 }
5122
5123 pr_trace_msg(trace_channel, 8, "using %s close() for path '%s'", fs->fs_name,
5124 fh->fh_path);
5125 res = (fs->close)(fh, fh->fh_fd);
5126 xerrno = errno;
5127
5128 if (res == 0) {
5129 pr_fs_clear_cache2(fh->fh_path);
5130 }
5131
5132 /* Make sure to scrub any buffered memory, too. */
5133 if (fh->fh_buf != NULL) {
5134 pr_buffer_t *pbuf;
5135
5136 pbuf = fh->fh_buf;
5137 pr_memscrub(pbuf->buf, pbuf->buflen);
5138 }
5139
5140 if (fh->fh_pool != NULL) {
5141 destroy_pool(fh->fh_pool);
5142 fh->fh_pool = NULL;
5143 }
5144
5145 errno = xerrno;
5146 return res;
5147 }
5148
pr_fsio_close_with_error(pool * p,pr_fh_t * fh,pr_error_t ** err)5149 int pr_fsio_close_with_error(pool *p, pr_fh_t *fh, pr_error_t **err) {
5150 int res;
5151
5152 res = pr_fsio_close(fh);
5153 if (res < 0) {
5154 int xerrno = errno;
5155
5156 if (p != NULL &&
5157 err != NULL) {
5158 int fd = -1;
5159
5160 *err = pr_error_create(p, xerrno);
5161
5162 if (fh != NULL) {
5163 fd = fh->fh_fd;
5164 }
5165
5166 if (pr_error_explain_close(*err, fd) < 0) {
5167 pr_error_destroy(*err);
5168 *err = NULL;
5169 }
5170 }
5171
5172 errno = xerrno;
5173 }
5174
5175 return res;
5176 }
5177
pr_fsio_pread(pr_fh_t * fh,void * buf,size_t size,off_t offset)5178 ssize_t pr_fsio_pread(pr_fh_t *fh, void *buf, size_t size, off_t offset) {
5179 ssize_t res;
5180 pr_fs_t *fs;
5181
5182 if (fh == NULL ||
5183 buf == NULL ||
5184 size == 0) {
5185 errno = EINVAL;
5186 return -1;
5187 }
5188
5189 /* Find the first non-NULL custom pread handler. If there are none,
5190 * use the system pread.
5191 */
5192 fs = fh->fh_fs;
5193 while (fs && fs->fs_next && !fs->pread) {
5194 fs = fs->fs_next;
5195 }
5196
5197 pr_trace_msg(trace_channel, 8, "using %s pread() for path '%s' (%lu bytes, %"
5198 PR_LU " offset)", fs->fs_name, fh->fh_path, (unsigned long) size,
5199 (pr_off_t) offset);
5200 res = (fs->pread)(fh, fh->fh_fd, buf, size, offset);
5201
5202 return res;
5203 }
5204
pr_fsio_read(pr_fh_t * fh,char * buf,size_t size)5205 int pr_fsio_read(pr_fh_t *fh, char *buf, size_t size) {
5206 int res;
5207 pr_fs_t *fs;
5208
5209 if (fh == NULL ||
5210 buf == NULL ||
5211 size == 0) {
5212 errno = EINVAL;
5213 return -1;
5214 }
5215
5216 /* Find the first non-NULL custom read handler. If there are none,
5217 * use the system read.
5218 */
5219 fs = fh->fh_fs;
5220 while (fs && fs->fs_next && !fs->read) {
5221 fs = fs->fs_next;
5222 }
5223
5224 pr_trace_msg(trace_channel, 8, "using %s read() for path '%s' (%lu bytes)",
5225 fs->fs_name, fh->fh_path, (unsigned long) size);
5226 res = (fs->read)(fh, fh->fh_fd, buf, size);
5227
5228 return res;
5229 }
5230
pr_fsio_read_with_error(pool * p,pr_fh_t * fh,char * buf,size_t sz,pr_error_t ** err)5231 int pr_fsio_read_with_error(pool *p, pr_fh_t *fh, char *buf, size_t sz,
5232 pr_error_t **err) {
5233 int res;
5234
5235 res = pr_fsio_read(fh, buf, sz);
5236 if (res < 0) {
5237 int xerrno = errno;
5238
5239 if (p != NULL &&
5240 err != NULL) {
5241 int fd = -1;
5242
5243 if (fh != NULL) {
5244 fd = fh->fh_fd;
5245 }
5246
5247 *err = pr_error_create(p, xerrno);
5248 if (pr_error_explain_read(*err, fd, buf, sz) < 0) {
5249 pr_error_destroy(*err);
5250 *err = NULL;
5251 }
5252 }
5253
5254 errno = xerrno;
5255 }
5256
5257 return res;
5258 }
5259
pr_fsio_pwrite(pr_fh_t * fh,const void * buf,size_t size,off_t offset)5260 ssize_t pr_fsio_pwrite(pr_fh_t *fh, const void *buf, size_t size,
5261 off_t offset) {
5262 ssize_t res;
5263 pr_fs_t *fs;
5264
5265 if (fh == NULL ||
5266 buf == NULL) {
5267 errno = EINVAL;
5268 return -1;
5269 }
5270
5271 /* Find the first non-NULL custom pwrite handler. If there are none,
5272 * use the system pwrite.
5273 */
5274 fs = fh->fh_fs;
5275 while (fs && fs->fs_next && !fs->pwrite) {
5276 fs = fs->fs_next;
5277 }
5278
5279 pr_trace_msg(trace_channel, 8, "using %s pwrite() for path '%s' (%lu bytes, %"
5280 PR_LU " offset)", fs->fs_name, fh->fh_path, (unsigned long) size,
5281 (pr_off_t) offset);
5282 res = (fs->pwrite)(fh, fh->fh_fd, buf, size, offset);
5283
5284 return res;
5285 }
5286
pr_fsio_write(pr_fh_t * fh,const char * buf,size_t size)5287 int pr_fsio_write(pr_fh_t *fh, const char *buf, size_t size) {
5288 int res;
5289 pr_fs_t *fs;
5290
5291 if (fh == NULL ||
5292 buf == NULL) {
5293 errno = EINVAL;
5294 return -1;
5295 }
5296
5297 /* Find the first non-NULL custom write handler. If there are none,
5298 * use the system write.
5299 */
5300 fs = fh->fh_fs;
5301 while (fs && fs->fs_next && !fs->write) {
5302 fs = fs->fs_next;
5303 }
5304
5305 pr_trace_msg(trace_channel, 8, "using %s write() for path '%s' (%lu bytes)",
5306 fs->fs_name, fh->fh_path, (unsigned long) size);
5307 res = (fs->write)(fh, fh->fh_fd, buf, size);
5308
5309 return res;
5310 }
5311
pr_fsio_write_with_error(pool * p,pr_fh_t * fh,const char * buf,size_t sz,pr_error_t ** err)5312 int pr_fsio_write_with_error(pool *p, pr_fh_t *fh, const char *buf, size_t sz,
5313 pr_error_t **err) {
5314 int res;
5315
5316 res = pr_fsio_write(fh, buf, sz);
5317 if (res < 0) {
5318 int xerrno = errno;
5319
5320 if (p != NULL &&
5321 err != NULL) {
5322 int fd = -1;
5323
5324 if (fh != NULL) {
5325 fd = fh->fh_fd;
5326 }
5327
5328 *err = pr_error_create(p, xerrno);
5329 if (pr_error_explain_write(*err, fd, buf, sz) < 0) {
5330 pr_error_destroy(*err);
5331 *err = NULL;
5332 }
5333 }
5334
5335 errno = xerrno;
5336 }
5337
5338 return res;
5339 }
5340
pr_fsio_lseek(pr_fh_t * fh,off_t offset,int whence)5341 off_t pr_fsio_lseek(pr_fh_t *fh, off_t offset, int whence) {
5342 off_t res;
5343 pr_fs_t *fs;
5344
5345 if (fh == NULL) {
5346 errno = EINVAL;
5347 return -1;
5348 }
5349
5350 /* Find the first non-NULL custom lseek handler. If there are none,
5351 * use the system lseek.
5352 */
5353 fs = fh->fh_fs;
5354 while (fs && fs->fs_next && !fs->lseek) {
5355 fs = fs->fs_next;
5356 }
5357
5358 pr_trace_msg(trace_channel, 8, "using %s lseek() for path '%s'", fs->fs_name,
5359 fh->fh_path);
5360 res = (fs->lseek)(fh, fh->fh_fd, offset, whence);
5361
5362 return res;
5363 }
5364
pr_fsio_link(const char * target_path,const char * link_path)5365 int pr_fsio_link(const char *target_path, const char *link_path) {
5366 int res;
5367 pr_fs_t *target_fs, *link_fs, *fs;
5368
5369 if (target_path == NULL ||
5370 link_path == NULL) {
5371 errno = EINVAL;
5372 return -1;
5373 }
5374
5375 target_fs = lookup_file_fs(target_path, NULL, FSIO_FILE_LINK);
5376 if (target_fs == NULL) {
5377 return -1;
5378 }
5379
5380 link_fs = lookup_file_fs(link_path, NULL, FSIO_FILE_LINK);
5381 if (link_fs == NULL) {
5382 return -1;
5383 }
5384
5385 if (target_fs->allow_xdev_link == FALSE ||
5386 link_fs->allow_xdev_link == FALSE) {
5387 if (target_fs != link_fs) {
5388 errno = EXDEV;
5389 return -1;
5390 }
5391 }
5392
5393 fs = link_fs;
5394
5395 /* Find the first non-NULL custom link handler. If there are none,
5396 * use the system link.
5397 */
5398 while (fs && fs->fs_next && !fs->link) {
5399 fs = fs->fs_next;
5400 }
5401
5402 pr_trace_msg(trace_channel, 8, "using %s link() for paths '%s', '%s'",
5403 fs->fs_name, target_path, link_path);
5404 res = (fs->link)(fs, target_path, link_path);
5405 if (res == 0) {
5406 pr_fs_clear_cache2(link_path);
5407 }
5408
5409 return res;
5410 }
5411
pr_fsio_symlink(const char * target_path,const char * link_path)5412 int pr_fsio_symlink(const char *target_path, const char *link_path) {
5413 int res;
5414 pr_fs_t *fs;
5415
5416 if (target_path == NULL ||
5417 link_path == NULL) {
5418 errno = EINVAL;
5419 return -1;
5420 }
5421
5422 fs = lookup_file_fs(link_path, NULL, FSIO_FILE_SYMLINK);
5423 if (fs == NULL) {
5424 return -1;
5425 }
5426
5427 /* Find the first non-NULL custom symlink handler. If there are none,
5428 * use the system symlink.
5429 */
5430 while (fs && fs->fs_next && !fs->symlink) {
5431 fs = fs->fs_next;
5432 }
5433
5434 pr_trace_msg(trace_channel, 8, "using %s symlink() for path '%s'",
5435 fs->fs_name, link_path);
5436 res = (fs->symlink)(fs, target_path, link_path);
5437 if (res == 0) {
5438 pr_fs_clear_cache2(link_path);
5439 }
5440
5441 return res;
5442 }
5443
pr_fsio_ftruncate(pr_fh_t * fh,off_t len)5444 int pr_fsio_ftruncate(pr_fh_t *fh, off_t len) {
5445 int res;
5446 pr_fs_t *fs;
5447
5448 if (fh == NULL) {
5449 errno = EINVAL;
5450 return -1;
5451 }
5452
5453 /* Find the first non-NULL custom ftruncate handler. If there are none,
5454 * use the system ftruncate.
5455 */
5456 fs = fh->fh_fs;
5457 while (fs && fs->fs_next && !fs->ftruncate) {
5458 fs = fs->fs_next;
5459 }
5460
5461 pr_trace_msg(trace_channel, 8, "using %s ftruncate() for path '%s'",
5462 fs->fs_name, fh->fh_path);
5463 res = (fs->ftruncate)(fh, fh->fh_fd, len);
5464 if (res == 0) {
5465 pr_fs_clear_cache2(fh->fh_path);
5466
5467 /* Clear any read buffer. */
5468 if (fh->fh_buf != NULL) {
5469 fh->fh_buf->current = fh->fh_buf->buf;
5470 fh->fh_buf->remaining = fh->fh_buf->buflen;
5471 }
5472 }
5473
5474 return res;
5475 }
5476
pr_fsio_truncate(const char * path,off_t len)5477 int pr_fsio_truncate(const char *path, off_t len) {
5478 int res;
5479 pr_fs_t *fs;
5480
5481 if (path == NULL) {
5482 errno = EINVAL;
5483 return -1;
5484 }
5485
5486 fs = lookup_file_fs(path, NULL, FSIO_FILE_TRUNC);
5487 if (fs == NULL) {
5488 return -1;
5489 }
5490
5491 /* Find the first non-NULL custom truncate handler. If there are none,
5492 * use the system truncate.
5493 */
5494 while (fs && fs->fs_next && !fs->truncate) {
5495 fs = fs->fs_next;
5496 }
5497
5498 pr_trace_msg(trace_channel, 8, "using %s truncate() for path '%s'",
5499 fs->fs_name, path);
5500 res = (fs->truncate)(fs, path, len);
5501 if (res == 0) {
5502 pr_fs_clear_cache2(path);
5503 }
5504
5505 return res;
5506 }
5507
pr_fsio_chmod(const char * name,mode_t mode)5508 int pr_fsio_chmod(const char *name, mode_t mode) {
5509 int res;
5510 pr_fs_t *fs;
5511
5512 if (name == NULL) {
5513 errno = EINVAL;
5514 return -1;
5515 }
5516
5517 fs = lookup_file_fs(name, NULL, FSIO_FILE_CHMOD);
5518 if (fs == NULL) {
5519 return -1;
5520 }
5521
5522 /* Find the first non-NULL custom chmod handler. If there are none,
5523 * use the system chmod.
5524 */
5525 while (fs && fs->fs_next && !fs->chmod) {
5526 fs = fs->fs_next;
5527 }
5528
5529 pr_trace_msg(trace_channel, 8, "using %s chmod() for path '%s'",
5530 fs->fs_name, name);
5531 res = (fs->chmod)(fs, name, mode);
5532 if (res == 0) {
5533 pr_fs_clear_cache2(name);
5534 }
5535
5536 return res;
5537 }
5538
pr_fsio_chmod_with_error(pool * p,const char * path,mode_t mode,pr_error_t ** err)5539 int pr_fsio_chmod_with_error(pool *p, const char *path, mode_t mode,
5540 pr_error_t **err) {
5541 int res;
5542
5543 res = pr_fsio_chmod(path, mode);
5544 if (res < 0) {
5545 int xerrno = errno;
5546
5547 if (p != NULL &&
5548 err != NULL) {
5549 *err = pr_error_create(p, xerrno);
5550 if (pr_error_explain_chmod(*err, path, mode) < 0) {
5551 pr_error_destroy(*err);
5552 *err = NULL;
5553 }
5554 }
5555
5556 errno = xerrno;
5557 }
5558
5559 return res;
5560 }
5561
pr_fsio_fchmod(pr_fh_t * fh,mode_t mode)5562 int pr_fsio_fchmod(pr_fh_t *fh, mode_t mode) {
5563 int res;
5564 pr_fs_t *fs;
5565
5566 if (fh == NULL) {
5567 errno = EINVAL;
5568 return -1;
5569 }
5570
5571 /* Find the first non-NULL custom fchmod handler. If there are none, use
5572 * the system fchmod.
5573 */
5574 fs = fh->fh_fs;
5575 while (fs && fs->fs_next && !fs->fchmod) {
5576 fs = fs->fs_next;
5577 }
5578
5579 pr_trace_msg(trace_channel, 8, "using %s fchmod() for path '%s'",
5580 fs->fs_name, fh->fh_path);
5581 res = (fs->fchmod)(fh, fh->fh_fd, mode);
5582 if (res == 0) {
5583 pr_fs_clear_cache2(fh->fh_path);
5584 }
5585
5586 return res;
5587 }
5588
pr_fsio_fchmod_with_error(pool * p,pr_fh_t * fh,mode_t mode,pr_error_t ** err)5589 int pr_fsio_fchmod_with_error(pool *p, pr_fh_t *fh, mode_t mode,
5590 pr_error_t **err) {
5591 int res;
5592
5593 res = pr_fsio_fchmod(fh, mode);
5594 if (res < 0) {
5595 int xerrno = errno;
5596
5597 if (p != NULL &&
5598 err != NULL) {
5599 int fd = -1;
5600
5601 if (fh != NULL) {
5602 fd = fh->fh_fd;
5603 }
5604
5605 *err = pr_error_create(p, xerrno);
5606 if (pr_error_explain_fchmod(*err, fd, mode) < 0) {
5607 pr_error_destroy(*err);
5608 *err = NULL;
5609 }
5610 }
5611
5612 errno = xerrno;
5613 }
5614
5615 return res;
5616 }
5617
pr_fsio_chown(const char * name,uid_t uid,gid_t gid)5618 int pr_fsio_chown(const char *name, uid_t uid, gid_t gid) {
5619 int res;
5620 pr_fs_t *fs;
5621
5622 if (name == NULL) {
5623 errno = EINVAL;
5624 return -1;
5625 }
5626
5627 fs = lookup_file_fs(name, NULL, FSIO_FILE_CHOWN);
5628 if (fs == NULL) {
5629 return -1;
5630 }
5631
5632 /* Find the first non-NULL custom chown handler. If there are none,
5633 * use the system chown.
5634 */
5635 while (fs && fs->fs_next && !fs->chown) {
5636 fs = fs->fs_next;
5637 }
5638
5639 pr_trace_msg(trace_channel, 8, "using %s chown() for path '%s'",
5640 fs->fs_name, name);
5641 res = (fs->chown)(fs, name, uid, gid);
5642 if (res == 0) {
5643 pr_fs_clear_cache2(name);
5644 }
5645
5646 return res;
5647 }
5648
pr_fsio_chown_with_error(pool * p,const char * path,uid_t uid,gid_t gid,pr_error_t ** err)5649 int pr_fsio_chown_with_error(pool *p, const char *path, uid_t uid, gid_t gid,
5650 pr_error_t **err) {
5651 int res;
5652
5653 res = pr_fsio_chown(path, uid, gid);
5654 if (res < 0) {
5655 int xerrno = errno;
5656
5657 if (p != NULL &&
5658 err != NULL) {
5659 *err = pr_error_create(p, xerrno);
5660 if (pr_error_explain_chown(*err, path, uid, gid) < 0) {
5661 pr_error_destroy(*err);
5662 *err = NULL;
5663 }
5664 }
5665
5666 errno = xerrno;
5667 }
5668
5669 return res;
5670 }
5671
pr_fsio_fchown(pr_fh_t * fh,uid_t uid,gid_t gid)5672 int pr_fsio_fchown(pr_fh_t *fh, uid_t uid, gid_t gid) {
5673 int res;
5674 pr_fs_t *fs;
5675
5676 if (fh == NULL) {
5677 errno = EINVAL;
5678 return -1;
5679 }
5680
5681 /* Find the first non-NULL custom fchown handler. If there are none, use
5682 * the system fchown.
5683 */
5684 fs = fh->fh_fs;
5685 while (fs && fs->fs_next && !fs->fchown) {
5686 fs = fs->fs_next;
5687 }
5688
5689 pr_trace_msg(trace_channel, 8, "using %s fchown() for path '%s'",
5690 fs->fs_name, fh->fh_path);
5691 res = (fs->fchown)(fh, fh->fh_fd, uid, gid);
5692 if (res == 0) {
5693 pr_fs_clear_cache2(fh->fh_path);
5694 }
5695
5696 return res;
5697 }
5698
pr_fsio_fchown_with_error(pool * p,pr_fh_t * fh,uid_t uid,gid_t gid,pr_error_t ** err)5699 int pr_fsio_fchown_with_error(pool *p, pr_fh_t *fh, uid_t uid, gid_t gid,
5700 pr_error_t **err) {
5701 int res;
5702
5703 res = pr_fsio_fchown(fh, uid, gid);
5704 if (res < 0) {
5705 int xerrno = errno;
5706
5707 if (p != NULL &&
5708 err != NULL) {
5709 int fd = -1;
5710
5711 if (fh != NULL) {
5712 fd = fh->fh_fd;
5713 }
5714
5715 *err = pr_error_create(p, xerrno);
5716 if (pr_error_explain_fchown(*err, fd, uid, gid) < 0) {
5717 pr_error_destroy(*err);
5718 *err = NULL;
5719 }
5720 }
5721
5722 errno = xerrno;
5723 }
5724
5725 return res;
5726 }
5727
pr_fsio_lchown(const char * name,uid_t uid,gid_t gid)5728 int pr_fsio_lchown(const char *name, uid_t uid, gid_t gid) {
5729 int res;
5730 pr_fs_t *fs;
5731
5732 if (name == NULL) {
5733 errno = EINVAL;
5734 return -1;
5735 }
5736
5737 fs = lookup_file_fs(name, NULL, FSIO_FILE_CHOWN);
5738 if (fs == NULL) {
5739 return -1;
5740 }
5741
5742 /* Find the first non-NULL custom lchown handler. If there are none,
5743 * use the system chown.
5744 */
5745 while (fs && fs->fs_next && !fs->lchown) {
5746 fs = fs->fs_next;
5747 }
5748
5749 pr_trace_msg(trace_channel, 8, "using %s lchown() for path '%s'",
5750 fs->fs_name, name);
5751 res = (fs->lchown)(fs, name, uid, gid);
5752 if (res == 0) {
5753 pr_fs_clear_cache2(name);
5754 }
5755
5756 return res;
5757 }
5758
pr_fsio_lchown_with_error(pool * p,const char * path,uid_t uid,gid_t gid,pr_error_t ** err)5759 int pr_fsio_lchown_with_error(pool *p, const char *path, uid_t uid, gid_t gid,
5760 pr_error_t **err) {
5761 int res;
5762
5763 res = pr_fsio_lchown(path, uid, gid);
5764 if (res < 0) {
5765 int xerrno = errno;
5766
5767 if (p != NULL &&
5768 err != NULL) {
5769 *err = pr_error_create(p, xerrno);
5770 if (pr_error_explain_lchown(*err, path, uid, gid) < 0) {
5771 pr_error_destroy(*err);
5772 *err = NULL;
5773 }
5774 }
5775
5776 errno = xerrno;
5777 }
5778
5779 return res;
5780 }
5781
pr_fsio_access(const char * path,int mode,uid_t uid,gid_t gid,array_header * suppl_gids)5782 int pr_fsio_access(const char *path, int mode, uid_t uid, gid_t gid,
5783 array_header *suppl_gids) {
5784 pr_fs_t *fs;
5785
5786 if (path == NULL) {
5787 errno = EINVAL;
5788 return -1;
5789 }
5790
5791 fs = lookup_file_fs(path, NULL, FSIO_FILE_ACCESS);
5792 if (fs == NULL) {
5793 return -1;
5794 }
5795
5796 /* Find the first non-NULL custom access handler. If there are none,
5797 * use the system access.
5798 */
5799 while (fs && fs->fs_next && !fs->access) {
5800 fs = fs->fs_next;
5801 }
5802
5803 pr_trace_msg(trace_channel, 8, "using %s access() for path '%s'",
5804 fs->fs_name, path);
5805 return (fs->access)(fs, path, mode, uid, gid, suppl_gids);
5806 }
5807
pr_fsio_faccess(pr_fh_t * fh,int mode,uid_t uid,gid_t gid,array_header * suppl_gids)5808 int pr_fsio_faccess(pr_fh_t *fh, int mode, uid_t uid, gid_t gid,
5809 array_header *suppl_gids) {
5810 pr_fs_t *fs;
5811
5812 if (fh == NULL) {
5813 errno = EINVAL;
5814 return -1;
5815 }
5816
5817 /* Find the first non-NULL custom faccess handler. If there are none,
5818 * use the system faccess.
5819 */
5820 fs = fh->fh_fs;
5821 while (fs && fs->fs_next && !fs->faccess) {
5822 fs = fs->fs_next;
5823 }
5824
5825 pr_trace_msg(trace_channel, 8, "using %s faccess() for path '%s'",
5826 fs->fs_name, fh->fh_path);
5827 return (fs->faccess)(fh, mode, uid, gid, suppl_gids);
5828 }
5829
pr_fsio_utimes(const char * path,struct timeval * tvs)5830 int pr_fsio_utimes(const char *path, struct timeval *tvs) {
5831 int res;
5832 pr_fs_t *fs;
5833
5834 if (path == NULL ||
5835 tvs == NULL) {
5836 errno = EINVAL;
5837 return -1;
5838 }
5839
5840 fs = lookup_file_fs(path, NULL, FSIO_FILE_UTIMES);
5841 if (fs == NULL) {
5842 return -1;
5843 }
5844
5845 /* Find the first non-NULL custom utimes handler. If there are none,
5846 * use the system utimes.
5847 */
5848 while (fs && fs->fs_next && !fs->utimes) {
5849 fs = fs->fs_next;
5850 }
5851
5852 pr_trace_msg(trace_channel, 8, "using %s utimes() for path '%s'",
5853 fs->fs_name, path);
5854 res = (fs->utimes)(fs, path, tvs);
5855 if (res == 0) {
5856 pr_fs_clear_cache2(path);
5857 }
5858
5859 return res;
5860 }
5861
5862 /* If the utimes(2) call fails because the process UID does not match the file
5863 * UID, then check to see if the GIDs match (and that the file has group write
5864 * permissions).
5865 *
5866 * This can be alleviated in two ways: a) if mod_cap is present, enable the
5867 * CAP_FOWNER capability for the session, or b) use root privs.
5868 */
pr_fsio_utimes_with_root(const char * path,struct timeval * tvs)5869 int pr_fsio_utimes_with_root(const char *path, struct timeval *tvs) {
5870 int res, xerrno, matching_gid = FALSE;
5871 struct stat st;
5872
5873 res = pr_fsio_utimes(path, tvs);
5874 xerrno = errno;
5875
5876 if (res == 0) {
5877 return 0;
5878 }
5879
5880 /* We only try these workarounds for EPERM. */
5881 if (xerrno != EPERM) {
5882 return res;
5883 }
5884
5885 pr_fs_clear_cache2(path);
5886 if (pr_fsio_stat(path, &st) < 0) {
5887 errno = xerrno;
5888 return -1;
5889 }
5890
5891 /* Be sure to check the primary and all the supplemental groups to which
5892 * this session belongs.
5893 */
5894 if (st.st_gid == session.gid) {
5895 matching_gid = TRUE;
5896
5897 } else if (session.gids != NULL) {
5898 register unsigned int i;
5899 gid_t *gids;
5900
5901 gids = session.gids->elts;
5902 for (i = 0; i < session.gids->nelts; i++) {
5903 if (st.st_gid == gids[i]) {
5904 matching_gid = TRUE;
5905 break;
5906 }
5907 }
5908 }
5909
5910 if (matching_gid == TRUE &&
5911 (st.st_mode & S_IWGRP)) {
5912
5913 /* Try the utimes(2) call again, this time with root privs. */
5914 pr_signals_block();
5915 PRIVS_ROOT
5916 res = pr_fsio_utimes(path, tvs);
5917 PRIVS_RELINQUISH
5918 pr_signals_unblock();
5919
5920 if (res == 0) {
5921 return 0;
5922 }
5923 }
5924
5925 errno = xerrno;
5926 return -1;
5927 }
5928
pr_fsio_futimes(pr_fh_t * fh,struct timeval * tvs)5929 int pr_fsio_futimes(pr_fh_t *fh, struct timeval *tvs) {
5930 int res;
5931 pr_fs_t *fs;
5932
5933 if (fh == NULL ||
5934 tvs == NULL) {
5935 errno = EINVAL;
5936 return -1;
5937 }
5938
5939 /* Find the first non-NULL custom futimes handler. If there are none,
5940 * use the system futimes.
5941 */
5942 fs = fh->fh_fs;
5943 while (fs && fs->fs_next && !fs->futimes) {
5944 fs = fs->fs_next;
5945 }
5946
5947 pr_trace_msg(trace_channel, 8, "using %s futimes() for path '%s'",
5948 fs->fs_name, fh->fh_path);
5949 res = (fs->futimes)(fh, fh->fh_fd, tvs);
5950 if (res == 0) {
5951 pr_fs_clear_cache2(fh->fh_path);
5952 }
5953
5954 return res;
5955 }
5956
pr_fsio_fsync(pr_fh_t * fh)5957 int pr_fsio_fsync(pr_fh_t *fh) {
5958 int res;
5959 pr_fs_t *fs;
5960
5961 if (fh == NULL) {
5962 errno = EINVAL;
5963 return -1;
5964 }
5965
5966 /* Find the first non-NULL custom fsync handler. If there are none,
5967 * use the system fsync.
5968 */
5969 fs = fh->fh_fs;
5970 while (fs && fs->fs_next && !fs->fsync) {
5971 fs = fs->fs_next;
5972 }
5973
5974 pr_trace_msg(trace_channel, 8, "using %s fsync() for path '%s'",
5975 fs->fs_name, fh->fh_path);
5976 res = (fs->fsync)(fh, fh->fh_fd);
5977 if (res == 0) {
5978 pr_fs_clear_cache2(fh->fh_path);
5979 }
5980
5981 return res;
5982 }
5983
pr_fsio_getxattr(pool * p,const char * path,const char * name,void * val,size_t valsz)5984 ssize_t pr_fsio_getxattr(pool *p, const char *path, const char *name, void *val,
5985 size_t valsz) {
5986 ssize_t res;
5987 pr_fs_t *fs;
5988
5989 if (p == NULL ||
5990 path == NULL ||
5991 name == NULL) {
5992 errno = EINVAL;
5993 return -1;
5994 }
5995
5996 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
5997 errno = ENOSYS;
5998 return -1;
5999 }
6000
6001 fs = lookup_file_fs(path, NULL, FSIO_FILE_GETXATTR);
6002 if (fs == NULL) {
6003 return -1;
6004 }
6005
6006 /* Find the first non-NULL custom getxattr handler. If there are none,
6007 * use the system getxattr.
6008 */
6009 while (fs && fs->fs_next && !fs->getxattr) {
6010 fs = fs->fs_next;
6011 }
6012
6013 pr_trace_msg(trace_channel, 8, "using %s getxattr() for path '%s'",
6014 fs->fs_name, path);
6015 res = (fs->getxattr)(p, fs, path, name, val, valsz);
6016 return res;
6017 }
6018
pr_fsio_lgetxattr(pool * p,const char * path,const char * name,void * val,size_t valsz)6019 ssize_t pr_fsio_lgetxattr(pool *p, const char *path, const char *name,
6020 void *val, size_t valsz) {
6021 ssize_t res;
6022 pr_fs_t *fs;
6023
6024 if (p == NULL ||
6025 path == NULL ||
6026 name == NULL) {
6027 errno = EINVAL;
6028 return -1;
6029 }
6030
6031 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6032 errno = ENOSYS;
6033 return -1;
6034 }
6035
6036 fs = lookup_file_fs(path, NULL, FSIO_FILE_LGETXATTR);
6037 if (fs == NULL) {
6038 return -1;
6039 }
6040
6041 /* Find the first non-NULL custom lgetxattr handler. If there are none,
6042 * use the system lgetxattr.
6043 */
6044 while (fs && fs->fs_next && !fs->lgetxattr) {
6045 fs = fs->fs_next;
6046 }
6047
6048 pr_trace_msg(trace_channel, 8, "using %s lgetxattr() for path '%s'",
6049 fs->fs_name, path);
6050 res = (fs->lgetxattr)(p, fs, path, name, val, valsz);
6051 return res;
6052 }
6053
pr_fsio_fgetxattr(pool * p,pr_fh_t * fh,const char * name,void * val,size_t valsz)6054 ssize_t pr_fsio_fgetxattr(pool *p, pr_fh_t *fh, const char *name, void *val,
6055 size_t valsz) {
6056 ssize_t res;
6057 pr_fs_t *fs;
6058
6059 if (p == NULL ||
6060 fh == NULL ||
6061 name == NULL) {
6062 errno = EINVAL;
6063 return -1;
6064 }
6065
6066 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6067 errno = ENOSYS;
6068 return -1;
6069 }
6070
6071 /* Find the first non-NULL custom fgetxattr handler. If there are none,
6072 * use the system fgetxattr.
6073 */
6074 fs = fh->fh_fs;
6075 while (fs && fs->fs_next && !fs->fgetxattr) {
6076 fs = fs->fs_next;
6077 }
6078
6079 pr_trace_msg(trace_channel, 8, "using %s fgetxattr() for path '%s'",
6080 fs->fs_name, fh->fh_path);
6081 res = (fs->fgetxattr)(p, fh, fh->fh_fd, name, val, valsz);
6082 return res;
6083 }
6084
pr_fsio_listxattr(pool * p,const char * path,array_header ** names)6085 int pr_fsio_listxattr(pool *p, const char *path, array_header **names) {
6086 int res;
6087 pr_fs_t *fs;
6088
6089 if (p == NULL ||
6090 path == NULL ||
6091 names == NULL) {
6092 errno = EINVAL;
6093 return -1;
6094 }
6095
6096 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6097 errno = ENOSYS;
6098 return -1;
6099 }
6100
6101 fs = lookup_file_fs(path, NULL, FSIO_FILE_LISTXATTR);
6102 if (fs == NULL) {
6103 return -1;
6104 }
6105
6106 /* Find the first non-NULL custom listxattr handler. If there are none,
6107 * use the system listxattr.
6108 */
6109 while (fs && fs->fs_next && !fs->listxattr) {
6110 fs = fs->fs_next;
6111 }
6112
6113 pr_trace_msg(trace_channel, 8, "using %s listxattr() for path '%s'",
6114 fs->fs_name, path);
6115 res = (fs->listxattr)(p, fs, path, names);
6116 return res;
6117 }
6118
pr_fsio_llistxattr(pool * p,const char * path,array_header ** names)6119 int pr_fsio_llistxattr(pool *p, const char *path, array_header **names) {
6120 int res;
6121 pr_fs_t *fs;
6122
6123 if (p == NULL ||
6124 path == NULL ||
6125 names == NULL) {
6126 errno = EINVAL;
6127 return -1;
6128 }
6129
6130 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6131 errno = ENOSYS;
6132 return -1;
6133 }
6134
6135 fs = lookup_file_fs(path, NULL, FSIO_FILE_LLISTXATTR);
6136 if (fs == NULL) {
6137 return -1;
6138 }
6139
6140 /* Find the first non-NULL custom llistxattr handler. If there are none,
6141 * use the system llistxattr.
6142 */
6143 while (fs && fs->fs_next && !fs->llistxattr) {
6144 fs = fs->fs_next;
6145 }
6146
6147 pr_trace_msg(trace_channel, 8, "using %s llistxattr() for path '%s'",
6148 fs->fs_name, path);
6149 res = (fs->llistxattr)(p, fs, path, names);
6150 return res;
6151 }
6152
pr_fsio_flistxattr(pool * p,pr_fh_t * fh,array_header ** names)6153 int pr_fsio_flistxattr(pool *p, pr_fh_t *fh, array_header **names) {
6154 int res;
6155 pr_fs_t *fs;
6156
6157 if (p == NULL ||
6158 fh == NULL ||
6159 names == NULL) {
6160 errno = EINVAL;
6161 return -1;
6162 }
6163
6164 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6165 errno = ENOSYS;
6166 return -1;
6167 }
6168
6169 /* Find the first non-NULL custom flistxattr handler. If there are none,
6170 * use the system flistxattr.
6171 */
6172 fs = fh->fh_fs;
6173 while (fs && fs->fs_next && !fs->flistxattr) {
6174 fs = fs->fs_next;
6175 }
6176
6177 pr_trace_msg(trace_channel, 8, "using %s flistxattr() for path '%s'",
6178 fs->fs_name, fh->fh_path);
6179 res = (fs->flistxattr)(p, fh, fh->fh_fd, names);
6180 return res;
6181 }
6182
pr_fsio_removexattr(pool * p,const char * path,const char * name)6183 int pr_fsio_removexattr(pool *p, const char *path, const char *name) {
6184 int res;
6185 pr_fs_t *fs;
6186
6187 if (p == NULL ||
6188 path == NULL ||
6189 name == NULL) {
6190 errno = EINVAL;
6191 return -1;
6192 }
6193
6194 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6195 errno = ENOSYS;
6196 return -1;
6197 }
6198
6199 fs = lookup_file_fs(path, NULL, FSIO_FILE_REMOVEXATTR);
6200 if (fs == NULL) {
6201 return -1;
6202 }
6203
6204 /* Find the first non-NULL custom removexattr handler. If there are none,
6205 * use the system removexattr.
6206 */
6207 while (fs && fs->fs_next && !fs->removexattr) {
6208 fs = fs->fs_next;
6209 }
6210
6211 pr_trace_msg(trace_channel, 8, "using %s removexattr() for path '%s'",
6212 fs->fs_name, path);
6213 res = (fs->removexattr)(p, fs, path, name);
6214 return res;
6215 }
6216
pr_fsio_lremovexattr(pool * p,const char * path,const char * name)6217 int pr_fsio_lremovexattr(pool *p, const char *path, const char *name) {
6218 int res;
6219 pr_fs_t *fs;
6220
6221 if (p == NULL ||
6222 path == NULL ||
6223 name == NULL) {
6224 errno = EINVAL;
6225 return -1;
6226 }
6227
6228 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6229 errno = ENOSYS;
6230 return -1;
6231 }
6232
6233 fs = lookup_file_fs(path, NULL, FSIO_FILE_LREMOVEXATTR);
6234 if (fs == NULL) {
6235 return -1;
6236 }
6237
6238 /* Find the first non-NULL custom lremovexattr handler. If there are none,
6239 * use the system lremovexattr.
6240 */
6241 while (fs && fs->fs_next && !fs->lremovexattr) {
6242 fs = fs->fs_next;
6243 }
6244
6245 pr_trace_msg(trace_channel, 8, "using %s lremovexattr() for path '%s'",
6246 fs->fs_name, path);
6247 res = (fs->lremovexattr)(p, fs, path, name);
6248 return res;
6249 }
6250
pr_fsio_fremovexattr(pool * p,pr_fh_t * fh,const char * name)6251 int pr_fsio_fremovexattr(pool *p, pr_fh_t *fh, const char *name) {
6252 int res;
6253 pr_fs_t *fs;
6254
6255 if (p == NULL ||
6256 fh == NULL ||
6257 name == NULL) {
6258 errno = EINVAL;
6259 return -1;
6260 }
6261
6262 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6263 errno = ENOSYS;
6264 return -1;
6265 }
6266
6267 /* Find the first non-NULL custom fremovexattr handler. If there are none,
6268 * use the system fremovexattr.
6269 */
6270 fs = fh->fh_fs;
6271 while (fs && fs->fs_next && !fs->fremovexattr) {
6272 fs = fs->fs_next;
6273 }
6274
6275 pr_trace_msg(trace_channel, 8, "using %s fremovexattr() for path '%s'",
6276 fs->fs_name, fh->fh_path);
6277 res = (fs->fremovexattr)(p, fh, fh->fh_fd, name);
6278 return res;
6279 }
6280
pr_fsio_setxattr(pool * p,const char * path,const char * name,void * val,size_t valsz,int flags)6281 int pr_fsio_setxattr(pool *p, const char *path, const char *name, void *val,
6282 size_t valsz, int flags) {
6283 int res;
6284 pr_fs_t *fs;
6285
6286 if (p == NULL ||
6287 path == NULL ||
6288 name == NULL) {
6289 errno = EINVAL;
6290 return -1;
6291 }
6292
6293 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6294 errno = ENOSYS;
6295 return -1;
6296 }
6297
6298 fs = lookup_file_fs(path, NULL, FSIO_FILE_SETXATTR);
6299 if (fs == NULL) {
6300 return -1;
6301 }
6302
6303 /* Find the first non-NULL custom setxattr handler. If there are none,
6304 * use the system setxattr.
6305 */
6306 while (fs && fs->fs_next && !fs->setxattr) {
6307 fs = fs->fs_next;
6308 }
6309
6310 pr_trace_msg(trace_channel, 8, "using %s setxattr() for path '%s'",
6311 fs->fs_name, path);
6312 res = (fs->setxattr)(p, fs, path, name, val, valsz, flags);
6313 return res;
6314 }
6315
pr_fsio_lsetxattr(pool * p,const char * path,const char * name,void * val,size_t valsz,int flags)6316 int pr_fsio_lsetxattr(pool *p, const char *path, const char *name, void *val,
6317 size_t valsz, int flags) {
6318 int res;
6319 pr_fs_t *fs;
6320
6321 if (p == NULL ||
6322 path == NULL ||
6323 name == NULL) {
6324 errno = EINVAL;
6325 return -1;
6326 }
6327
6328 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6329 errno = ENOSYS;
6330 return -1;
6331 }
6332
6333 fs = lookup_file_fs(path, NULL, FSIO_FILE_LSETXATTR);
6334 if (fs == NULL) {
6335 return -1;
6336 }
6337
6338 /* Find the first non-NULL custom lsetxattr handler. If there are none,
6339 * use the system lsetxattr.
6340 */
6341 while (fs && fs->fs_next && !fs->lsetxattr) {
6342 fs = fs->fs_next;
6343 }
6344
6345 pr_trace_msg(trace_channel, 8, "using %s lsetxattr() for path '%s'",
6346 fs->fs_name, path);
6347 res = (fs->lsetxattr)(p, fs, path, name, val, valsz, flags);
6348 return res;
6349 }
6350
pr_fsio_fsetxattr(pool * p,pr_fh_t * fh,const char * name,void * val,size_t valsz,int flags)6351 int pr_fsio_fsetxattr(pool *p, pr_fh_t *fh, const char *name, void *val,
6352 size_t valsz, int flags) {
6353 int res;
6354 pr_fs_t *fs;
6355
6356 if (p == NULL ||
6357 fh == NULL ||
6358 name == NULL) {
6359 errno = EINVAL;
6360 return -1;
6361 }
6362
6363 if (fsio_opts & PR_FSIO_OPT_IGNORE_XATTR) {
6364 errno = ENOSYS;
6365 return -1;
6366 }
6367
6368 /* Find the first non-NULL custom fsetxattr handler. If there are none,
6369 * use the system fsetxattr.
6370 */
6371 fs = fh->fh_fs;
6372 while (fs && fs->fs_next && !fs->fsetxattr) {
6373 fs = fs->fs_next;
6374 }
6375
6376 pr_trace_msg(trace_channel, 8, "using %s fsetxattr() for path '%s'",
6377 fs->fs_name, fh->fh_path);
6378 res = (fs->fsetxattr)(p, fh, fh->fh_fd, name, val, valsz, flags);
6379 return res;
6380 }
6381
6382 /* If the wrapped chroot() function succeeds (e.g. returns 0), then all
6383 * pr_fs_ts currently registered in the fs_map will have their paths
6384 * rewritten to reflect the new root.
6385 */
pr_fsio_chroot(const char * path)6386 int pr_fsio_chroot(const char *path) {
6387 int res = 0, xerrno = 0;
6388 pr_fs_t *fs;
6389
6390 if (path == NULL) {
6391 errno = EINVAL;
6392 return -1;
6393 }
6394
6395 fs = lookup_dir_fs(path, FSIO_DIR_CHROOT);
6396 if (fs == NULL) {
6397 return -1;
6398 }
6399
6400 /* Find the first non-NULL custom chroot handler. If there are none,
6401 * use the system chroot.
6402 */
6403 while (fs && fs->fs_next && !fs->chroot) {
6404 fs = fs->fs_next;
6405 }
6406
6407 pr_trace_msg(trace_channel, 8, "using %s chroot() for path '%s'",
6408 fs->fs_name, path);
6409 res = (fs->chroot)(fs, path);
6410 xerrno = errno;
6411
6412 if (res == 0) {
6413 unsigned int iter_start = 0;
6414
6415 /* The filesystem handles in fs_map need to be readjusted to the new root.
6416 */
6417 register unsigned int i = 0;
6418 pool *map_pool = make_sub_pool(permanent_pool);
6419 array_header *new_map = make_array(map_pool, 0, sizeof(pr_fs_t *));
6420 pr_fs_t **fs_objs = NULL;
6421
6422 pr_pool_tag(map_pool, "FSIO Map Pool");
6423
6424 if (fs_map) {
6425 fs_objs = (pr_fs_t **) fs_map->elts;
6426 }
6427
6428 if (fs != root_fs) {
6429 if (strncmp(fs->fs_path, path, strlen(path)) == 0) {
6430 memmove(fs->fs_path, fs->fs_path + strlen(path),
6431 strlen(fs->fs_path) - strlen(path) + 1);
6432 }
6433
6434 *((pr_fs_t **) push_array(new_map)) = fs;
6435 iter_start = 1;
6436 }
6437
6438 for (i = iter_start; i < (fs_map ? fs_map->nelts : 0); i++) {
6439 pr_fs_t *tmpfs = fs_objs[i];
6440
6441 /* The memory for this field has already been allocated, so futzing
6442 * with it like this should be fine. Watch out for any paths that
6443 * may be different, e.g. added manually, not through pr_register_fs().
6444 * Any absolute paths that are outside of the chroot path are discarded.
6445 * Deferred-resolution paths (eg "~" paths) and relative paths are kept.
6446 */
6447
6448 if (strncmp(tmpfs->fs_path, path, strlen(path)) == 0) {
6449 pr_fs_t *next;
6450
6451 memmove(tmpfs->fs_path, tmpfs->fs_path + strlen(path),
6452 strlen(tmpfs->fs_path) - strlen(path) + 1);
6453
6454 /* Need to do this for any stacked FSs as well. */
6455 next = tmpfs->fs_next;
6456 while (next) {
6457 pr_signals_handle();
6458
6459 memmove(next->fs_path, next->fs_path + strlen(path),
6460 strlen(next->fs_path) - strlen(path) + 1);
6461
6462 next = next->fs_next;
6463 }
6464 }
6465
6466 /* Add this FS to the new fs_map. */
6467 *((pr_fs_t **) push_array(new_map)) = tmpfs;
6468 }
6469
6470 /* Sort the new map */
6471 qsort(new_map->elts, new_map->nelts, sizeof(pr_fs_t *), fs_cmp);
6472
6473 /* Destroy the old map */
6474 if (fs_map != NULL) {
6475 destroy_pool(fs_map->pool);
6476 }
6477
6478 fs_map = new_map;
6479 chk_fs_map = TRUE;
6480 }
6481
6482 errno = xerrno;
6483 return res;
6484 }
6485
pr_fsio_chroot_with_error(pool * p,const char * path,pr_error_t ** err)6486 int pr_fsio_chroot_with_error(pool *p, const char *path, pr_error_t **err) {
6487 int res;
6488
6489 res = pr_fsio_chroot(path);
6490 if (res < 0) {
6491 int xerrno = errno;
6492
6493 if (p != NULL &&
6494 err != NULL) {
6495 *err = pr_error_create(p, xerrno);
6496 if (pr_error_explain_chroot(*err, path) < 0) {
6497 pr_error_destroy(*err);
6498 *err = NULL;
6499 }
6500 }
6501
6502 errno = xerrno;
6503 }
6504
6505 return res;
6506 }
6507
pr_fsio_getpipebuf(pool * p,int fd,long * bufsz)6508 char *pr_fsio_getpipebuf(pool *p, int fd, long *bufsz) {
6509 char *buf = NULL;
6510 long buflen;
6511
6512 if (p == NULL) {
6513 errno = EINVAL;
6514 return NULL;
6515 }
6516
6517 if (fd < 0) {
6518 errno = EBADF;
6519 return NULL;
6520 }
6521
6522 #if defined(PIPE_BUF)
6523 buflen = PIPE_BUF;
6524
6525 #elif defined(HAVE_FPATHCONF)
6526 /* Some platforms do not define a PIPE_BUF constant. For them, we need
6527 * to use fpathconf(2), if available.
6528 */
6529 buflen = fpathconf(fd, _PC_PIPE_BUF);
6530 if (buflen < 0) {
6531 return NULL;
6532 }
6533
6534 #else
6535 errno = ENOSYS;
6536 return NULL;
6537 #endif
6538
6539 if (bufsz != NULL) {
6540 *bufsz = buflen;
6541 }
6542
6543 buf = palloc(p, buflen);
6544 return buf;
6545 }
6546
pr_fsio_gets(char * buf,size_t size,pr_fh_t * fh)6547 char *pr_fsio_gets(char *buf, size_t size, pr_fh_t *fh) {
6548 char *bp = NULL;
6549 int toread = 0;
6550 pr_buffer_t *pbuf = NULL;
6551
6552 if (buf == NULL ||
6553 fh == NULL ||
6554 size == 0) {
6555 errno = EINVAL;
6556 return NULL;
6557 }
6558
6559 if (fh->fh_buf == NULL) {
6560 size_t bufsz;
6561
6562 /* Conscientious callers who want the optimal IO on the file should
6563 * set the fh->fh_iosz hint.
6564 */
6565 bufsz = fh->fh_iosz ? fh->fh_iosz : PR_TUNABLE_BUFFER_SIZE;
6566
6567 fh->fh_buf = pcalloc(fh->fh_pool, sizeof(pr_buffer_t));
6568 fh->fh_buf->buf = fh->fh_buf->current = pcalloc(fh->fh_pool, bufsz);
6569 fh->fh_buf->remaining = fh->fh_buf->buflen = bufsz;
6570 }
6571
6572 pbuf = fh->fh_buf;
6573 bp = buf;
6574
6575 while (size) {
6576 pr_signals_handle();
6577
6578 if (pbuf->current == NULL ||
6579 pbuf->remaining == pbuf->buflen) { /* empty buffer */
6580
6581 toread = pr_fsio_read(fh, pbuf->buf, pbuf->buflen);
6582 if (toread <= 0) {
6583 if (bp != buf) {
6584 *bp = '\0';
6585 return buf;
6586 }
6587
6588 return NULL;
6589 }
6590
6591 pbuf->remaining = pbuf->buflen - toread;
6592 pbuf->current = pbuf->buf;
6593
6594 } else {
6595 toread = pbuf->buflen - pbuf->remaining;
6596 }
6597
6598 /* TODO: Improve the efficiency of this copy by using a strnchr(3)
6599 * scan to find the next LF, and then a memmove(2) to do the copy.
6600 */
6601 while (size &&
6602 toread > 0 &&
6603 *pbuf->current != '\n' &&
6604 toread--) {
6605 pr_signals_handle();
6606
6607 *bp++ = *pbuf->current++;
6608 size--;
6609 pbuf->remaining++;
6610 }
6611
6612 if (size &&
6613 toread &&
6614 *pbuf->current == '\n') {
6615 size--;
6616 toread--;
6617 *bp++ = *pbuf->current++;
6618 pbuf->remaining++;
6619 break;
6620 }
6621
6622 if (!toread) {
6623 pbuf->current = NULL;
6624 }
6625 }
6626
6627 *bp = '\0';
6628 return buf;
6629 }
6630
6631 /* pr_fsio_getline() is an fgets() with backslash-newline stripping, copied from
6632 * Wietse Venema's tcpwrapppers-7.6 code. The extra *lineno argument is
6633 * needed, at the moment, to properly track which line of the configuration
6634 * file is being read in, so that errors can be reported with line numbers
6635 * correctly.
6636 */
pr_fsio_getline(char * buf,size_t buflen,pr_fh_t * fh,unsigned int * lineno)6637 char *pr_fsio_getline(char *buf, size_t buflen, pr_fh_t *fh,
6638 unsigned int *lineno) {
6639 int inlen;
6640 char *start;
6641
6642 if (buf == NULL ||
6643 fh == NULL ||
6644 buflen == 0) {
6645 errno = EINVAL;
6646 return NULL;
6647 }
6648
6649 start = buf;
6650 while (pr_fsio_gets(buf, buflen, fh) != NULL) {
6651 pr_signals_handle();
6652
6653 inlen = strlen(buf);
6654
6655 if (inlen >= 1) {
6656 if (buf[inlen - 1] == '\n') {
6657 if (lineno != NULL) {
6658 (*lineno)++;
6659 }
6660
6661 if (inlen >= 2 && buf[inlen - 2] == '\\') {
6662 char *bufp;
6663
6664 inlen -= 2;
6665
6666 /* Watch for commented lines when handling line continuations.
6667 * Advance past any leading whitespace, to see if the first
6668 * non-whitespace character is the comment character.
6669 */
6670 for (bufp = buf; *bufp && PR_ISSPACE(*bufp); bufp++);
6671
6672 if (*bufp == '#') {
6673 continue;
6674 }
6675
6676 } else {
6677 return start;
6678 }
6679 }
6680 }
6681
6682 /* Be careful of reading too much. */
6683 if (buflen - inlen == 0) {
6684 return buf;
6685 }
6686
6687 buf += inlen;
6688 buflen -= inlen;
6689 buf[0] = 0;
6690 }
6691
6692 return (buf > start ? start : NULL);
6693 }
6694
6695 #define FSIO_MAX_FD_COUNT 1024
6696
pr_fs_close_extra_fds(void)6697 void pr_fs_close_extra_fds(void) {
6698 register unsigned int i;
6699 long nfiles = 0;
6700 struct rlimit rlim;
6701
6702 /* Close any but the big three open fds.
6703 *
6704 * First, use getrlimit() to obtain the maximum number of open files
6705 * for this process -- then close that number.
6706 */
6707 #if defined(RLIMIT_NOFILE) || defined(RLIMIT_OFILE)
6708 # if defined(RLIMIT_NOFILE)
6709 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
6710 # elif defined(RLIMIT_OFILE)
6711 if (getrlimit(RLIMIT_OFILE, &rlim) < 0) {
6712 # endif
6713 /* Ignore ENOSYS (and EPERM, since some libc's use this as ENOSYS); pick
6714 * some arbitrary high number.
6715 */
6716 nfiles = FSIO_MAX_FD_COUNT;
6717
6718 } else {
6719 nfiles = rlim.rlim_max;
6720 }
6721
6722 #else /* no RLIMIT_NOFILE or RLIMIT_OFILE */
6723 nfiles = FSIO_MAX_FD_COUNT;
6724 #endif
6725
6726 /* Yes, using a long for the nfiles variable is not quite kosher; it should
6727 * be an unsigned type, otherwise a large limit (say, RLIMIT_INFINITY)
6728 * might overflow the data type. In that case, though, we want to know
6729 * about it -- and using a signed type, we will know if the overflowed
6730 * value is a negative number. Chances are we do NOT want to be closing
6731 * fds whose value is as high as they can possibly get; that's too many
6732 * fds to iterate over. Long story short, using a long int is just fine.
6733 * (Plus it makes mod_exec work on Mac OSX 10.4; without this tweak,
6734 * mod_exec's forked processes never return/exit.)
6735 */
6736
6737 if (nfiles < 0 ||
6738 nfiles > FSIO_MAX_FD_COUNT) {
6739 nfiles = FSIO_MAX_FD_COUNT;
6740 }
6741
6742 /* Close the "non-standard" file descriptors. */
6743 for (i = 3; i < nfiles; i++) {
6744 /* This is a potentially long-running loop, so handle signals. */
6745 pr_signals_handle();
6746 (void) close(i);
6747 }
6748 }
6749
6750 /* Be generous in the maximum allowed number of dup fds, in our search for
6751 * one that is outside the big three.
6752 *
6753 * In theory, this should be a runtime lookup using getdtablesize(2), being
6754 * sure to handle the ENOSYS case (for older systems).
6755 */
6756 #define FSIO_MAX_DUPFDS 512
6757
6758 /* The main three fds (stdin, stdout, stderr) need to be protected, reserved
6759 * for use. This function uses dup(2) to open new fds on the given fd
6760 * until the new fd is not one of the big three.
6761 */
6762 int pr_fs_get_usable_fd(int fd) {
6763 register int i;
6764 int fdi, dup_fds[FSIO_MAX_DUPFDS], n;
6765
6766 if (fd > STDERR_FILENO) {
6767 return fd;
6768 }
6769
6770 memset(dup_fds, -1, sizeof(dup_fds));
6771 i = 0;
6772 n = -1;
6773
6774 fdi = fd;
6775 while (i < FSIO_MAX_DUPFDS) {
6776 pr_signals_handle();
6777
6778 dup_fds[i] = dup(fdi);
6779 if (dup_fds[i] < 0) {
6780 register int j;
6781 int xerrno = errno;
6782
6783 /* Need to clean up any previously opened dups as well. */
6784 for (j = 0; j <= i; j++) {
6785 close(dup_fds[j]);
6786 dup_fds[j] = -1;
6787 }
6788
6789 errno = xerrno;
6790 return -1;
6791 }
6792
6793 if (dup_fds[i] <= STDERR_FILENO) {
6794 /* Continue searching for an open fd that isn't 0, 1, or 2. */
6795 fdi = dup_fds[i];
6796 i++;
6797 continue;
6798 }
6799
6800 n = i;
6801 fdi = dup_fds[n];
6802 break;
6803 }
6804
6805 /* If n is -1, we reached the max number of dups without finding an
6806 * open one. Hard to imagine this happening, but catch the case anyway.
6807 */
6808 if (n == -1) {
6809 /* Free up the fds we opened in our search. */
6810 for (i = 0; i < FSIO_MAX_DUPFDS; i++) {
6811 if (dup_fds[i] >= 0) {
6812 close(dup_fds[i]);
6813 dup_fds[i] = -1;
6814 }
6815 }
6816
6817 errno = EPERM;
6818 return -1;
6819 }
6820
6821 /* Free up the fds we opened in our search. */
6822 for (i = 0; i < n; i++) {
6823 (void) close(dup_fds[i]);
6824 dup_fds[i] = -1;
6825 }
6826
6827 return fdi;
6828 }
6829
6830 int pr_fs_get_usable_fd2(int *fd) {
6831 int new_fd = -1, res = 0;
6832
6833 if (fd == NULL) {
6834 errno = EINVAL;
6835 return -1;
6836 }
6837
6838 if (*fd > STDERR_FILENO) {
6839 /* No need to obtain a different fd; the given one is already not one
6840 * of the big three.
6841 */
6842 return 0;
6843 }
6844
6845 new_fd = pr_fs_get_usable_fd(*fd);
6846 if (new_fd >= 0) {
6847 (void) close(*fd);
6848 *fd = new_fd;
6849
6850 } else {
6851 res = -1;
6852 }
6853
6854 return res;
6855 }
6856
6857 /* Simple multiplication and division doesn't work with very large
6858 * filesystems (overflows 32 bits). This code should handle it.
6859 *
6860 * Note that this returns a size in KB, not bytes.
6861 */
6862 static off_t get_fs_size(size_t nblocks, size_t blocksz) {
6863 off_t bl_lo, bl_hi;
6864 off_t res_lo, res_hi, tmp;
6865
6866 bl_lo = nblocks & 0x0000ffff;
6867 bl_hi = nblocks & 0xffff0000;
6868
6869 tmp = (bl_hi >> 16) * blocksz;
6870 res_hi = tmp & 0xffff0000;
6871 res_lo = (tmp & 0x0000ffff) << 16;
6872 res_lo += bl_lo * blocksz;
6873
6874 if (res_hi & 0xfc000000) {
6875 /* Overflow */
6876 return 0;
6877 }
6878
6879 return (res_lo >> 10) | (res_hi << 6);
6880 }
6881
6882 static int fs_getsize(int fd, char *path, off_t *fs_size) {
6883 int res = -1;
6884
6885 # if defined(HAVE_SYS_STATVFS_H)
6886
6887 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
6888 defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
6889 !defined(SOLARIS2_7)
6890 /* Note: somewhere along the way, Sun decided that the prototype for
6891 * its statvfs64(2) function would include a statvfs64_t rather than
6892 * struct statvfs64. In 2.6 and 2.7, it's struct statvfs64, and
6893 * in 8, 9 it's statvfs64_t. This should silence compiler warnings.
6894 * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
6895 * LFS systems).
6896 */
6897 statvfs_t fs;
6898 # else
6899 struct statvfs fs;
6900 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
6901
6902 if (fs_size == NULL) {
6903 errno = EINVAL;
6904 return -1;
6905 }
6906
6907 if (path != NULL) {
6908 pr_trace_msg(trace_channel, 18, "using statvfs() on '%s'", path);
6909
6910 } else {
6911 pr_trace_msg(trace_channel, 18, "using statvfs() on fd %d", fd);
6912 }
6913
6914 if (path != NULL) {
6915 res = statvfs(path, &fs);
6916
6917 } else {
6918 res = fstatvfs(fd, &fs);
6919 }
6920
6921 if (res < 0) {
6922 int xerrno = errno;
6923
6924 if (path != NULL) {
6925 pr_trace_msg(trace_channel, 3, "statvfs() error using '%s': %s",
6926 path, strerror(xerrno));
6927
6928 } else {
6929 pr_trace_msg(trace_channel, 3, "statvfs() error using fd %d: %s",
6930 fd, strerror(xerrno));
6931 }
6932
6933 errno = xerrno;
6934 return -1;
6935 }
6936
6937 /* The get_fs_size() function is only useful for 32-bit numbers;
6938 * if either of our two values are in datatypes larger than 4 bytes,
6939 * we'll use typecasting.
6940 */
6941 if (sizeof(fs.f_bavail) > 4 ||
6942 sizeof(fs.f_frsize) > 4) {
6943
6944 /* In order to return a size in KB, as get_fs_size() does, we need
6945 * to divide by 1024.
6946 */
6947 *fs_size = (((off_t) fs.f_bavail * (off_t) fs.f_frsize) / 1024);
6948
6949 } else {
6950 *fs_size = get_fs_size(fs.f_bavail, fs.f_frsize);
6951 }
6952
6953 res = 0;
6954
6955 # elif defined(HAVE_SYS_VFS_H)
6956 struct statfs fs;
6957
6958 if (fs_size == NULL) {
6959 errno = EINVAL;
6960 return -1;
6961 }
6962
6963 if (path != NULL) {
6964 pr_trace_msg(trace_channel, 18, "using statfs() on '%s'", path);
6965
6966 } else {
6967 pr_trace_msg(trace_channel, 18, "using statfs() on fd %d", fd);
6968 }
6969
6970 if (path != NULL) {
6971 res = statfs(path, &fs);
6972
6973 } else {
6974 res = fstatfs(fd, &fs);
6975 }
6976
6977 if (res < 0) {
6978 int xerrno = errno;
6979
6980 if (path != NULL) {
6981 pr_trace_msg(trace_channel, 3, "statfs() error using '%s': %s",
6982 path, strerror(xerrno));
6983
6984 } else {
6985 pr_trace_msg(trace_channel, 3, "statfs() error using fd %d: %s",
6986 fd, strerror(xerrno));
6987 }
6988
6989 errno = xerrno;
6990 return -1;
6991 }
6992
6993 /* The get_fs_size() function is only useful for 32-bit numbers;
6994 * if either of our two values are in datatypes larger than 4 bytes,
6995 * we'll use typecasting.
6996 */
6997 if (sizeof(fs.f_bavail) > 4 ||
6998 sizeof(fs.f_frsize) > 4) {
6999
7000 /* In order to return a size in KB, as get_fs_size() does, we need
7001 * to divide by 1024.
7002 */
7003 *fs_size = (((off_t) fs.f_bavail * (off_t) fs.f_frsize) / 1024);
7004
7005 } else {
7006 *fs_size = get_fs_size(fs.f_bavail, fs.f_frsize);
7007 }
7008
7009 res = 0;
7010
7011 # elif defined(HAVE_STATFS)
7012 struct statfs fs;
7013
7014 if (fs_size == NULL) {
7015 errno = EINVAL;
7016 return -1;
7017 }
7018
7019 if (path != NULL) {
7020 pr_trace_msg(trace_channel, 18, "using statfs() on '%s'", path);
7021
7022 } else {
7023 pr_trace_msg(trace_channel, 18, "using statfs() on fd %d", fd);
7024 }
7025
7026 if (path != NULL) {
7027 res = statfs(path, &fs);
7028
7029 } else {
7030 res = fstatfs(fd, &fs);
7031 }
7032
7033 if (res < 0) {
7034 int xerrno = errno;
7035
7036 if (path != NULL) {
7037 pr_trace_msg(trace_channel, 3, "statfs() error using '%s': %s",
7038 path, strerror(xerrno));
7039
7040 } else {
7041 pr_trace_msg(trace_channel, 3, "statfs() error using fd %d: %s",
7042 fd, strerror(xerrno));
7043 }
7044
7045 errno = xerrno;
7046 return -1;
7047 }
7048
7049 /* The get_fs_size() function is only useful for 32-bit numbers;
7050 * if either of our two values are in datatypes larger than 4 bytes,
7051 * we'll use typecasting.
7052 */
7053 if (sizeof(fs.f_bavail) > 4 ||
7054 sizeof(fs.f_frsize) > 4) {
7055
7056 /* In order to return a size in KB, as get_fs_size() does, we need
7057 * to divide by 1024.
7058 */
7059 *fs_size = (((off_t) fs.f_bavail * (off_t) fs.f_frsize) / 1024);
7060
7061 } else {
7062 *fs_size = get_fs_size(fs.f_bavail, fs.f_frsize);
7063 }
7064
7065 res = 0;
7066
7067 # else
7068 errno = ENOSYS:
7069 res = -1;
7070 # endif /* !HAVE_STATFS && !HAVE_SYS_STATVFS && !HAVE_SYS_VFS */
7071
7072 return res;
7073 }
7074
7075 #if defined(HAVE_STATFS) || defined(HAVE_SYS_STATVFS_H) || \
7076 defined(HAVE_SYS_VFS_H)
7077 off_t pr_fs_getsize(char *path) {
7078 int res;
7079 off_t fs_size;
7080
7081 res = pr_fs_getsize2(path, &fs_size);
7082 if (res < 0) {
7083 errno = EINVAL;
7084 fs_size = -1;
7085 }
7086
7087 return fs_size;
7088 }
7089 #endif /* !HAVE_STATFS && !HAVE_SYS_STATVFS && !HAVE_SYS_VFS */
7090
7091 /* Returns the size in KB via the `fs_size' argument. */
7092 int pr_fs_getsize2(char *path, off_t *fs_size) {
7093 return fs_getsize(-1, path, fs_size);
7094 }
7095
7096 int pr_fs_fgetsize(int fd, off_t *fs_size) {
7097 return fs_getsize(fd, NULL, fs_size);
7098 }
7099
7100 void pr_fs_fadvise(int fd, off_t offset, off_t len, int advice) {
7101 #if defined(HAVE_POSIX_ADVISE)
7102 int res, posix_advice;
7103 const char *advice_str;
7104
7105 /* Convert from our advice values to the ones from the header; the
7106 * indirection is needed for platforms which do not provide posix_fadvise(3).
7107 */
7108 switch (advice) {
7109 case PR_FS_FADVISE_NORMAL:
7110 advice_str = "NORMAL";
7111 posix_advice = POSIX_FADV_NORMAL;
7112 break;
7113
7114 case PR_FS_FADVISE_RANDOM:
7115 advice_str = "RANDOM";
7116 posix_advice = POSIX_FADV_RANDOM;
7117 break;
7118
7119 case PR_FS_FADVISE_SEQUENTIAL:
7120 advice_str = "SEQUENTIAL";
7121 posix_advice = POSIX_FADV_SEQUENTIAL;
7122 break;
7123
7124 case PR_FS_FADVISE_WILLNEED:
7125 advice_str = "WILLNEED";
7126 posix_advice = POSIX_FADV_WILLNEED;
7127 break;
7128
7129 case PR_FS_FADVISE_DONTNEED:
7130 advice_str = "DONTNEED";
7131 posix_advice = POSIX_FADV_DONTNEED;
7132 break;
7133
7134 case PR_FS_FADVISE_NOREUSE:
7135 advice_str = "NOREUSE";
7136 posix_advice = POSIX_FADV_NOREUSE;
7137 break;
7138
7139 default:
7140 pr_trace_msg(trace_channel, 9,
7141 "unknown/unsupported advice: %d", advice);
7142 return;
7143 }
7144
7145 res = posix_fadvise(fd, offset, len, posix_advice);
7146 if (res < 0) {
7147 pr_trace_msg(trace_channel, 9,
7148 "posix_fadvise() error on fd %d (off %" PR_LU ", len %" PR_LU ", "
7149 "advice %s): %s", fd, (pr_off_t) offset, (pr_off_t) len, advice_str,
7150 strerror(errno));
7151 }
7152 #endif
7153
7154 return;
7155 }
7156
7157 int pr_fs_have_access(struct stat *st, int mode, uid_t uid, gid_t gid,
7158 array_header *suppl_gids) {
7159 mode_t mask;
7160
7161 if (st == NULL) {
7162 errno = EINVAL;
7163 return -1;
7164 }
7165
7166 /* Root always succeeds for reads/writes. */
7167 if (uid == PR_ROOT_UID &&
7168 mode != X_OK) {
7169 return 0;
7170 }
7171
7172 /* Initialize mask to reflect the permission bits that are applicable for
7173 * the given user. mask contains the user-bits if the user ID equals the
7174 * ID of the file owner. mask contains the group bits if the group ID
7175 * belongs to the group of the file. mask will always contain the other
7176 * bits of the permission bits.
7177 */
7178 mask = S_IROTH|S_IWOTH|S_IXOTH;
7179
7180 if (st->st_uid == uid) {
7181 mask |= S_IRUSR|S_IWUSR|S_IXUSR;
7182 }
7183
7184 /* Check the current group, as well as all supplementary groups.
7185 * Fortunately, we have this information cached, so accessing it is
7186 * almost free.
7187 */
7188 if (st->st_gid == gid) {
7189 mask |= S_IRGRP|S_IWGRP|S_IXGRP;
7190
7191 } else {
7192 if (suppl_gids != NULL) {
7193 register unsigned int i = 0;
7194
7195 for (i = 0; i < suppl_gids->nelts; i++) {
7196 if (st->st_gid == ((gid_t *) suppl_gids->elts)[i]) {
7197 mask |= S_IRGRP|S_IWGRP|S_IXGRP;
7198 break;
7199 }
7200 }
7201 }
7202 }
7203
7204 mask &= st->st_mode;
7205
7206 /* Perform requested access checks. */
7207 if (mode & R_OK) {
7208 if (!(mask & (S_IRUSR|S_IRGRP|S_IROTH))) {
7209 errno = EACCES;
7210 return -1;
7211 }
7212 }
7213
7214 if (mode & W_OK) {
7215 if (!(mask & (S_IWUSR|S_IWGRP|S_IWOTH))) {
7216 errno = EACCES;
7217 return -1;
7218 }
7219 }
7220
7221 if (mode & X_OK) {
7222 if (!(mask & (S_IXUSR|S_IXGRP|S_IXOTH))) {
7223 errno = EACCES;
7224 return -1;
7225 }
7226 }
7227
7228 /* F_OK already checked by checking the return value of stat. */
7229 return 0;
7230 }
7231
7232 int pr_fs_is_nfs(const char *path) {
7233 #if defined(HAVE_STATFS_F_TYPE) || defined(HAVE_STATFS_F_FSTYPENAME)
7234 struct statfs fs;
7235 int res = FALSE;
7236
7237 if (path == NULL) {
7238 errno = EINVAL;
7239 return -1;
7240 }
7241
7242 pr_trace_msg(trace_channel, 18, "using statfs() on '%s'", path);
7243 if (statfs(path, &fs) < 0) {
7244 int xerrno = errno;
7245
7246 pr_trace_msg(trace_channel, 3, "statfs() error using '%s': %s",
7247 path, strerror(xerrno));
7248
7249 errno = xerrno;
7250 return -1;
7251 }
7252
7253 # if defined(HAVE_STATFS_F_FSTYPENAME)
7254 pr_trace_msg(trace_channel, 12,
7255 "path '%s' resides on a filesystem of type '%s'", path, fs.f_fstypename);
7256 if (strcasecmp(fs.f_fstypename, "nfs") == 0) {
7257 res = TRUE;
7258 }
7259 # elif defined(HAVE_STATFS_F_TYPE)
7260 /* Probably a Linux system. */
7261 if (fs.f_type == NFS_SUPER_MAGIC) {
7262 pr_trace_msg(trace_channel, 12,
7263 "path '%s' resides on an NFS_SUPER_MAGIC filesystem (type 0x%08x)", path,
7264 (int) fs.f_type);
7265 res = TRUE;
7266
7267 } else {
7268 pr_trace_msg(trace_channel, 12,
7269 "path '%s' resides on a filesystem of type 0x%08x (not NFS_SUPER_MAGIC)",
7270 path, (int) fs.f_type);
7271 }
7272 # endif
7273
7274 return res;
7275
7276 #else
7277 errno = ENOSYS;
7278 return -1;
7279 #endif /* No HAVE_STATFS_F_FSTYPENAME or HAVE_STATFS_F_TYPE */
7280 }
7281
7282 int pr_fsio_puts(const char *buf, pr_fh_t *fh) {
7283 if (fh == NULL ||
7284 buf == NULL) {
7285 errno = EINVAL;
7286 return -1;
7287 }
7288
7289 return pr_fsio_write(fh, buf, strlen(buf));
7290 }
7291
7292 int pr_fsio_set_block(pr_fh_t *fh) {
7293 int flags, res;
7294
7295 if (fh == NULL) {
7296 errno = EINVAL;
7297 return -1;
7298 }
7299
7300 flags = fcntl(fh->fh_fd, F_GETFL);
7301 if (flags < 0) {
7302 return -1;
7303 }
7304
7305 res = fcntl(fh->fh_fd, F_SETFL, flags & (U32BITS ^ O_NONBLOCK));
7306 return res;
7307 }
7308
7309 void pr_resolve_fs_map(void) {
7310 register unsigned int i = 0;
7311
7312 if (fs_map == NULL) {
7313 return;
7314 }
7315
7316 for (i = 0; i < fs_map->nelts; i++) {
7317 char *newpath = NULL;
7318 int add_slash = FALSE;
7319 pr_fs_t *fsi;
7320
7321 pr_signals_handle();
7322 fsi = ((pr_fs_t **) fs_map->elts)[i];
7323
7324 /* Skip if this fs is the root fs. */
7325 if (fsi == root_fs) {
7326 continue;
7327 }
7328
7329 /* Note that dir_realpath() does _not_ handle "../blah" paths
7330 * well, so...at least for now, hope that such paths are screened
7331 * by the code adding such paths into the fs_map. Check for
7332 * a trailing slash in the unadjusted path, so that I know if I need
7333 * to re-add that slash to the adjusted path -- these trailing slashes
7334 * are important!
7335 */
7336 if ((strncmp(fsi->fs_path, "/", 2) != 0 &&
7337 (fsi->fs_path)[strlen(fsi->fs_path) - 1] == '/')) {
7338 add_slash = TRUE;
7339 }
7340
7341 newpath = dir_realpath(fsi->fs_pool, fsi->fs_path);
7342 if (newpath != NULL) {
7343
7344 if (add_slash) {
7345 newpath = pstrcat(fsi->fs_pool, newpath, "/", NULL);
7346 }
7347
7348 /* Note that this does cause a slightly larger memory allocation from
7349 * the pr_fs_t's pool, as the original path value was also allocated
7350 * from that pool, and that original pointer is being overwritten.
7351 * However, as this function is only called once, and that pool
7352 * is freed later, I think this may be acceptable.
7353 */
7354 fsi->fs_path = newpath;
7355 }
7356 }
7357
7358 /* Resort the map */
7359 qsort(fs_map->elts, fs_map->nelts, sizeof(pr_fs_t *), fs_cmp);
7360
7361 return;
7362 }
7363
7364 int init_fs(void) {
7365 char cwdbuf[PR_TUNABLE_PATH_MAX + 1] = {'\0'};
7366
7367 /* Establish the default pr_fs_t that will handle any path */
7368 root_fs = pr_create_fs(permanent_pool, "system");
7369 if (root_fs == NULL) {
7370
7371 /* Do not insert this fs into the FS map. This will allow other
7372 * modules to insert filesystems at "/", if they want.
7373 */
7374 pr_log_pri(PR_LOG_WARNING, "error: unable to initialize default FS");
7375 exit(1);
7376 }
7377
7378 root_fs->fs_path = pstrdup(root_fs->fs_pool, "/");
7379
7380 /* Set the root FSIO handlers. */
7381 root_fs->stat = sys_stat;
7382 root_fs->fstat = sys_fstat;
7383 root_fs->lstat = sys_lstat;
7384 root_fs->rename = sys_rename;
7385 root_fs->unlink = sys_unlink;
7386 root_fs->open = sys_open;
7387 root_fs->close = sys_close;
7388 root_fs->pread = sys_pread;
7389 root_fs->read = sys_read;
7390 root_fs->pwrite = sys_pwrite;
7391 root_fs->write = sys_write;
7392 root_fs->lseek = sys_lseek;
7393 root_fs->link = sys_link;
7394 root_fs->readlink = sys_readlink;
7395 root_fs->symlink = sys_symlink;
7396 root_fs->ftruncate = sys_ftruncate;
7397 root_fs->truncate = sys_truncate;
7398 root_fs->chmod = sys_chmod;
7399 root_fs->fchmod = sys_fchmod;
7400 root_fs->chown = sys_chown;
7401 root_fs->fchown = sys_fchown;
7402 root_fs->lchown = sys_lchown;
7403 root_fs->access = sys_access;
7404 root_fs->faccess = sys_faccess;
7405 root_fs->utimes = sys_utimes;
7406 root_fs->futimes = sys_futimes;
7407 root_fs->fsync = sys_fsync;
7408
7409 root_fs->getxattr = sys_getxattr;
7410 root_fs->lgetxattr = sys_lgetxattr;
7411 root_fs->fgetxattr = sys_fgetxattr;
7412 root_fs->listxattr = sys_listxattr;
7413 root_fs->llistxattr = sys_llistxattr;
7414 root_fs->flistxattr = sys_flistxattr;
7415 root_fs->removexattr = sys_removexattr;
7416 root_fs->lremovexattr = sys_lremovexattr;
7417 root_fs->fremovexattr = sys_fremovexattr;
7418 root_fs->setxattr = sys_setxattr;
7419 root_fs->lsetxattr = sys_lsetxattr;
7420 root_fs->fsetxattr = sys_fsetxattr;
7421
7422 root_fs->chdir = sys_chdir;
7423 root_fs->chroot = sys_chroot;
7424 root_fs->opendir = sys_opendir;
7425 root_fs->closedir = sys_closedir;
7426 root_fs->readdir = sys_readdir;
7427 root_fs->mkdir = sys_mkdir;
7428 root_fs->rmdir = sys_rmdir;
7429
7430 if (getcwd(cwdbuf, sizeof(cwdbuf)-1)) {
7431 cwdbuf[sizeof(cwdbuf)-1] = '\0';
7432 pr_fs_setcwd(cwdbuf);
7433
7434 } else {
7435 pr_fsio_chdir("/", FALSE);
7436 pr_fs_setcwd("/");
7437 }
7438
7439 /* Prepare the stat cache as well. */
7440 statcache_pool = make_sub_pool(permanent_pool);
7441 pr_pool_tag(statcache_pool, "FS Statcache Pool");
7442 stat_statcache_tab = pr_table_alloc(statcache_pool, 0);
7443 stat_statcache_set = xaset_create(statcache_pool, NULL);
7444 lstat_statcache_tab = pr_table_alloc(statcache_pool, 0);
7445 lstat_statcache_set = xaset_create(statcache_pool, NULL);
7446
7447 return 0;
7448 }
7449
7450 #ifdef PR_USE_DEVEL
7451
7452 static const char *get_fs_hooks_str(pool *p, pr_fs_t *fs) {
7453 char *hooks = "";
7454
7455 if (fs->stat) {
7456 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "stat(2)", NULL);
7457 }
7458
7459 if (fs->lstat) {
7460 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "lstat(2)", NULL);
7461 }
7462
7463 if (fs->fstat) {
7464 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "fstat(2)", NULL);
7465 }
7466
7467 if (fs->rename) {
7468 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "rename(2)", NULL);
7469 }
7470
7471 if (fs->link) {
7472 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "link(2)", NULL);
7473 }
7474
7475 if (fs->unlink) {
7476 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "unlink(2)", NULL);
7477 }
7478
7479 if (fs->open) {
7480 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "open(2)", NULL);
7481 }
7482
7483 if (fs->close) {
7484 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "close(2)", NULL);
7485 }
7486
7487 if (fs->read) {
7488 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "read(2)", NULL);
7489 }
7490
7491 if (fs->lseek) {
7492 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "lseek(2)", NULL);
7493 }
7494
7495 if (fs->readlink) {
7496 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "readlink(2)", NULL);
7497 }
7498
7499 if (fs->symlink) {
7500 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "symlink(2)", NULL);
7501 }
7502
7503 if (fs->ftruncate) {
7504 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "ftruncate(2)", NULL);
7505 }
7506
7507 if (fs->truncate) {
7508 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "truncate(2)", NULL);
7509 }
7510
7511 if (fs->chmod) {
7512 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "chmod(2)", NULL);
7513 }
7514
7515 if (fs->chown) {
7516 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "chown(2)", NULL);
7517 }
7518
7519 if (fs->fchown) {
7520 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "fchown(2)", NULL);
7521 }
7522
7523 if (fs->lchown) {
7524 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "lchown(2)", NULL);
7525 }
7526
7527 if (fs->access) {
7528 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "access(2)", NULL);
7529 }
7530
7531 if (fs->faccess) {
7532 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "faccess(2)", NULL);
7533 }
7534
7535 if (fs->utimes) {
7536 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "utimes(2)", NULL);
7537 }
7538
7539 if (fs->futimes) {
7540 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "futimes(2)", NULL);
7541 }
7542
7543 if (fs->fsync) {
7544 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "fsync(2)", NULL);
7545 }
7546
7547 if (fs->chdir) {
7548 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "chdir(2)", NULL);
7549 }
7550
7551 if (fs->chroot) {
7552 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "chroot(2)", NULL);
7553 }
7554
7555 if (fs->opendir) {
7556 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "opendir(3)", NULL);
7557 }
7558
7559 if (fs->closedir) {
7560 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "closedir(3)", NULL);
7561 }
7562
7563 if (fs->readdir) {
7564 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "readdir(3)", NULL);
7565 }
7566
7567 if (fs->mkdir) {
7568 hooks = pstrcat(p, hooks, *hooks ? ", " : "", "mkdir(2)", NULL);
7569 }
7570
7571 if (!*hooks) {
7572 return pstrdup(p, "(none)");
7573 }
7574
7575 return hooks;
7576 }
7577
7578 static void get_fs_info(pool *p, int depth, pr_fs_t *fs,
7579 void (*dumpf)(const char *, ...)) {
7580
7581 dumpf("FS#%u: '%s', mounted at '%s', implementing the following hooks:",
7582 depth, fs->fs_name, fs->fs_path);
7583 dumpf("FS#%u: %s", depth, get_fs_hooks_str(p, fs));
7584 }
7585
7586 static void fs_printf(const char *fmt, ...) {
7587 char buf[PR_TUNABLE_BUFFER_SIZE+1];
7588 va_list msg;
7589
7590 memset(buf, '\0', sizeof(buf));
7591 va_start(msg, fmt);
7592 pr_vsnprintf(buf, sizeof(buf)-1, fmt, msg);
7593 va_end(msg);
7594
7595 buf[sizeof(buf)-1] = '\0';
7596 pr_trace_msg(trace_channel, 19, "%s", buf);
7597 }
7598
7599 void pr_fs_dump(void (*dumpf)(const char *, ...)) {
7600 pool *p;
7601
7602 if (dumpf == NULL) {
7603 dumpf = fs_printf;
7604 }
7605
7606 dumpf("FS#0: 'system' mounted at '/', implementing the following hooks:");
7607 dumpf("FS#0: (all)");
7608
7609 if (!fs_map ||
7610 fs_map->nelts == 0) {
7611 return;
7612 }
7613
7614 p = make_sub_pool(permanent_pool);
7615
7616 if (fs_map->nelts > 0) {
7617 pr_fs_t **fs_objs = (pr_fs_t **) fs_map->elts;
7618 register unsigned int i;
7619
7620 for (i = 0; i < fs_map->nelts; i++) {
7621 pr_fs_t *fsi = fs_objs[i];
7622
7623 for (; fsi->fs_next; fsi = fsi->fs_next) {
7624 get_fs_info(p, i+1, fsi, dumpf);
7625 }
7626 }
7627 }
7628
7629 destroy_pool(p);
7630 }
7631 #endif /* PR_USE_DEVEL */
7632