struct mail_index * mail_index_alloc_cache_get(const char *mailbox_path, const char *index_dir, const char *prefix) { struct mail_index_alloc_cache_list *match; struct stat st; /* compare index_dir inodes so we don't break even with symlinks. if index_dir doesn't exist yet or if using in-memory indexes, just compare mailbox paths */ memset(&st, 0, sizeof(st)); if (index_dir == NULL) { /* in-memory indexes */ } else if (stat(index_dir, &st) < 0) { if (errno == ENOENT) { /* it'll be created later */ } else if (errno == EACCES) { i_error("%s", eacces_error_get("stat", index_dir)); } else { i_error("stat(%s) failed: %m", index_dir); } } match = mail_index_alloc_cache_find(mailbox_path, index_dir, &st); if (match == NULL) { struct mail_index *index = mail_index_alloc(index_dir, prefix); match = mail_index_alloc_cache_add(index, mailbox_path, &st); } else { match->refcount++; } i_assert(match->index != NULL); return match->index; }
static int master_service_open_config(struct master_service *service, const struct master_service_settings_input *input, const char **path_r, const char **error_r) { struct stat st; const char *path; int fd; *path_r = path = input->config_path != NULL ? input->config_path : master_service_get_config_path(service); if (service->config_fd != -1 && input->config_path == NULL && !service->config_path_changed_with_param) { /* use the already opened config socket */ fd = service->config_fd; service->config_fd = -1; return fd; } if (!service->config_path_from_master && !service->config_path_changed_with_param && input->config_path == NULL) { /* first try to connect to the default config socket. configuration may contain secrets, so in default config this fails because the socket is 0600. it's useful for developers though. :) */ fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH); if (fd >= 0) { *path_r = DOVECOT_CONFIG_SOCKET_PATH; net_set_nonblock(fd, FALSE); return fd; } /* fallback to executing doveconf */ } if (stat(path, &st) < 0) { *error_r = errno == EACCES ? eacces_error_get("stat", path) : t_strdup_printf("stat(%s) failed: %m", path); return -1; } if (!S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) { /* it's not an UNIX socket, don't even try to connect */ fd = -1; errno = ENOTSOCK; } else { fd = net_connect_unix_with_retries(path, 1000); } if (fd < 0) { *error_r = t_strdup_printf("net_connect_unix(%s) failed: %m", path); config_exec_fallback(service, input); return -1; } net_set_nonblock(fd, FALSE); return fd; }
int auth_server_connection_connect(struct auth_server_connection *conn) { const char *handshake; int fd; i_assert(!conn->connected); i_assert(conn->fd == -1); conn->last_connect = ioloop_time; timeout_remove(&conn->to); /* max. 1 second wait here. */ fd = net_connect_unix_with_retries(conn->client->auth_socket_path, 1000); if (fd == -1) { if (errno == EACCES) { i_error("auth: %s", eacces_error_get("connect", conn->client->auth_socket_path)); } else { i_error("auth: connect(%s) failed: %m", conn->client->auth_socket_path); } return -1; } conn->fd = fd; conn->io = io_add(fd, IO_READ, auth_server_connection_input, conn); conn->input = i_stream_create_fd(fd, AUTH_SERVER_CONN_MAX_LINE_LENGTH); conn->output = o_stream_create_fd(fd, (size_t)-1); conn->connected = TRUE; handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n", AUTH_CLIENT_PROTOCOL_MAJOR_VERSION, AUTH_CLIENT_PROTOCOL_MINOR_VERSION, conn->client->client_pid); if (o_stream_send_str(conn->output, handshake) < 0) { i_warning("Error sending handshake to auth server: %s", o_stream_get_error(conn->output)); auth_server_connection_disconnect(conn, o_stream_get_error(conn->output)); return -1; } conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT, auth_client_handshake_timeout, conn); return 0; }
static void sieve_file_storage_update_mtime (struct sieve_storage *storage, const char *path, time_t mtime) { struct utimbuf times = { .actime = mtime, .modtime = mtime }; if ( utime(path, ×) < 0 ) { switch ( errno ) { case ENOENT: break; case EACCES: sieve_storage_sys_error(storage, "save: " "%s", eacces_error_get("utime", path)); break; default: sieve_storage_sys_error(storage, "save: " "utime(%s) failed: %m", path); } } }
static int sieve_file_storage_script_move (struct sieve_file_save_context *fsctx, const char *dst) { struct sieve_storage_save_context *sctx = &fsctx->context; struct sieve_storage *storage = sctx->storage; int result = 0; T_BEGIN { /* Using rename() to ensure existing files are replaced * without conflicts with other processes using the same * file. The kernel wont fully delete the original until * all processes have closed the file. */ if (rename(fsctx->tmp_path, dst) == 0) result = 0; else { result = -1; if ( ENOQUOTA(errno) ) { sieve_storage_set_error(storage, SIEVE_ERROR_NO_QUOTA, "Not enough disk quota"); } else if ( errno == EACCES ) { sieve_storage_set_critical(storage, "save: " "Failed to save Sieve script: " "%s", eacces_error_get("rename", dst)); } else { sieve_storage_set_critical(storage, "save: " "rename(%s, %s) failed: %m", fsctx->tmp_path, dst); } } /* Always destroy temp file */ if (unlink(fsctx->tmp_path) < 0 && errno != ENOENT) { sieve_storage_sys_warning(storage, "save: " "unlink(%s) failed: %m", fsctx->tmp_path); } } T_END; return result; }
static int filter_connect(struct mail_filter_istream *mstream, const char *socket_path, const char *args) { const char **argv; string_t *str; int fd; argv = t_strsplit(args, " "); if ((fd = net_connect_unix_with_retries(socket_path, 1000)) < 0) { if (errno == EACCES) { i_error("ext-filter: %s", eacces_error_get("net_connect_unix", socket_path)); } else { i_error("ext-filter: net_connect_unix(%s) failed: %m", socket_path); } return -1; } if (mstream->istream.istream.blocking) net_set_nonblock(fd, FALSE); mstream->fd = fd; mstream->ext_in = i_stream_create_fd(fd, mstream->istream.max_buffer_size, FALSE); mstream->ext_out = o_stream_create_fd(fd, 0, FALSE); str = t_str_new(256); str_append(str, "VERSION\tscript\t3\t0\nnoreply\n"); for (; *argv != NULL; argv++) { str_append(str, *argv); str_append_c(str, '\n'); } str_append_c(str, '\n'); o_stream_send(mstream->ext_out, str_data(str), str_len(str)); return 0; }
static int passwd_file_sync(struct auth_request *request, struct passwd_file *pw) { struct stat st; const char *error; if (pw->last_sync_time == ioloop_time) return hash_table_is_created(pw->users) ? 0 : -1; pw->last_sync_time = ioloop_time; if (stat(pw->path, &st) < 0) { /* with variables don't give hard errors, or errors about nonexistent files */ if (errno == EACCES) { auth_request_log_error(request, AUTH_SUBSYS_DB, "%s", eacces_error_get("stat", pw->path)); } else { auth_request_log_error(request, AUTH_SUBSYS_DB, "stat(%s) failed: %m", pw->path); } if (pw->db->default_file != pw) passwd_file_free(pw); return -1; } if (st.st_mtime != pw->stamp || st.st_size != pw->size) { passwd_file_close(pw); if (passwd_file_open(pw, FALSE, &error) < 0) { auth_request_log_error(request, AUTH_SUBSYS_DB, "%s", error); return -1; } } return 0; }
static int mail_storage_service_init_post(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, struct mail_storage_service_privileges *priv, struct mail_user **mail_user_r, const char **error_r) { const struct mail_storage_settings *mail_set; const char *home = priv->home; struct mail_user *mail_user; /* NOTE: if more user initialization is added, add it also to mail_user_dup() */ mail_user = mail_user_alloc(user->input.username, user->user_info, user->user_set); mail_user->_service_user = user; mail_user_set_home(mail_user, *home == '\0' ? NULL : home); mail_user_set_vars(mail_user, ctx->service->name, &user->input.local_ip, &user->input.remote_ip); mail_user->uid = priv->uid == (uid_t)-1 ? geteuid() : priv->uid; mail_user->gid = priv->gid == (gid_t)-1 ? getegid() : priv->gid; mail_user->anonymous = user->anonymous; mail_user->admin = user->admin; mail_user->auth_token = p_strdup(mail_user->pool, user->auth_token); mail_user->auth_user = p_strdup(mail_user->pool, user->auth_user); mail_user->session_id = p_strdup(mail_user->pool, user->input.session_id); mail_user->userdb_fields = user->input.userdb_fields == NULL ? NULL : p_strarray_dup(mail_user->pool, user->input.userdb_fields); mail_user->autoexpunge_enabled = (user->flags & MAIL_STORAGE_SERVICE_FLAG_AUTOEXPUNGE) != 0; mail_set = mail_user_set_get_storage_set(mail_user); if (mail_set->mail_debug) { string_t *str = t_str_new(64); str_printfa(str, "Effective uid=%s, gid=%s, home=%s", dec2str(geteuid()), dec2str(getegid()), home); if (*priv->chroot != '\0') str_printfa(str, ", chroot=%s", priv->chroot); i_debug("%s", str_c(str)); } if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 && (user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) == 0) { /* we don't want to write core files to any users' home directories since they could contain information about other users' mails as well. so do no chdiring to home. */ } else if (*home != '\0' && (user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) { /* If possible chdir to home directory, so that core file could be written in case we crash. */ if (chdir(home) < 0) { if (errno == EACCES) { i_error("%s", eacces_error_get("chdir", t_strconcat(home, "/", NULL))); } if (errno != ENOENT) i_error("chdir(%s) failed: %m", home); else if (mail_set->mail_debug) i_debug("Home dir not found: %s", home); } } if (mail_user_init(mail_user, error_r) < 0) { mail_user_unref(&mail_user); return -1; } if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES) == 0) { if (mail_namespaces_init(mail_user, error_r) < 0) { mail_user_unref(&mail_user); return -1; } } *mail_user_r = mail_user; return 0; }
static int sieve_file_script_sequence_read_dir (struct sieve_file_script_sequence *fseq, const char *path) { struct sieve_storage *storage = fseq->seq.storage; DIR *dirp; int ret = 0; /* Open the directory */ if ( (dirp = opendir(path)) == NULL ) { switch ( errno ) { case ENOENT: sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND, "Script sequence location not found"); break; case EACCES: sieve_storage_set_error(storage, SIEVE_ERROR_NO_PERMISSION, "Script sequence location not accessible"); sieve_storage_sys_error(storage, "Failed to open sieve sequence: " "%s", eacces_error_get("stat", path)); break; default: sieve_storage_set_critical(storage, "Failed to open sieve sequence: " "opendir(%s) failed: %m", path); break; } return -1; } /* Read and sort script files */ for (;;) { const char *const *files; unsigned int count, i; const char *file; struct dirent *dp; struct stat st; errno = 0; if ( (dp=readdir(dirp)) == NULL ) break; if ( !sieve_script_file_has_extension(dp->d_name) ) continue; file = NULL; T_BEGIN { if ( path[strlen(path)-1] == '/' ) file = t_strconcat(path, dp->d_name, NULL); else file = t_strconcat(path, "/", dp->d_name, NULL); if ( stat(file, &st) == 0 && S_ISREG(st.st_mode) ) file = p_strdup(fseq->pool, dp->d_name); else file = NULL; } T_END; if (file == NULL) continue; /* Insert into sorted array */ files = array_get(&fseq->script_files, &count); for ( i = 0; i < count; i++ ) { if ( strcmp(file, files[i]) < 0 ) break; } if ( i == count ) array_append(&fseq->script_files, &file, 1); else array_insert(&fseq->script_files, i, &file, 1); } if ( errno != 0 ) { sieve_storage_set_critical(storage, "Failed to read sequence directory: " "readdir(%s) failed: %m", path); ret = -1; } /* Close the directory */ if ( dirp != NULL && closedir(dirp) < 0 ) { sieve_storage_sys_error(storage, "Failed to close sequence directory: " "closedir(%s) failed: %m", path); } return ret; }
struct sieve_script_sequence *sieve_file_storage_get_script_sequence (struct sieve_storage *storage, enum sieve_error *error_r) { struct sieve_file_storage *fstorage = (struct sieve_file_storage *)storage; struct sieve_file_script_sequence *fseq = NULL; const char *name = storage->script_name; const char *file; pool_t pool; struct stat st; /* Specified path can either be a regular file or a directory */ if ( stat(fstorage->path, &st) != 0 ) { switch ( errno ) { case ENOENT: sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND, "Script sequence location not found"); break; case EACCES: sieve_storage_set_error(storage, SIEVE_ERROR_NO_PERMISSION, "Script sequence location not accessible"); sieve_storage_sys_error(storage, "Failed to open sieve sequence: " "%s", eacces_error_get("stat", fstorage->path)); break; default: sieve_storage_set_critical(storage, "Failed to open sieve sequence: " "stat(%s) failed: %m", fstorage->path); break; } *error_r = storage->error_code; return NULL; } /* Create sequence object */ pool = pool_alloconly_create("sieve_file_script_sequence", 1024); fseq = p_new(pool, struct sieve_file_script_sequence, 1); fseq->pool = pool; sieve_script_sequence_init(&fseq->seq, storage); if ( S_ISDIR(st.st_mode) ) { i_array_init(&fseq->script_files, 16); /* Path is directory */ if (name == 0 || *name == '\0') { /* Read all '.sieve' files in directory */ if (sieve_file_script_sequence_read_dir (fseq, fstorage->path) < 0) { *error_r = storage->error_code; sieve_file_script_sequence_destroy(&fseq->seq); return NULL; } } else { /* Read specific script file */ file = sieve_script_file_from_name(name); file = p_strdup(pool, file); array_append(&fseq->script_files, &file, 1); } } else { /* Path is a file (apparently; we'll see about that once it is opened) */ fseq->storage_is_file = TRUE; } return &fseq->seq; }
static int sieve_file_storage_save_to(struct sieve_file_storage *fstorage, string_t *temp_path, struct istream *input, const char *target) { struct sieve_storage *storage = &fstorage->storage; struct ostream *output; int fd; // FIXME: move this to base class // FIXME: use io_stream_temp fd = safe_mkstemp_hostpid (temp_path, fstorage->file_create_mode, (uid_t)-1, (gid_t)-1); if ( fd < 0 ) { if ( errno == EACCES ) { sieve_storage_set_critical(storage, "Failed to create temporary file: %s", eacces_error_get_creating("open", str_c(temp_path))); } else { sieve_storage_set_critical(storage, "Failed to create temporary file: open(%s) failed: %m", str_c(temp_path)); } return -1; } output = o_stream_create_fd(fd, 0); switch ( o_stream_send_istream(output, input) ) { case OSTREAM_SEND_ISTREAM_RESULT_FINISHED: break; case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT: case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT: i_unreached(); case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT: sieve_storage_set_critical(storage, "read(%s) failed: %s", i_stream_get_name(input), i_stream_get_error(input)); o_stream_destroy(&output); i_unlink(str_c(temp_path)); return -1; case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT: sieve_storage_set_critical(storage, "write(%s) failed: %s", str_c(temp_path), o_stream_get_error(output)); o_stream_destroy(&output); i_unlink(str_c(temp_path)); return -1; } o_stream_destroy(&output); if ( rename(str_c(temp_path), target) < 0 ) { if ( ENOQUOTA(errno) ) { sieve_storage_set_error(storage, SIEVE_ERROR_NO_QUOTA, "Not enough disk quota"); } else if ( errno == EACCES ) { sieve_storage_set_critical(storage, "%s", eacces_error_get("rename", target)); } else { sieve_storage_set_critical(storage, "rename(%s, %s) failed: %m", str_c(temp_path), target); } i_unlink(str_c(temp_path)); } return 0; }
static int passwd_file_open(struct passwd_file *pw, bool startup, const char **error_r) { const char *no_args = NULL; struct istream *input; const char *line; struct stat st; time_t start_time, end_time; unsigned int time_secs; int fd; fd = open(pw->path, O_RDONLY); if (fd == -1) { if (errno == EACCES) *error_r = eacces_error_get("open", pw->path); else { *error_r = t_strdup_printf("open(%s) failed: %m", pw->path); } return -1; } if (fstat(fd, &st) != 0) { *error_r = t_strdup_printf("fstat(%s) failed: %m", pw->path); i_close_fd(&fd); return -1; } pw->fd = fd; pw->stamp = st.st_mtime; pw->size = st.st_size; pw->pool = pool_alloconly_create(MEMPOOL_GROWING"passwd_file", 10240); hash_table_create(&pw->users, pw->pool, 0, str_hash, strcmp); start_time = time(NULL); input = i_stream_create_fd(pw->fd, (size_t)-1, FALSE); i_stream_set_return_partial_line(input, TRUE); while ((line = i_stream_read_next_line(input)) != NULL) { if (*line == '\0' || *line == ':' || *line == '#') continue; /* no username or comment */ T_BEGIN { const char *const *args = t_strsplit(line, ":"); if (args[1] != NULL) { /* at least username+password */ passwd_file_add(pw, args[0], args[1], args+2); } else { /* only username */ passwd_file_add(pw, args[0], NULL, &no_args); } } T_END; } i_stream_destroy(&input); end_time = time(NULL); time_secs = end_time - start_time; if ((time_secs > PARSE_TIME_STARTUP_WARN_SECS && startup) || (time_secs > PARSE_TIME_RELOAD_WARN_SECS && !startup)) { i_warning("passwd-file %s: Reading %u users took %u secs", pw->path, hash_table_count(pw->users), time_secs); } else if (pw->db->debug) { i_debug("passwd-file %s: Read %u users in %u secs", pw->path, hash_table_count(pw->users), time_secs); } return 0; }
const char *mail_error_eacces_msg(const char *func, const char *path) { return eacces_error_get(func, path); }
bool sieve_binary_file_open (struct sieve_binary_file *file, struct sieve_instance *svinst, const char *path, enum sieve_error *error_r) { int fd; bool result = TRUE; struct stat st; if ( error_r != NULL ) *error_r = SIEVE_ERROR_NONE; if ( (fd=open(path, O_RDONLY)) < 0 ) { switch ( errno ) { case ENOENT: if ( error_r != NULL ) *error_r = SIEVE_ERROR_NOT_FOUND; break; case EACCES: sieve_sys_error(svinst, "binary open: failed to open: %s", eacces_error_get("open", path)); if ( error_r != NULL ) *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_sys_error(svinst, "binary open: failed to open: " "open(%s) failed: %m", path); if ( error_r != NULL ) *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } return FALSE; } if ( fstat(fd, &st) < 0 ) { if ( errno != ENOENT ) { sieve_sys_error(svinst, "binary open: fstat(fd=%s) failed: %m", path); } result = FALSE; } if ( result && !S_ISREG(st.st_mode) ) { sieve_sys_error(svinst, "binary open: %s is not a regular file", path); result = FALSE; } if ( !result ) { if ( close(fd) < 0 ) { sieve_sys_error(svinst, "binary open: close(fd=%s) failed after error: %m", path); } return FALSE; } file->svinst = svinst; file->fd = fd; file->st = st; return TRUE; }