Esempio n. 1
0
int acl_rights_update_import(struct acl_rights_update *update,
			     const char *id, const char *const *rights,
			     const char **error_r)
{
	ARRAY_TYPE(const_string) dest_rights, dest_neg_rights, *dest;
	unsigned int i, j;

	if (acl_identifier_parse(id, &update->rights) < 0) {
		*error_r = t_strdup_printf("Invalid ID: %s", id);
		return -1;
	}
	if (rights == NULL) {
		update->modify_mode = ACL_MODIFY_MODE_CLEAR;
		update->neg_modify_mode = ACL_MODIFY_MODE_CLEAR;
		return 0;
	}

	t_array_init(&dest_rights, 8);
	t_array_init(&dest_neg_rights, 8);
	for (i = 0; rights[i] != NULL; i++) {
		const char *right = rights[i];

		if (right[0] != '-')
			dest = &dest_rights;
		else {
			right++;
			dest = &dest_neg_rights;
		}
		if (strcmp(right, "all") != 0) {
			if (*right == ':') {
				/* non-standard right */
				right++;
				array_append(dest, &right, 1);
			} else if (is_standard_right(right)) {
				array_append(dest, &right, 1);
			} else {
				*error_r = t_strdup_printf("Invalid right '%s'",
							   right);
				return -1;
			}
		} else {
			for (j = 0; all_mailbox_rights[j] != NULL; j++)
				array_append(dest, &all_mailbox_rights[j], 1);
		}
	}
	if (array_count(&dest_rights) > 0) {
		array_append_zero(&dest_rights);
		update->rights.rights = array_idx(&dest_rights, 0);
	} else if (update->modify_mode == ACL_MODIFY_MODE_REPLACE) {
		update->modify_mode = ACL_MODIFY_MODE_CLEAR;
	}
	if (array_count(&dest_neg_rights) > 0) {
		array_append_zero(&dest_neg_rights);
		update->rights.neg_rights = array_idx(&dest_neg_rights, 0);
	} else if (update->neg_modify_mode == ACL_MODIFY_MODE_REPLACE) {
		update->neg_modify_mode = ACL_MODIFY_MODE_CLEAR;
	}
	return 0;
}
Esempio n. 2
0
static uint32_t
maildir_save_set_recent_flags(struct maildir_save_context *ctx)
{
	struct maildir_mailbox *mbox = ctx->mbox;
	ARRAY_TYPE(seq_range) saved_sorted_uids;
	const struct seq_range *uids;
	unsigned int i, count;
	uint32_t uid;

	count = array_count(&ctx->ctx.transaction->changes->saved_uids);
	if (count == 0)
		return 0;

	t_array_init(&saved_sorted_uids, count);
	array_append_array(&saved_sorted_uids,
			   &ctx->ctx.transaction->changes->saved_uids);
	array_sort(&saved_sorted_uids, seq_range_cmp);

	uids = array_get(&saved_sorted_uids, &count);
	for (i = 0; i < count; i++) {
		for (uid = uids[i].seq1; uid <= uids[i].seq2; uid++)
			mailbox_recent_flags_set_uid(&mbox->box, uid);
	}
	return uids[count-1].seq2 + 1;
}
static int cmd_deduplicate_uidlist(struct mailbox *box, struct uidlist *uidlist)
{
	struct mailbox_transaction_context *trans;
	struct mail_search_context *search_ctx;
	struct mail_search_args *search_args;
	struct mail_search_arg *arg;
	struct mail *mail;
	ARRAY_TYPE(seq_range) uids;
	int ret = 0;

	/* the uidlist is reversed with oldest mails at the end.
	   we'll delete everything but the oldest mail. */
	if (uidlist->next == NULL)
		return 0;

	t_array_init(&uids, 8);
	for (; uidlist->next != NULL; uidlist = uidlist->next)
		seq_range_array_add(&uids, uidlist->uid);

	search_args = mail_search_build_init();
	arg = mail_search_build_add(search_args, SEARCH_UIDSET);
	arg->value.seqset = uids;

	trans = mailbox_transaction_begin(box, 0);
	search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
	mail_search_args_unref(&search_args);

	while (mailbox_search_next(search_ctx, &mail))
		mail_expunge(mail);
	if (mailbox_search_deinit(&search_ctx) < 0)
		ret = -1;
	if (mailbox_transaction_commit(&trans) < 0)
		ret = -1;
	return ret;
}
Esempio n. 4
0
static void
dbox_sync_index_copy_from_old(struct dbox_sync_rebuild_context *ctx,
			      struct mail_index_view *view,
			      uint32_t old_seq, uint32_t new_seq)
{
	struct mail_index *index = mail_index_view_get_index(view);
	const struct mail_index_record *rec;
	ARRAY_TYPE(keyword_indexes) old_keywords;
	struct mail_keywords *kw;
	uint64_t modseq;

	/* copy flags */
	rec = mail_index_lookup(view, old_seq);
	mail_index_update_flags(ctx->trans, new_seq,
				MODIFY_REPLACE, rec->flags);

	/* copy keywords */
	t_array_init(&old_keywords, 32);
	mail_index_lookup_keywords(view, old_seq, &old_keywords);
	kw = mail_index_keywords_create_from_indexes(index, &old_keywords);
	mail_index_update_keywords(ctx->trans, new_seq, MODIFY_REPLACE, kw);
	mail_index_keywords_unref(&kw);

	/* copy modseq */
	modseq = mail_index_modseq_lookup(view, old_seq);
	mail_index_update_modseq(ctx->trans, new_seq, modseq);

	dbox_sync_index_copy_cache(ctx, view, old_seq, new_seq);
}
Esempio n. 5
0
static void env_clean_except_real(const char *const preserve_envs[])
{
	ARRAY_TYPE(const_string) copy;
	const char *value, *const *envp;
	unsigned int i;

	t_array_init(&copy, 16);
	for (i = 0; preserve_envs[i] != NULL; i++) {
		const char *key = preserve_envs[i];

		value = getenv(key);
		if (value != NULL) {
			value = t_strconcat(key, "=", value, NULL);
			array_append(&copy, &value, 1);
		}
	}

	/* Note that if the original environment was set with env_put(), the
	   environment strings will be invalid after env_clean(). That's why
	   we t_strconcat() them above. */
	env_clean();

	array_foreach(&copy, envp)
		env_put(*envp);
}
Esempio n. 6
0
static void
mirror_get_remote_cmd_line(const char *const *argv,
			   const char *const **cmd_args_r)
{
	ARRAY_TYPE(const_string) cmd_args;
	unsigned int i;
	const char *p;

	i_assert(argv[0] != NULL);

	t_array_init(&cmd_args, 16);
	for (i = 0; argv[i] != NULL; i++) {
		p = argv[i];
		array_append(&cmd_args, &p, 1);
	}

	if (legacy_dsync) {
		/* we're executing dsync */
		p = "server";
	} else {
		/* we're executing doveadm */
		p = "dsync-server";
	}
	array_append(&cmd_args, &p, 1);
	array_append_zero(&cmd_args);
	*cmd_args_r = array_idx(&cmd_args, 0);
}
Esempio n. 7
0
static void
boundaries_permute(uint32_t *input, unsigned int i, unsigned int count)
{
	ARRAY_TYPE(seq_range) range;
	const struct seq_range *seqs;
	unsigned int seqs_count;
	uint32_t tmp;
	unsigned int j;

	if (i+1 < count) {
		for (j = i; j < count; j++) {
			tmp = input[i]; input[i] = input[j]; input[j] = tmp;
			boundaries_permute(input, i+1, count);
			tmp = input[i]; input[i] = input[j]; input[j] = tmp;
		}
		return;
	}
	t_array_init(&range, 4);
	for (i = 0; i < count; i++)
		seq_range_array_add(&range, input[i]);
	seqs = array_get(&range, &seqs_count);
	test_assert(seqs_count == 2);
	test_assert(seqs[0].seq1 == 0);
	test_assert(seqs[0].seq2 == 1);
	test_assert(seqs[1].seq1 == (uint32_t)-2);
	test_assert(seqs[1].seq2 == (uint32_t)-1);
}
Esempio n. 8
0
static void test_seq_range_array_remove_nth(void)
{
	ARRAY_TYPE(seq_range) range;
	const struct seq_range *r;

	test_begin("seq_range_array_remove_nth()");
	t_array_init(&range, 8);
	seq_range_array_add_range(&range, 1, 5);
	seq_range_array_add(&range, 7);
	seq_range_array_add_range(&range, 10,20);
	test_assert(array_count(&range) == 3);

	seq_range_array_remove_nth(&range, 0, 2);
	r = array_idx(&range, 0); test_assert(r->seq1 == 3 && r->seq2 == 5);

	seq_range_array_remove_nth(&range, 1, 4);
	r = array_idx(&range, 0); test_assert(r->seq1 == 3 && r->seq2 == 3);
	r = array_idx(&range, 1); test_assert(r->seq1 == 11 && r->seq2 == 20);

	seq_range_array_remove_nth(&range, 5, (uint32_t)-1);
	r = array_idx(&range, 1); test_assert(r->seq1 == 11 && r->seq2 == 14);

	test_assert(array_count(&range) == 2);
	test_end();
}
Esempio n. 9
0
int main(int argc, char *argv[])
{
	ARRAY_TYPE(const_string) aenvs;
	const char *binary;
	const char *const *envs;
	int c, i;

	master_service = master_service_init("script", 0, &argc, &argv, "+e:");

	t_array_init(&aenvs, 16);
	while ((c = master_getopt(master_service)) > 0) {
		switch (c) {
		case 'e':
			envs = t_strsplit_spaces(optarg,", \t");
			while (*envs != NULL) {
				array_append(&aenvs, envs, 1);
				envs++;
			}
			break;
		default:
			return FATAL_DEFAULT;
		}
	}
	argc -= optind;
	argv += optind;

	array_append_zero(&aenvs);
	accepted_envs = p_strarray_dup(default_pool, array_idx(&aenvs, 0));

	master_service_init_log(master_service, "script: ");
	if (argv[0] == NULL)
		i_fatal("Missing script path");
	restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
	restrict_access_allow_coredumps(TRUE);

	master_service_init_finish(master_service);
	master_service_set_service_count(master_service, 1);

	if (argv[0][0] == '/')
		binary = argv[0];
	else
		binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL);

	i_array_init(&exec_args, argc + 16);
	array_append(&exec_args, &binary, 1);
	for (i = 1; i < argc; i++) {
		const char *arg = argv[i];

		array_append(&exec_args, &arg, 1);
	}

	master_service_run(master_service, client_connected);
	array_free(&exec_args);
	i_free(accepted_envs);
	master_service_deinit(&master_service);
	return 0;
}
Esempio n. 10
0
static void test_seq_range_array_add_merge(void)
{
	ARRAY_TYPE(seq_range) range;

	test_begin("seq_range_array_add() merging");
	t_array_init(&range, 8);
	seq_range_array_add(&range, 4);
	seq_range_array_add(&range, 1);
	seq_range_array_add(&range, 2);
	test_assert(array_count(&range) == 2);
	test_end();
}
Esempio n. 11
0
static const char *
maildir_filename_guess(struct maildir_mailbox *mbox, uint32_t uid,
		       const char *fname,
		       enum maildir_uidlist_rec_flag *uidlist_flags,
		       bool *have_flags_r)

