Beispiel #1
0
static int replication_notify_sync(struct mail_user *user)
{
	struct replication_user *ruser = REPLICATION_USER_CONTEXT(user);
	string_t *str;
	char buf[1024];
	int fd;
	ssize_t ret;

	fd = net_connect_unix(ruser->socket_path);
	if (fd == -1) {
		i_error("net_connect_unix(%s) failed: %m", ruser->socket_path);
		return -1;
	}
	net_set_nonblock(fd, FALSE);

	/* <username> \t "sync" */
	str = t_str_new(256);
	str_append_tabescaped(str, user->username);
	str_append(str, "\tsync\n");
	alarm(ruser->sync_secs);
	if (write_full(fd, str_data(str), str_len(str)) < 0) {
		i_error("write(%s) failed: %m", ruser->socket_path);
		ret = -1;
	} else {
		/* + | - */
		ret = read(fd, buf, sizeof(buf));
		if (ret < 0) {
			if (errno != EINTR) {
				i_error("read(%s) failed: %m",
					ruser->socket_path);
			} else {
				i_warning("replication(%s): Sync failure: "
					  "Timeout in %u secs",
					  user->username, ruser->sync_secs);
			}
		} else if (ret == 0) {
			i_error("read(%s) failed: EOF", ruser->socket_path);
			ret = -1;
		} else if (buf[0] == '+') {
			/* success */
			ret = 0;
		} else if (buf[0] == '-') {
			/* failure */
			if (buf[ret-1] == '\n') ret--;
			i_warning("replication(%s): Sync failure: %s",
				  user->username, t_strndup(buf+1, ret-1));
			ret = -1;
		} else {
			i_warning("replication(%s): "
				  "Remote sent invalid input: %s",
				  user->username, t_strndup(buf, ret));
		}
	}
	alarm(0);
	if (close(fd) < 0)
		i_error("close(%s) failed: %m", ruser->socket_path);
	return ret;
}
Beispiel #2
0
bool cmd_create(struct client_command_context *cmd)
{
	enum mailbox_name_status status;
	struct mail_namespace *ns;
	const char *mailbox, *storage_name;
	struct mailbox *box;
	bool directory;
	size_t len;

	/* <mailbox> */
	if (!client_read_string_args(cmd, 1, &mailbox))
		return FALSE;

	ns = client_find_namespace(cmd, mailbox, &storage_name, NULL);
	if (ns == NULL)
		return TRUE;

	len = strlen(mailbox);
	if (len == 0 || mailbox[len-1] != ns->sep)
		directory = FALSE;
	else if (*storage_name == '\0') {
		client_send_tagline(cmd, "NO ["IMAP_RESP_CODE_ALREADYEXISTS
				    "] Namespace already exists.");
		return TRUE;
	} else {
		/* name ends with hierarchy separator - client is just
		   informing us that it wants to create children under this
		   mailbox. */
                directory = TRUE;
		storage_name = t_strndup(storage_name, strlen(storage_name)-1);
		mailbox = t_strndup(mailbox, len-1);
	}

	ns = client_find_namespace(cmd, mailbox, &storage_name, &status);
	if (ns == NULL)
		return TRUE;
	switch (status) {
	case MAILBOX_NAME_VALID:
		break;
	case MAILBOX_NAME_EXISTS_DIR:
		if (!directory)
			break;
		/* fall through */
	case MAILBOX_NAME_EXISTS_MAILBOX:
	case MAILBOX_NAME_INVALID:
	case MAILBOX_NAME_NOINFERIORS:
		client_fail_mailbox_name_status(cmd, mailbox, NULL, status);
		return TRUE;
	}

	box = mailbox_alloc(ns->list, storage_name, 0);
	if (mailbox_create(box, NULL, directory) < 0)
		client_send_storage_error(cmd, mailbox_get_storage(box));
	else
		client_send_tagline(cmd, "OK Create completed.");
	mailbox_free(&box);
	return TRUE;
}
static int
quota_count_namespace(struct quota_root *root, struct mail_namespace *ns,
		      uint64_t *bytes, uint64_t *count)
{
	struct mailbox_list_iterate_context *ctx;
	const struct mailbox_info *info;
	int ret = 0;

	ctx = mailbox_list_iter_init(ns->list, "*",
				     MAILBOX_LIST_ITER_SKIP_ALIASES |
				     MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
	while ((info = mailbox_list_iter_next(ctx)) != NULL) {
		if ((info->flags & (MAILBOX_NONEXISTENT |
				    MAILBOX_NOSELECT)) == 0) {
			ret = quota_count_mailbox(root, ns, info->vname,
						  bytes, count);
			if (ret < 0)
				break;
		}
	}
	if (mailbox_list_iter_deinit(&ctx) < 0)
		ret = -1;
	if (ns->prefix_len > 0 && ret == 0 &&
	    (ns->prefix_len != 6 || strncasecmp(ns->prefix, "INBOX", 5) != 0)) {
		/* if the namespace prefix itself exists, count it also */
		const char *name = t_strndup(ns->prefix, ns->prefix_len-1);
		ret = quota_count_mailbox(root, ns, name, bytes, count);
	}
	return ret;
}
Beispiel #4
0
static void
mech_external_auth_continue(struct auth_request *request,
			    const unsigned char *data, size_t data_size)
{
	const char *authzid, *error;

	authzid = t_strndup(data, data_size);
	if (request->user == NULL) {
		auth_request_log_info(request, AUTH_SUBSYS_MECH,
				      "username not known");
		auth_request_fail(request);
		return;
	}

	/* this call is done simply to put the username through translation
	   settings */
	if (!auth_request_set_username(request, "", &error)) {
		auth_request_log_info(request, AUTH_SUBSYS_MECH,
				      "Invalid username");
		auth_request_fail(request);
		return;
	}

	if (*authzid != '\0' &&
	    !auth_request_set_login_username(request, authzid, &error)) {
		/* invalid login username */
		auth_request_log_info(request, AUTH_SUBSYS_MECH,
				      "login user: %s", error);
		auth_request_fail(request);
	} else {
                auth_request_verify_plain(request, "",
                                          plain_verify_callback);
	}
}
Beispiel #5
0
static bool
access_applications_have_access(struct imap_url *url,
				const char *const *access_applications)
{
	const char *const *application;

	if (access_applications == NULL)
		return FALSE;

	application = access_applications;
	for (; *application != NULL; application++) {
		const char *app = *application;
		bool have_userid = FALSE;
		size_t len = strlen(app);

		if (app[len-1] == '+') {
			have_userid = TRUE;
			app = t_strndup(app, len-1);
		}

		if (strcasecmp(url->uauth_access_application, app) == 0) {
			if (have_userid)
				return url->uauth_access_user != NULL;
			else
				return url->uauth_access_user == NULL;
		}
	}
	return FALSE;
}
Beispiel #6
0
static bool
dump_msg_hdr(struct istream *input, unsigned int hdr_size, uoff_t *msg_size_r)
{
	struct dbox_message_header hdr;
	const unsigned char *data;
	size_t size;
	uoff_t msg_size;

	if (i_stream_read_bytes(input, &data, &size, hdr_size) <= 0) {
		if (size == 0)
			return FALSE;
		i_fatal("Partial message header read at %"PRIuUOFF_T": "
			"%"PRIuSIZE_T" bytes", input->v_offset, size);
	}
	printf("offset %"PRIuUOFF_T":\n", input->v_offset);

	if (hdr_size < sizeof(hdr))
		i_fatal("file.hdr_size too small: %u", hdr_size);
	memcpy(&hdr, data, sizeof(hdr));

	if (memcmp(hdr.magic_pre, DBOX_MAGIC_PRE, sizeof(hdr.magic_pre)) != 0)
		i_fatal("dbox wrong pre-magic at %"PRIuUOFF_T, input->v_offset);

	msg_size = dump_size(input, "msg.size",
		t_strndup(hdr.message_size_hex, sizeof(hdr.message_size_hex)));

	i_stream_skip(input, hdr_size);
	*msg_size_r = msg_size;
	return TRUE;
}
Beispiel #7
0
static int
http_parse_auth_param(struct http_parser *parser,
	const char **param_r, const char **value_r)
{
	const unsigned char *first = parser->cur, *end_token;
	int ret;

	/* auth-param     = token BWS "=" BWS ( token / quoted-string ) */

	/* token */
	if ((ret=http_parser_skip_token(parser)) <= 0) {
		parser->cur = first;
		return ret;
	}
	end_token = parser->cur;

	/* BWS "=" BWS */
	http_parse_ows(parser);
	if (parser->cur >= parser->end || *parser->cur != '=') {
		parser->cur = first;
		return 0;
	}
	parser->cur++;
	http_parse_ows(parser);

	/* ( token / quoted-string ) */
	if ((ret=http_parse_token_or_qstring(parser, value_r)) <= 0) {
		parser->cur = first;
		return ret;
	}

	*param_r = t_strndup(first, end_token - first);
	return 1;
}
Beispiel #8
0
static void
drop_privileges(struct service *service)
{
	struct restrict_access_settings rset;
	bool disallow_root;
	unsigned int len;

	if (service->vsz_limit != 0)
		restrict_process_size(service->vsz_limit);

	restrict_access_init(&rset);
	rset.uid = service->uid;
	rset.gid = service->gid;
	rset.privileged_gid = service->privileged_gid;
	rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
		service->set->chroot;
	if (rset.chroot_dir != NULL) {
		/* drop trailing / if it exists */
		len = strlen(rset.chroot_dir);
		if (rset.chroot_dir[len-1] == '/')
			rset.chroot_dir = t_strndup(rset.chroot_dir, len-1);
	}
	rset.extra_groups = service->extra_gids;

	restrict_access_set_env(&rset);
	if (service->set->drop_priv_before_exec) {
		disallow_root = service->type == SERVICE_TYPE_LOGIN;
		restrict_access(&rset, NULL, disallow_root);
	}
}
static bool
fts_tokenizer_generic_simple_current_token(struct generic_fts_tokenizer *tok,
                                           const char **token_r)
{
	const unsigned char *data = tok->token->data;
	size_t len = tok->token->used;

	if (tok->untruncated_length <= tok->max_length) {
		/* Remove the trailing apostrophe - it was made
		   into U+0027 earlier. There can be only a single such
		   apostrophe, because otherwise the token would have already
		   been split. We also want to remove the trailing apostrophe
		   only if it's the the last character in the nontruncated
		   token - a truncated token may end with apostrophe. */
		if (len > 0 && data[len-1] == '\'') {
			len--;
			i_assert(len > 0 && data[len-1] != '\'');
		}
	} else {
		fts_tokenizer_delete_trailing_partial_char(data, &len);
	}
	i_assert(len <= tok->max_length);

	*token_r = len == 0 ? "" :
		t_strndup(tok->token->data, len);
	buffer_set_used_size(tok->token, 0);
	tok->untruncated_length = 0;
	tok->prev_letter = LETTER_TYPE_NONE;
	return len > 0;
}
Beispiel #10
0
bool password_generate_encoded(const char *plaintext, const struct password_generate_params *params,
			       const char *scheme, const char **password_r)
{
	const struct password_scheme *s;
	const unsigned char *raw_password;
	enum password_encoding encoding;
	string_t *str;
	size_t size;

	s = password_scheme_lookup(scheme, &encoding);
	if (s == NULL)
		return FALSE;

	s->password_generate(plaintext, params, &raw_password, &size);
	switch (encoding) {
	case PW_ENCODING_NONE:
		*password_r = t_strndup(raw_password, size);
		break;
	case PW_ENCODING_BASE64:
		str = t_str_new(MAX_BASE64_ENCODED_SIZE(size) + 1);
		base64_encode(raw_password, size, str);
		*password_r = str_c(str);
		break;
	case PW_ENCODING_HEX:
		*password_r = binary_to_hex(raw_password, size);
		break;
	}
	return TRUE;
}
Beispiel #11
0
int http_parse_token(struct http_parser *parser, const char **token_r)
{
	const unsigned char *first = parser->cur;
	int ret;

	if ((ret=http_parser_skip_token(parser)) <= 0)
		return ret;
	*token_r = t_strndup(first, parser->cur - first);
	return 1;
}
static const char *asn1_string_to_c(ASN1_STRING *asn_str)
{
	const char *cstr;
	unsigned int len;

	len = ASN1_STRING_length(asn_str);
	cstr = t_strndup(ASN1_STRING_data(asn_str), len);
	if (strlen(cstr) != len) {
		/* NULs in the name - could be some MITM attack.
		   never allow. */
		return "";
	}
	return cstr;
}
Beispiel #13
0
static bool readfile(const char *path, const char **data_r)
{
	char buf[1024];
	int fd, ret;

	fd = open(path, O_RDONLY);
	if (fd == -1)
		return FALSE;
	ret = read(fd, buf, sizeof(buf));
	i_close_fd(&fd);
	if (ret <= 0)
		return FALSE;

	*data_r = t_strndup(buf, ret);
	return TRUE;
}
Beispiel #14
0
int http_parse_token(struct http_parser *parser, const char **token_r)
{
	const unsigned char *first;

	/* token          = 1*tchar */

	if (parser->cur >= parser->end || !http_char_is_token(*parser->cur))
		return 0;

	first = parser->cur++;
	while (parser->cur < parser->end && http_char_is_token(*parser->cur))
		parser->cur++;

	*token_r = t_strndup(first, parser->cur - first);
	return 1;
}
Beispiel #15
0
static int
client_connection_authenticate(struct client_connection *conn)
{
	const char *line, *pass;
	buffer_t *plain;
	const unsigned char *data;
	size_t size;

	if ((line = i_stream_read_next_line(conn->input)) == NULL) {
		if (conn->input->eof)
			return -1;
		return 0;
	}

	if (*conn->set->doveadm_password == '\0') {
		i_error("doveadm_password not set, "
			"remote authentication disabled");
		return -1;
	}

	/* FIXME: some day we should probably let auth process do this and
	   support all kinds of authentication */
	if (strncmp(line, "PLAIN\t", 6) != 0) {
		i_error("doveadm client attempted non-PLAIN authentication");
		return -1;
	}

	plain = buffer_create_dynamic(pool_datastack_create(), 128);
	if (base64_decode(line + 6, strlen(line + 6), NULL, plain) < 0) {
		i_error("doveadm client sent invalid base64 auth PLAIN data");
		return -1;
	}
	data = plain->data;
	size = plain->used;

	if (size < 10 || data[0] != '\0' ||
	    memcmp(data+1, "doveadm", 7) != 0 || data[8] != '\0') {
		i_error("doveadm client didn't authenticate as 'doveadm'");
		return -1;
	}
	pass = t_strndup(data + 9, size - 9);
	if (strcmp(pass, conn->set->doveadm_password) != 0) {
		i_error("doveadm client authenticated with wrong password");
		return -1;
	}
	return 1;
}
Beispiel #16
0
static const char *
acl_mailbox_list_iter_get_name(struct mailbox_list_iterate_context *ctx,
			       const char *vname)
{
	struct mail_namespace *ns = ctx->list->ns;
	const char *name;
	unsigned int len;

	name = mailbox_list_get_storage_name(ns->list, vname);
	len = strlen(name);
	if (len > 0 && name[len-1] == mailbox_list_get_hierarchy_sep(ns->list)) {
		/* name ends with separator. this can happen if doing e.g.
		   LIST "" foo/% and it lists "foo/". */
		name = t_strndup(name, len-1);
	}
	return name;
}
static bool acl_ns_prefix_exists(struct mail_namespace *ns)
{
	struct mailbox *box;
	const char *vname;
	enum mailbox_existence existence;
	bool ret;

	if (ns->list->mail_set->mail_shared_explicit_inbox)
		return FALSE;

	vname = t_strndup(ns->prefix, ns->prefix_len-1);
	box = mailbox_alloc(ns->list, vname, 0);
	ret = mailbox_exists(box, FALSE, &existence) == 0 &&
		existence == MAILBOX_EXISTENCE_SELECT;
	mailbox_free(&box);
	return ret;
}
static int
stream_read_value(struct istream **input, const char **value_r)
{
	const unsigned char *data;
	size_t size;
	ssize_t ret;

	while ((ret = i_stream_read(*input)) > 0) ;
	if (ret == 0)
		return 0;
	i_assert(ret == -1);
	if ((*input)->stream_errno != 0)
		return -1;

	data = i_stream_get_data(*input, &size);
	*value_r = t_strndup(data, size);
	i_stream_unref(input);
	return 1;
}
Beispiel #19
0
bool cmd_create(struct client_command_context *cmd)
{
	struct mail_namespace *ns;
	const char *mailbox, *orig_mailbox;
	struct mailbox *box;
	bool directory;
	size_t len;

	/* <mailbox> */
	if (!client_read_string_args(cmd, 1, &mailbox))
		return FALSE;

	orig_mailbox = mailbox;
	ns = client_find_namespace(cmd, &mailbox);
	if (ns == NULL)
		return TRUE;

	len = strlen(orig_mailbox);
	if (len == 0 || orig_mailbox[len-1] != mail_namespace_get_sep(ns))
		directory = FALSE;
	else {
		/* name ends with hierarchy separator - client is just
		   informing us that it wants to create children under this
		   mailbox. */
                directory = TRUE;

		/* drop separator from mailbox. it's already dropped when
		   WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */
		if (len == strlen(mailbox))
			mailbox = t_strndup(mailbox, len-1);
	}

	box = mailbox_alloc(ns->list, mailbox, 0);
	mailbox_set_reason(box, "CREATE");
	if (mailbox_create(box, NULL, directory) < 0)
		client_send_box_error(cmd, box);
	else
		client_send_tagline(cmd, "OK Create completed.");
	mailbox_free(&box);
	return TRUE;
}
Beispiel #20
0
static const struct mailbox_info *
quota_mailbox_iter_next(struct quota_mailbox_iter *iter)
{
	struct mail_namespace *const *namespaces;
	const struct mailbox_info *info;
	unsigned int count;

	if (iter->iter == NULL) {
		namespaces = array_get(&iter->root->quota->namespaces, &count);
		if (iter->ns_idx >= count)
			return NULL;

		iter->ns = namespaces[iter->ns_idx++];
		iter->iter = mailbox_list_iter_init(iter->ns->list, "*",
			MAILBOX_LIST_ITER_SKIP_ALIASES |
			MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
			MAILBOX_LIST_ITER_NO_AUTO_BOXES);
	}
	while ((info = mailbox_list_iter_next(iter->iter)) != NULL) {
		if ((info->flags & (MAILBOX_NONEXISTENT |
				    MAILBOX_NOSELECT)) == 0)
			return info;
	}
	if (mailbox_list_iter_deinit(&iter->iter) < 0) {
		i_error("quota: Listing namespace '%s' failed: %s",
			iter->ns->prefix,
			mailbox_list_get_last_error(iter->ns->list, NULL));
		iter->failed = TRUE;
	}
	if (iter->ns->prefix_len > 0 &&
	    (iter->ns->prefix_len != 6 ||
	     strncasecmp(iter->ns->prefix, "INBOX", 5) != 0)) {
		/* if the namespace prefix itself exists, count it also */
		iter->info.ns = iter->ns;
		iter->info.vname = t_strndup(iter->ns->prefix,
					     iter->ns->prefix_len-1);
		return &iter->info;
	}
	/* try the next namespace */
	return quota_mailbox_iter_next(iter);
}
Beispiel #21
0
static void
parse_imap_keywords_list(struct mbox_sync_mail_context *ctx,
                         struct message_header_line *hdr, size_t pos)
{
	struct mailbox *box = &ctx->sync_ctx->mbox->box;
	struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
	const char *keyword, *error;
	size_t keyword_start;
	unsigned int idx, count;

	count = 0;
	while (pos < hdr->full_value_len) {
		if (IS_LWSP_LF(hdr->full_value[pos])) {
                        pos++;
			continue;
		}

		/* read the keyword */
		keyword_start = pos;
		for (; pos < hdr->full_value_len; pos++) {
			if (IS_LWSP_LF(hdr->full_value[pos]))
				break;
		}

		/* add it to index's keyword list if it's not there already */
		keyword = t_strndup(hdr->full_value + keyword_start,
				    pos - keyword_start);
		if (mailbox_keyword_is_valid(&ctx->sync_ctx->mbox->box,
					     keyword, &error)) {
			mail_index_keyword_lookup_or_create(box->index,
							    keyword, &idx);
		}
		count++;
	}

	if (count != array_count(ibox->keyword_names)) {
		/* need to update this list */
		ctx->imapbase_rewrite = TRUE;
		ctx->need_rewrite = TRUE;
	}
}
Beispiel #22
0
static void tcpwrap_client_input(struct tcpwrap_client *client)
{
	unsigned char buf[1024];
	ssize_t ret;
	int check_fd = -1;

	ret = fd_read(client->fd, buf, sizeof(buf), &check_fd);
	if (ret <= 0) {
		i_error("fd_read() failed: %m");
	} else if (ret > 1 && (size_t)ret < sizeof(buf) && buf[ret-1] == '\n') {
		tcpwrap_client_handle(client, check_fd, t_strndup(buf, ret-1));
	} else {
		i_error("Invalid input from client");
	}

	if (check_fd != -1) {
		if (close(check_fd) < 0)
			i_error("close(fdread fd) failed: %m");
	}
	tcpwrap_client_destroy(&client);
}
Beispiel #23
0
void mailbox_list_delete_until_root(struct mailbox_list *list, const char *path,
				    enum mailbox_list_path_type type)
{
	const char *root_dir, *p;
	unsigned int len;

	root_dir = mailbox_list_get_path(list, NULL, type);
	if (strncmp(path, root_dir, strlen(root_dir)) != 0) {
		/* mbox workaround: name=child/box, root_dir=mail/.imap/,
		   path=mail/child/.imap/box. we'll want to try to delete
		   the .imap/ part, but no further. */
		len = strlen(path);
		while (len > 0 && path[len-1] != '/')
			len--;
		if (len == 0)
			return;
		len--;
		while (len > 0 && path[len-1] != '/')
			len--;
		if (len == 0)
			return;

		root_dir = t_strndup(path, len-1);
	}
	while (strcmp(path, root_dir) != 0) {
		if (rmdir(path) < 0 && errno != ENOENT) {
			if (errno == ENOTEMPTY || errno == EEXIST)
				return;

			mailbox_list_set_critical(list, "rmdir(%s) failed: %m",
						  path);
			return;
		}
		p = strrchr(path, '/');
		if (p == NULL)
			break;

		path = t_strdup_until(path, p);
	}
}
Beispiel #24
0
static void
client_parse_input(const unsigned char *data, unsigned int len,
		   struct client_input *input_r)
{
	unsigned int taglen;

	i_assert(len > 0);

	memset(input_r, 0, sizeof(*input_r));

	if (data[0] == '1')
		input_r->send_untagged_capability = TRUE;
	data++; len--;

	input_r->tag = t_strndup(data, len);
	taglen = strlen(input_r->tag) + 1;

	if (len > taglen) {
		input_r->input = data + taglen;
		input_r->input_size = len - taglen;
	}
}
Beispiel #25
0
static int
http_parse_token68(struct http_parser *parser, const char **token68_r)
{
	const unsigned char *first;

	/* token68        = 1*( ALPHA / DIGIT /
                      "-" / "." / "_" / "~" / "+" / "/" ) *"="
	 */

	/* 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) */
	if (parser->cur >= parser->end || !http_char_is_token68(*parser->cur))
		return 0;
	first = parser->cur++;
	while (parser->cur < parser->end && http_char_is_token68(*parser->cur))
		parser->cur++;

	/* *"=" */
	while (parser->cur < parser->end && *parser->cur == '=')
		parser->cur++;
	
	*token68_r = t_strndup(first, parser->cur - first);
	return 1;
}
static int
fts_filter_stemmer_snowball_filter(struct fts_filter *filter,
                                   const char **token, const char **error_r)
{
    struct fts_filter_stemmer_snowball *sp =
        (struct fts_filter_stemmer_snowball *) filter;
    const sb_symbol *base;

    if (sp->stemmer == NULL) {
        if (fts_filter_stemmer_snowball_create_stemmer(sp, error_r) < 0)
            return -1;
    }

    base = sb_stemmer_stem(sp->stemmer, (const unsigned char *)*token, strlen(*token));
    if (base == NULL) {
        /* the only reason why this could fail is because of
           out of memory. */
        i_fatal_status(FATAL_OUTOFMEM,
                       "sb_stemmer_stem(len=%"PRIuSIZE_T") failed: "
                       "Out of memory", strlen(*token));
    }
    *token = t_strndup(base, sb_stemmer_length(sp->stemmer));
    return 1;
}
static int set_line(struct mail_storage_service_ctx *ctx,
		    struct mail_storage_service_user *user,
		    const char *line)
{
	struct setting_parser_context *set_parser = user->set_parser;
	bool mail_debug;
	const char *key, *orig_key, *append_value = NULL;
	unsigned int len;
	int ret;

	mail_debug = mail_user_set_get_mail_debug(user->user_info,
						  user->user_set);
	if (strchr(line, '=') == NULL)
		line = t_strconcat(line, "=yes", NULL);
	orig_key = key = t_strcut(line, '=');

	len = strlen(key);
	if (len > 0 && key[len-1] == '+') {
		/* key+=value */
		append_value = line + len + 1;
		key = t_strndup(key, len-1);
	}

	if (!settings_parse_is_valid_key(set_parser, key)) {
		/* assume it's a plugin setting */
		key = t_strconcat("plugin/", key, NULL);
		line = t_strconcat("plugin/", line, NULL);
	}

	if (master_service_set_has_config_override(ctx->service, key)) {
		/* this setting was already overridden with -o parameter */
		if (mail_debug) {
			i_debug("Ignoring overridden (-o) userdb setting: %s",
				key);
		}
		return 1;
	}

	if (append_value != NULL) {
		const void *value;
		enum setting_type type;

		value = settings_parse_get_value(set_parser, key, &type);
		if (type == SET_STR) {
			const char *const *strp = value;

			line = t_strdup_printf("%s=%s%s",
					       key, *strp, append_value);
		} else {
			i_error("Ignoring %s userdb setting. "
				"'+' can only be used for strings.", orig_key);
		}
	}

	ret = settings_parse_line(set_parser, line);
	if (mail_debug && ret >= 0) {
		if (strstr(key, "pass") != NULL) {
			/* possibly a password field (e.g. imapc_password).
			   hide the value. */
			line = t_strconcat(key, "=<hidden>", NULL);
		}
		i_debug(ret == 0 ?
			"Unknown userdb setting: %s" :
			"Added userdb setting: %s", line);
	}
	return ret;
}
static int
mail_storage_service_next_real(struct mail_storage_service_ctx *ctx,
			       struct mail_storage_service_user *user,
			       struct mail_user **mail_user_r)
{
	struct mail_storage_service_privileges priv;
	const char *error;
	unsigned int len;
	bool disallow_root =
		(user->flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0;
	bool temp_priv_drop =
		(user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0;
	bool use_chroot;

	if (service_parse_privileges(ctx, user, &priv, &error) < 0) {
		i_error("%s", error);
		return -2;
	}

	if (*priv.home != '/' && *priv.home != '\0') {
		i_error("Relative home directory paths not supported: %s",
			priv.home);
		return -2;
	}

	/* we can't chroot if we want to switch between users. there's
	   not much point either (from security point of view). but if we're
	   already chrooted, we'll just have to continue and hope that the
	   current chroot is the same as the wanted chroot */
	use_chroot = !temp_priv_drop ||
		restrict_access_get_current_chroot() != NULL;

	len = strlen(priv.chroot);
	if (len > 2 && strcmp(priv.chroot + len - 2, "/.") == 0 &&
	    strncmp(priv.home, priv.chroot, len - 2) == 0) {
		/* mail_chroot = /chroot/. means that the home dir already
		   contains the chroot dir. remove it from home. */
		if (use_chroot) {
			priv.home += len - 2;
			if (*priv.home == '\0')
				priv.home = "/";
			priv.chroot = t_strndup(priv.chroot, len - 2);

			set_keyval(ctx, user, "mail_home", priv.home);
			set_keyval(ctx, user, "mail_chroot", priv.chroot);
		}
	} else if (len > 0 && !use_chroot) {
		/* we're not going to chroot. fix home directory so we can
		   access it. */
		if (*priv.home == '\0' || strcmp(priv.home, "/") == 0)
			priv.home = priv.chroot;
		else
			priv.home = t_strconcat(priv.chroot, priv.home, NULL);
		priv.chroot = "";
		set_keyval(ctx, user, "mail_home", priv.home);
	}

	/* create ioloop context regardless of logging. it's also used by
	   stats plugin. */
	user->ioloop_ctx = io_loop_context_new(current_ioloop);

	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0)
		mail_storage_service_init_log(ctx, user, &priv);

	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) {
		if (service_drop_privileges(user, &priv,
					    disallow_root, temp_priv_drop,
					    FALSE, &error) < 0) {
			i_error("Couldn't drop privileges: %s", error);
			return -1;
		}
		if (!temp_priv_drop ||
		    (user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) != 0)
			restrict_access_allow_coredumps(TRUE);
	}

	/* privileges are dropped. initialize plugins that haven't been
	   initialized yet. */
	module_dir_init(mail_storage_service_modules);

	if (mail_storage_service_init_post(ctx, user, &priv,
					   mail_user_r, &error) < 0) {
		i_error("User initialization failed: %s", error);
		return -2;
	}
	return 0;
}
static int
mailbox_list_subscription_fill_one(struct mailbox_list *list,
				   struct mailbox_list *src_list,
				   const char *name)
{
	struct mail_namespace *ns, *default_ns = list->ns;
	struct mail_namespace *namespaces = default_ns->user->namespaces;
	struct mailbox_node *node;
	const char *vname, *ns_name, *error;
	unsigned int len;
	bool created;

	/* default_ns is whatever namespace we're currently listing.
	   if we have e.g. prefix="" and prefix=pub/ namespaces with
	   pub/ namespace having subscriptions=no, we want to:

	   1) when listing "" namespace we want to skip over any names
	   that begin with pub/. */
	if (src_list->ns->prefix_len == 0)
		ns_name = name;
	else {
		/* we could have two-level namespace: ns/ns2/ */
		ns_name = t_strconcat(src_list->ns->prefix, name, NULL);
	}
	ns = mail_namespace_find_unsubscribable(namespaces, ns_name);
	if (ns != NULL && ns != default_ns) {
		if (ns->prefix_len > 0)
			return 0;
		/* prefix="" namespace=no : catching this is basically the
		   same as not finding any namespace. */
		ns = NULL;
	}

	/* 2) when listing pub/ namespace, skip over entries that don't
	   begin with pub/. */
	if (ns == NULL &&
	    (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0)
		return 0;

	/* When listing shared namespace's subscriptions, we need to
	   autocreate all the visible child namespaces. their subscriptions
	   are listed later. */
	if (ns != NULL && mail_namespace_is_shared_user_root(ns)) {
		/* we'll need to get the namespace autocreated.
		   one easy way is to just ask to join a reference and
		   pattern */
		(void)mailbox_list_join_refpattern(ns->list, ns_name, "");
	}

	/* When listing pub/ namespace, skip over the namespace
	   prefix in the name. the rest of the name is storage_name. */
	if (ns == NULL)
		ns = default_ns;
	else if (strncmp(ns_name, ns->prefix, ns->prefix_len) == 0) {
		ns_name += ns->prefix_len;
		name = ns_name;
	} else {
		/* "pub" entry - this shouldn't be possible normally, because
		   it should be saved as "pub/", but handle it anyway */
		i_assert(strncmp(ns_name, ns->prefix, ns->prefix_len-1) == 0 &&
			 ns_name[ns->prefix_len-1] == '\0');
		name = ns_name = "";
	}

	len = strlen(name);
	if (len > 0 && name[len-1] == mail_namespace_get_sep(ns)) {
		/* entry ends with hierarchy separator, remove it.
		   this exists mainly for backwards compatibility with old
		   Dovecot versions and non-Dovecot software that added them */
		name = t_strndup(name, len-1);
	}

	if (!mailbox_list_is_valid_name(list, name, &error)) {
		/* we'll only get into trouble if we show this */
		return -1;
	} else {
		vname = mailbox_list_get_vname(list, name);
		if (!uni_utf8_str_is_valid(vname))
			return -1;
		node = mailbox_tree_get(list->subscriptions, vname, &created);
		node->flags = MAILBOX_SUBSCRIBED;
	}
	return 0;
}
Beispiel #30
0
int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
			    struct mail_namespace *ns, const char *box_name,
			    const guid_128_t box_guid,
			    const char *const *exclude_mailboxes,
			    enum mail_error *error_r)
{
	const enum mailbox_list_iter_flags list_flags =
		/* FIXME: we'll skip symlinks, because we can't handle them
		   currently. in future we could detect them and create them
		   by creating the symlink. */
		MAILBOX_LIST_ITER_SKIP_ALIASES |
		MAILBOX_LIST_ITER_NO_AUTO_BOXES;
	const enum mailbox_list_iter_flags subs_list_flags =
		MAILBOX_LIST_ITER_NO_AUTO_BOXES |
		MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
	struct mailbox_list_iterate_context *iter;
	struct dsync_mailbox_node *node, *dup_node1, *dup_node2;
	const struct mailbox_info *info;
	const char *list_pattern =
		box_name != NULL && box_name[0] != '\\' ? box_name : "*";
	int ret = 0;

	i_assert(mail_namespace_get_sep(ns) == tree->sep);

	/* assign namespace to its root, so it gets copied to children */
	if (ns->prefix_len > 0) {
		node = dsync_mailbox_tree_get(tree,
			t_strndup(ns->prefix, ns->prefix_len-1));
		node->ns = ns;
	} else {
		tree->root.ns = ns;
	}

	/* first add all of the existing mailboxes */
	iter = mailbox_list_iter_init(ns->list, list_pattern, list_flags);
	while ((info = mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
		if (dsync_mailbox_info_is_wanted(info, box_name,
						 exclude_mailboxes)) {
			if (dsync_mailbox_tree_add(tree, info, box_guid, error_r) < 0)
				ret = -1;
		}
	} T_END;
	if (mailbox_list_iter_deinit(&iter) < 0) {
		i_error("Mailbox listing for namespace '%s' failed: %s",
			ns->prefix, mailbox_list_get_last_internal_error(ns->list, error_r));
		ret = -1;
	}

	/* add subscriptions */
	iter = mailbox_list_iter_init(ns->list, list_pattern, subs_list_flags);
	while ((info = mailbox_list_iter_next(iter)) != NULL) {
		if (dsync_mailbox_tree_add_node(tree, info, &node) == 0)
			node->subscribed = TRUE;
		else {
			*error_r = MAIL_ERROR_TEMP;
			ret = -1;
		}
	}
	if (mailbox_list_iter_deinit(&iter) < 0) {
		i_error("Mailbox listing for namespace '%s' failed: %s",
			ns->prefix, mailbox_list_get_last_internal_error(ns->list, error_r));
		ret = -1;
	}
	if (ret < 0)
		return -1;

	while (dsync_mailbox_tree_build_guid_hash(tree, &dup_node1,
						  &dup_node2) < 0) {
		if (dsync_mailbox_tree_fix_guid_duplicate(tree, dup_node1, dup_node2) < 0)
			return -1;
	}

	/* add timestamps */
	if (dsync_mailbox_tree_add_change_timestamps(tree, ns) < 0)
		return -1;
	return 0;
}