static struct userdb_module * passwd_file_preinit(pool_t pool, const char *args) { struct passwd_file_userdb_module *module; const char *format = PASSWD_FILE_DEFAULT_USERNAME_FORMAT; const char *p; if (strncmp(args, "username_format=", 16) == 0) { args += 16; p = strchr(args, ' '); if (p == NULL) { format = p_strdup(pool, args); args = ""; } else { format = p_strdup_until(pool, args, p); args = p + 1; } } if (*args == '\0') i_fatal("userdb passwd-file: Missing args"); module = p_new(pool, struct passwd_file_userdb_module, 1); module->pwf = db_passwd_file_init(args, TRUE, global_auth_settings->debug); module->username_format = format; return &module->module; }
static int http_request_parse_target(struct http_request_parser *parser) { struct http_message_parser *_parser = &parser->parser; const unsigned char *p = parser->parser.cur; /* We'll just parse anything up to the first SP or a control char. We could also implement workarounds for buggy HTTP clients and parse anything up to the HTTP-version and return 301 with the target properly encoded (FIXME). */ while (p < _parser->end && *p > ' ') p++; /* target is too long when explicit limit is exceeded or when input buffer runs out of space */ /* FIXME: put limit on full request line rather than target and method separately */ /* FIXME: is it wise to keep target in stream buffer? It can become very large for some applications, increasing the stream buffer size */ if ((uoff_t)(p - _parser->cur) > parser->max_target_length || (p == _parser->end && ((uoff_t)(p - _parser->cur) >= i_stream_get_max_buffer_size(_parser->input)))) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG; parser->parser.error = "HTTP request target is too long"; return -1; } if (p == _parser->end) return 0; parser->request_target = p_strdup_until(_parser->msg.pool, _parser->cur, p); parser->parser.cur = p; return 1; }
static void mail_filter_parse_setting(struct mail_user *user, const char *name, const char **socket_path_r, const char **args_r) { const char *value, *p; value = mail_user_plugin_getenv(user, name); if (value == NULL) return; p = strchr(value, ' '); if (p == NULL) { *socket_path_r = p_strdup(user->pool, value); *args_r = ""; } else { *socket_path_r = p_strdup_until(user->pool, value, p); *args_r = p_strdup(user->pool, p + 1); } if (**socket_path_r != '/') { /* relative to base_dir */ *socket_path_r = p_strdup_printf(user->pool, "%s/%s", user->set->base_dir, *socket_path_r); } if (user->mail_debug) { i_debug("mail_filter: Filtering %s via socket %s", name, *socket_path_r); } }
const char *p_str_rtrim(pool_t pool, const char *str, const char *chars) { const char *begin, *end; str_trim_parse(str, chars, STR_TRIM_RIGHT, &begin, &end); if (begin == NULL) return ""; return p_strdup_until(pool, begin, end); }
static int http_request_parse_method(struct http_request_parser *parser) { const unsigned char *p = parser->parser.cur; /* method = token */ while (p < parser->parser.end && http_char_is_token(*p)) p++; if ((p - parser->parser.cur) > HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG; parser->parser.error = "HTTP request method is too long"; return -1; } if (p == parser->parser.end) return 0; parser->request_method = p_strdup_until(parser->parser.msg.pool, parser->parser.cur, p); parser->parser.cur = p; return 1; }
int str_unescape_next(const char **str, const char **unescaped_r) { const char *p; char *escaped; bool esc_found = FALSE; for (p = *str; *p != '\0'; p++) { if (*p == '"') break; else if (*p == '\\') { if (p[1] == '\0') return -1; esc_found = TRUE; p++; } } if (*p != '"') return -1; escaped = p_strdup_until(unsafe_data_stack_pool, *str, p); *str = p+1; *unescaped_r = !esc_found ? escaped : str_unescape(escaped); return 0; }
static bool lsb_distro_get(const char *path, const char **name_r) { const char *data, *const *p, *str, *end; if (!readfile(path, &data)) return FALSE; for (p = t_strsplit(data, "\n"); *p != NULL; p++) { if (strncmp(*p, "DISTRIB_DESCRIPTION=", 20) == 0) break; } if (*p == NULL) return FALSE; str = t_strcut(*p + 20, '\n'); if (*str != '"') *name_r = str; else { end = strrchr(++str, '"'); *name_r = str_unescape(p_strdup_until(unsafe_data_stack_pool, str, end)); } return TRUE; }
static int maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field, const char **value_r) { struct index_mail *mail = (struct index_mail *)_mail; struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box; const char *path, *fname = NULL, *end, *guid, *uidl, *order; struct stat st; switch (field) { case MAIL_FETCH_GUID: /* use GUID from uidlist if it exists */ i_assert(!_mail->saving); if (mail->data.guid != NULL) { *value_r = mail->data.guid; return 0; } /* first make sure that we have a refreshed uidlist */ if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0) return -1; guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_GUID); if (guid != NULL) { if (*guid != '\0') { *value_r = mail->data.guid = p_strdup(mail->mail.data_pool, guid); return 0; } mail_storage_set_critical(_mail->box->storage, "Maildir %s: Corrupted dovecot-uidlist: " "UID %u had empty GUID, clearing it", mailbox_get_path(_mail->box), _mail->uid); maildir_uidlist_unset_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_GUID); } /* default to base filename: */ if (maildir_mail_get_special(_mail, MAIL_FETCH_STORAGE_ID, value_r) < 0) return -1; mail->data.guid = mail->data.filename; return 0; case MAIL_FETCH_STORAGE_ID: if (mail->data.filename != NULL) { *value_r = mail->data.filename; return 0; } if (fname != NULL) { /* we came here from MAIL_FETCH_GUID, avoid a second lookup */ } else if (!_mail->saving) { if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0) return -1; } else { path = maildir_save_file_get_path(_mail->transaction, _mail->seq); fname = strrchr(path, '/'); fname = fname != NULL ? fname + 1 : path; } end = strchr(fname, MAILDIR_INFO_SEP); mail->data.filename = end == NULL ? p_strdup(mail->mail.data_pool, fname) : p_strdup_until(mail->mail.data_pool, fname, end); *value_r = mail->data.filename; return 0; case MAIL_FETCH_UIDL_BACKEND: uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_POP3_UIDL); if (uidl == NULL) { /* use the default */ *value_r = ""; } else if (*uidl == '\0') { /* special optimization case: use the base file name */ return maildir_mail_get_special(_mail, MAIL_FETCH_STORAGE_ID, value_r); } else { *value_r = p_strdup(mail->mail.data_pool, uidl); } return 0; case MAIL_FETCH_POP3_ORDER: order = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_POP3_ORDER); if (order == NULL) { *value_r = ""; } else { *value_r = p_strdup(mail->mail.data_pool, order); } return 0; case MAIL_FETCH_REFCOUNT: if (maildir_mail_stat(_mail, &st) < 0) return -1; *value_r = p_strdup_printf(mail->mail.data_pool, "%lu", (unsigned long)st.st_nlink); return 0; default: return index_mail_get_special(_mail, field, value_r); } }
bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx) { struct imap_fetch_body_data *body; const struct imap_arg *list_args; unsigned int list_count; const char *str, *p, *error; i_assert(strncmp(ctx->name, "BINARY", 6) == 0); p = ctx->name + 6; body = p_new(ctx->pool, struct imap_fetch_body_data, 1); body->binary = TRUE; if (strncmp(p, ".SIZE", 5) == 0) { /* fetch decoded size of the section */ p += 5; body->binary_size = TRUE; } else if (strncmp(p, ".PEEK", 5) == 0) { p += 5; } else { ctx->fetch_ctx->flags_update_seen = TRUE; } if (*p != '[') { ctx->error = "Invalid BINARY[..] parameter: Missing '['"; return FALSE; } if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) { /* BINARY[HEADER.FIELDS.. (headers list)] */ if (!imap_arg_get_atom(&ctx->args[1], &str) || str[0] != ']') { ctx->error = "Invalid BINARY[..] parameter: Missing ']'"; return FALSE; } if (body_header_fields_parse(ctx, body, p+1, list_args, list_count) < 0) return FALSE; p = str+1; ctx->args += 2; } else { /* no headers list */ body->section = p+1; p = strchr(body->section, ']'); if (p == NULL) { ctx->error = "Invalid BINARY[..] parameter: Missing ']'"; return FALSE; } body->section = p_strdup_until(ctx->pool, body->section, p); p++; } if (imap_msgpart_parse(body->section, &body->msgpart) < 0) { ctx->error = "Invalid BINARY[..] section"; return FALSE; } imap_msgpart_set_decode_to_binary(body->msgpart); ctx->fetch_ctx->fetch_data |= imap_msgpart_get_fetch_data(body->msgpart); if (!body->binary_size) { if (body_parse_partial(body, p, &error) < 0) { ctx->error = p_strdup_printf(ctx->pool, "Invalid BINARY[..] parameter: %s", error); return FALSE; } } /* update the section name for the imap_fetch_add_handler() */ ctx->name = p_strdup(ctx->pool, get_body_name(body)); if (body->binary_size) { imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT, "0", fetch_binary_size, body); } else { imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT, "NIL", fetch_body_msgpart, body); } return TRUE; }
static void mech_apop_auth_initial(struct auth_request *auth_request, const unsigned char *data, size_t data_size) { struct apop_auth_request *request = (struct apop_auth_request *)auth_request; const unsigned char *tmp, *end, *username = NULL; unsigned long pid, connect_uid, timestamp; const char *error; /* pop3-login handles sending the challenge and getting the response. Our input here is: <challenge> \0 <username> \0 <response> */ if (data_size == 0) { /* Should never happen */ auth_request_log_info(auth_request, "apop", "no initial respone"); auth_request_fail(auth_request); return; } tmp = data; end = data + data_size; /* get the challenge */ while (tmp != end && *tmp != '\0') tmp++; request->challenge = p_strdup_until(request->pool, data, tmp); if (tmp != end) { /* get the username */ username = ++tmp; while (tmp != end && *tmp != '\0') tmp++; } if (tmp + 1 + 16 != end) { /* Should never happen */ auth_request_log_info(auth_request, "apop", "malformed data"); auth_request_fail(auth_request); return; } memcpy(request->response_digest, tmp + 1, sizeof(request->response_digest)); /* the challenge must begin with trusted unique ID. we trust only ourself, so make sure it matches our connection specific UID which we told to client in handshake. Also require a timestamp which is later than this process's start time. */ if (sscanf(request->challenge, "<%lx.%lx.%lx.", &pid, &connect_uid, ×tamp) != 3 || connect_uid != auth_request->connect_uid || pid != (unsigned long)getpid() || (time_t)timestamp < process_start_time) { auth_request_log_info(auth_request, "apop", "invalid challenge"); auth_request_fail(auth_request); return; } if (!auth_request_set_username(auth_request, (const char *)username, &error)) { auth_request_log_info(auth_request, "apop", "%s", error); auth_request_fail(auth_request); return; } auth_request_lookup_credentials(auth_request, "PLAIN", apop_credentials_callback); }
static int virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line, const char **error_r) { struct mail_user *user = ctx->mbox->storage->storage.user; struct virtual_backend_box *bbox; const char *p; bool no_wildcards = FALSE; if (*line == ' ' || *line == '\t') { /* continues the previous search rule */ if (ctx->rule_idx == array_count(&ctx->mbox->backend_boxes)) { *error_r = "Search rule without a mailbox"; return -1; } while (*line == ' ' || *line == '\t') line++; str_append_c(ctx->rule, ' '); str_append(ctx->rule, line); return 0; } /* if there is no rule yet, it means we want the previous mailboxes to use the rule that comes later */ if (str_len(ctx->rule) > 0) { if (virtual_config_add_rule(ctx, error_r) < 0) return -1; } if (!uni_utf8_str_is_valid(line)) { *error_r = t_strdup_printf("Mailbox name not UTF-8: %s", line); return -1; } /* new mailbox. the search args are added to it later. */ bbox = p_new(ctx->pool, struct virtual_backend_box, 1); bbox->virtual_mbox = ctx->mbox; if (strcasecmp(line, "INBOX") == 0) line = "INBOX"; bbox->name = p_strdup(ctx->pool, line); switch (bbox->name[0]) { case '+': bbox->name++; bbox->clear_recent = TRUE; break; case '-': bbox->name++; bbox->negative_match = TRUE; break; case '!': /* save messages here */ if (ctx->mbox->save_bbox != NULL) { *error_r = "Multiple save mailboxes defined"; return -1; } bbox->name++; ctx->mbox->save_bbox = bbox; no_wildcards = TRUE; break; } if (bbox->name[0] == '/') { /* [+-!]/metadata entry:value */ if ((p = strchr(bbox->name, ':')) == NULL) { *error_r = "':' separator missing between metadata entry name and value"; return -1; } bbox->metadata_entry = p_strdup_until(ctx->pool, bbox->name, p++); bbox->metadata_value = p; if (!imap_metadata_verify_entry_name(bbox->metadata_entry, error_r)) return -1; no_wildcards = TRUE; } if (!no_wildcards && (strchr(bbox->name, '*') != NULL || strchr(bbox->name, '%') != NULL)) { bbox->glob = imap_match_init(ctx->pool, bbox->name, TRUE, ctx->sep); ctx->have_wildcards = TRUE; } if (bbox->metadata_entry == NULL) { /* now that the prefix characters have been processed, find the namespace */ bbox->ns = strcasecmp(bbox->name, "INBOX") == 0 ? mail_namespace_find_inbox(user->namespaces) : mail_namespace_find(user->namespaces, bbox->name); if (bbox->ns == NULL) { *error_r = t_strdup_printf("Namespace not found for %s", bbox->name); return -1; } if (strcmp(bbox->name, ctx->mbox->box.vname) == 0) { *error_r = "Virtual mailbox can't point to itself"; return -1; } ctx->have_mailbox_defines = TRUE; } array_append(&ctx->mbox->backend_boxes, &bbox, 1); return 0; }
const char *t_strdup_until(const void *start, const void *end) { return p_strdup_until(unsafe_data_stack_pool, start, end); }
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; }
const char *message_id_get_next(const char **msgid_p) { const char *msgid = *msgid_p; const char *p; string_t *str = NULL; bool found_at; if (*msgid_p == NULL) return NULL; for (;;) { /* skip until '<' */ while (*msgid != '<') { if (*msgid == '\0') { *msgid_p = msgid; return NULL; } msgid++; } msgid++; /* check it through quickly to see if it's already normalized */ p = msgid; found_at = FALSE; for (;; p++) { if ((unsigned char)*p >= 'A') /* matches most */ continue; if (*p == '@') found_at = TRUE; if (*p == '>' || *p == '"' || *p == '(' || *p == '[') break; if (*p == '\0') { *msgid_p = p; return NULL; } } if (*p == '>') { *msgid_p = p+1; if (found_at) { char *s; s = p_strdup_until(unsafe_data_stack_pool, msgid, p); strip_lwsp(s); return s; } } else { /* ok, do it the slow way */ *msgid_p = msgid; if (str == NULL) { /* allocate only once, so we don't leak with multiple invalid message IDs */ str = t_str_new(256); } if (get_untokenized_msgid(msgid_p, str)) return str_c(str); } /* invalid message id, see if there's another valid one */ msgid = *msgid_p; } }
char *i_strdup_until(const void *str, const void *end) { return p_strdup_until(default_pool, str, end); }