{
	struct mail_index_view *view = mbox->flags_view;
	struct maildir_keywords_sync_ctx *kw_ctx;
	enum mail_flags flags;
	ARRAY_TYPE(keyword_indexes) keywords;
	const char *p;
	uint32_t seq;

	if (view == NULL || !mail_index_lookup_seq(view, uid, &seq)) {
		*have_flags_r = FALSE;
		return fname;
	}

	t_array_init(&keywords, 32);
	mail_index_lookup_view_flags(view, seq, &flags, &keywords);
	if (array_count(&keywords) == 0) {
		*have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0;
		fname = maildir_filename_flags_set(fname, flags);
	} else {
		*have_flags_r = TRUE;
		kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords,
							     mbox->box.index);
		fname = maildir_filename_flags_kw_set(kw_ctx, fname,
						      flags, &keywords);
		maildir_keywords_sync_deinit(&kw_ctx);
	}

	if (*have_flags_r) {
		/* don't even bother looking into new/ dir */
		*uidlist_flags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
	} else if ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_MOVED) == 0 &&
		   ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 ||
		    mailbox_recent_flags_have_uid(&mbox->box, uid))) {
		/* probably in new/ dir, drop ":2," from fname */
		*uidlist_flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
		p = strrchr(fname, MAILDIR_INFO_SEP);
		if (p != NULL)
			fname = t_strdup_until(fname, p);
	}

	return fname;
}
Esempio n. 12
0
static struct imap_match_glob *
imap_match_dup_real(pool_t pool, const struct imap_match_glob *glob)
{
	ARRAY_TYPE(const_string) patterns;
	const struct imap_match_pattern *p;
	bool inboxcase = FALSE;

	t_array_init(&patterns, 8);
	for (p = glob->patterns; p->pattern != NULL; p++) {
		if (p->inboxcase)
			inboxcase = TRUE;
		array_append(&patterns, &p->pattern, 1);
	}
	array_append_zero(&patterns);
	return imap_match_init_multiple_real(pool, array_idx(&patterns, 0),
					     inboxcase, glob->sep);
}
Esempio n. 13
0
static void
index_storage_mailbox_update_cache(struct mailbox *box,
				   const struct mailbox_update *update)
{
	const struct mailbox_cache_field *updates = update->cache_updates;
	ARRAY(struct mail_cache_field) new_fields;
	const struct mail_cache_field *old_fields;
	struct mail_cache_field field;
	unsigned int i, j, old_count;

	old_fields = mail_cache_register_get_list(box->cache,
						  pool_datastack_create(),
						  &old_count);

	/* There shouldn't be many fields, so don't worry about O(n^2). */
	t_array_init(&new_fields, 32);
	for (i = 0; updates[i].name != NULL; i++) {
		/* see if it's an existing field */
		for (j = 0; j < old_count; j++) {
			if (strcmp(updates[i].name, old_fields[j].name) == 0)
				break;
		}
		if (j != old_count) {
			field = old_fields[j];
		} else if (strncmp(updates[i].name, "hdr.", 4) == 0) {
			/* new header */
			memset(&field, 0, sizeof(field));
			field.name = updates[i].name;
			field.type = MAIL_CACHE_FIELD_HEADER;
		} else {
			/* new unknown field. we can't do anything about
			   this since we don't know its type */
			continue;
		}
		field.decision = updates[i].decision;
		if (updates[i].last_used != (time_t)-1)
			field.last_used = updates[i].last_used;
		array_append(&new_fields, &field, 1);
	}
	if (array_count(&new_fields) > 0) {
		mail_cache_register_fields(box->cache,
					   array_idx_modifiable(&new_fields, 0),
					   array_count(&new_fields));
	}
}
Esempio n. 14
0
static void
dsync_brain_slave_send_mailbox_lost(struct dsync_brain *brain,
				    const struct dsync_mailbox *dsync_box)
{
	struct dsync_mailbox delete_box;

	if (brain->debug) {
		i_debug("brain %c: We don't have mailbox %s",
			brain->master_brain ? 'M' : 'S',
			guid_128_to_string(dsync_box->mailbox_guid));
	}
	memset(&delete_box, 0, sizeof(delete_box));
	memcpy(delete_box.mailbox_guid, dsync_box->mailbox_guid,
	       sizeof(delete_box.mailbox_guid));
	t_array_init(&delete_box.cache_fields, 0);
	delete_box.mailbox_lost = TRUE;
	dsync_ibc_send_mailbox(brain->ibc, &delete_box);
}
Esempio n. 15
0
static int tst_test_multiscript_operation_execute
(const struct sieve_runtime_env *renv, sieve_size_t *address)
{
	struct sieve_stringlist *scripts_list;
	string_t *script_name;
	ARRAY_TYPE (const_string) scriptfiles;
	bool result = TRUE;
	int ret;

	/*
	 * Read operands
	 */

	if ( (ret=sieve_opr_stringlist_read(renv, address, "scripts", &scripts_list))
		<= 0 )
		return ret;

	/*
	 * Perform operation
	 */

	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
		"testsuite: test_multiscript test");
	sieve_runtime_trace_descend(renv);

	t_array_init(&scriptfiles, 16);

	script_name = NULL;
	while ( result &&
		(ret=sieve_stringlist_next_item(scripts_list, &script_name)) > 0 ) {
		const char *script = t_strdup(str_c(script_name));

		array_append(&scriptfiles, &script, 1);
	}

	result = result && (ret >= 0) &&
		testsuite_script_multiscript(renv, &scriptfiles);

	/* Set result */
	sieve_interpreter_set_test_result(renv->interp, result);

	return SIEVE_EXEC_OK;
}
Esempio n. 16
0
static struct mail_keywords *
mailbox_keywords_create_skip(struct mailbox *box,
			     const char *const keywords[])
{
	struct mail_keywords *kw;

	T_BEGIN {
		ARRAY(const char *) valid_keywords;
		const char *error;

		t_array_init(&valid_keywords, 32);
		for (; *keywords != NULL; keywords++) {
			if (mailbox_keyword_is_valid(box, *keywords, &error))
				array_append(&valid_keywords, keywords, 1);
		}
		array_append_zero(&valid_keywords); /* NULL-terminate */
		kw = mail_index_keywords_create(box->index, keywords);
	} T_END;
	return kw;
}
Esempio n. 17
0
static void
index_storage_get_status_cache_fields(struct mailbox *box,
				      struct mailbox_status *status_r)
{
	const struct mail_cache_field *fields;
	enum mail_cache_decision_type dec;
	ARRAY_TYPE(const_string) *cache_fields;
	unsigned int i, count;

