void lmtp_client_add_rcpt(struct lmtp_client *client, const char *address, lmtp_callback_t *rcpt_to_callback, lmtp_callback_t *data_callback, void *context) { struct lmtp_rcpt *rcpt; rcpt = array_append_space(&client->recipients); rcpt->address = p_strdup(client->pool, address); rcpt->rcpt_to_callback = rcpt_to_callback; rcpt->data_callback = data_callback; rcpt->context = context; if (client->global_fail_string != NULL) { client->rcpt_next_receive_idx++; i_assert(client->rcpt_next_receive_idx == array_count(&client->recipients)); rcpt->failed = TRUE; rcpt_to_callback(FALSE, client->global_fail_string, context); } else if (client->input_state == LMTP_INPUT_STATE_RCPT_TO) lmtp_client_send_rcpts(client); }
static bool user_callback(const char *reply, void *context) { struct auth_request *request = context; enum userdb_result result; const char *username, *args; if (str_begins(reply, "FAIL\t")) { result = USERDB_RESULT_INTERNAL_FAILURE; args = reply + 5; } else if (str_begins(reply, "NOTFOUND\t")) { result = USERDB_RESULT_USER_UNKNOWN; args = reply + 9; } else if (str_begins(reply, "OK\t")) { result = USERDB_RESULT_OK; username = reply + 3; args = strchr(username, '\t'); if (args == NULL) args = ""; else username = t_strdup_until(username, args++); if (username[0] != '\0' && strcmp(request->user, username) != 0) request->user = p_strdup(request->pool, username); } else { result = USERDB_RESULT_INTERNAL_FAILURE; i_error("BUG: auth-worker sent invalid user reply"); args = ""; } if (*args != '\0') { auth_fields_import(request->userdb_reply, args, 0); if (auth_fields_exists(request->userdb_reply, "tempfail")) request->userdb_lookup_tempfailed = TRUE; } auth_request_userdb_callback(result, request); auth_request_unref(&request); return TRUE; }
static struct userdb_module * passwd_file_preinit(pool_t pool, const char *args) { struct passwd_file_userdb_module *module; const char *format = PASSWD_FILE_DEFAULT_USERNAME_FORMAT; const char *p; if (strncmp(args, "username_format=", 16) == 0) { args += 16; p = strchr(args, ' '); if (p == NULL) { format = p_strdup(pool, args); args = ""; } else { format = p_strdup_until(pool, args, p); args = p + 1; } } if (*args == '\0') i_fatal("userdb passwd-file: Missing args"); module = p_new(pool, struct passwd_file_userdb_module, 1); module->pwf = db_passwd_file_init(args, TRUE, global_auth_settings->debug); module->username_format = format; if (!module->pwf->vars) module->module.cache_key = PASSWD_FILE_CACHE_KEY; else { module->module.cache_key = auth_cache_parse_key(pool, t_strconcat(PASSWD_FILE_CACHE_KEY, module->pwf->path, NULL)); } return &module->module; }
static void ldap_bind_lookup_dn_callback(struct ldap_connection *conn, struct ldap_request *ldap_request, LDAPMessage *res) { struct passdb_ldap_request *passdb_ldap_request = (struct passdb_ldap_request *)ldap_request; struct auth_request *auth_request = ldap_request->auth_request; struct ldap_request_bind *brequest; char *dn; if (res != NULL && ldap_msgtype(res) == LDAP_RES_SEARCH_ENTRY) { if (passdb_ldap_request->entries++ > 0) { /* too many replies */ return; } /* first entry */ ldap_query_save_result(conn, auth_request, &passdb_ldap_request->request.search, res); /* save dn */ dn = ldap_get_dn(conn->ld, res); passdb_ldap_request->dn = p_strdup(auth_request->pool, dn); ldap_memfree(dn); } else if (res == NULL || passdb_ldap_request->entries != 1) { /* failure */ ldap_bind_lookup_dn_fail(auth_request, passdb_ldap_request, res); } else { /* convert search request to bind request */ brequest = &passdb_ldap_request->request.bind; memset(brequest, 0, sizeof(*brequest)); brequest->request.type = LDAP_REQUEST_TYPE_BIND; brequest->request.auth_request = auth_request; brequest->dn = passdb_ldap_request->dn; ldap_auth_bind(conn, brequest); } }
bool client_read_args(struct client_command_context *cmd, unsigned int count, unsigned int flags, const struct imap_arg **args_r) { string_t *str; int ret; i_assert(count <= INT_MAX); ret = imap_parser_read_args(cmd->parser, count, flags, args_r); if (ret >= (int)count) { /* all parameters read successfully */ i_assert(cmd->client->input_lock == NULL || cmd->client->input_lock == cmd); str = t_str_new(256); imap_write_args(str, *args_r); cmd->args = p_strdup(cmd->pool, str_c(str)); cmd->start_time = ioloop_timeval; cmd->start_ioloop_wait_usecs = io_loop_get_wait_usecs(current_ioloop); cmd->client->input_lock = NULL; return TRUE; } else if (ret == -2) { /* need more data */ if (cmd->client->input->closed) { /* disconnected */ cmd->state = CLIENT_COMMAND_STATE_DONE; } return FALSE; } else { /* error, or missing arguments */ client_send_command_error(cmd, ret < 0 ? NULL : "Missing arguments"); return FALSE; } }
static void ext_editheader_config_headers (struct sieve_instance *svinst, struct ext_editheader_config *ext_config, const char *setting, bool forbid_add, bool forbid_delete) { const char *setval; setval = sieve_setting_get(svinst, setting); if ( setval != NULL ) { const char **headers = t_strsplit_spaces(setval, " \t"); while ( *headers != NULL ) { struct ext_editheader_header *header; if ( !rfc2822_header_field_name_verify (*headers, strlen(*headers)) ) { sieve_sys_warning(svinst, "editheader: " "setting %s contains invalid header field name " "`%s' (ignored)", setting, *headers); continue; } header=ext_editheader_config_header_find(ext_config, *headers); if ( header == NULL ) { header = array_append_space(&ext_config->headers); header->name = p_strdup(ext_config->pool, *headers); } if (forbid_add) header->forbid_add = TRUE; if (forbid_delete) header->forbid_delete = TRUE; headers++; } } }
static int acllist_append(struct acl_backend_vfile *backend, struct ostream *output, const char *vname) { struct acl_object *aclobj; struct acl_object_list_iter *iter; struct acl_rights rights; struct acl_backend_vfile_acllist acllist; const char *name; int ret; name = mail_namespace_get_storage_name(backend->backend.list->ns, vname); acl_cache_flush(backend->backend.cache, name); aclobj = acl_object_init_from_name(&backend->backend, name); iter = acl_object_list_init(aclobj); while ((ret = acl_object_list_next(iter, &rights)) > 0) { if (acl_rights_has_nonowner_lookup_changes(&rights)) break; } acl_object_list_deinit(&iter); if (acl_backend_vfile_object_get_mtime(aclobj, &acllist.mtime) < 0) ret = -1; if (ret > 0) { acllist.name = p_strdup(backend->acllist_pool, name); array_append(&backend->acllist, &acllist, 1); T_BEGIN { const char *line; line = t_strdup_printf("%s %s\n", dec2str(acllist.mtime), name); o_stream_send_str(output, line); } T_END; }
static void cmd_copy_init(struct doveadm_mail_cmd_context *_ctx, const char *const args[]) { struct copy_cmd_context *ctx = (struct copy_cmd_context *)_ctx; const char *destname = args[0], *cmdname = ctx->move ? "move" : "copy"; if (destname == NULL || args[1] == NULL) doveadm_mail_help_name(cmdname); args++; if (args[0] != NULL && args[1] != NULL && strcasecmp(args[0], "user") == 0) { if ((_ctx->service_flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) i_fatal("Use -u parameter to specify destination user"); cmd_copy_alloc_source_user(ctx, args[1]); args += 2; } ctx->destname = p_strdup(ctx->ctx.pool, destname); _ctx->search_args = doveadm_mail_build_search_args(args); expunge_search_args_check(ctx->ctx.search_args, cmdname); }
int mail_search_build(struct mail_search_register *reg, struct mail_search_parser *parser, const char *charset, struct mail_search_args **args_r, const char **error_r) { struct mail_search_build_context ctx; struct mail_search_args *args; struct mail_search_arg *root; *args_r = NULL; *error_r = NULL; args = mail_search_build_init(); args->charset = p_strdup(args->pool, charset); memset(&ctx, 0, sizeof(ctx)); ctx.pool = args->pool; ctx.reg = reg; ctx.parser = parser; if (mail_search_build_list(&ctx, &root) < 0) { *error_r = ctx._error != NULL ? t_strdup(ctx._error) : t_strdup(mail_search_parser_get_error(parser)); pool_unref(&args->pool); return -1; } if (root->type == SEARCH_SUB && !root->not) { /* simple SUB root */ args->args = root->value.subargs; } else { args->args = root; } *args_r = args; return 0; }
static const char * get_body_human_name(pool_t pool, struct imap_fetch_body_data *body) { string_t *str; uoff_t partial_offset, partial_size; str = t_str_new(64); if (body->binary) str_append(str, "BINARY["); else str_append(str, "BODY["); str_append(str, body->section); str_append_c(str, ']'); partial_offset = imap_msgpart_get_partial_offset(body->msgpart); partial_size = imap_msgpart_get_partial_size(body->msgpart); if (partial_offset != 0 || partial_size != (uoff_t)-1) { str_printfa(str, "<%"PRIuUOFF_T, partial_offset); if (partial_size != (uoff_t)-1) str_printfa(str, ".%"PRIuUOFF_T, partial_size); str_append_c(str, '>'); } return p_strdup(pool, str_c(str)); }
void auth_fields_add(struct auth_fields *fields, const char *key, const char *value, enum auth_field_flags flags) { struct auth_field *field; unsigned int idx; i_assert(*key != '\0'); i_assert(strchr(key, '\t') == NULL && strchr(key, '\n') == NULL); if (!auth_fields_find_idx(fields, key, &idx)) { if (!array_is_created(&fields->fields)) p_array_init(&fields->fields, fields->pool, 16); field = array_append_space(&fields->fields); field->key = p_strdup(fields->pool, key); } else { auth_fields_snapshot_preserve(fields); field = array_idx_modifiable(&fields->fields, idx); } field->value = p_strdup_empty(fields->pool, value); field->flags = flags | AUTH_FIELD_FLAG_CHANGED; }
void lmtp_client_set_data_header(struct lmtp_client *client, const char *str) { client->data_header = p_strdup(client->pool, str); }
struct client * client_create(int fd, bool ssl, pool_t pool, const struct master_service_connection *conn, const struct login_settings *set, const struct master_service_ssl_settings *ssl_set, void **other_sets) { struct client *client; i_assert(fd != -1); client = login_binary->client_vfuncs->alloc(pool); client->v = *login_binary->client_vfuncs; if (client->v.auth_send_challenge == NULL) client->v.auth_send_challenge = client_auth_send_challenge; if (client->v.auth_parse_response == NULL) client->v.auth_parse_response = client_auth_parse_response; client->created = ioloop_time; client->refcount = 1; client->pool = pool; client->set = set; client->ssl_set = ssl_set; p_array_init(&client->module_contexts, client->pool, 5); client->fd = fd; client->tls = ssl; client->local_ip = conn->local_ip; client->local_port = conn->local_port; client->ip = conn->remote_ip; client->remote_port = conn->remote_port; client->real_local_ip = conn->real_local_ip; client->real_local_port = conn->real_local_port; client->real_remote_ip = conn->real_remote_ip; client->real_remote_port = conn->real_remote_port; client->listener_name = p_strdup(client->pool, conn->name); client->trusted = client_is_trusted(client); client->secured = ssl || client->trusted || net_ip_compare(&conn->real_remote_ip, &conn->real_local_ip); client->proxy_ttl = LOGIN_PROXY_TTL; if (last_client == NULL) last_client = client; DLLIST_PREPEND(&clients, client); clients_count++; client->to_disconnect = timeout_add(CLIENT_LOGIN_TIMEOUT_MSECS, client_idle_disconnect_timeout, client); client_open_streams(client); hook_client_allocated(client); client->v.create(client, other_sets); if (auth_client_is_connected(auth_client)) client_notify_auth_ready(client); else client_set_auth_waiting(client); login_refresh_proctitle(); return client; }
static bool test_parse_header_line(struct test_parser *parser, struct test *test, const char *line, const char **error_r) { struct test_connection *test_conn; const char *key, *value; unsigned int idx; value = strchr(line, ':'); if (value == NULL) { *error_r = "Missing ':'"; return FALSE; } for (key = value; key[-1] == ' '; key--) ; key = t_str_lcase(t_strdup_until(line, key)); for (value++; *value == ' '; value++) ; if (strcmp(key, "capabilities") == 0) { test->required_capabilities = (const char *const *) p_strsplit_spaces(parser->pool, value, " "); return TRUE; } if (strcmp(key, "connections") == 0) { test->connection_count = strcmp(value, "n") == 0 ? 2 : strtoul(value, NULL, 10); return TRUE; } if (strncmp(key, "user ", 5) == 0 && str_to_uint(key+5, &idx) == 0 && idx != 0) { /* FIXME: kludgy kludgy */ if (strcmp(value, "$user2") == 0 || strcmp(value, "${user2}") == 0) { test->require_user2 = TRUE; value = conf.username2_template; } test_conn = array_idx_modifiable(&test->connections, idx-1); test_conn->username = p_strdup(parser->pool, value); return TRUE; } if (strcmp(key, "messages") == 0) { test->message_count = strcmp(value, "all") == 0 ? UINT_MAX : strtoul(value, NULL, 10); return TRUE; } if (strcmp(key, "state") == 0) { if (strcasecmp(value, "nonauth") == 0) test->startup_state = TEST_STARTUP_STATE_NONAUTH; else if (strcasecmp(value, "auth") == 0) test->startup_state = TEST_STARTUP_STATE_DELETED; else if (strcasecmp(value, "created") == 0) test->startup_state = TEST_STARTUP_STATE_CREATED; else if (strcasecmp(value, "appended") == 0) test->startup_state = TEST_STARTUP_STATE_APPENDED; else if (strcasecmp(value, "selected") == 0) test->startup_state = TEST_STARTUP_STATE_SELECTED; else { *error_r = "Unknown state value"; return FALSE; } return TRUE; } *error_r = "Unknown setting"; return FALSE; }
storage->storage = maildir_storage; storage->storage.pool = pool; return &storage->storage; } static int maildir_storage_create(struct mail_storage *_storage, struct mail_namespace *ns, const char **error_r ATTR_UNUSED) { struct maildir_storage *storage = (struct maildir_storage *)_storage; struct mailbox_list *list = ns->list; const char *dir; storage->set = mail_storage_get_driver_settings(_storage); storage->temp_prefix = p_strdup(_storage->pool, mailbox_list_get_temp_prefix(list)); if (list->set.control_dir == NULL && list->set.inbox_path == NULL && (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) { /* put the temp files into tmp/ directory preferrably */ storage->temp_prefix = p_strconcat(_storage->pool, "tmp/", storage->temp_prefix, NULL); dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_DIR); } else { /* control dir should also be writable */ dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_CONTROL); } _storage->temp_path_prefix = p_strconcat(_storage->pool, dir, "/", storage->temp_prefix, NULL); return 0; }
int index_mail_get_special(struct mail *_mail, enum mail_fetch_field field, const char **value_r) { struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; string_t *str; switch (field) { case MAIL_FETCH_IMAP_BODY: { unsigned int body_cache_field = cache_fields[MAIL_CACHE_IMAP_BODY].idx; unsigned int bodystructure_cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (data->body != NULL) { *value_r = data->body; return 0; } /* 1) use plain-7bit-ascii flag if it exists 2) get BODY if it exists 3) get it using BODYSTRUCTURE if it exists 4) parse body structure, and save BODY/BODYSTRUCTURE depending on what we want cached */ str = str_new(mail->data_pool, 128); if ((mail->data.cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 && get_cached_parts(mail)) { index_mail_get_plain_bodystructure(mail, str, FALSE); data->body = str_c(str); } else if (index_mail_cache_lookup_field(mail, str, body_cache_field) > 0) data->body = str_c(str); else if (index_mail_cache_lookup_field(mail, str, bodystructure_cache_field) > 0) { data->bodystructure = p_strdup(mail->data_pool, str_c(str)); str_truncate(str, 0); if (imap_body_parse_from_bodystructure( data->bodystructure, str)) data->body = str_c(str); else { /* broken, continue.. */ mail_set_cache_corrupted(_mail, MAIL_FETCH_IMAP_BODYSTRUCTURE); } } if (data->body == NULL) { str_free(&str); if (index_mail_parse_bodystructure(mail, MAIL_CACHE_IMAP_BODY) < 0) return -1; } i_assert(data->body != NULL); *value_r = data->body; return 0; } case MAIL_FETCH_IMAP_BODYSTRUCTURE: { unsigned int bodystructure_cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (data->bodystructure != NULL) { *value_r = data->bodystructure; return 0; } str = str_new(mail->data_pool, 128); if ((mail->data.cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 && get_cached_parts(mail)) { index_mail_get_plain_bodystructure(mail, str, TRUE); data->bodystructure = str_c(str); } else if (index_mail_cache_lookup_field(mail, str, bodystructure_cache_field) > 0) { data->bodystructure = str_c(str); } else { str_free(&str); if (index_mail_parse_bodystructure(mail, MAIL_CACHE_IMAP_BODYSTRUCTURE) < 0) return -1; } i_assert(data->bodystructure != NULL); *value_r = data->bodystructure; return 0; } case MAIL_FETCH_IMAP_ENVELOPE: if (data->envelope == NULL) { if (index_mail_headers_get_envelope(mail) < 0) return -1; } *value_r = data->envelope; return 0; case MAIL_FETCH_FROM_ENVELOPE: case MAIL_FETCH_UIDL_FILE_NAME: case MAIL_FETCH_UIDL_BACKEND: case MAIL_FETCH_SEARCH_SCORE: case MAIL_FETCH_GUID: case MAIL_FETCH_HEADER_MD5: *value_r = ""; return 0; case MAIL_FETCH_MAILBOX_NAME: *value_r = _mail->box->vname; return 0; default: i_unreached(); return -1; } }
} return TRUE; } static void args_directive(struct list_directives_context *ctx, ARRAY_TYPE(imap_arg_list) *args_arr, const char *directive) { const struct imap_arg *nextarg; struct imap_arg *arg; nextarg = array_idx(args_arr, 0); arg = array_insert_space(args_arr, 0); arg->parent = nextarg->parent; arg->type = IMAP_ARG_ATOM; arg->_data.str = p_strdup(ctx->parser->pool, directive); } static void test_add_default_directives(struct list_directives_context *ctx, ARRAY_TYPE(imap_arg_list) *args_arr) { if (ctx->parent == NULL) return; if (strcmp(ctx->reply_name, "list") == 0 || strcmp(ctx->reply_name, "lsub") == 0) { if (ctx->parent->parent == NULL && ctx->parent->parent_chain_idx == 0 && ctx->parent_chain_idx == 1) { /* list|lsub (flags) sep mailbox */ args_directive(ctx, args_arr, "$!unordered");
bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx) { struct imap_fetch_body_data *body; const struct imap_arg *list_args; unsigned int list_count; const char *str, *p, *error; i_assert(strncmp(ctx->name, "BINARY", 6) == 0); p = ctx->name + 6; body = p_new(ctx->pool, struct imap_fetch_body_data, 1); body->binary = TRUE; if (strncmp(p, ".SIZE", 5) == 0) { /* fetch decoded size of the section */ p += 5; body->binary_size = TRUE; } else if (strncmp(p, ".PEEK", 5) == 0) { p += 5; } else { ctx->fetch_ctx->flags_update_seen = TRUE; } if (*p != '[') { ctx->error = "Invalid BINARY[..] parameter: Missing '['"; return FALSE; } if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) { /* BINARY[HEADER.FIELDS.. (headers list)] */ if (!imap_arg_get_atom(&ctx->args[1], &str) || str[0] != ']') { ctx->error = "Invalid BINARY[..] parameter: Missing ']'"; return FALSE; } if (body_header_fields_parse(ctx, body, p+1, list_args, list_count) < 0) return FALSE; p = str+1; ctx->args += 2; } else { /* no headers list */ body->section = p+1; p = strchr(body->section, ']'); if (p == NULL) { ctx->error = "Invalid BINARY[..] parameter: Missing ']'"; return FALSE; } body->section = p_strdup_until(ctx->pool, body->section, p); p++; } if (imap_msgpart_parse(body->section, &body->msgpart) < 0) { ctx->error = "Invalid BINARY[..] section"; return FALSE; } imap_msgpart_set_decode_to_binary(body->msgpart); ctx->fetch_ctx->fetch_data |= imap_msgpart_get_fetch_data(body->msgpart); if (!body->binary_size) { if (body_parse_partial(body, p, &error) < 0) { ctx->error = p_strdup_printf(ctx->pool, "Invalid BINARY[..] parameter: %s", error); return FALSE; } } /* update the section name for the imap_fetch_add_handler() */ ctx->name = p_strdup(ctx->pool, get_body_name(body)); if (body->binary_size) { imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT, "0", fetch_binary_size, body); } else { imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT, "NIL", fetch_body_msgpart, body); } return TRUE; }
static int dsync_connect_tcp(struct dsync_cmd_context *ctx, const struct mail_storage_settings *mail_set, const char *target, bool ssl, const char **error_r) { struct doveadm_server *server; struct server_connection *conn; struct ioloop *ioloop; string_t *cmd; const char *error; server = p_new(ctx->ctx.pool, struct doveadm_server, 1); server->name = p_strdup(ctx->ctx.pool, target); if (ssl) { if (dsync_init_ssl_ctx(ctx, mail_set, &error) < 0) { *error_r = t_strdup_printf( "Couldn't initialize SSL context: %s", error); return -1; } server->ssl_ctx = ctx->ssl_ctx; } p_array_init(&server->connections, ctx->ctx.pool, 1); p_array_init(&server->queue, ctx->ctx.pool, 1); ioloop = io_loop_create(); if (server_connection_create(server, &conn) < 0) { *error_r = "Couldn't create server connection"; return -1; } /* <flags> <username> <command> [<args>] */ cmd = t_str_new(256); if (doveadm_debug) str_append_c(cmd, 'D'); str_append_c(cmd, '\t'); str_append_tabescaped(cmd, ctx->ctx.cur_username); str_append(cmd, "\tdsync-server\t-u"); str_append_tabescaped(cmd, ctx->ctx.cur_username); if (ctx->replicator_notify) str_append(cmd, "\t-U"); str_append_c(cmd, '\n'); ctx->tcp_conn = conn; server_connection_cmd(conn, str_c(cmd), dsync_connected_callback, ctx); io_loop_run(ioloop); ctx->tcp_conn = NULL; if (array_count(&server->connections) > 0) server_connection_destroy(&conn); io_loop_destroy(&ioloop); if (ctx->error != NULL) { *error_r = ctx->error; ctx->error = NULL; return -1; } ctx->run_type = DSYNC_RUN_TYPE_STREAM; return 0; }
char *auth_cache_parse_key(pool_t pool, const char *query) { string_t *str; bool key_seen[AUTH_REQUEST_VAR_TAB_COUNT]; const char *extra_vars; unsigned int i, idx, size, tab_idx; memset(key_seen, 0, sizeof(key_seen)); str = t_str_new(32); for (; *query != '\0'; ) { if (*query != '%') { query++; continue; } var_get_key_range(++query, &idx, &size); if (size == 0) { /* broken %variable ending too early */ break; } query += idx; if (!auth_request_var_expand_tab_find(query, size, &tab_idx)) { /* just add the key. it would be nice to prevent duplicates here as well, but that's just too much trouble and probably very rare. */ auth_cache_key_add_var(str, query, size); } else { i_assert(tab_idx < N_ELEMENTS(key_seen)); key_seen[tab_idx] = TRUE; } query += size; } if (key_seen[AUTH_REQUEST_VAR_TAB_USERNAME_IDX] && key_seen[AUTH_REQUEST_VAR_TAB_DOMAIN_IDX]) { /* %n and %d both used -> replace with %u */ key_seen[AUTH_REQUEST_VAR_TAB_USER_IDX] = TRUE; key_seen[AUTH_REQUEST_VAR_TAB_USERNAME_IDX] = FALSE; key_seen[AUTH_REQUEST_VAR_TAB_DOMAIN_IDX] = FALSE; } /* we rely on these being at the beginning */ i_assert(AUTH_REQUEST_VAR_TAB_USER_IDX == 0); i_assert(AUTH_REQUEST_VAR_TAB_USERNAME_IDX == 1); i_assert(AUTH_REQUEST_VAR_TAB_DOMAIN_IDX == 2); extra_vars = t_strdup(str_c(str)); str_truncate(str, 0); for (i = 0; i < N_ELEMENTS(key_seen); i++) { if (key_seen[i]) auth_cache_key_add_tab_idx(str, i); } if (*extra_vars != '\0') { if (str_len(str) > 0) str_append_c(str, '\t'); str_append(str, extra_vars); } return p_strdup(pool, str_c(str)); }
static int shared_storage_create(struct mail_storage *_storage, struct mail_namespace *ns, const char **error_r) { struct shared_storage *storage = (struct shared_storage *)_storage; struct mail_storage *storage_class; const char *driver, *p; char *wildcardp, key; bool have_username; /* location must begin with the actual mailbox driver */ p = strchr(ns->set->location, ':'); if (p == NULL) { *error_r = "Shared mailbox location not prefixed with driver"; return -1; } driver = t_strdup_until(ns->set->location, p); storage->location = p_strdup(_storage->pool, ns->set->location); storage->unexpanded_location = p_strdup(_storage->pool, ns->unexpanded_set->location); storage->storage_class_name = p_strdup(_storage->pool, driver); storage_class = mail_user_get_storage_class(_storage->user, driver); if (storage_class != NULL) _storage->class_flags = storage_class->class_flags; else if (strcmp(driver, "auto") != 0) { *error_r = t_strconcat("Unknown shared storage driver: ", driver, NULL); return -1; } wildcardp = strchr(ns->prefix, '%'); if (wildcardp == NULL) { *error_r = "Shared namespace prefix doesn't contain %"; return -1; } storage->ns_prefix_pattern = p_strdup(_storage->pool, wildcardp); have_username = FALSE; for (p = storage->ns_prefix_pattern; *p != '\0'; p++) { if (*p != '%') continue; key = p[1]; if (key == 'u' || key == 'n') have_username = TRUE; else if (key != '%' && key != 'd') break; } if (*p != '\0') { *error_r = "Shared namespace prefix contains unknown variables"; return -1; } if (!have_username) { *error_r = "Shared namespace prefix doesn't contain %u or %n"; return -1; } if (p[-1] != mail_namespace_get_sep(ns) && (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_LIST_CHILDREN)) != 0) { *error_r = "Shared namespace prefix doesn't end with hierarchy separator"; return -1; } /* truncate prefix after the above checks are done, so they can log the full prefix in error conditions */ *wildcardp = '\0'; ns->prefix_len = strlen(ns->prefix); return 0; }
static int mail_storage_service_lookup_real(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, bool update_log_prefix, struct mail_storage_service_user **user_r, const char **error_r) { enum mail_storage_service_flags flags; struct mail_storage_service_user *user; const char *username = input->username; const struct setting_parser_info *user_info; const struct mail_user_settings *user_set; const char *const *userdb_fields, *error; struct auth_user_reply reply; const struct setting_parser_context *set_parser; void **sets; pool_t user_pool, temp_pool; int ret = 1; user_pool = pool_alloconly_create(MEMPOOL_GROWING"mail storage service user", 1024*6); flags = mail_storage_service_input_get_flags(ctx, input); if ((flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 && geteuid() != 0) { /* we dropped privileges only temporarily. switch back to root before reading settings, so we'll definitely have enough permissions to connect to the config socket. */ mail_storage_service_seteuid_root(); } if (mail_storage_service_read_settings(ctx, input, user_pool, &user_info, &set_parser, &error) < 0) { if (ctx->config_permission_denied) { /* just restart and maybe next time we will open the config socket before dropping privileges */ i_fatal("%s", error); } i_error("%s", error); pool_unref(&user_pool); *error_r = MAIL_ERRSTR_CRITICAL_MSG; return -1; } if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0 && !ctx->log_initialized) { /* initialize logging again, in case we only read the settings for the first above */ ctx->log_initialized = TRUE; master_service_init_log(ctx->service, t_strconcat(ctx->service->name, ": ", NULL)); update_log_prefix = TRUE; } sets = master_service_settings_parser_get_others(master_service, set_parser); user_set = sets[0]; if (update_log_prefix) mail_storage_service_set_log_prefix(ctx, user_set, NULL, input, NULL); if (ctx->conn == NULL) mail_storage_service_first_init(ctx, user_info, user_set); /* load global plugins */ if (mail_storage_service_load_modules(ctx, user_info, user_set, &error) < 0) { i_error("%s", error); pool_unref(&user_pool); *error_r = MAIL_ERRSTR_CRITICAL_MSG; return -1; } if (ctx->userdb_next_pool == NULL) temp_pool = pool_alloconly_create("userdb lookup", 2048); else { temp_pool = ctx->userdb_next_pool; ctx->userdb_next_pool = NULL; pool_ref(temp_pool); } if ((flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) { ret = service_auth_userdb_lookup(ctx, input, temp_pool, &username, &userdb_fields, error_r); if (ret <= 0) { pool_unref(&temp_pool); pool_unref(&user_pool); return ret; } if (ctx->userdb_next_fieldsp != NULL) *ctx->userdb_next_fieldsp = userdb_fields; } else { userdb_fields = input->userdb_fields; } user = p_new(user_pool, struct mail_storage_service_user, 1); user->service_ctx = ctx; user->pool = user_pool; user->input = *input; user->input.userdb_fields = userdb_fields == NULL ? NULL : p_strarray_dup(user_pool, userdb_fields); user->input.username = p_strdup(user_pool, username); user->input.session_id = p_strdup(user_pool, input->session_id); if (user->input.session_id == NULL) { user->input.session_id = mail_storage_service_generate_session_id(user_pool, input->session_id_prefix); } user->user_info = user_info; user->flags = flags; user->set_parser = settings_parser_dup(set_parser, user_pool); sets = master_service_settings_parser_get_others(master_service, user->set_parser); user->user_set = sets[0]; user->gid_source = "mail_gid setting"; user->uid_source = "mail_uid setting"; if ((flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0) (void)settings_parse_line(user->set_parser, "mail_debug=yes"); if ((flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) { const char *home = getenv("HOME"); if (home != NULL) set_keyval(ctx, user, "mail_home", home); } if (userdb_fields != NULL) { auth_user_fields_parse(userdb_fields, temp_pool, &reply); array_sort(&reply.extra_fields, extra_field_key_cmp_p); if (user_reply_handle(ctx, user, &reply, &error) < 0) { i_error("Invalid settings in userdb: %s", error); *error_r = ERRSTR_INVALID_USER_SETTINGS; ret = -2; } } if (ret > 0 && !settings_parser_check(user->set_parser, user_pool, &error)) { i_error("Invalid settings (probably caused by userdb): %s", error); *error_r = ERRSTR_INVALID_USER_SETTINGS; ret = -2; } pool_unref(&temp_pool); /* load per-user plugins */ if (ret > 0) { if (mail_storage_service_load_modules(ctx, user_info, user->user_set, &error) < 0) { i_error("%s", error); *error_r = MAIL_ERRSTR_CRITICAL_MSG; ret = -2; } } *user_r = user; return ret; }
static int virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line, const char **error_r) { struct mail_user *user = ctx->mbox->storage->storage.user; struct virtual_backend_box *bbox; const char *p; bool no_wildcards = FALSE; if (*line == ' ' || *line == '\t') { /* continues the previous search rule */ if (ctx->rule_idx == array_count(&ctx->mbox->backend_boxes)) { *error_r = "Search rule without a mailbox"; return -1; } while (*line == ' ' || *line == '\t') line++; str_append_c(ctx->rule, ' '); str_append(ctx->rule, line); return 0; } /* if there is no rule yet, it means we want the previous mailboxes to use the rule that comes later */ if (str_len(ctx->rule) > 0) { if (virtual_config_add_rule(ctx, error_r) < 0) return -1; } if (!uni_utf8_str_is_valid(line)) { *error_r = t_strdup_printf("Mailbox name not UTF-8: %s", line); return -1; } /* new mailbox. the search args are added to it later. */ bbox = p_new(ctx->pool, struct virtual_backend_box, 1); bbox->virtual_mbox = ctx->mbox; if (strcasecmp(line, "INBOX") == 0) line = "INBOX"; bbox->name = p_strdup(ctx->pool, line); switch (bbox->name[0]) { case '+': bbox->name++; bbox->clear_recent = TRUE; break; case '-': bbox->name++; bbox->negative_match = TRUE; break; case '!': /* save messages here */ if (ctx->mbox->save_bbox != NULL) { *error_r = "Multiple save mailboxes defined"; return -1; } bbox->name++; ctx->mbox->save_bbox = bbox; no_wildcards = TRUE; break; } if (bbox->name[0] == '/') { /* [+-!]/metadata entry:value */ if ((p = strchr(bbox->name, ':')) == NULL) { *error_r = "':' separator missing between metadata entry name and value"; return -1; } bbox->metadata_entry = p_strdup_until(ctx->pool, bbox->name, p++); bbox->metadata_value = p; if (!imap_metadata_verify_entry_name(bbox->metadata_entry, error_r)) return -1; no_wildcards = TRUE; } if (!no_wildcards && (strchr(bbox->name, '*') != NULL || strchr(bbox->name, '%') != NULL)) { bbox->glob = imap_match_init(ctx->pool, bbox->name, TRUE, ctx->sep); ctx->have_wildcards = TRUE; } if (bbox->metadata_entry == NULL) { /* now that the prefix characters have been processed, find the namespace */ bbox->ns = strcasecmp(bbox->name, "INBOX") == 0 ? mail_namespace_find_inbox(user->namespaces) : mail_namespace_find(user->namespaces, bbox->name); if (bbox->ns == NULL) { *error_r = t_strdup_printf("Namespace not found for %s", bbox->name); return -1; } if (strcmp(bbox->name, ctx->mbox->box.vname) == 0) { *error_r = "Virtual mailbox can't point to itself"; return -1; } ctx->have_mailbox_defines = TRUE; } array_append(&ctx->mbox->backend_boxes, &bbox, 1); return 0; }
static int maildir_keywords_sync(struct maildir_keywords *mk) { struct istream *input; struct stat st; char *line, *p, *new_name; const char **strp; unsigned int idx; int fd; /* Remember that we rely on uidlist file locking in here. That's why we rely on stat()'s timestamp and don't bother handling ESTALE errors. */ if (mk->storage->set->mail_nfs_storage) { /* file is updated only by replacing it, no need to flush attribute cache */ nfs_flush_file_handle_cache(mk->path); } if (nfs_safe_stat(mk->path, &st) < 0) { if (errno == ENOENT) { maildir_keywords_clear(mk); mk->synced = TRUE; return 0; } mail_storage_set_critical(mk->storage, "stat(%s) failed: %m", mk->path); return -1; } if (st.st_mtime == mk->synced_mtime) { /* hasn't changed */ mk->synced = TRUE; return 0; } mk->synced_mtime = st.st_mtime; fd = open(mk->path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) { maildir_keywords_clear(mk); mk->synced = TRUE; return 0; } mail_storage_set_critical(mk->storage, "open(%s) failed: %m", mk->path); return -1; } maildir_keywords_clear(mk); input = i_stream_create_fd(fd, 1024, FALSE); while ((line = i_stream_read_next_line(input)) != NULL) { p = strchr(line, ' '); if (p == NULL) { /* note that when converting .customflags file this case happens in the first line. */ continue; } *p++ = '\0'; if (str_to_uint(line, &idx) < 0 || idx >= MAILDIR_MAX_KEYWORDS || *p == '\0') { /* shouldn't happen */ continue; } /* save it */ new_name = p_strdup(mk->pool, p); hash_table_insert(mk->hash, new_name, POINTER_CAST(idx + 1)); strp = array_idx_modifiable(&mk->list, idx); *strp = new_name; } i_stream_destroy(&input); if (close(fd) < 0) { mail_storage_set_critical(mk->storage, "close(%s) failed: %m", mk->path); return -1; } mk->synced = TRUE; return 0; }
static int user_reply_handle(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, const struct auth_user_reply *reply, const char **error_r) { const char *home = reply->home; const char *chroot = reply->chroot; const char *const *str, *line, *p; unsigned int i, count; int ret = 0; if (reply->uid != (uid_t)-1) { if (reply->uid == 0) { *error_r = "userdb returned 0 as uid"; return -1; } user->uid_source = "userdb lookup"; set_keyval(ctx, user, "mail_uid", dec2str(reply->uid)); } if (reply->gid != (uid_t)-1) { user->gid_source = "userdb lookup"; set_keyval(ctx, user, "mail_gid", dec2str(reply->gid)); } if (home != NULL && chroot == NULL && *user->user_set->valid_chroot_dirs != '\0' && (p = strstr(home, "/./")) != NULL) { /* wu-ftpd like <chroot>/./<home> - check only if there's even a possibility of using them (non-empty valid_chroot_dirs) */ chroot = t_strdup_until(home, p); home = p + 2; } if (home != NULL) set_keyval(ctx, user, "mail_home", home); if (chroot != NULL) { if (!validate_chroot(user->user_set, chroot)) { *error_r = t_strdup_printf( "userdb returned invalid chroot directory: %s " "(see valid_chroot_dirs setting)", chroot); return -1; } set_keyval(ctx, user, "mail_chroot", chroot); } user->anonymous = reply->anonymous; str = array_get(&reply->extra_fields, &count); for (i = 0; i < count; i++) { line = str[i]; if (strncmp(line, "system_groups_user="******"nice=", 5) == 0) { #ifdef HAVE_SETPRIORITY int n; if (str_to_int(line + 5, &n) < 0) { i_error("userdb returned invalid nice value %s", line + 5); } else if (n != 0) { if (setpriority(PRIO_PROCESS, 0, n) < 0) i_error("setpriority(%d) failed: %m", n); } #endif } else if (strncmp(line, "auth_token=", 11) == 0) { user->auth_token = p_strdup(user->pool, line+11); } else if (strncmp(line, "auth_user="******"admin=", 6) == 0) { user->admin = line[6] == 'y' || line[6] == 'Y' || line[6] == '1'; } else T_BEGIN { ret = set_line(ctx, user, line); } T_END; if (ret < 0) break; } if (ret < 0) { *error_r = t_strdup_printf("Invalid userdb input '%s': %s", str[i], settings_parser_get_error(user->set_parser)); } return ret; }
if (line == NULL) { i_error("Director disconnected unexpectedly"); doveadm_exit_code = EX_TEMPFAIL; } director_disconnect(ctx); } static void user_list_add(const char *username, pool_t pool, HASH_TABLE_TYPE(user_list) users) { struct user_list *user, *old_user; unsigned int user_hash; user = p_new(pool, struct user_list, 1); user->name = p_strdup(pool, username); user_hash = mail_user_hash(username, doveadm_settings->director_username_hash); old_user = hash_table_lookup(users, POINTER_CAST(user_hash)); if (old_user != NULL) user->next = old_user; hash_table_insert(users, POINTER_CAST(user_hash), user); } static void ATTR_NULL(1) userdb_get_user_list(const char *auth_socket_path, pool_t pool, HASH_TABLE_TYPE(user_list) users) { struct auth_master_user_list_ctx *ctx; struct auth_master_connection *conn; const char *username;
struct http_client *http_client_init(const struct http_client_settings *set) { struct http_client *client; pool_t pool; pool = pool_alloconly_create("http client", 1024); client = p_new(pool, struct http_client, 1); client->pool = pool; client->set.dns_client = set->dns_client; client->set.dns_client_socket_path = p_strdup_empty(pool, set->dns_client_socket_path); client->set.user_agent = p_strdup_empty(pool, set->user_agent); client->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir); client->set.ssl_ca_dir = p_strdup(pool, set->ssl_ca_dir); client->set.ssl_ca_file = p_strdup(pool, set->ssl_ca_file); client->set.ssl_ca = p_strdup(pool, set->ssl_ca); client->set.ssl_crypto_device = p_strdup(pool, set->ssl_crypto_device); client->set.ssl_allow_invalid_cert = set->ssl_allow_invalid_cert; client->set.ssl_cert = p_strdup(pool, set->ssl_cert); client->set.ssl_key = p_strdup(pool, set->ssl_key); client->set.ssl_key_password = p_strdup(pool, set->ssl_key_password); if (set->proxy_socket_path != NULL && *set->proxy_socket_path != '\0') { client->set.proxy_socket_path = p_strdup(pool, set->proxy_socket_path); } else if (set->proxy_url != NULL) { client->set.proxy_url = http_url_clone(pool, set->proxy_url); } client->set.proxy_username = p_strdup_empty(pool, set->proxy_username); client->set.proxy_password = p_strdup_empty(pool, set->proxy_password); client->set.max_idle_time_msecs = set->max_idle_time_msecs; client->set.max_parallel_connections = (set->max_parallel_connections > 0 ? set->max_parallel_connections : 1); client->set.max_pipelined_requests = (set->max_pipelined_requests > 0 ? set->max_pipelined_requests : 1); client->set.max_attempts = set->max_attempts; client->set.max_connect_attempts = set->max_connect_attempts; client->set.connect_backoff_time_msecs = set->connect_backoff_time_msecs == 0 ? HTTP_CLIENT_DEFAULT_BACKOFF_TIME_MSECS : set->connect_backoff_time_msecs; client->set.connect_backoff_max_time_msecs = set->connect_backoff_max_time_msecs == 0 ? HTTP_CLIENT_DEFAULT_BACKOFF_MAX_TIME_MSECS : set->connect_backoff_max_time_msecs; client->set.no_auto_redirect = set->no_auto_redirect; client->set.no_ssl_tunnel = set->no_ssl_tunnel; client->set.max_redirects = set->max_redirects; client->set.response_hdr_limits = set->response_hdr_limits; client->set.request_absolute_timeout_msecs = set->request_absolute_timeout_msecs; client->set.request_timeout_msecs = set->request_timeout_msecs; client->set.connect_timeout_msecs = set->connect_timeout_msecs; client->set.soft_connect_timeout_msecs = set->soft_connect_timeout_msecs; client->set.max_auto_retry_delay = set->max_auto_retry_delay; client->set.debug = set->debug; i_array_init(&client->delayed_failing_requests, 1); client->conn_list = http_client_connection_list_init(); hash_table_create(&client->hosts, default_pool, 0, str_hash, strcmp); hash_table_create(&client->peers, default_pool, 0, http_client_peer_addr_hash, http_client_peer_addr_cmp); return client; }
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 maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field, const char **value_r) { struct index_mail *mail = (struct index_mail *)_mail; struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box; const char *path, *fname = NULL, *end, *guid, *uidl, *order; struct stat st; switch (field) { case MAIL_FETCH_GUID: /* use GUID from uidlist if it exists */ i_assert(!_mail->saving); if (mail->data.guid != NULL) { *value_r = mail->data.guid; return 0; } /* first make sure that we have a refreshed uidlist */ if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0) return -1; guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_GUID); if (guid != NULL) { if (*guid != '\0') { *value_r = mail->data.guid = p_strdup(mail->mail.data_pool, guid); return 0; } mail_storage_set_critical(_mail->box->storage, "Maildir %s: Corrupted dovecot-uidlist: " "UID %u had empty GUID, clearing it", mailbox_get_path(_mail->box), _mail->uid); maildir_uidlist_unset_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_GUID); } /* default to base filename: */ if (maildir_mail_get_special(_mail, MAIL_FETCH_STORAGE_ID, value_r) < 0) return -1; mail->data.guid = mail->data.filename; return 0; case MAIL_FETCH_STORAGE_ID: if (mail->data.filename != NULL) { *value_r = mail->data.filename; return 0; } if (fname != NULL) { /* we came here from MAIL_FETCH_GUID, avoid a second lookup */ } else if (!_mail->saving) { if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0) return -1; } else { path = maildir_save_file_get_path(_mail->transaction, _mail->seq); fname = strrchr(path, '/'); fname = fname != NULL ? fname + 1 : path; } end = strchr(fname, MAILDIR_INFO_SEP); mail->data.filename = end == NULL ? p_strdup(mail->mail.data_pool, fname) : p_strdup_until(mail->mail.data_pool, fname, end); *value_r = mail->data.filename; return 0; case MAIL_FETCH_UIDL_BACKEND: uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_POP3_UIDL); if (uidl == NULL) { /* use the default */ *value_r = ""; } else if (*uidl == '\0') { /* special optimization case: use the base file name */ return maildir_mail_get_special(_mail, MAIL_FETCH_STORAGE_ID, value_r); } else { *value_r = p_strdup(mail->mail.data_pool, uidl); } return 0; case MAIL_FETCH_POP3_ORDER: order = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_POP3_ORDER); if (order == NULL) { *value_r = ""; } else { *value_r = p_strdup(mail->mail.data_pool, order); } return 0; case MAIL_FETCH_REFCOUNT: if (maildir_mail_stat(_mail, &st) < 0) return -1; *value_r = p_strdup_printf(mail->mail.data_pool, "%lu", (unsigned long)st.st_nlink); return 0; default: return index_mail_get_special(_mail, field, value_r); } }
int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, pool_t pool, const struct setting_parser_info **user_info_r, const struct setting_parser_context **parser_r, const char **error_r) { struct master_service_settings_input set_input; const struct setting_parser_info *const *roots; struct master_service_settings_output set_output; const struct dynamic_settings_parser *dyn_parsers; enum mail_storage_service_flags flags; unsigned int i; ctx->config_permission_denied = FALSE; flags = input == NULL ? ctx->flags : mail_storage_service_input_get_flags(ctx, input); memset(&set_input, 0, sizeof(set_input)); set_input.roots = ctx->set_roots; set_input.preserve_user = TRUE; /* settings reader may exec doveconf, which is going to clear environment, and if we're not doing a userdb lookup we want to use $HOME */ set_input.preserve_home = (flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0; set_input.use_sysexits = (flags & MAIL_STORAGE_SERVICE_FLAG_USE_SYSEXITS) != 0; if (input != NULL) { set_input.module = input->module; set_input.service = input->service; set_input.username = input->username; set_input.local_ip = input->local_ip; set_input.remote_ip = input->remote_ip; } if (input == NULL) { /* global settings read - don't create a cache for thi */ } else if (ctx->set_cache == NULL) { ctx->set_cache_module = p_strdup(ctx->pool, set_input.module); ctx->set_cache_service = p_strdup(ctx->pool, set_input.service); ctx->set_cache = master_service_settings_cache_init( ctx->service, set_input.module, set_input.service); } else { /* already looked up settings at least once. we really shouldn't be execing anymore. */ set_input.never_exec = TRUE; } dyn_parsers = mail_storage_get_dynamic_parsers(pool); if (null_strcmp(set_input.module, ctx->set_cache_module) == 0 && null_strcmp(set_input.service, ctx->set_cache_service) == 0 && ctx->set_cache != NULL) { if (master_service_settings_cache_read(ctx->set_cache, &set_input, dyn_parsers, parser_r, error_r) < 0) { *error_r = t_strdup_printf( "Error reading configuration: %s", *error_r); return -1; } } else { settings_parser_dyn_update(pool, &set_input.roots, dyn_parsers); if (master_service_settings_read(ctx->service, &set_input, &set_output, error_r) < 0) { *error_r = t_strdup_printf( "Error reading configuration: %s", *error_r); ctx->config_permission_denied = set_output.permission_denied; return -1; } *parser_r = ctx->service->set_parser; } roots = settings_parser_get_roots(*parser_r); for (i = 0; roots[i] != NULL; i++) { if (strcmp(roots[i]->module_name, mail_user_setting_parser_info.module_name) == 0) { *user_info_r = roots[i]; return 0; } } i_unreached(); return -1; }