http_mime::~http_mime() { if (mime_state_) mime_state_free(mime_state_); std::list<http_mime_node*>::iterator it = mime_nodes_.begin(); for (; it != mime_nodes_.end(); ++it) delete *it; }
void cleanup_state_free(CLEANUP_STATE *state) { vstring_free(state->attr_buf); vstring_free(state->temp1); vstring_free(state->temp2); if (cleanup_strip_chars) vstring_free(state->stripped_buf); if (state->fullname) myfree(state->fullname); if (state->sender) myfree(state->sender); if (state->recip) myfree(state->recip); if (state->orig_rcpt) myfree(state->orig_rcpt); if (state->return_receipt) myfree(state->return_receipt); if (state->errors_to) myfree(state->errors_to); argv_free(state->auto_hdrs); if (state->hbc_rcpt) argv_free(state->hbc_rcpt); if (state->queue_name) myfree(state->queue_name); if (state->queue_id) myfree(state->queue_id); been_here_free(state->dups); if (state->reason) myfree(state->reason); if (state->smtp_reply) myfree(state->smtp_reply); nvtable_free(state->attr); if (state->mime_state) mime_state_free(state->mime_state); if (state->filter) myfree(state->filter); if (state->redirect) myfree(state->redirect); if (state->dsn_envid) myfree(state->dsn_envid); if (state->dsn_orcpt) myfree(state->dsn_orcpt); if (state->verp_delims) myfree(state->verp_delims); if (state->milters) milter_free(state->milters); if (state->milter_ext_from) vstring_free(state->milter_ext_from); if (state->milter_ext_rcpt) vstring_free(state->milter_ext_rcpt); if (state->milter_err_text) vstring_free(state->milter_err_text); cleanup_region_done(state); myfree((void *) state); }
http_mime::~http_mime() { if (boundary_) acl_myfree(boundary_); if (save_path_) acl_myfree(save_path_); if (mime_state_) mime_state_free(mime_state_); std::list<http_mime_node*>::iterator it = mime_nodes_.begin(); for (; it != mime_nodes_.end(); ++it) delete *it; }
void smtp_session_free(SMTP_SESSION *session) { #ifdef USE_TLS if (session->stream) { vstream_fflush(session->stream); if (session->tls_context) tls_client_stop(smtp_tls_ctx, session->stream, var_smtp_starttls_tmout, 0, session->tls_context); } if (session->tls_protocols) myfree(session->tls_protocols); if (session->tls_grade) myfree(session->tls_grade); if (session->tls_exclusions) vstring_free(session->tls_exclusions); if (session->tls_matchargv) argv_free(session->tls_matchargv); #endif if (session->stream) vstream_fclose(session->stream); myfree(session->dest); myfree(session->host); myfree(session->addr); myfree(session->namaddr); myfree(session->namaddrport); if (session->helo) myfree(session->helo); vstring_free(session->buffer); vstring_free(session->scratch); vstring_free(session->scratch2); if (session->history) smtp_chat_reset(session); if (session->mime_state) mime_state_free(session->mime_state); #ifdef USE_SASL_AUTH smtp_sasl_cleanup(session); #endif debug_peer_restore(); myfree((char *) session); }
void smtp_session_free(SMTP_SESSION *session) { #ifdef USE_TLS if (session->stream) { vstream_fflush(session->stream); } if (session->tls_context) { if (session->features & (SMTP_FEATURE_FROM_CACHE | SMTP_FEATURE_FROM_PROXY)) tls_proxy_context_free(session->tls_context); else tls_client_stop(smtp_tls_ctx, session->stream, var_smtp_starttls_tmout, 0, session->tls_context); } #endif if (session->stream) vstream_fclose(session->stream); myfree(session->namaddr); myfree(session->namaddrport); if (session->helo) myfree(session->helo); vstring_free(session->buffer); vstring_free(session->scratch); vstring_free(session->scratch2); if (session->history) smtp_chat_reset(session); if (session->mime_state) mime_state_free(session->mime_state); #ifdef USE_SASL_AUTH smtp_sasl_cleanup(session); #endif debug_peer_restore(); myfree((void *) session); }
int main(int argc, char **argv) { int rec_type; VSTRING *buf; int err; MIME_STATE *mime_state; HBC_TEST_CONTEXT context; static HBC_CALL_BACKS call_backs[1] = { log_cb, /* logger */ out_cb, /* prepend */ }; /* * Sanity check. */ if (argc != 5) msg_fatal("usage: %s header_checks mime_header_checks nested_header_checks body_checks", argv[0]); /* * Initialize. */ #define MIME_OPTIONS \ (MIME_OPT_REPORT_8BIT_IN_7BIT_BODY \ | MIME_OPT_REPORT_8BIT_IN_HEADER \ | MIME_OPT_REPORT_ENCODING_DOMAIN \ | MIME_OPT_REPORT_TRUNC_HEADER \ | MIME_OPT_REPORT_NESTING \ | MIME_OPT_DOWNGRADE) msg_vstream_init(basename(argv[0]), VSTREAM_OUT); buf = vstring_alloc(10); mime_state = mime_state_alloc(MIME_OPTIONS, head_out, head_end, body_out, body_end, err_print, (void *) &context); context.header_checks = hbc_header_checks_create("header_checks", argv[1], "mime_header_checks", argv[2], "nested_header_checks", argv[3], call_backs); context.body_checks = hbc_body_checks_create("body_checks", argv[4], call_backs); context.buf = vstring_alloc(100); context.fp = VSTREAM_OUT; context.queueid = "test-queueID"; context.recno = 0; /* * Main loop. */ do { rec_type = rec_streamlf_get(VSTREAM_IN, buf, REC_LEN); VSTRING_TERMINATE(buf); err = mime_state_update(mime_state, rec_type, STR(buf), LEN(buf)); vstream_fflush(VSTREAM_OUT); } while (rec_type > 0); /* * Error reporting. */ if (err & MIME_ERR_TRUNC_HEADER) msg_warn("message header length exceeds safety limit"); if (err & MIME_ERR_NESTING) msg_warn("MIME nesting exceeds safety limit"); if (err & MIME_ERR_8BIT_IN_HEADER) msg_warn("improper use of 8-bit data in message header"); if (err & MIME_ERR_8BIT_IN_7BIT_BODY) msg_warn("improper use of 8-bit data in message body"); if (err & MIME_ERR_ENCODING_DOMAIN) msg_warn("improper message/* or multipart/* encoding domain"); #ifdef __APPLE_OS_X_SERVER__ if (err & MIME_ERR_BODY_TOO_LARGE) msg_warn("MIME body part too large"); #endif /* * Cleanup. */ if (context.header_checks) hbc_header_checks_free(context.header_checks); if (context.body_checks) hbc_body_checks_free(context.body_checks); vstring_free(context.buf); mime_state_free(mime_state); vstring_free(buf); exit(0); }
static void enqueue(const int flags, const char *encoding, const char *dsn_envid, int dsn_ret, int dsn_notify, const char *rewrite_context, const char *sender, const char *full_name, char **recipients) { VSTRING *buf; VSTREAM *dst; char *saved_sender; char **cpp; int type; char *start; int skip_from_; TOK822 *tree; TOK822 *tp; int rcpt_count = 0; enum { STRIP_CR_DUNNO, STRIP_CR_DO, STRIP_CR_DONT, STRIP_CR_ERROR } strip_cr; MAIL_STREAM *handle; VSTRING *postdrop_command; uid_t uid = getuid(); int status; int naddr; int prev_type; MIME_STATE *mime_state = 0; SM_STATE state; int mime_errs; const char *errstr; int addr_count; int level; static NAME_CODE sm_fix_eol_table[] = { SM_FIX_EOL_ALWAYS, STRIP_CR_DO, SM_FIX_EOL_STRICT, STRIP_CR_DUNNO, SM_FIX_EOL_NEVER, STRIP_CR_DONT, 0, STRIP_CR_ERROR, }; /* * Access control is enforced in the postdrop command. The code here * merely produces a more user-friendly interface. */ if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl, uid)) != 0) msg_fatal_status(EX_NOPERM, "User %s(%ld) is not allowed to submit mail", errstr, (long) uid); /* * Initialize. */ buf = vstring_alloc(100); /* * Stop run-away process accidents by limiting the queue file size. This * is not a defense against DOS attack. */ if (var_message_limit > 0 && get_file_limit() > var_message_limit) set_file_limit((off_t) var_message_limit); /* * The sender name is provided by the user. In principle, the mail pickup * service could deduce the sender name from queue file ownership, but: * pickup would not be able to run chrooted, and it may not be desirable * to use login names at all. */ if (sender != 0) { VSTRING_RESET(buf); VSTRING_TERMINATE(buf); tree = tok822_parse(sender); for (naddr = 0, tp = tree; tp != 0; tp = tp->next) if (tp->type == TOK822_ADDR && naddr++ == 0) tok822_internalize(buf, tp->head, TOK822_STR_DEFL); tok822_free_tree(tree); saved_sender = mystrdup(STR(buf)); if (naddr > 1) msg_warn("-f option specified malformed sender: %s", sender); } else { if ((sender = username()) == 0) msg_fatal_status(EX_OSERR, "no login name found for user ID %lu", (unsigned long) uid); saved_sender = mystrdup(sender); } /* * Let the postdrop command open the queue file for us, and sanity check * the content. XXX Make postdrop a manifest constant. */ errno = 0; postdrop_command = vstring_alloc(1000); vstring_sprintf(postdrop_command, "%s/postdrop -r", var_command_dir); for (level = 0; level < msg_verbose; level++) vstring_strcat(postdrop_command, " -v"); if ((handle = mail_stream_command(STR(postdrop_command))) == 0) msg_fatal_status(EX_UNAVAILABLE, "%s(%ld): unable to execute %s: %m", saved_sender, (long) uid, STR(postdrop_command)); vstring_free(postdrop_command); dst = handle->stream; /* * First, write envelope information to the output stream. * * For sendmail compatibility, parse each command-line recipient as if it * were an RFC 822 message header; some MUAs specify comma-separated * recipient lists; and some MUAs even specify "word word <address>". * * Sort-uniq-ing the recipient list is done after address canonicalization, * before recipients are written to queue file. That's cleaner than * having the queue manager nuke duplicate recipient status records. * * XXX Should limit the size of envelope records. * * With "sendmail -N", instead of a per-message NOTIFY record we store one * per recipient so that we can simplify the implementation somewhat. */ if (dsn_envid) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_DSN_ENVID, dsn_envid); if (dsn_ret) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_RET, dsn_ret); rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_RWR_CONTEXT, rewrite_context); if (full_name || (full_name = fullname()) != 0) rec_fputs(dst, REC_TYPE_FULL, full_name); rec_fputs(dst, REC_TYPE_FROM, saved_sender); if (verp_delims && *saved_sender == 0) msg_fatal_status(EX_USAGE, "%s(%ld): -V option requires non-null sender address", saved_sender, (long) uid); if (encoding) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding); if (DEL_REQ_TRACE_FLAGS(flags)) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_TRACE_FLAGS, DEL_REQ_TRACE_FLAGS(flags)); if (verp_delims) rec_fputs(dst, REC_TYPE_VERP, verp_delims); if (recipients) { for (cpp = recipients; *cpp != 0; cpp++) { tree = tok822_parse(*cpp); for (addr_count = 0, tp = tree; tp != 0; tp = tp->next) { if (tp->type == TOK822_ADDR) { tok822_internalize(buf, tp->head, TOK822_STR_DEFL); if (dsn_notify) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); if (REC_PUT_BUF(dst, REC_TYPE_RCPT, buf) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); ++rcpt_count; ++addr_count; } } tok822_free_tree(tree); if (addr_count == 0) { if (rec_put(dst, REC_TYPE_RCPT, "", 0) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); ++rcpt_count; } } } /* * Append the message contents to the queue file. Write chunks of at most * 1kbyte. Internally, we use different record types for data ending in * LF and for data that doesn't, so we can actually be binary transparent * for local mail. Unfortunately, SMTP has no record continuation * convention, so there is no guarantee that arbitrary data will be * delivered intact via SMTP. Strip leading From_ lines. For the benefit * of UUCP environments, also get rid of leading >>>From_ lines. */ rec_fputs(dst, REC_TYPE_MESG, ""); if (DEL_REQ_TRACE_ONLY(flags) != 0) { if (flags & SM_FLAG_XRCPT) msg_fatal_status(EX_USAGE, "%s(%ld): -t option cannot be used with -bv", saved_sender, (long) uid); if (*saved_sender) rec_fprintf(dst, REC_TYPE_NORM, "From: %s", saved_sender); rec_fprintf(dst, REC_TYPE_NORM, "Subject: probe"); if (recipients) { rec_fprintf(dst, REC_TYPE_CONT, "To:"); for (cpp = recipients; *cpp != 0; cpp++) { rec_fprintf(dst, REC_TYPE_NORM, " %s%s", *cpp, cpp[1] ? "," : ""); } } } else { /* * Initialize the MIME processor and set up the callback context. */ if (flags & SM_FLAG_XRCPT) { state.dst = dst; state.recipients = argv_alloc(2); state.resent_recip = argv_alloc(2); state.resent = 0; state.saved_sender = saved_sender; state.uid = uid; state.temp = vstring_alloc(10); mime_state = mime_state_alloc(MIME_OPT_DISABLE_MIME | MIME_OPT_REPORT_TRUNC_HEADER, output_header, (MIME_STATE_ANY_END) 0, output_text, (MIME_STATE_ANY_END) 0, (MIME_STATE_ERR_PRINT) 0, (void *) &state); } /* * Process header/body lines. */ skip_from_ = 1; strip_cr = name_code(sm_fix_eol_table, NAME_CODE_FLAG_STRICT_CASE, var_sm_fix_eol); if (strip_cr == STRIP_CR_ERROR) msg_fatal_status(EX_USAGE, "invalid %s value: %s", VAR_SM_FIX_EOL, var_sm_fix_eol); for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit)) != REC_TYPE_EOF; prev_type = type) { if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) { if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r') strip_cr = STRIP_CR_DO; else strip_cr = STRIP_CR_DONT; } if (skip_from_) { if (type == REC_TYPE_NORM) { start = STR(buf); if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) continue; } skip_from_ = 0; } if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM) while (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r') vstring_truncate(buf, VSTRING_LEN(buf) - 1); if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT && VSTRING_LEN(buf) == 1 && *STR(buf) == '.') break; if (mime_state) { mime_errs = mime_state_update(mime_state, type, STR(buf), VSTRING_LEN(buf)); if (mime_errs) msg_fatal_status(EX_DATAERR, "%s(%ld): unable to extract recipients: %s", saved_sender, (long) uid, mime_state_error(mime_errs)); } else { if (REC_PUT_BUF(dst, type, buf) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); } } } /* * Finish MIME processing. We need a final mime_state_update() call in * order to flush text that is still buffered. That can happen when the * last line did not end in newline. */ if (mime_state) { mime_errs = mime_state_update(mime_state, REC_TYPE_EOF, "", 0); if (mime_errs) msg_fatal_status(EX_DATAERR, "%s(%ld): unable to extract recipients: %s", saved_sender, (long) uid, mime_state_error(mime_errs)); mime_state = mime_state_free(mime_state); } /* * Append recipient addresses that were extracted from message headers. */ rec_fputs(dst, REC_TYPE_XTRA, ""); if (flags & SM_FLAG_XRCPT) { for (cpp = state.resent ? state.resent_recip->argv : state.recipients->argv; *cpp; cpp++) { if (dsn_notify) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); if (rec_put(dst, REC_TYPE_RCPT, *cpp, strlen(*cpp)) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); ++rcpt_count; } argv_free(state.recipients); argv_free(state.resent_recip); vstring_free(state.temp); } if (rcpt_count == 0) msg_fatal_status(EX_USAGE, (flags & SM_FLAG_XRCPT) ? "%s(%ld): No recipient addresses found in message header" : "%s(%ld): Recipient addresses must be specified on" " the command line or via the -t option", saved_sender, (long) uid); /* * Identify the end of the queue file. */ rec_fputs(dst, REC_TYPE_END, ""); /* * Make sure that the message makes it to the file system. Once we have * terminated with successful exit status we cannot lose the message due * to "frivolous reasons". If all goes well, prevent the run-time error * handler from removing the file. */ if (vstream_ferror(VSTREAM_IN)) msg_fatal_status(EX_DATAERR, "%s(%ld): error reading input: %m", saved_sender, (long) uid); if ((status = mail_stream_finish(handle, (VSTRING *) 0)) != 0) msg_fatal_status((status & CLEANUP_STAT_BAD) ? EX_SOFTWARE : (status & CLEANUP_STAT_WRITE) ? EX_TEMPFAIL : EX_UNAVAILABLE, "%s(%ld): %s", saved_sender, (long) uid, cleanup_strerror(status)); /* * Don't leave them in the dark. */ if (DEL_REQ_TRACE_FLAGS(flags)) { vstream_printf("Mail Delivery Status Report will be mailed to <%s>.\n", saved_sender); vstream_fflush(VSTREAM_OUT); } /* * Cleanup. Not really necessary as we're about to exit, but good for * debugging purposes. */ vstring_free(buf); myfree(saved_sender); }
static int postmap_queries(VSTREAM *in, char **maps, const int map_count, const int postmap_flags, const int dict_flags) { int found = 0; VSTRING *keybuf = vstring_alloc(100); DICT **dicts; const char *map_name; const char *value; int n; /* * Sanity check. */ if (map_count <= 0) msg_panic("postmap_queries: bad map count"); /* * Prepare to open maps lazily. */ dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); for (n = 0; n < map_count; n++) dicts[n] = 0; /* * Perform all queries. Open maps on the fly, to avoid opening unecessary * maps. */ if ((postmap_flags & POSTMAP_FLAG_HB_KEY) == 0) { while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { for (n = 0; n < map_count; n++) { if (dicts[n] == 0) dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ? dict_open3(maps[n], map_name, O_RDONLY, dict_flags) : dict_open3(var_db_type, maps[n], O_RDONLY, dict_flags)); if ((value = dict_get(dicts[n], STR(keybuf))) != 0) { if (*value == 0) { msg_warn("table %s:%s: key %s: empty string result is not allowed", dicts[n]->type, dicts[n]->name, STR(keybuf)); msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND", dicts[n]->type, dicts[n]->name); } vstream_printf("%s %s\n", STR(keybuf), value); found = 1; break; } if (dicts[n]->error) msg_fatal("table %s:%s: query error: %m", dicts[n]->type, dicts[n]->name); } } } else { POSTMAP_KEY_STATE key_state; MIME_STATE *mime_state; int mime_errs = 0; /* * Bundle up the request and instantiate a MIME parsing engine. */ key_state.dicts = dicts; key_state.maps = maps; key_state.map_count = map_count; key_state.dict_flags = dict_flags; key_state.header_done = 0; key_state.found = 0; mime_state = mime_state_alloc((postmap_flags & POSTMAP_FLAG_MIME_KEY) ? 0 : MIME_OPT_DISABLE_MIME, (postmap_flags & POSTMAP_FLAG_HEADER_KEY) ? postmap_header : (MIME_STATE_HEAD_OUT) 0, (postmap_flags & POSTMAP_FLAG_FULL_KEY) ? (MIME_STATE_ANY_END) 0 : postmap_head_end, (postmap_flags & POSTMAP_FLAG_BODY_KEY) ? postmap_body : (MIME_STATE_BODY_OUT) 0, (MIME_STATE_ANY_END) 0, (MIME_STATE_ERR_PRINT) 0, (void *) &key_state); /* * Process the input message. */ while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF && key_state.header_done == 0 && mime_errs == 0) mime_errs = mime_state_update(mime_state, REC_TYPE_NORM, STR(keybuf), LEN(keybuf)); /* * Flush the MIME engine output buffer and tidy up loose ends. */ if (mime_errs == 0) mime_errs = mime_state_update(mime_state, REC_TYPE_END, "", 0); if (mime_errs) msg_fatal("message format error: %s", mime_state_detail(mime_errs)->text); mime_state_free(mime_state); found = key_state.found; } if (found) vstream_fflush(VSTREAM_OUT); /* * Cleanup. */ for (n = 0; n < map_count; n++) if (dicts[n]) dict_close(dicts[n]); myfree((void *) dicts); vstring_free(keybuf); return (found); }