Пример #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;
}
Пример #2
0
static void
exec_child(struct master_service_connection *conn, const char *const *args)
{
	unsigned int i, socket_count;

	if (dup2(conn->fd, STDIN_FILENO) < 0)
		i_fatal("dup2() failed: %m");
	if (dup2(conn->fd, STDOUT_FILENO) < 0)
		i_fatal("dup2() failed: %m");

	/* close all fds */
	socket_count = master_service_get_socket_count(master_service);
	for (i = 0; i < socket_count; i++) {
		if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
			i_error("close(listener) failed: %m");
	}
	if (close(MASTER_STATUS_FD) < 0)
		i_error("close(status) failed: %m");
	if (close(conn->fd) < 0)
		i_error("close(conn->fd) failed: %m");

	for (; *args != NULL; args++)
		array_append(&exec_args, args, 1);
	array_append_zero(&exec_args);

	env_clean();
	args = array_idx(&exec_args, 0);
	execvp_const(args[0], args);
}
Пример #3
0
struct istream *
istream_attachment_connector_finish(struct istream_attachment_connector **_conn)
{
	struct istream_attachment_connector *conn = *_conn;
	struct istream **inputs, *input;
	uoff_t trailer_size;

	*_conn = NULL;

	if (conn->base_input_offset != conn->msg_size) {
		i_assert(conn->base_input_offset < conn->msg_size);

		trailer_size = conn->msg_size - conn->encoded_offset;
		input = i_stream_create_range(conn->base_input,
					      conn->base_input_offset,
					      trailer_size);
		array_append(&conn->streams, &input, 1);
	}
	array_append_zero(&conn->streams);

	inputs = array_idx_modifiable(&conn->streams, 0);
	input = i_stream_create_concat(inputs);

	i_stream_unref(&conn->base_input);
	pool_unref(&conn->pool);
	return input;
}
Пример #4
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);
}
Пример #5
0
int pop3c_sync_get_uidls(struct pop3c_mailbox *mbox)
{
	ARRAY_TYPE(const_string) uidls;
	struct istream *input;
	const char *error, *cline;
	char *line, *p;
	unsigned int seq, line_seq;

	if (mbox->msg_uidls != NULL)
		return 0;
	if ((pop3c_client_get_capabilities(mbox->client) &
	     POP3C_CAPABILITY_UIDL) == 0) {
		mail_storage_set_error(mbox->box.storage,
				       MAIL_ERROR_NOTPOSSIBLE,
				       "UIDLs not supported by server");
		return -1;
	}

	if (pop3c_client_cmd_stream(mbox->client, "UIDL\r\n",
				    &input, &error) < 0) {
		mail_storage_set_critical(mbox->box.storage,
					  "UIDL failed: %s", error);
		return -1;
	}

	mbox->uidl_pool = pool_alloconly_create("POP3 UIDLs", 1024*32);
	p_array_init(&uidls, mbox->uidl_pool, 64); seq = 0;
	while ((line = i_stream_read_next_line(input)) != NULL) {
		seq++;
		p = strchr(line, ' ');
		if (p == NULL) {
			mail_storage_set_critical(mbox->box.storage,
				"Invalid UIDL line: %s", line);
			break;
		}
		*p++ = '\0';
		if (str_to_uint(line, &line_seq) < 0 || line_seq != seq) {
			mail_storage_set_critical(mbox->box.storage,
				"Unexpected UIDL seq: %s != %u", line, seq);
			break;
		}

		cline = p_strdup(mbox->uidl_pool, p);
		array_append(&uidls, &cline, 1);
	}
	i_stream_destroy(&input);
	if (line != NULL) {
		pool_unref(&mbox->uidl_pool);
		return -1;
	}
	if (seq == 0) {
		/* make msg_uidls non-NULL */
		array_append_zero(&uidls);
	}
	mbox->msg_uidls = array_idx(&uidls, 0);
	mbox->msg_count = seq;
	return 0;
}
Пример #6
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;
}
Пример #7
0
static int
config_read_reply_header(struct istream *istream, const char *path, pool_t pool,
			 const struct master_service_settings_input *input,
			 struct master_service_settings_output *output_r,
			 const char **error_r)
{
	const char *line;
	ssize_t ret;

	while ((ret = i_stream_read(istream)) > 0) {
		line = i_stream_next_line(istream);
		if (line != NULL)
			break;
	}
	if (ret <= 0) {
		if (ret == 0)
			return 1;
		*error_r = istream->stream_errno != 0 ?
			t_strdup_printf("read(%s) failed: %s", path,
					i_stream_get_error(istream)) :
			t_strdup_printf("read(%s) failed: EOF", path);
		return -1;
	}

	T_BEGIN {
		const char *const *arg = t_strsplit_tabescaped(line);
		ARRAY_TYPE(const_string) services;

		p_array_init(&services, pool, 8);
		for (; *arg != NULL; arg++) {
			if (strcmp(*arg, "service-uses-local") == 0)
				output_r->service_uses_local = TRUE;
			else if (strcmp(*arg, "service-uses-remote") == 0)
				output_r->service_uses_remote = TRUE;
			if (strcmp(*arg, "used-local") == 0)
				output_r->used_local = TRUE;
			else if (strcmp(*arg, "used-remote") == 0)
				output_r->used_remote = TRUE;
			else if (strncmp(*arg, "service=", 8) == 0) {
				const char *name = p_strdup(pool, *arg + 8);
				array_append(&services, &name, 1);
			 }
		}
		if (input->service == NULL) {
			array_append_zero(&services);
			output_r->specific_services = array_idx(&services, 0);
		}
	} T_END;
	return 0;
}
Пример #8
0
bool client_parse_mail_flags(struct client_command_context *cmd,
			     const struct imap_arg *args,
			     enum mail_flags *flags_r,
			     const char *const **keywords_r)
{
	const char *atom;
	enum mail_flags flag;
	ARRAY(const char *) keywords;

	*flags_r = 0;
	*keywords_r = NULL;
	p_array_init(&keywords, cmd->pool, 16);

	while (!IMAP_ARG_IS_EOL(args)) {
		if (!imap_arg_get_atom(args, &atom)) {
			client_send_command_error(cmd,
				"Flags list contains non-atoms.");
			return FALSE;
		}

		if (*atom == '\\') {
			/* system flag */
			atom = t_str_ucase(atom);
			flag = imap_parse_system_flag(atom);
			if (flag != 0 && flag != MAIL_RECENT)
				*flags_r |= flag;
			else {
				client_send_command_error(cmd, t_strconcat(
					"Invalid system flag ", atom, NULL));
				return FALSE;
			}
		} else {
			/* keyword validity checks are done by lib-storage */
			array_append(&keywords, &atom, 1);
		}

		args++;
	}

	if (array_count(&keywords) == 0)
		*keywords_r = NULL;
	else {
		array_append_zero(&keywords); /* NULL-terminate */
		*keywords_r = array_idx(&keywords, 0);
	}
	return TRUE;
}
Пример #9
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);
}
Пример #10
0
static void cmd_dsync_init(struct doveadm_mail_cmd_context *_ctx,
			   const char *const args[])
{
	struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;

	if (ctx->default_replica_location) {
		if (args[0] != NULL)
			i_error("Don't give mail location with -d parameter");
	} else {
		if (args[0] == NULL)
			doveadm_mail_help_name(_ctx->cmd->name);
	}
	if (array_count(&ctx->exclude_mailboxes) > 0)
		array_append_zero(&ctx->exclude_mailboxes);

	lib_signals_ignore(SIGHUP, TRUE);
}
Пример #11
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;
}
static void cmd_flags_init(struct doveadm_mail_cmd_context *_ctx,
			   const char *const args[])
{
	struct flags_cmd_context *ctx = (struct flags_cmd_context *)_ctx;
	const char *const *tmp;
	enum mail_flags flag;
	ARRAY_TYPE(const_string) keywords;

	if (args[0] == NULL || args[1] == NULL) {
		switch (ctx->modify_type) {
		case MODIFY_ADD:
			doveadm_mail_help_name("flags add");
		case MODIFY_REMOVE:
			doveadm_mail_help_name("flags remove");
		case MODIFY_REPLACE:
			doveadm_mail_help_name("flags replace");
		}
		i_unreached();
	}

	p_array_init(&keywords, _ctx->pool, 8);
	for (tmp = t_strsplit(args[0], " "); *tmp != NULL; tmp++) {
		const char *str = *tmp;

		if (str[0] == '\\') {
			flag = imap_parse_system_flag(str);
			if (flag == 0)
				i_fatal("Invalid system flag: %s", str);
			ctx->flags |= flag;
		} else {
			str = p_strdup(_ctx->pool, str);
			array_append(&keywords, &str, 1);
		}
	}
	if (array_count(&keywords) > 0 || ctx->modify_type == MODIFY_REPLACE) {
		array_append_zero(&keywords);
		ctx->keywords = array_idx(&keywords, 0);
	}

	_ctx->search_args = doveadm_mail_build_search_args(args+1);
}
Пример #13
0
void io_loop_handle_add(struct io_file *io)
{
	struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
	struct io_list **list;
	struct epoll_event event;
	int op;
	bool first;

	list = array_idx_modifiable(&ctx->fd_index, io->fd);
	if (*list == NULL)
		*list = i_new(struct io_list, 1);

	first = ioloop_iolist_add(*list, io);

	memset(&event, 0, sizeof(event));
	event.data.ptr = *list;
	event.events = epoll_event_mask(*list);

	op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;

	if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
		if (errno == EPERM && op == EPOLL_CTL_ADD) {
			i_fatal("epoll_ctl(add, %d) failed: %m "
				"(fd doesn't support epoll%s)", io->fd,
				io->fd != STDIN_FILENO ? "" :
				" - instead of '<file', try 'cat file|'");
		}
		i_panic("epoll_ctl(%s, %d) failed: %m",
			op == EPOLL_CTL_ADD ? "add" : "mod", io->fd);
	}

	if (first) {
		/* allow epoll_wait() to return the maximum number of events
		   by keeping space allocated for each file descriptor */
		if (ctx->deleted_count > 0)
			ctx->deleted_count--;
		else
			array_append_zero(&ctx->events);
	}
}
Пример #14
0
void io_loop_handle_add(struct io_file *io)
{
	struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
	struct kevent ev;

	if ((io->io.condition & (IO_READ | IO_ERROR)) != 0) {
		MY_EV_SET(&ev, io->fd, EVFILT_READ, EV_ADD, 0, 0, io);
		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
			i_fatal("kevent(EV_ADD, READ, %d) failed: %m", io->fd);
	}
	if ((io->io.condition & IO_WRITE) != 0) {
		MY_EV_SET(&ev, io->fd, EVFILT_WRITE, EV_ADD, 0, 0, io);
		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
			i_fatal("kevent(EV_ADD, WRITE, %d) failed: %m", io->fd);
	}

	/* allow kevent() to return the maximum number of events
	   by keeping space allocated for each handle */
	if (ctx->deleted_count > 0)
		ctx->deleted_count--;
	else
		array_append_zero(&ctx->events);
}
Пример #15
0
static int config_connection_request(struct config_connection *conn,
				     const char *const *args)
{
	struct config_export_context *ctx;
	struct master_service_settings_output output;
	struct config_filter filter;
	const char *path, *error, *module, *const *wanted_modules;
	ARRAY(const char *) modules;
	bool is_master = FALSE;

	/* [<args>] */
	t_array_init(&modules, 4);
	memset(&filter, 0, sizeof(filter));
	for (; *args != NULL; args++) {
		if (strncmp(*args, "service=", 8) == 0)
			filter.service = *args + 8;
		else if (strncmp(*args, "module=", 7) == 0) {
			module = *args + 7;
			if (strcmp(module, "master") == 0)
				is_master = TRUE;
			array_append(&modules, &module, 1);
		} else if (strncmp(*args, "lname=", 6) == 0)
			filter.local_name = *args + 6;
		else if (strncmp(*args, "lip=", 4) == 0) {
			if (net_addr2ip(*args + 4, &filter.local_net) == 0) {
				filter.local_bits =
					IPADDR_IS_V4(&filter.local_net) ?
					32 : 128;
			}
		} else if (strncmp(*args, "rip=", 4) == 0) {
			if (net_addr2ip(*args + 4, &filter.remote_net) == 0) {
				filter.remote_bits =
					IPADDR_IS_V4(&filter.remote_net) ?
					32 : 128;
			}
		}
	}
	array_append_zero(&modules);
	wanted_modules = array_count(&modules) == 1 ? NULL :
		array_idx(&modules, 0);

	if (is_master) {
		/* master reads configuration only when reloading settings */
		path = master_service_get_config_path(master_service);
		if (config_parse_file(path, TRUE, NULL, &error) <= 0) {
			o_stream_nsend_str(conn->output,
				t_strconcat("\nERROR ", error, "\n", NULL));
			config_connection_destroy(conn);
			return -1;
		}
	}

	o_stream_cork(conn->output);

	ctx = config_export_init(wanted_modules, CONFIG_DUMP_SCOPE_SET, 0,
				 config_request_output, conn->output);
	config_export_by_filter(ctx, &filter);
	config_export_get_output(ctx, &output);

	if (output.specific_services != NULL) {
		const char *const *s;

		for (s = output.specific_services; *s != NULL; s++) {
			o_stream_nsend_str(conn->output,
				t_strdup_printf("service=%s\t", *s));
		}
	}
	if (output.service_uses_local)
		o_stream_nsend_str(conn->output, "service-uses-local\t");
	if (output.service_uses_remote)
		o_stream_nsend_str(conn->output, "service-uses-remote\t");
	if (output.used_local)
		o_stream_nsend_str(conn->output, "used-local\t");
	if (output.used_remote)
		o_stream_nsend_str(conn->output, "used-remote\t");
	o_stream_nsend_str(conn->output, "\n");

	if (config_export_finish(&ctx) < 0) {
		config_connection_destroy(conn);
		return -1;
	}
	o_stream_nsend_str(conn->output, "\n");
	o_stream_uncork(conn->output);
	return 0;
}
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;
}
Пример #17
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);
	}
}
Пример #18
0
static int smtp_parse_ehlo_line(struct smtp_parser *parser,
	const char **key_r, const char *const **params_r)
{
	const unsigned char *pbegin = parser->cur;
	ARRAY_TYPE(const_string) params = ARRAY_INIT;
	const char *param;

	/*
	   ehlo-line      = ehlo-keyword *( SP ehlo-param )
	   ehlo-keyword   = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
	                    ; additional syntax of ehlo-params depends on
	                    ; ehlo-keyword
	   ehlo-param     = 1*(%d33-126)
	                    ; any CHAR excluding <SP> and all
	                    ; control characters (US-ASCII 0-31 and 127
	                    ; inclusive)
	 */

	if (parser->cur >= parser->end || !i_isalnum(*parser->cur)) {
		parser->error = "Unexpected character in EHLO keyword";
		return -1;
	}
	parser->cur++;

	while (parser->cur < parser->end &&
		(i_isalnum(*parser->cur) || *parser->cur == '-'))
		parser->cur++;

	if (key_r != NULL)
		*key_r = p_strdup_until(parser->pool, pbegin, parser->cur);

	if (parser->cur >= parser->end) {
		if (params_r != NULL)
			*params_r = p_new(parser->pool, const char *, 1);
		return 1;
	}
	if (*parser->cur != ' ') {
		parser->error = "Unexpected character in EHLO keyword";
		return -1;
	}
	parser->cur++;

	pbegin = parser->cur;
	if (params_r != NULL)
		p_array_init(&params, parser->pool, 32);
	while (parser->cur < parser->end) {
		if (*parser->cur == ' ') {
			if (parser->cur+1 >= parser->end || *(parser->cur+1) == ' ') {
				parser->error = "Missing EHLO parameter after ' '";
				return -1;
			}
			if (params_r != NULL) {
				param = p_strdup_until(parser->pool, pbegin, parser->cur);
				array_append(&params, &param, 1);
			}
			pbegin = parser->cur + 1;
		} else if (!smtp_char_is_ehlo_param(*parser->cur)) {
			parser->error = "Unexpected character in EHLO parameter";
			return -1;
		}
		parser->cur++;
	}

	if (params_r != NULL) {
		array_append_zero(&params);
		*params_r = array_idx(&params, 0);
	}
	return 1;
}
Пример #19
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;
}
Пример #20
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;
}