char *dir_canonical_vpath(pool *p, const char *path) { char buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; char work[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; if (p == NULL || path == NULL) { errno = EINVAL; return NULL; } if (*path == '~') { if (pr_fs_interpolate(path, work, sizeof(work)-1) != 1) { if (pr_fs_dircat(work, sizeof(work), pr_fs_getvwd(), path) < 0) { return NULL; } } } else { if (pr_fs_dircat(work, sizeof(work), pr_fs_getvwd(), path) < 0) { return NULL; } } pr_fs_clean_path(work, buf, sizeof(buf)-1); return pstrdup(p, buf); }
/* dir_best_path() creates the "most" fully canonicalized path possible * (i.e. if path components at the end don't exist, they are ignored). */ char *dir_best_path(pool *p, const char *path) { char workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; char realpath_buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; char *target = NULL, *ntarget; int fini = 0; if (*path == '~') { if (pr_fs_interpolate(path, workpath, sizeof(workpath)-1) != 1) { if (pr_fs_dircat(workpath, sizeof(workpath), pr_fs_getcwd(), path) < 0) return NULL; } } else { if (pr_fs_dircat(workpath, sizeof(workpath), pr_fs_getcwd(), path) < 0) return NULL; } pr_fs_clean_path(pstrdup(p, workpath), workpath, sizeof(workpath)-1); while (!fini && *workpath) { if (pr_fs_resolve_path(workpath, realpath_buf, sizeof(realpath_buf)-1, 0) != -1) break; ntarget = strrchr(workpath, '/'); if (ntarget) { if (target) { if (pr_fs_dircat(workpath, sizeof(workpath), workpath, target) < 0) return NULL; } target = ntarget; *target++ = '\0'; } else fini++; } if (!fini && *workpath) { if (target) { if (pr_fs_dircat(workpath, sizeof(workpath), realpath_buf, target) < 0) return NULL; } else sstrncpy(workpath, realpath_buf, sizeof(workpath)); } else { if (pr_fs_dircat(workpath, sizeof(workpath), "/", target) < 0) return NULL; } return pstrdup(p, workpath); }
int vroot_fsio_chroot(pr_fs_t *fs, const char *path) { char base[PR_TUNABLE_PATH_MAX + 1]; char *chroot_path = "/", *tmp = NULL; config_rec *c; size_t baselen = 0; if (path == NULL || *path == '\0') { errno = EINVAL; return -1; } memset(base, '\0', sizeof(base)); if (path[0] == '/' && path[1] == '\0') { /* chrooting to '/', nothing needs to be done. */ return 0; } c = find_config(main_server->conf, CONF_PARAM, "VRootServerRoot", FALSE); if (c != NULL) { int res; char *server_root, *ptr = NULL; server_root = c->argv[0]; /* If the last character in the configured path is a slash, remove * it temporarily. */ if (server_root[strlen(server_root)-1] == '/') { ptr = &(server_root[strlen(server_root)-1]); *ptr = '\0'; } /* Now, make sure that the given path is below the configured * VRootServerRoot. If so, then we perform a real chroot to the * VRootServerRoot directory, then use vroots from there. */ res = strncmp(path, server_root, strlen(server_root)); if (ptr != NULL) { *ptr = '/'; } if (res == 0) { (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION, "chroot path '%s' within VRootServerRoot '%s', " "chrooting to VRootServerRoot", path, server_root); if (chroot(server_root) < 0) { int xerrno = errno; (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION, "error chrooting to VRootServerRoot '%s': %s", server_root, strerror(xerrno)); errno = xerrno; return -1; } pr_fs_clean_path(path + strlen(server_root), base, sizeof(base)); chroot_path = server_root; } else { (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION, "chroot path '%s' is not within VRootServerRoot '%s', " "not chrooting to VRootServerRoot", path, server_root); pr_fs_clean_path(path, base, sizeof(base)); } } else { pr_fs_clean_path(path, base, sizeof(base)); } tmp = base; /* Advance to the end of the path. */ while (*tmp != '\0') { tmp++; } for (;;) { tmp--; pr_signals_handle(); if (tmp == base || *tmp != '/') { break; } *tmp = '\0'; } baselen = strlen(base); if (baselen >= PR_TUNABLE_PATH_MAX) { errno = ENAMETOOLONG; return -1; } /* Store the base path in the session notes, for use by e.g. other modules. */ if (pr_table_add_dup(session.notes, "mod_vroot.chroot-path", base, 0) < 0) { pr_trace_msg(trace_channel, 3, "error stashing 'mod_vroot.chroot-path' in session.notes: %s", strerror(errno)); } vroot_path_set_base(base, baselen); session.chroot_path = pstrdup(session.pool, chroot_path); return 0; }