	fields = mail_cache_register_get_list(box->cache,
					      pool_datastack_create(), &count);

	cache_fields = t_new(ARRAY_TYPE(const_string), 1);
	t_array_init(cache_fields, count);
	for (i = 0; i < count; i++) {
		dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
		if (dec != MAIL_CACHE_DECISION_NO)
			array_append(cache_fields, &fields[i].name, 1);
	}
	status_r->cache_fields = cache_fields;
}
Esempio n. 18
0
static struct mail_search_register *
mail_search_register_init_human(struct mail_search_register *imap_register)
{
	struct mail_search_register *reg;
	mail_search_register_fallback_t *fallback;
	ARRAY(struct mail_search_register_arg) copy_args;
	const struct mail_search_register_arg *human_args, *imap_args;
	unsigned int i, j, human_count, imap_count;
	int ret;

	reg = mail_search_register_init();
	mail_search_register_add(reg, human_register_args,
				 N_ELEMENTS(human_register_args));

	/* find and register args in imap that don't exist in human */
	imap_args = mail_search_register_get(imap_register, &imap_count);
	human_args = mail_search_register_get(reg, &human_count);
	t_array_init(&copy_args, imap_count);
	for (i = j = 0; i < imap_count && j < human_count; ) {
		ret = strcmp(imap_args[i].key, human_args[j].key);
		if (ret < 0) {
			array_append(&copy_args, &imap_args[i], 1);
			i++;
		} else if (ret > 0) {
			j++;
		} else {
			i++; j++;
		}
	}
	for (; i < imap_count; i++)
		array_append(&copy_args, &imap_args[i], 1);

	imap_args = array_get(&copy_args, &imap_count);
	mail_search_register_add(reg, imap_args, imap_count);

	if (mail_search_register_get_fallback(imap_register, &fallback))
		mail_search_register_fallback(reg, fallback);
	return reg;
}
Esempio n. 19
0
static const char *test_aqueue2(unsigned int initial_size)
{
	ARRAY(unsigned int) aqueue_array;
	unsigned int i, j, k;

	for (i = 0; i < N_ELEMENTS(aqueue_input); i++) {
		for (k = 0; k < N_ELEMENTS(aqueue_input); k++) {
			struct aqueue *aqueue;

			t_array_init(&aqueue_array, initial_size);
			aqueue = aqueue_init(&aqueue_array.arr);
			aqueue->head = aqueue->tail = initial_size - 1;
			for (j = 0; j < k; j++) {
				aqueue_append(aqueue, &aqueue_input[j]);
				if (aqueue_count(aqueue) != j + 1) {
					return t_strdup_printf("Wrong count after append %u vs %u)",
							       aqueue_count(aqueue), j + 1);
				}
				if (!aqueue_is_ok(aqueue, UINT_MAX))
					return "Invalid data after append";
			}

			if (k != 0 && i < k) {
				aqueue_delete(aqueue, i);
				if (aqueue_count(aqueue) != k - 1)
					return "Wrong count after delete";
				if (!aqueue_is_ok(aqueue, i))
					return "Invalid data after delete";
			}
			aqueue_clear(aqueue);
			if (aqueue_count(aqueue) != 0)
				return "aqueue_clear() broken";
			aqueue_deinit(&aqueue);
		}
	}
	return NULL;
}
Esempio n. 20
0
static int search_arg_match_keywords(struct index_search_context *ctx,
				     struct mail_search_arg *arg)
{
	ARRAY_TYPE(keyword_indexes) keyword_indexes_arr;
	const struct mail_keywords *search_kws = arg->value.keywords;
	const unsigned int *keyword_indexes;
	unsigned int i, j, count;

