static int replication_notify_sync(struct mail_user *user) { struct replication_user *ruser = REPLICATION_USER_CONTEXT(user); string_t *str; char buf[1024]; int fd; ssize_t ret; fd = net_connect_unix(ruser->socket_path); if (fd == -1) { i_error("net_connect_unix(%s) failed: %m", ruser->socket_path); return -1; } net_set_nonblock(fd, FALSE); /* <username> \t "sync" */ str = t_str_new(256); str_append_tabescaped(str, user->username); str_append(str, "\tsync\n"); alarm(ruser->sync_secs); if (write_full(fd, str_data(str), str_len(str)) < 0) { i_error("write(%s) failed: %m", ruser->socket_path); ret = -1; } else { /* + | - */ ret = read(fd, buf, sizeof(buf)); if (ret < 0) { if (errno != EINTR) { i_error("read(%s) failed: %m", ruser->socket_path); } else { i_warning("replication(%s): Sync failure: " "Timeout in %u secs", user->username, ruser->sync_secs); } } else if (ret == 0) { i_error("read(%s) failed: EOF", ruser->socket_path); ret = -1; } else if (buf[0] == '+') { /* success */ ret = 0; } else if (buf[0] == '-') { /* failure */ if (buf[ret-1] == '\n') ret--; i_warning("replication(%s): Sync failure: %s", user->username, t_strndup(buf+1, ret-1)); ret = -1; } else { i_warning("replication(%s): " "Remote sent invalid input: %s", user->username, t_strndup(buf, ret)); } } alarm(0); if (close(fd) < 0) i_error("close(%s) failed: %m", ruser->socket_path); return ret; }
bool cmd_create(struct client_command_context *cmd) { enum mailbox_name_status status; struct mail_namespace *ns; const char *mailbox, *storage_name; struct mailbox *box; bool directory; size_t len; /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); if (ns == NULL) return TRUE; len = strlen(mailbox); if (len == 0 || mailbox[len-1] != ns->sep) directory = FALSE; else if (*storage_name == '\0') { client_send_tagline(cmd, "NO ["IMAP_RESP_CODE_ALREADYEXISTS "] Namespace already exists."); return TRUE; } else { /* name ends with hierarchy separator - client is just informing us that it wants to create children under this mailbox. */ directory = TRUE; storage_name = t_strndup(storage_name, strlen(storage_name)-1); mailbox = t_strndup(mailbox, len-1); } ns = client_find_namespace(cmd, mailbox, &storage_name, &status); if (ns == NULL) return TRUE; switch (status) { case MAILBOX_NAME_VALID: break; case MAILBOX_NAME_EXISTS_DIR: if (!directory) break; /* fall through */ case MAILBOX_NAME_EXISTS_MAILBOX: case MAILBOX_NAME_INVALID: case MAILBOX_NAME_NOINFERIORS: client_fail_mailbox_name_status(cmd, mailbox, NULL, status); return TRUE; } box = mailbox_alloc(ns->list, storage_name, 0); if (mailbox_create(box, NULL, directory) < 0) client_send_storage_error(cmd, mailbox_get_storage(box)); else client_send_tagline(cmd, "OK Create completed."); mailbox_free(&box); return TRUE; }
static int quota_count_namespace(struct quota_root *root, struct mail_namespace *ns, uint64_t *bytes, uint64_t *count) { struct mailbox_list_iterate_context *ctx; const struct mailbox_info *info; int ret = 0; ctx = mailbox_list_iter_init(ns->list, "*", MAILBOX_LIST_ITER_SKIP_ALIASES | MAILBOX_LIST_ITER_RETURN_NO_FLAGS); while ((info = mailbox_list_iter_next(ctx)) != NULL) { if ((info->flags & (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) == 0) { ret = quota_count_mailbox(root, ns, info->vname, bytes, count); if (ret < 0) break; } } if (mailbox_list_iter_deinit(&ctx) < 0) ret = -1; if (ns->prefix_len > 0 && ret == 0 && (ns->prefix_len != 6 || strncasecmp(ns->prefix, "INBOX", 5) != 0)) { /* if the namespace prefix itself exists, count it also */ const char *name = t_strndup(ns->prefix, ns->prefix_len-1); ret = quota_count_mailbox(root, ns, name, bytes, count); } return ret; }
static void mech_external_auth_continue(struct auth_request *request, const unsigned char *data, size_t data_size) { const char *authzid, *error; authzid = t_strndup(data, data_size); if (request->user == NULL) { auth_request_log_info(request, AUTH_SUBSYS_MECH, "username not known"); auth_request_fail(request); return; } /* this call is done simply to put the username through translation settings */ if (!auth_request_set_username(request, "", &error)) { auth_request_log_info(request, AUTH_SUBSYS_MECH, "Invalid username"); auth_request_fail(request); return; } if (*authzid != '\0' && !auth_request_set_login_username(request, authzid, &error)) { /* invalid login username */ auth_request_log_info(request, AUTH_SUBSYS_MECH, "login user: %s", error); auth_request_fail(request); } else { auth_request_verify_plain(request, "", plain_verify_callback); } }
static bool access_applications_have_access(struct imap_url *url, const char *const *access_applications) { const char *const *application; if (access_applications == NULL) return FALSE; application = access_applications; for (; *application != NULL; application++) { const char *app = *application; bool have_userid = FALSE; size_t len = strlen(app); if (app[len-1] == '+') { have_userid = TRUE; app = t_strndup(app, len-1); } if (strcasecmp(url->uauth_access_application, app) == 0) { if (have_userid) return url->uauth_access_user != NULL; else return url->uauth_access_user == NULL; } } return FALSE; }
static bool dump_msg_hdr(struct istream *input, unsigned int hdr_size, uoff_t *msg_size_r) { struct dbox_message_header hdr; const unsigned char *data; size_t size; uoff_t msg_size; if (i_stream_read_bytes(input, &data, &size, hdr_size) <= 0) { if (size == 0) return FALSE; i_fatal("Partial message header read at %"PRIuUOFF_T": " "%"PRIuSIZE_T" bytes", input->v_offset, size); } printf("offset %"PRIuUOFF_T":\n", input->v_offset); if (hdr_size < sizeof(hdr)) i_fatal("file.hdr_size too small: %u", hdr_size); memcpy(&hdr, data, sizeof(hdr)); if (memcmp(hdr.magic_pre, DBOX_MAGIC_PRE, sizeof(hdr.magic_pre)) != 0) i_fatal("dbox wrong pre-magic at %"PRIuUOFF_T, input->v_offset); msg_size = dump_size(input, "msg.size", t_strndup(hdr.message_size_hex, sizeof(hdr.message_size_hex))); i_stream_skip(input, hdr_size); *msg_size_r = msg_size; return TRUE; }
static int http_parse_auth_param(struct http_parser *parser, const char **param_r, const char **value_r) { const unsigned char *first = parser->cur, *end_token; int ret; /* auth-param = token BWS "=" BWS ( token / quoted-string ) */ /* token */ if ((ret=http_parser_skip_token(parser)) <= 0) { parser->cur = first; return ret; } end_token = parser->cur; /* BWS "=" BWS */ http_parse_ows(parser); if (parser->cur >= parser->end || *parser->cur != '=') { parser->cur = first; return 0; } parser->cur++; http_parse_ows(parser); /* ( token / quoted-string ) */ if ((ret=http_parse_token_or_qstring(parser, value_r)) <= 0) { parser->cur = first; return ret; } *param_r = t_strndup(first, end_token - first); return 1; }
static void drop_privileges(struct service *service) { struct restrict_access_settings rset; bool disallow_root; unsigned int len; if (service->vsz_limit != 0) restrict_process_size(service->vsz_limit); restrict_access_init(&rset); rset.uid = service->uid; rset.gid = service->gid; rset.privileged_gid = service->privileged_gid; rset.chroot_dir = *service->set->chroot == '\0' ? NULL : service->set->chroot; if (rset.chroot_dir != NULL) { /* drop trailing / if it exists */ len = strlen(rset.chroot_dir); if (rset.chroot_dir[len-1] == '/') rset.chroot_dir = t_strndup(rset.chroot_dir, len-1); } rset.extra_groups = service->extra_gids; restrict_access_set_env(&rset); if (service->set->drop_priv_before_exec) { disallow_root = service->type == SERVICE_TYPE_LOGIN; restrict_access(&rset, NULL, disallow_root); } }
static bool fts_tokenizer_generic_simple_current_token(struct generic_fts_tokenizer *tok, const char **token_r) { const unsigned char *data = tok->token->data; size_t len = tok->token->used; if (tok->untruncated_length <= tok->max_length) { /* Remove the trailing apostrophe - it was made into U+0027 earlier. There can be only a single such apostrophe, because otherwise the token would have already been split. We also want to remove the trailing apostrophe only if it's the the last character in the nontruncated token - a truncated token may end with apostrophe. */ if (len > 0 && data[len-1] == '\'') { len--; i_assert(len > 0 && data[len-1] != '\''); } } else { fts_tokenizer_delete_trailing_partial_char(data, &len); } i_assert(len <= tok->max_length); *token_r = len == 0 ? "" : t_strndup(tok->token->data, len); buffer_set_used_size(tok->token, 0); tok->untruncated_length = 0; tok->prev_letter = LETTER_TYPE_NONE; return len > 0; }
bool password_generate_encoded(const char *plaintext, const struct password_generate_params *params, const char *scheme, const char **password_r) { const struct password_scheme *s; const unsigned char *raw_password; enum password_encoding encoding; string_t *str; size_t size; s = password_scheme_lookup(scheme, &encoding); if (s == NULL) return FALSE; s->password_generate(plaintext, params, &raw_password, &size); switch (encoding) { case PW_ENCODING_NONE: *password_r = t_strndup(raw_password, size); break; case PW_ENCODING_BASE64: str = t_str_new(MAX_BASE64_ENCODED_SIZE(size) + 1); base64_encode(raw_password, size, str); *password_r = str_c(str); break; case PW_ENCODING_HEX: *password_r = binary_to_hex(raw_password, size); break; } return TRUE; }
int http_parse_token(struct http_parser *parser, const char **token_r) { const unsigned char *first = parser->cur; int ret; if ((ret=http_parser_skip_token(parser)) <= 0) return ret; *token_r = t_strndup(first, parser->cur - first); return 1; }
static const char *asn1_string_to_c(ASN1_STRING *asn_str) { const char *cstr; unsigned int len; len = ASN1_STRING_length(asn_str); cstr = t_strndup(ASN1_STRING_data(asn_str), len); if (strlen(cstr) != len) { /* NULs in the name - could be some MITM attack. never allow. */ return ""; } return cstr; }
static bool readfile(const char *path, const char **data_r) { char buf[1024]; int fd, ret; fd = open(path, O_RDONLY); if (fd == -1) return FALSE; ret = read(fd, buf, sizeof(buf)); i_close_fd(&fd); if (ret <= 0) return FALSE; *data_r = t_strndup(buf, ret); return TRUE; }
int http_parse_token(struct http_parser *parser, const char **token_r) { const unsigned char *first; /* token = 1*tchar */ if (parser->cur >= parser->end || !http_char_is_token(*parser->cur)) return 0; first = parser->cur++; while (parser->cur < parser->end && http_char_is_token(*parser->cur)) parser->cur++; *token_r = t_strndup(first, parser->cur - first); return 1; }
static int client_connection_authenticate(struct client_connection *conn) { const char *line, *pass; buffer_t *plain; const unsigned char *data; size_t size; if ((line = i_stream_read_next_line(conn->input)) == NULL) { if (conn->input->eof) return -1; return 0; } if (*conn->set->doveadm_password == '\0') { i_error("doveadm_password not set, " "remote authentication disabled"); return -1; } /* FIXME: some day we should probably let auth process do this and support all kinds of authentication */ if (strncmp(line, "PLAIN\t", 6) != 0) { i_error("doveadm client attempted non-PLAIN authentication"); return -1; } plain = buffer_create_dynamic(pool_datastack_create(), 128); if (base64_decode(line + 6, strlen(line + 6), NULL, plain) < 0) { i_error("doveadm client sent invalid base64 auth PLAIN data"); return -1; } data = plain->data; size = plain->used; if (size < 10 || data[0] != '\0' || memcmp(data+1, "doveadm", 7) != 0 || data[8] != '\0') { i_error("doveadm client didn't authenticate as 'doveadm'"); return -1; } pass = t_strndup(data + 9, size - 9); if (strcmp(pass, conn->set->doveadm_password) != 0) { i_error("doveadm client authenticated with wrong password"); return -1; } return 1; }
static const char * acl_mailbox_list_iter_get_name(struct mailbox_list_iterate_context *ctx, const char *vname) { struct mail_namespace *ns = ctx->list->ns; const char *name; unsigned int len; name = mailbox_list_get_storage_name(ns->list, vname); len = strlen(name); if (len > 0 && name[len-1] == mailbox_list_get_hierarchy_sep(ns->list)) { /* name ends with separator. this can happen if doing e.g. LIST "" foo/% and it lists "foo/". */ name = t_strndup(name, len-1); } return name; }
static bool acl_ns_prefix_exists(struct mail_namespace *ns) { struct mailbox *box; const char *vname; enum mailbox_existence existence; bool ret; if (ns->list->mail_set->mail_shared_explicit_inbox) return FALSE; vname = t_strndup(ns->prefix, ns->prefix_len-1); box = mailbox_alloc(ns->list, vname, 0); ret = mailbox_exists(box, FALSE, &existence) == 0 && existence == MAILBOX_EXISTENCE_SELECT; mailbox_free(&box); return ret; }
static int stream_read_value(struct istream **input, const char **value_r) { const unsigned char *data; size_t size; ssize_t ret; while ((ret = i_stream_read(*input)) > 0) ; if (ret == 0) return 0; i_assert(ret == -1); if ((*input)->stream_errno != 0) return -1; data = i_stream_get_data(*input, &size); *value_r = t_strndup(data, size); i_stream_unref(input); return 1; }
bool cmd_create(struct client_command_context *cmd) { struct mail_namespace *ns; const char *mailbox, *orig_mailbox; struct mailbox *box; bool directory; size_t len; /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; orig_mailbox = mailbox; ns = client_find_namespace(cmd, &mailbox); if (ns == NULL) return TRUE; len = strlen(orig_mailbox); if (len == 0 || orig_mailbox[len-1] != mail_namespace_get_sep(ns)) directory = FALSE; else { /* name ends with hierarchy separator - client is just informing us that it wants to create children under this mailbox. */ directory = TRUE; /* drop separator from mailbox. it's already dropped when WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */ if (len == strlen(mailbox)) mailbox = t_strndup(mailbox, len-1); } box = mailbox_alloc(ns->list, mailbox, 0); mailbox_set_reason(box, "CREATE"); if (mailbox_create(box, NULL, directory) < 0) client_send_box_error(cmd, box); else client_send_tagline(cmd, "OK Create completed."); mailbox_free(&box); return TRUE; }
static const struct mailbox_info * quota_mailbox_iter_next(struct quota_mailbox_iter *iter) { struct mail_namespace *const *namespaces; const struct mailbox_info *info; unsigned int count; if (iter->iter == NULL) { namespaces = array_get(&iter->root->quota->namespaces, &count); if (iter->ns_idx >= count) return NULL; iter->ns = namespaces[iter->ns_idx++]; iter->iter = mailbox_list_iter_init(iter->ns->list, "*", MAILBOX_LIST_ITER_SKIP_ALIASES | MAILBOX_LIST_ITER_RETURN_NO_FLAGS | MAILBOX_LIST_ITER_NO_AUTO_BOXES); } while ((info = mailbox_list_iter_next(iter->iter)) != NULL) { if ((info->flags & (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) == 0) return info; } if (mailbox_list_iter_deinit(&iter->iter) < 0) { i_error("quota: Listing namespace '%s' failed: %s", iter->ns->prefix, mailbox_list_get_last_error(iter->ns->list, NULL)); iter->failed = TRUE; } if (iter->ns->prefix_len > 0 && (iter->ns->prefix_len != 6 || strncasecmp(iter->ns->prefix, "INBOX", 5) != 0)) { /* if the namespace prefix itself exists, count it also */ iter->info.ns = iter->ns; iter->info.vname = t_strndup(iter->ns->prefix, iter->ns->prefix_len-1); return &iter->info; } /* try the next namespace */ return quota_mailbox_iter_next(iter); }
static void parse_imap_keywords_list(struct mbox_sync_mail_context *ctx, struct message_header_line *hdr, size_t pos) { struct mailbox *box = &ctx->sync_ctx->mbox->box; struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); const char *keyword, *error; size_t keyword_start; unsigned int idx, count; count = 0; while (pos < hdr->full_value_len) { if (IS_LWSP_LF(hdr->full_value[pos])) { pos++; continue; } /* read the keyword */ keyword_start = pos; for (; pos < hdr->full_value_len; pos++) { if (IS_LWSP_LF(hdr->full_value[pos])) break; } /* add it to index's keyword list if it's not there already */ keyword = t_strndup(hdr->full_value + keyword_start, pos - keyword_start); if (mailbox_keyword_is_valid(&ctx->sync_ctx->mbox->box, keyword, &error)) { mail_index_keyword_lookup_or_create(box->index, keyword, &idx); } count++; } if (count != array_count(ibox->keyword_names)) { /* need to update this list */ ctx->imapbase_rewrite = TRUE; ctx->need_rewrite = TRUE; } }
static void tcpwrap_client_input(struct tcpwrap_client *client) { unsigned char buf[1024]; ssize_t ret; int check_fd = -1; ret = fd_read(client->fd, buf, sizeof(buf), &check_fd); if (ret <= 0) { i_error("fd_read() failed: %m"); } else if (ret > 1 && (size_t)ret < sizeof(buf) && buf[ret-1] == '\n') { tcpwrap_client_handle(client, check_fd, t_strndup(buf, ret-1)); } else { i_error("Invalid input from client"); } if (check_fd != -1) { if (close(check_fd) < 0) i_error("close(fdread fd) failed: %m"); } tcpwrap_client_destroy(&client); }
void mailbox_list_delete_until_root(struct mailbox_list *list, const char *path, enum mailbox_list_path_type type) { const char *root_dir, *p; unsigned int len; root_dir = mailbox_list_get_path(list, NULL, type); if (strncmp(path, root_dir, strlen(root_dir)) != 0) { /* mbox workaround: name=child/box, root_dir=mail/.imap/, path=mail/child/.imap/box. we'll want to try to delete the .imap/ part, but no further. */ len = strlen(path); while (len > 0 && path[len-1] != '/') len--; if (len == 0) return; len--; while (len > 0 && path[len-1] != '/') len--; if (len == 0) return; root_dir = t_strndup(path, len-1); } while (strcmp(path, root_dir) != 0) { if (rmdir(path) < 0 && errno != ENOENT) { if (errno == ENOTEMPTY || errno == EEXIST) return; mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path); return; } p = strrchr(path, '/'); if (p == NULL) break; path = t_strdup_until(path, p); } }
static void client_parse_input(const unsigned char *data, unsigned int len, struct client_input *input_r) { unsigned int taglen; i_assert(len > 0); memset(input_r, 0, sizeof(*input_r)); if (data[0] == '1') input_r->send_untagged_capability = TRUE; data++; len--; input_r->tag = t_strndup(data, len); taglen = strlen(input_r->tag) + 1; if (len > taglen) { input_r->input = data + taglen; input_r->input_size = len - taglen; } }
static int http_parse_token68(struct http_parser *parser, const char **token68_r) { const unsigned char *first; /* token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"=" */ /* 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) */ if (parser->cur >= parser->end || !http_char_is_token68(*parser->cur)) return 0; first = parser->cur++; while (parser->cur < parser->end && http_char_is_token68(*parser->cur)) parser->cur++; /* *"=" */ while (parser->cur < parser->end && *parser->cur == '=') parser->cur++; *token68_r = t_strndup(first, parser->cur - first); return 1; }
static int fts_filter_stemmer_snowball_filter(struct fts_filter *filter, const char **token, const char **error_r) { struct fts_filter_stemmer_snowball *sp = (struct fts_filter_stemmer_snowball *) filter; const sb_symbol *base; if (sp->stemmer == NULL) { if (fts_filter_stemmer_snowball_create_stemmer(sp, error_r) < 0) return -1; } base = sb_stemmer_stem(sp->stemmer, (const unsigned char *)*token, strlen(*token)); if (base == NULL) { /* the only reason why this could fail is because of out of memory. */ i_fatal_status(FATAL_OUTOFMEM, "sb_stemmer_stem(len=%"PRIuSIZE_T") failed: " "Out of memory", strlen(*token)); } *token = t_strndup(base, sb_stemmer_length(sp->stemmer)); return 1; }
static int set_line(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, const char *line) { struct setting_parser_context *set_parser = user->set_parser; bool mail_debug; const char *key, *orig_key, *append_value = NULL; unsigned int len; int ret; mail_debug = mail_user_set_get_mail_debug(user->user_info, user->user_set); if (strchr(line, '=') == NULL) line = t_strconcat(line, "=yes", NULL); orig_key = key = t_strcut(line, '='); len = strlen(key); if (len > 0 && key[len-1] == '+') { /* key+=value */ append_value = line + len + 1; key = t_strndup(key, len-1); } if (!settings_parse_is_valid_key(set_parser, key)) { /* assume it's a plugin setting */ key = t_strconcat("plugin/", key, NULL); line = t_strconcat("plugin/", line, NULL); } if (master_service_set_has_config_override(ctx->service, key)) { /* this setting was already overridden with -o parameter */ if (mail_debug) { i_debug("Ignoring overridden (-o) userdb setting: %s", key); } return 1; } if (append_value != NULL) { const void *value; enum setting_type type; value = settings_parse_get_value(set_parser, key, &type); if (type == SET_STR) { const char *const *strp = value; line = t_strdup_printf("%s=%s%s", key, *strp, append_value); } else { i_error("Ignoring %s userdb setting. " "'+' can only be used for strings.", orig_key); } } ret = settings_parse_line(set_parser, line); if (mail_debug && ret >= 0) { if (strstr(key, "pass") != NULL) { /* possibly a password field (e.g. imapc_password). hide the value. */ line = t_strconcat(key, "=<hidden>", NULL); } i_debug(ret == 0 ? "Unknown userdb setting: %s" : "Added userdb setting: %s", line); } return ret; }
static int mail_storage_service_next_real(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, struct mail_user **mail_user_r) { struct mail_storage_service_privileges priv; const char *error; unsigned int len; bool disallow_root = (user->flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0; bool temp_priv_drop = (user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0; bool use_chroot; if (service_parse_privileges(ctx, user, &priv, &error) < 0) { i_error("%s", error); return -2; } if (*priv.home != '/' && *priv.home != '\0') { i_error("Relative home directory paths not supported: %s", priv.home); return -2; } /* we can't chroot if we want to switch between users. there's not much point either (from security point of view). but if we're already chrooted, we'll just have to continue and hope that the current chroot is the same as the wanted chroot */ use_chroot = !temp_priv_drop || restrict_access_get_current_chroot() != NULL; len = strlen(priv.chroot); if (len > 2 && strcmp(priv.chroot + len - 2, "/.") == 0 && strncmp(priv.home, priv.chroot, len - 2) == 0) { /* mail_chroot = /chroot/. means that the home dir already contains the chroot dir. remove it from home. */ if (use_chroot) { priv.home += len - 2; if (*priv.home == '\0') priv.home = "/"; priv.chroot = t_strndup(priv.chroot, len - 2); set_keyval(ctx, user, "mail_home", priv.home); set_keyval(ctx, user, "mail_chroot", priv.chroot); } } else if (len > 0 && !use_chroot) { /* we're not going to chroot. fix home directory so we can access it. */ if (*priv.home == '\0' || strcmp(priv.home, "/") == 0) priv.home = priv.chroot; else priv.home = t_strconcat(priv.chroot, priv.home, NULL); priv.chroot = ""; set_keyval(ctx, user, "mail_home", priv.home); } /* create ioloop context regardless of logging. it's also used by stats plugin. */ user->ioloop_ctx = io_loop_context_new(current_ioloop); if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0) mail_storage_service_init_log(ctx, user, &priv); if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) { if (service_drop_privileges(user, &priv, disallow_root, temp_priv_drop, FALSE, &error) < 0) { i_error("Couldn't drop privileges: %s", error); return -1; } if (!temp_priv_drop || (user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) != 0) restrict_access_allow_coredumps(TRUE); } /* privileges are dropped. initialize plugins that haven't been initialized yet. */ module_dir_init(mail_storage_service_modules); if (mail_storage_service_init_post(ctx, user, &priv, mail_user_r, &error) < 0) { i_error("User initialization failed: %s", error); return -2; } return 0; }
static int mailbox_list_subscription_fill_one(struct mailbox_list *list, struct mailbox_list *src_list, const char *name) { struct mail_namespace *ns, *default_ns = list->ns; struct mail_namespace *namespaces = default_ns->user->namespaces; struct mailbox_node *node; const char *vname, *ns_name, *error; unsigned int len; bool created; /* default_ns is whatever namespace we're currently listing. if we have e.g. prefix="" and prefix=pub/ namespaces with pub/ namespace having subscriptions=no, we want to: 1) when listing "" namespace we want to skip over any names that begin with pub/. */ if (src_list->ns->prefix_len == 0) ns_name = name; else { /* we could have two-level namespace: ns/ns2/ */ ns_name = t_strconcat(src_list->ns->prefix, name, NULL); } ns = mail_namespace_find_unsubscribable(namespaces, ns_name); if (ns != NULL && ns != default_ns) { if (ns->prefix_len > 0) return 0; /* prefix="" namespace=no : catching this is basically the same as not finding any namespace. */ ns = NULL; } /* 2) when listing pub/ namespace, skip over entries that don't begin with pub/. */ if (ns == NULL && (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) return 0; /* When listing shared namespace's subscriptions, we need to autocreate all the visible child namespaces. their subscriptions are listed later. */ if (ns != NULL && mail_namespace_is_shared_user_root(ns)) { /* we'll need to get the namespace autocreated. one easy way is to just ask to join a reference and pattern */ (void)mailbox_list_join_refpattern(ns->list, ns_name, ""); } /* When listing pub/ namespace, skip over the namespace prefix in the name. the rest of the name is storage_name. */ if (ns == NULL) ns = default_ns; else if (strncmp(ns_name, ns->prefix, ns->prefix_len) == 0) { ns_name += ns->prefix_len; name = ns_name; } else { /* "pub" entry - this shouldn't be possible normally, because it should be saved as "pub/", but handle it anyway */ i_assert(strncmp(ns_name, ns->prefix, ns->prefix_len-1) == 0 && ns_name[ns->prefix_len-1] == '\0'); name = ns_name = ""; } len = strlen(name); if (len > 0 && name[len-1] == mail_namespace_get_sep(ns)) { /* entry ends with hierarchy separator, remove it. this exists mainly for backwards compatibility with old Dovecot versions and non-Dovecot software that added them */ name = t_strndup(name, len-1); } if (!mailbox_list_is_valid_name(list, name, &error)) { /* we'll only get into trouble if we show this */ return -1; } else { vname = mailbox_list_get_vname(list, name); if (!uni_utf8_str_is_valid(vname)) return -1; node = mailbox_tree_get(list->subscriptions, vname, &created); node->flags = MAILBOX_SUBSCRIBED; } return 0; }
int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, struct mail_namespace *ns, const char *box_name, const guid_128_t box_guid, const char *const *exclude_mailboxes, enum mail_error *error_r) { const enum mailbox_list_iter_flags list_flags = /* FIXME: we'll skip symlinks, because we can't handle them currently. in future we could detect them and create them by creating the symlink. */ MAILBOX_LIST_ITER_SKIP_ALIASES | MAILBOX_LIST_ITER_NO_AUTO_BOXES; const enum mailbox_list_iter_flags subs_list_flags = MAILBOX_LIST_ITER_NO_AUTO_BOXES | MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | MAILBOX_LIST_ITER_RETURN_NO_FLAGS; struct mailbox_list_iterate_context *iter; struct dsync_mailbox_node *node, *dup_node1, *dup_node2; const struct mailbox_info *info; const char *list_pattern = box_name != NULL && box_name[0] != '\\' ? box_name : "*"; int ret = 0; i_assert(mail_namespace_get_sep(ns) == tree->sep); /* assign namespace to its root, so it gets copied to children */ if (ns->prefix_len > 0) { node = dsync_mailbox_tree_get(tree, t_strndup(ns->prefix, ns->prefix_len-1)); node->ns = ns; } else { tree->root.ns = ns; } /* first add all of the existing mailboxes */ iter = mailbox_list_iter_init(ns->list, list_pattern, list_flags); while ((info = mailbox_list_iter_next(iter)) != NULL) T_BEGIN { if (dsync_mailbox_info_is_wanted(info, box_name, exclude_mailboxes)) { if (dsync_mailbox_tree_add(tree, info, box_guid, error_r) < 0) ret = -1; } } T_END; if (mailbox_list_iter_deinit(&iter) < 0) { i_error("Mailbox listing for namespace '%s' failed: %s", ns->prefix, mailbox_list_get_last_internal_error(ns->list, error_r)); ret = -1; } /* add subscriptions */ iter = mailbox_list_iter_init(ns->list, list_pattern, subs_list_flags); while ((info = mailbox_list_iter_next(iter)) != NULL) { if (dsync_mailbox_tree_add_node(tree, info, &node) == 0) node->subscribed = TRUE; else { *error_r = MAIL_ERROR_TEMP; ret = -1; } } if (mailbox_list_iter_deinit(&iter) < 0) { i_error("Mailbox listing for namespace '%s' failed: %s", ns->prefix, mailbox_list_get_last_internal_error(ns->list, error_r)); ret = -1; } if (ret < 0) return -1; while (dsync_mailbox_tree_build_guid_hash(tree, &dup_node1, &dup_node2) < 0) { if (dsync_mailbox_tree_fix_guid_duplicate(tree, dup_node1, dup_node2) < 0) return -1; } /* add timestamps */ if (dsync_mailbox_tree_add_change_timestamps(tree, ns) < 0) return -1; return 0; }