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; }
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); }
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; }
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); }
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; }
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; }
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; }
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; }
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); }
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); }
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); }
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); } }
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); }
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; }
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); } }
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(¶ms, 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(¶ms, ¶m, 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(¶ms); *params_r = array_idx(¶ms, 0); } return 1; }
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 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; }