int parse_config_path2(pool *p, const char *path, unsigned int depth) { struct stat st; int have_glob; void *dirh; struct dirent *dent; array_header *file_list; char *dup_path, *ptr; pool *tmp_pool; if (p == NULL || path == NULL || (depth > PR_PARSER_INCLUDE_MAX_DEPTH)) { errno = EINVAL; return -1; } if (pr_fs_valid_path(path) < 0) { errno = EINVAL; return -1; } have_glob = pr_str_is_fnmatch(path); if (have_glob) { /* Even though the path may be valid, it also may not be a filesystem * path; consider custom FSIO modules. Thus if the path does not start * with a slash, it should not be treated as having globs. */ if (*path != '/') { have_glob = FALSE; } } pr_fs_clear_cache2(path); if (have_glob) { pr_trace_msg(trace_channel, 19, "parsing '%s' as a globbed path", path); } if (!have_glob && pr_fsio_lstat(path, &st) < 0) { return -1; } /* If path is not a glob pattern, and is a symlink OR is not a directory, * then use the normal parsing function for the file. */ if (have_glob == FALSE && (S_ISLNK(st.st_mode) || !S_ISDIR(st.st_mode))) { int res, xerrno; PRIVS_ROOT res = pr_parser_parse_file(p, path, NULL, 0); xerrno = errno; PRIVS_RELINQUISH errno = xerrno; return res; } tmp_pool = make_sub_pool(p); pr_pool_tag(tmp_pool, "Include sub-pool"); /* Handle the glob/directory. */ dup_path = pstrdup(tmp_pool, path); ptr = strrchr(dup_path, '/'); if (have_glob) { int have_glob_dir; /* Note that we know, by definition, that ptr CANNOT be null here; dup_path * is a duplicate of path, and the first character (if nothing else) of * path MUST be a slash, per earlier checks. */ *ptr = '\0'; /* We just changed ptr, thus we DO need to check whether the now-modified * path contains fnmatch(3) characters again. */ have_glob_dir = pr_str_is_fnmatch(dup_path); if (have_glob_dir) { const char *glob_dir; if (parser_include_opts & PR_PARSER_INCLUDE_OPT_IGNORE_WILDCARDS) { pr_log_pri(PR_LOG_WARNING, "error: wildcard patterns not allowed in " "configuration directory name '%s'", dup_path); destroy_pool(tmp_pool); errno = EINVAL; return -1; } *ptr = '/'; glob_dir = pstrdup(p, dup_path); destroy_pool(tmp_pool); return parse_wildcard_config_path(p, glob_dir, depth); } ptr++; /* Check the directory component. */ pr_fs_clear_cache2(dup_path); if (pr_fsio_lstat(dup_path, &st) < 0) { int xerrno = errno; pr_log_pri(PR_LOG_WARNING, "error: failed to check configuration path '%s': %s", dup_path, strerror(xerrno)); destroy_pool(tmp_pool); errno = xerrno; return -1; } if (S_ISLNK(st.st_mode) && !(parser_include_opts & PR_PARSER_INCLUDE_OPT_ALLOW_SYMLINKS)) { pr_log_pri(PR_LOG_WARNING, "error: cannot read configuration path '%s': Symbolic link", path); destroy_pool(tmp_pool); errno = ENOTDIR; return -1; } if (have_glob_dir == FALSE && pr_str_is_fnmatch(ptr) == FALSE) { pr_log_pri(PR_LOG_WARNING, "error: wildcard pattern required for file '%s'", ptr); destroy_pool(tmp_pool); errno = EINVAL; return -1; } } pr_log_pri(PR_LOG_DEBUG, "processing configuration directory '%s'", dup_path); dirh = pr_fsio_opendir(dup_path); if (dirh == NULL) { pr_log_pri(PR_LOG_WARNING, "error: unable to open configuration directory '%s': %s", dup_path, strerror(errno)); destroy_pool(tmp_pool); errno = EINVAL; return -1; } file_list = make_array(tmp_pool, 0, sizeof(char *)); while ((dent = pr_fsio_readdir(dirh)) != NULL) { pr_signals_handle(); if (strncmp(dent->d_name, ".", 2) == 0 || strncmp(dent->d_name, "..", 3) == 0) { continue; } if (parser_include_opts & PR_PARSER_INCLUDE_OPT_IGNORE_TMP_FILES) { if (is_tmp_file(dent->d_name) == TRUE) { pr_trace_msg(trace_channel, 19, "ignoring temporary file '%s' found in directory '%s'", dent->d_name, dup_path); continue; } } if (have_glob == FALSE || (ptr != NULL && pr_fnmatch(ptr, dent->d_name, PR_FNM_PERIOD) == 0)) { *((char **) push_array(file_list)) = pdircat(tmp_pool, dup_path, dent->d_name, NULL); } } pr_fsio_closedir(dirh); if (file_list->nelts) { register unsigned int i; qsort((void *) file_list->elts, file_list->nelts, sizeof(char *), config_filename_cmp); for (i = 0; i < file_list->nelts; i++) { int res, xerrno; char *file; file = ((char **) file_list->elts)[i]; /* Make sure we always parse the files with root privs. The * previously parsed file might have had root privs relinquished * (e.g. by its directive handlers), but when we first start up, * we have root privs. See Bug#3855. */ PRIVS_ROOT res = pr_parser_parse_file(tmp_pool, file, NULL, 0); xerrno = errno; PRIVS_RELINQUISH if (res < 0) { pr_log_pri(PR_LOG_WARNING, "error: unable to open parse file '%s': %s", file, strerror(xerrno)); } } } destroy_pool(tmp_pool); return 0; }
int pr_namebind_create(server_rec *server, const char *name, pr_netaddr_t *addr, unsigned int port) { pr_ipbind_t *ipbind = NULL; pr_namebind_t *namebind = NULL, **namebinds = NULL; if (server == NULL || name == NULL) { errno = EINVAL; return -1; } /* First, find the ipbind to hold this namebind. */ ipbind = pr_ipbind_find(addr, port, FALSE); if (ipbind == NULL) { pr_netaddr_t wildcard_addr; int addr_family; /* If not found, look for the wildcard address. */ addr_family = pr_netaddr_get_family(addr); pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, addr_family); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); #ifdef PR_USE_IPV6 if (ipbind == FALSE && addr_family == AF_INET6 && pr_netaddr_use_ipv6()) { /* No IPv6 wildcard address found; try the IPv4 wildcard address. */ pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, AF_INET); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); } #endif /* PR_USE_IPV6 */ } if (ipbind == NULL) { errno = ENOENT; return -1; } /* Make sure we can add this namebind. */ if (!ipbind->ib_namebinds) { ipbind->ib_namebinds = make_array(binding_pool, 0, sizeof(pr_namebind_t *)); } else { register unsigned int i = 0; namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; /* See if there is already a namebind for the given name. */ for (i = 0; i < ipbind->ib_namebinds->nelts; i++) { namebind = namebinds[i]; if (namebind != NULL && namebind->nb_name != NULL) { /* DNS names are case-insensitive, hence the case-insensitive check * here. * * XXX Ideally, we should check whether any existing namebinds which * are globs will match the newly added namebind as well. */ if (strcasecmp(namebind->nb_name, name) == 0) { errno = EEXIST; return -1; } } } } namebind = (pr_namebind_t *) pcalloc(server->pool, sizeof(pr_namebind_t)); namebind->nb_name = name; namebind->nb_server = server; namebind->nb_isactive = FALSE; if (pr_str_is_fnmatch(name) == TRUE) { namebind->nb_iswildcard = TRUE; } pr_trace_msg(trace_channel, 8, "created named binding '%s' for %s#%u, server %p", name, pr_netaddr_get_ipstr(server->addr), server->ServerPort, server->ServerName); /* The given server should already have the following populated: * * server->ServerName * server->ServerAddress * server->ServerFQDN */ /* These TCP socket tweaks will not apply to the control connection (it will * already have been established by the time this named vhost is used), * but WILL apply to any data connections established to this named vhost. */ #if 0 namebind->nb_server->tcp_mss_len = (server->tcp_mss_len ? server->tcp_mss_len : main_server->tcp_mss_len); namebind->nb_server->tcp_rcvbuf_len = (server->tcp_rcvbuf_len ? server->tcp_rcvbuf_len : main_server->tcp_rcvbuf_len); namebind->nb_server->tcp_rcvbuf_override = (server->tcp_rcvbuf_override ? TRUE : main_server->tcp_rcvbuf_override); namebind->nb_server->tcp_sndbuf_len = (server->tcp_sndbuf_len ? server->tcp_sndbuf_len : main_server->tcp_sndbuf_len); namebind->nb_server->tcp_sndbuf_override = (server->tcp_sndbuf_override ? TRUE : main_server->tcp_sndbuf_override); /* XXX Shouldn't need these; the ipbind container handles all of the * connection (listener, port, addr) stuff. */ namebind->nb_server->addr = (server->addr ? server->addr : main_server->addr); namebind->nb_server->ServerPort = (server->ServerPort ? server->ServerPort : main_server->ServerPort); namebind->nb_listener = (server->listen ? server->listen : main_server->listen); #endif *((pr_namebind_t **) push_array(ipbind->ib_namebinds)) = namebind; return 0; }