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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #10
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;
}
Beispiel #12
0
void lmtp_client_set_data_header(struct lmtp_client *client, const char *str)
{
	client->data_header = p_strdup(client->pool, str);
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
    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;
}
Beispiel #16
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;
	}
}
Beispiel #17
0
	}
	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");
Beispiel #18
0
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;
}
Beispiel #19
0
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;
}
Beispiel #20
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));
}
Beispiel #21
0
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;
}
Beispiel #23
0
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;
}
Beispiel #24
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;
}
Beispiel #26
0
	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;
Beispiel #27
0
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;
}
Beispiel #29
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;
}