	t_array_init(&keyword_indexes_arr, 128);
	mail_index_lookup_keywords(ctx->view, ctx->mail_ctx.seq,
				   &keyword_indexes_arr);
	keyword_indexes = array_get(&keyword_indexes_arr, &count);

	/* there probably aren't many keywords, so O(n*m) for now */
	for (i = 0; i < search_kws->count; i++) {
		for (j = 0; j < count; j++) {
			if (search_kws->idx[i] == keyword_indexes[j])
				break;
		}
		if (j == count)
			return 0;
	}
	return 1;
}
Esempio n. 21
0
static bool client_exec_script(struct master_service_connection *conn)
{
	ARRAY_TYPE(const_string) envs;
	const char *const *args;
	string_t *input;
	void *buf;
	size_t prev_size, scanpos;
	bool header_complete = FALSE, noreply = FALSE;
	ssize_t ret;
	int status;
	pid_t pid;

	net_set_nonblock(conn->fd, FALSE);
	input = t_buffer_create(IO_BLOCK_SIZE);

	/* Input contains:

	   VERSION .. <lf>
	   [alarm=<secs> <lf>]
	   "noreply" | "-" (or anything really) <lf>

	   arg 1 <lf>
	   arg 2 <lf>
	   ...
	   <lf>
	   DATA

	   This is quite a horrible protocol. If alarm is specified, it MUST be
	   before "noreply". If "noreply" isn't given, something other string
	   (typically "-") must be given which is eaten away.
	*/		
	alarm(SCRIPT_READ_TIMEOUT_SECS);
	scanpos = 1;
	while (!header_complete) {
		const unsigned char *pos, *end;

		prev_size = input->used;
		buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);

		/* peek in socket input buffer */
		ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
		if (ret <= 0) {
			buffer_set_used_size(input, prev_size);
			if (strchr(str_c(input), '\n') != NULL)
				script_verify_version(t_strcut(str_c(input), '\n'));

			if (ret < 0)
				i_fatal("recv(MSG_PEEK) failed: %m");

			i_fatal("recv(MSG_PEEK) failed: disconnected");
		}

		/* scan for final \n\n */
		pos = CONST_PTR_OFFSET(input->data, scanpos);
		end = CONST_PTR_OFFSET(input->data, prev_size + ret);
		for (; pos < end; pos++) {
			if (pos[-1] == '\n' && pos[0] == '\n') {
				header_complete = TRUE;
				pos++;
				break;
			}
		}
		scanpos = pos - (const unsigned char *)input->data;

		/* read data for real (up to and including \n\n) */
		ret = recv(conn->fd, buf, scanpos-prev_size, 0);
		if (prev_size+ret != scanpos) {
			if (ret < 0)
				i_fatal("recv() failed: %m");
			if (ret == 0)
				i_fatal("recv() failed: disconnected");
			i_fatal("recv() failed: size of definitive recv() differs from peek");
		}
		buffer_set_used_size(input, scanpos);
	}
	alarm(0);

	/* drop the last two LFs */
	buffer_set_used_size(input, scanpos-2);

	args = t_strsplit(str_c(input), "\n");
	script_verify_version(*args); args++;
	t_array_init(&envs, 16);
	if (*args != NULL) {
		const char *p;

		if (str_begins(*args, "alarm=")) {
			unsigned int seconds;
			if (str_to_uint(*args + 6, &seconds) < 0)
				i_fatal("invalid alarm option");
			alarm(seconds);
			args++;
		}
		while (str_begins(*args, "env_")) {
			const char *envname, *env;

			env = t_str_tabunescape(*args+4);
			p = strchr(env, '=');
			if (p == NULL)
				i_fatal("invalid environment variable");
			envname = t_strdup_until(*args+4, p);

			if (str_array_find(accepted_envs, envname))
				array_append(&envs, &env, 1);
			args++;
		}
		if (strcmp(*args, "noreply") == 0) {
			noreply = TRUE;
		}
		if (**args == '\0')
			i_fatal("empty options");
		args++;
	}
	array_append_zero(&envs);

	if (noreply) {
		/* no need to fork and check exit status */
		exec_child(conn, args, array_idx(&envs, 0));
		i_unreached();
	}

	if ((pid = fork()) == (pid_t)-1) {
		i_error("fork() failed: %m");
		return FALSE;
	}

	if (pid == 0) {
		/* child */
		exec_child(conn, args, array_idx(&envs, 0));
		i_unreached();
	}

	/* parent */

	/* check script exit status */
	if (waitpid(pid, &status, 0) < 0) {
		i_error("waitpid() failed: %m");
		return FALSE;
	} else if (WIFEXITED(status)) {
		ret = WEXITSTATUS(status);
		if (ret != 0) {
			i_error("Script terminated abnormally, exit status %d", (int)ret);
			return FALSE;
		}
	} else if (WIFSIGNALED(status)) {
		i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
		return FALSE;
	} else if (WIFSTOPPED(status)) {
		i_fatal("Script stopped, signal %d", WSTOPSIG(status));
		return FALSE;
	} else {
		i_fatal("Script terminated abnormally, return status %d", status);
		return FALSE;
	}
	return TRUE;
}
int rfc2231_parse(struct rfc822_parser_context *ctx,
                  const char *const **result_r)
{
    ARRAY_TYPE(const_string) result;
    ARRAY(struct rfc2231_parameter) rfc2231_params_arr;
    struct rfc2231_parameter rfc2231_param;
    const struct rfc2231_parameter *rfc2231_params;
    const char *key, *value, *p, *p2;
    string_t *str;
    unsigned int i, j, count, next, next_idx;
    bool ok, have_extended, broken = FALSE;
    int ret;

    /* Get a list of all parameters. RFC 2231 uses key*<n>[*]=value pairs,
       which we want to merge to a key[*]=value pair. Save them to a
       separate array. */
    memset(&rfc2231_param, 0, sizeof(rfc2231_param));
    t_array_init(&result, 8);
    t_array_init(&rfc2231_params_arr, 8);
    while ((ret = rfc822_parse_content_param(ctx, &key, &value)) != 0) {
        if (ret < 0) {
            /* try to continue anyway.. */
            broken = TRUE;
            if (ctx->data == ctx->end)
                break;
            ctx->data++;
            continue;
        }
        p = strchr(key, '*');
        if (p != NULL) {
            p2 = p;
            if (p[1] != '\0') {
                p++;
                rfc2231_param.idx = 0;
                for (; *p >= '0' && *p <= '9'; p++) {
                    rfc2231_param.idx =
                        rfc2231_param.idx*10 + *p - '0';
                }
            }
            if (*p != '*')
                rfc2231_param.extended = FALSE;
            else {
                rfc2231_param.extended = TRUE;
                p++;
            }
            if (*p != '\0')
                p = NULL;
            else {
                rfc2231_param.key = t_strdup_until(key, p2);
                rfc2231_param.value = value;
                array_append(&rfc2231_params_arr,
                             &rfc2231_param, 1);
            }
        }
        if (p == NULL) {
            array_append(&result, &key, 1);
            array_append(&result, &value, 1);
        }
    }

    if (array_count(&rfc2231_params_arr) == 0) {
        /* No RFC 2231 parameters */
        array_append_zero(&result); /* NULL-terminate */
        *result_r = array_idx(&result, 0);
        return broken ? -1 : 0;
    }

    /* Merge the RFC 2231 parameters. Since their order isn't guaranteed to
       be ascending, start by sorting them. */
    array_sort(&rfc2231_params_arr, rfc2231_parameter_cmp);
    rfc2231_params = array_get(&rfc2231_params_arr, &count);

    /* keys are now sorted primarily by their name and secondarily by
       their index. If any indexes are missing, fallback to assuming
       these aren't RFC 2231 encoded parameters. */
    str = t_str_new(64);
    for (i = 0; i < count; i = next) {
        ok = TRUE;
        have_extended = FALSE;
        next_idx = 0;
        for (j = i; j < count; j++) {
            if (strcasecmp(rfc2231_params[i].key,
                           rfc2231_params[j].key) != 0)
                break;
            if (rfc2231_params[j].idx != next_idx) {
                /* missing indexes */
                ok = FALSE;
            }
            if (rfc2231_params[j].extended)
                have_extended = TRUE;
            next_idx++;
        }
        next = j;

        if (!ok) {
            /* missing indexes */
            for (j = i; j < next; j++) {
                key = t_strdup_printf(
                          rfc2231_params[j].extended ?
                          "%s*%u*" : "%s*%u",
                          rfc2231_params[j].key,
                          rfc2231_params[j].idx);
                array_append(&result, &key, 1);
                array_append(&result,
                             &rfc2231_params[j].value, 1);
            }
        } else {
            /* everything was successful */
            str_truncate(str, 0);
            if (!rfc2231_params[i].extended && have_extended)
                str_append(str, "''");
            for (j = i; j < next; j++) {
                if (!rfc2231_params[j].extended &&
                        have_extended) {
                    rfc2231_escape(str,
                                   rfc2231_params[j].value);
                } else {
                    str_append(str,
                               rfc2231_params[j].value);
                }
            }
            key = rfc2231_params[i].key;
            if (have_extended)
                key = t_strconcat(key, "*", NULL);
            value = t_strdup(str_c(str));
            array_append(&result, &key, 1);
            array_append(&result, &value, 1);
        }
    }
    array_append_zero(&result); /* NULL-terminate */
    *result_r = array_idx(&result, 0);
    return broken ? -1 : 0;
}
Esempio n. 23
0
static void
service_dup_fds(struct service *service)
{
	struct service_listener *const *listeners;
	ARRAY_TYPE(dup2) dups;
	string_t *listener_settings;
	int fd = MASTER_LISTEN_FD_FIRST;
	unsigned int i, count, socket_listener_count;

	/* stdin/stdout is already redirected to /dev/null. Other master fds
	   should have been opened with fd_close_on_exec() so we don't have to
	   worry about them.

	   because the destination fd might be another one's source fd we have
	   to be careful not to overwrite anything. dup() the fd when needed */

        socket_listener_count = 0;
	listeners = array_get(&service->listeners, &count);
	t_array_init(&dups, count + 10);

	switch (service->type) {
	case SERVICE_TYPE_LOG:
		i_assert(fd == MASTER_LISTEN_FD_FIRST);
		services_log_dup2(&dups, service->list, fd,
				  &socket_listener_count);
		fd += socket_listener_count;
		break;
	case SERVICE_TYPE_ANVIL:
		dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
			    MASTER_ANVIL_LOG_FDPASS_FD);
		/* nonblocking anvil fd must be the first one. anvil treats it
		   as the master's fd */
		dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
		dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
		socket_listener_count += 2;
		break;
	default:
		break;
	}

	/* add listeners */
	listener_settings = t_str_new(256);
	for (i = 0; i < count; i++) {
		if (listeners[i]->fd != -1) {
			str_truncate(listener_settings, 0);
			str_append_tabescaped(listener_settings, listeners[i]->name);

			if (listeners[i]->type == SERVICE_LISTENER_INET) {
				if (listeners[i]->set.inetset.set->ssl)
					str_append(listener_settings, "\tssl");
				if (listeners[i]->set.inetset.set->haproxy)
					str_append(listener_settings, "\thaproxy");
			}
			
			dup2_append(&dups, listeners[i]->fd, fd++);

			env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
				socket_listener_count, str_c(listener_settings)));
			socket_listener_count++;
		}
	}

	if (service->login_notify_fd != -1) {
		dup2_append(&dups, service->login_notify_fd,
			    MASTER_LOGIN_NOTIFY_FD);
	}
	switch (service->type) {
	case SERVICE_TYPE_LOG:
	case SERVICE_TYPE_ANVIL:
	case SERVICE_TYPE_CONFIG:
		dup2_append(&dups, null_fd, MASTER_ANVIL_FD);
		break;
	case SERVICE_TYPE_UNKNOWN:
	case SERVICE_TYPE_LOGIN:
	case SERVICE_TYPE_STARTUP:
		dup2_append(&dups, service_anvil_global->blocking_fd[1],
			    MASTER_ANVIL_FD);
		break;
	}
	dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
	if (service->type != SERVICE_TYPE_ANVIL) {
		dup2_append(&dups, service->list->master_dead_pipe_fd[1],
			    MASTER_DEAD_FD);
	} else {
		dup2_append(&dups, global_master_dead_pipe_fd[1],
			    MASTER_DEAD_FD);
	}

	if (service->type == SERVICE_TYPE_LOG) {
		/* keep stderr as-is. this is especially important when
		   log_path=/dev/stderr, but might be helpful even in other
		   situations for logging startup errors */
	} else {
		/* set log file to stderr. dup2() here immediately so that
		   we can set up logging to it without causing any log messages
		   to be lost. */
		i_assert(service->log_fd[1] != -1);

		env_put("LOG_SERVICE=1");
		if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
			i_fatal("dup2(log fd) failed: %m");
		i_set_failure_internal();
	}

	/* make sure we don't leak syslog fd. try to do it as late as possible,
	   but also before dup2()s in case syslog fd is one of them. */
	closelog();

	if (dup2_array(&dups) < 0)
		i_fatal("service(%s): dup2s failed", service->set->name);

	i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count);
	env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
}
Esempio n. 24
0
static bool parse_x_keywords_real(struct mbox_sync_mail_context *ctx,
				  struct message_header_line *hdr)
{
	struct mailbox *box = &ctx->sync_ctx->mbox->box;
	ARRAY_TYPE(keyword_indexes) keyword_list;
	const unsigned int *list;
	string_t *keyword;
	size_t keyword_start;
	unsigned int i, idx, count;
	size_t pos;

	if (array_is_created(&ctx->mail.keywords))
		return FALSE; /* duplicate header, delete */

	/* read keyword indexes to temporary array first */
	keyword = t_str_new(128);
	t_array_init(&keyword_list, 16);

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

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

		str_truncate(keyword, 0);
		str_append_n(keyword, hdr->full_value + keyword_start,
			     pos - keyword_start);
		if (!mail_index_keyword_lookup(box->index, str_c(keyword),
					       &idx)) {
			/* keyword wasn't found. that means the sent mail
			   originally contained X-Keywords header. Delete it. */
			return FALSE;
		}

		/* check that the keyword isn't already added there.
		   we don't want duplicates. */
		list = array_get(&keyword_list, &count);
		for (i = 0; i < count; i++) {
			if (list[i] == idx)
				break;
		}

		if (i == count)
			array_append(&keyword_list, &idx, 1);
	}

	/* once we know how many keywords there are, we can allocate the array
	   from mail_keyword_pool without wasting memory. */
	if (array_count(&keyword_list) > 0) {
		p_array_init(&ctx->mail.keywords,
			     ctx->sync_ctx->mail_keyword_pool,
			     array_count(&keyword_list));
		array_append_array(&ctx->mail.keywords, &keyword_list);
	}

	ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header);
	parse_trailing_whitespace(ctx, hdr);
	return TRUE;
}
Esempio n. 25
0
int uri_parse_path(struct uri_parser *parser,
		   int *relative_r, const char *const **path_r)
{
	const unsigned char *pbegin = parser->cur;
	ARRAY_TYPE(const_string) segments;
	const char *segment = NULL;
	unsigned int count;
	int relative = 1;
	int ret;

	t_array_init(&segments, 16);

	/* check for a leading '/' and indicate absolute path
	   when it is present
	 */
	if (parser->cur < parser->end && *parser->cur == '/') {
		parser->cur++;
		relative = 0;
	}
	
	/* parse first segment */
	if ((ret = uri_parse_path_segment(parser, &segment)) < 0)
		return -1;
	
	for (;;) {
		if (ret > 0) {
			/* strip dot segments */
			if (segment[0] == '.') {
				if (segment[1] == '.') {
					if (segment[2] == '\0') {
						/* '..' -> skip and... */
						segment = NULL;

						/* ... pop last segment (if any) */
						count = array_count(&segments);
						if (count > 0) {
							array_delete(&segments, count-1, 1);
						} else if ( relative > 0 ) {
							relative++;
						}
					}
				} else if (segment[1] == '\0') {
					/* '.' -> skip */
					segment = NULL;
				}
			}
		} else {
			segment = "";
		}

		if (segment != NULL)
			array_append(&segments, &segment, 1);

		if (parser->cur >= parser->end || *parser->cur != '/')
			break;
		parser->cur++;

		/* parse next path segment */
		if ((ret = uri_parse_path_segment(parser, &segment)) < 0)
			return -1;
	}

	*path_r = NULL;
	*relative_r = relative;

	if (parser->cur == pbegin) {
		/* path part of URI is empty */
		return 0;
	}

	/* special treatment for a trailing '..' or '.' */
	if (segment == NULL) {
		segment = "";
		array_append(&segments, &segment, 1);
	}
	array_append_zero(&segments);
	*path_r = array_get(&segments, &count);
	return 1;
}
Esempio n. 26
0
int main(int argc, char *argv[])
{
	static const struct setting_parser_info *set_roots[] = {
		&imap_urlauth_worker_setting_parser_info,
		NULL
	};
	enum master_service_flags service_flags = 0;
	enum mail_storage_service_flags storage_service_flags =
		MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP |
		MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT;
	ARRAY_TYPE (const_string) access_apps;
	const char *access_user = NULL;
	int c;

	if (IS_STANDALONE()) {
		service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
			MASTER_SERVICE_FLAG_STD_CLIENT;
	} else {
		service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
		storage_service_flags |=
			MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT;
	}

	master_service = master_service_init("imap-urlauth-worker", service_flags,
					     &argc, &argv, "a:");

	t_array_init(&access_apps, 4);
	while ((c = master_getopt(master_service)) > 0) {
		switch (c) {
		case 'a': {
			const char *app = t_strdup(optarg);

			array_append(&access_apps, &app, 1);
			break;
		}
		default:
			return FATAL_DEFAULT;
		}
	}

	if ( optind < argc ) {
		access_user = argv[optind++];
	}

	if (optind != argc) {
		i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
	}

	master_service_init_log(master_service,
				t_strdup_printf("imap-urlauth[%s]: ", my_pid));

	master_service_init_finish(master_service);
	master_service_set_die_callback(master_service, imap_urlauth_worker_die);

	random_init();
	storage_service =
		mail_storage_service_init(master_service,
					  set_roots, storage_service_flags);

	/* fake that we're running, so we know if client was destroyed
	   while handling its initial input */
	io_loop_set_running(current_ioloop);

	if (IS_STANDALONE()) {
		T_BEGIN {
			if (array_count(&access_apps) > 0) {
				(void)array_append_space(&access_apps);
				main_stdio_run(access_user, array_idx(&access_apps,0));
			} else {
				main_stdio_run(access_user, NULL);
			}
		} T_END;
	} else {
Esempio n. 27
0
static void
dsync_cache_fields_update(const struct dsync_mailbox *local_box,
			  const struct dsync_mailbox *remote_box,
			  struct mailbox_update *update)
{
	ARRAY_TYPE(mailbox_cache_field) local_sorted, remote_sorted, changes;
	const struct mailbox_cache_field *local_fields, *remote_fields;
	unsigned int li, ri, local_count, remote_count;
	time_t drop_older_timestamp;
	int ret;

	if (array_count(&remote_box->cache_fields) == 0) {
		/* remote has no cached fields. there's nothing to update. */
		return;
	}

	t_array_init(&local_sorted, array_count(&local_box->cache_fields));
	t_array_init(&remote_sorted, array_count(&remote_box->cache_fields));
	array_append_array(&local_sorted, &local_box->cache_fields);
	array_append_array(&remote_sorted, &remote_box->cache_fields);
	array_sort(&local_sorted, mailbox_cache_field_name_cmp);
	array_sort(&remote_sorted, mailbox_cache_field_name_cmp);

	if (array_count(&local_sorted) == 0) {
		/* local has no cached fields. set them to same as remote. */
		array_append_zero(&remote_sorted);
		update->cache_updates = array_idx(&remote_sorted, 0);
		return;
	}

	/* figure out what to change */
	local_fields = array_get(&local_sorted, &local_count);
	remote_fields = array_get(&remote_sorted, &remote_count);
	t_array_init(&changes, local_count + remote_count);
	drop_older_timestamp = ioloop_time - MAIL_CACHE_FIELD_DROP_SECS;

	for (li = ri = 0; li < local_count || ri < remote_count; ) {
		ret = li == local_count ? 1 :
			ri == remote_count ? -1 :
			strcmp(local_fields[li].name, remote_fields[ri].name);
		if (ret == 0) {
			/* field exists in both local and remote */
			const struct mailbox_cache_field *lf = &local_fields[li];
			const struct mailbox_cache_field *rf = &remote_fields[ri];

			if (lf->last_used > rf->last_used ||
			    (lf->last_used == rf->last_used &&
			     lf->decision > rf->decision)) {
				/* use local decision and timestamp */
			} else {
				array_append(&changes, rf, 1);
			}
			li++; ri++;
		} else if (ret < 0) {
			/* remote field doesn't exist */
			li++;
		} else {
			/* local field doesn't exist */
			if (remote_fields[ri].last_used < drop_older_timestamp) {
				/* field hasn't be used for a long time, remote
				   will probably drop this soon as well */
			} else {
				array_append(&changes, &remote_fields[ri], 1);
			}
			ri++;
		}
	}
	i_assert(li == local_count && ri == remote_count);
	if (array_count(&changes) > 0) {
		array_append_zero(&changes);
		update->cache_updates = array_idx(&changes, 0);
	}
}
bool sieve_extprogram_name_is_valid(string_t *name)
{
	ARRAY_TYPE(unichars) uni_name;
	unsigned int count, i;
	const unichar_t *name_chars;
	size_t namelen = str_len(name);

	/* Check minimum length */
	if ( namelen == 0 )
		return FALSE;

	/* Check worst-case maximum length */
	if ( namelen > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN * 4 )
		return FALSE;

	/* Intialize array for unicode characters */
	t_array_init(&uni_name, namelen * 4);

	/* Convert UTF-8 to UCS4/UTF-32 */
	if ( uni_utf8_to_ucs4_n(str_data(name), namelen, &uni_name) < 0 )
		return FALSE;
	name_chars = array_get(&uni_name, &count);

	/* Check true maximum length */
	if ( count > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN )
		return FALSE;

	/* Scan name for invalid characters
	 *   FIXME: compliance with Net-Unicode Definition (Section 2 of
	 *          RFC 5198) is not checked fully and no normalization
	 *          is performed.
	 */
	for ( i = 0; i < count; i++ ) {

		/* 0000-001F; [CONTROL CHARACTERS] */
		if ( name_chars[i] <= 0x001f )
			return FALSE;

		/* 002F; SLASH */
		if ( name_chars[i] == 0x002f )
			return FALSE;

		/* 007F; DELETE */
		if ( name_chars[i] == 0x007f )
			return FALSE;

		/* 0080-009F; [CONTROL CHARACTERS] */
		if ( name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f )
			return FALSE;

		/* 00FF */
		if ( name_chars[i] == 0x00ff )
			return FALSE;

		/* 2028; LINE SEPARATOR */
		/* 2029; PARAGRAPH SEPARATOR */
		if ( name_chars[i] == 0x2028 || name_chars[i] == 0x2029 )
			return FALSE;
	}

	return TRUE;
}
Esempio n. 29
0
static int
cmd_altmove_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
{
	struct altmove_cmd_context *ctx = (struct altmove_cmd_context *)_ctx;
	const enum mailbox_list_iter_flags iter_flags =
		MAILBOX_LIST_ITER_NO_AUTO_BOXES |
		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
	struct doveadm_mailbox_list_iter *iter;
	const struct mailbox_info *info;
	struct mail_namespace *ns, *prev_ns = NULL;
	ARRAY(struct mail_storage *) purged_storages;
	struct mail_storage *const *storages, *ns_storage, *prev_storage = NULL;
	unsigned int i, count;
	int ret = 0;

	t_array_init(&purged_storages, 8);
	iter = doveadm_mailbox_list_iter_init(_ctx, user, _ctx->search_args,
					      iter_flags);
	while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
		ns_storage = mail_namespace_get_default_storage(info->ns);
		if (ns_storage != prev_storage) {
			if (prev_storage != NULL) {
				if (ns_purge(_ctx, prev_ns, prev_storage) < 0)
					ret = -1;
				array_append(&purged_storages,
					     &prev_storage, 1);
			}
			prev_storage = ns_storage;
			prev_ns = info->ns;
		}
		if (cmd_altmove_box(_ctx, info, _ctx->search_args, ctx->reverse) < 0)
			ret = -1;
	} T_END;
	if (doveadm_mailbox_list_iter_deinit(&iter) < 0)
		ret = -1;

	if (prev_storage != NULL) {
		if (ns_purge(_ctx, prev_ns, prev_storage) < 0)
			ret = -1;
		array_append(&purged_storages, &prev_storage, 1);
	}

	/* make sure all private storages have been purged */
	storages = array_get(&purged_storages, &count);
	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
		if (ns->type != MAIL_NAMESPACE_TYPE_PRIVATE)
			continue;

		ns_storage = mail_namespace_get_default_storage(ns);
		for (i = 0; i < count; i++) {
			if (ns_storage == storages[i])
				break;
		}
		if (i == count) {
			if (ns_purge(_ctx, ns, ns_storage) < 0)
				ret = -1;
			array_append(&purged_storages, &ns_storage, 1);
			storages = array_get(&purged_storages, &count);
		}
	}
	return ret;
}
Esempio n. 30
0
void sieve_jumplist_init_temp
(struct sieve_jumplist *jlist, struct sieve_binary_block *sblock)
{
	jlist->block = sblock;
	t_array_init(&jlist->jumps, 4);
}