Ejemplo n.º 1
0
void    qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream)
{
    QMGR_QUEUE *queue;
    QMGR_ENTRY *entry;

    /*
     * Find out if this delivery process is really available. Once elected,
     * the delivery process is supposed to express its happiness. If there is
     * a problem, wipe the pending deliveries for this transport. This
     * routine runs in response to an external event, so it does not run
     * while some other queue manipulation is happening.
     */
    if (qmgr_deliver_initial_reply(stream) != 0) {
	qmgr_transport_throttle(transport, "mail transport unavailable");
	qmgr_defer_transport(transport, transport->reason);
	(void) vstream_fclose(stream);
	return;
    }

    /*
     * Find a suitable queue entry. Things may have changed since this
     * transport was allocated. If no suitable entry is found,
     * unceremoniously disconnect from the delivery process. The delivery
     * agent request reading routine is prepared for the queue manager to
     * change its mind for no apparent reason.
     */
    if ((queue = qmgr_queue_select(transport)) == 0
	|| (entry = qmgr_entry_select(queue)) == 0) {
	(void) vstream_fclose(stream);
	return;
    }

    /*
     * Send the queue file info and recipient info to the delivery process.
     * If there is a problem, wipe the pending deliveries for this transport.
     * This routine runs in response to an external event, so it does not run
     * while some other queue manipulation is happening.
     */
    if (qmgr_deliver_send_request(entry, stream) < 0) {
	qmgr_entry_unselect(queue, entry);
	qmgr_transport_throttle(transport, "mail transport unavailable");
	qmgr_defer_transport(transport, transport->reason);
	/* warning: entry and queue may be dangling pointers here */
	(void) vstream_fclose(stream);
	return;
    }

    /*
     * If we get this far, go wait for the delivery status report.
     */
    qmgr_deliver_concurrency++;
    entry->stream = stream;
    event_enable_read(vstream_fileno(stream),
		      qmgr_deliver_update, (char *) entry);

    /*
     * Guard against broken systems.
     */
    event_request_timer(qmgr_deliver_abort, (char *) entry, var_daemon_timeout);
}
Ejemplo n.º 2
0
static int deliver_message(DELIVER_REQUEST *request)
{
    const char *myname = "deliver_message";
    VSTREAM *src;
    int     result = 0;
    int     status;
    RECIPIENT *rcpt;
    int     nrcpt;
    DSN_SPLIT dp;
    DSN     dsn;

    if (msg_verbose)
	msg_info("deliver_message: from %s", request->sender);

    /*
     * Sanity checks.
     */
    if (request->nexthop[0] == 0)
	msg_fatal("empty nexthop hostname");
    if (request->rcpt_list.len <= 0)
	msg_fatal("recipient count: %d", request->rcpt_list.len);

    /*
     * Open the queue file. Opening the file can fail for a variety of
     * reasons, such as the system running out of resources. Instead of
     * throwing away mail, we're raising a fatal error which forces the mail
     * system to back off, and retry later.
     */
    src = mail_queue_open(request->queue_name, request->queue_id,
			  O_RDWR, 0);
    if (src == 0)
	msg_fatal("%s: open %s %s: %m", myname,
		  request->queue_name, request->queue_id);
    if (msg_verbose)
	msg_info("%s: file %s", myname, VSTREAM_PATH(src));

    /*
     * Discard all recipients.
     */
#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags)

    dsn_split(&dp, "2.0.0", request->nexthop);
    (void) DSN_SIMPLE(&dsn, DSN_STATUS(dp.dsn), dp.text);
    for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
	rcpt = request->rcpt_list.info + nrcpt;
	status = sent(BOUNCE_FLAGS(request), request->queue_id,
		      &request->msg_stats, rcpt, "none", &dsn);
	if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
	    deliver_completed(src, rcpt->offset);
	result |= status;
    }

    /*
     * Clean up.
     */
    if (vstream_fclose(src))
	msg_warn("close %s %s: %m", request->queue_name, request->queue_id);

    return (result);
}
Ejemplo n.º 3
0
static int deliver_message(DELIVER_REQUEST *request)
{
    char   *myname = "deliver_message";
    VSTREAM *src;
    int     result = 0;
    int     status;
    RECIPIENT *rcpt;
    int     nrcpt;

    if (msg_verbose)
	msg_info("deliver_message: from %s", request->sender);

    /*
     * Sanity checks.
     */
    if (request->nexthop[0] == 0)
	msg_fatal("empty nexthop hostname");
    if (request->rcpt_list.len <= 0)
	msg_fatal("recipient count: %d", request->rcpt_list.len);

    /*
     * Open the queue file. Opening the file can fail for a variety of
     * reasons, such as the system running out of resources. Instead of
     * throwing away mail, we're raising a fatal error which forces the mail
     * system to back off, and retry later.
     */
    src = mail_queue_open(request->queue_name, request->queue_id,
			  O_RDWR, 0);
    if (src == 0)
	msg_fatal("%s: open %s %s: %m", myname,
		  request->queue_name, request->queue_id);
    if (msg_verbose)
	msg_info("%s: file %s", myname, VSTREAM_PATH(src));

    /*
     * Bounce all recipients.
     */
#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags)

    for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
	rcpt = request->rcpt_list.info + nrcpt;
	if (rcpt->offset >= 0) {
	    status = bounce_append(BOUNCE_FLAGS(request), request->queue_id,
				   rcpt->orig_addr, rcpt->address,
				rcpt->offset, "none", request->arrival_time,
				   "%s", request->nexthop);
	    if (status == 0)
		deliver_completed(src, rcpt->offset);
	    result |= status;
	}
    }

    /*
     * Clean up.
     */
    if (vstream_fclose(src))
	msg_warn("close %s %s: %m", request->queue_name, request->queue_id);

    return (result);
}
Ejemplo n.º 4
0
static void close_session(SESSION *session)
{
    event_disable_readwrite(vstream_fileno(session->stream));
    vstream_fclose(session->stream);
    session->stream = 0;
    start_another(session);
}
Ejemplo n.º 5
0
void    load_file(const char *path, LOAD_FILE_FN action, void *context)
{
    VSTREAM *fp;
    struct stat st;
    time_t  before;
    time_t  after;

    /*
     * Read the file again if it is hot. This may result in reading a partial
     * parameter name or missing end marker when a file changes in the middle
     * of a read.
     */
    for (before = time((time_t *) 0); /* see below */ ; before = after) {
	if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
	    msg_fatal("open %s: %m", path);
	action(fp, context);
	if (fstat(vstream_fileno(fp), &st) < 0)
	    msg_fatal("fstat %s: %m", path);
	if (vstream_ferror(fp) || vstream_fclose(fp))
	    msg_fatal("read %s: %m", path);
	after = time((time_t *) 0);
	if (st.st_mtime < before - 1 || st.st_mtime > after)
	    break;
	if (msg_verbose)
	    msg_info("pausing to let %s cool down", path);
	doze(300000);
    }
}
Ejemplo n.º 6
0
int     edit_file_close(EDIT_FILE *ep)
{
    VSTREAM *fp = ep->tmp_fp;
    int     fd = vstream_fileno(fp);
    int     saved_errno;

    /*
     * The rename/unlock portion of the protocol is relatively simple. The
     * only things that really matter here are that we change permissions as
     * late as possible, and that we rename the file to its final pathname
     * before we lose the exclusive lock.
     * 
     * Applications that are concerned about maximal safety should protect the
     * edit_file_close() call with sigdelay() and sigresume() calls. It is
     * not safe for us to call these functions directly, because the calls do
     * not nest. It is also not nice to force every caller to run with
     * interrupts turned off.
     */
    if (vstream_fflush(fp) < 0
	|| fchmod(fd, ep->final_mode) < 0
#ifdef HAS_FSYNC
	|| fsync(fd) < 0
#endif
	|| rename(ep->tmp_path, ep->final_path) < 0) {
	saved_errno = errno;
	edit_file_cleanup(ep);
	errno = saved_errno;
	return (VSTREAM_EOF);
    } else {
	(void) vstream_fclose(ep->tmp_fp);
	EDIT_FILE_FREE(ep);
	return (0);
    }
}
Ejemplo n.º 7
0
int     dict_load_file_xt(const char *dict_name, const char *path)
{
    VSTREAM *fp;
    struct stat st;
    time_t  before;
    time_t  after;

    /*
     * Read the file again if it is hot. This may result in reading a partial
     * parameter name when a file changes in the middle of a read.
     */
    for (before = time((time_t *) 0); /* see below */ ; before = after) {
	if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
	    return (0);
	dict_load_fp(dict_name, fp);
	if (fstat(vstream_fileno(fp), &st) < 0)
	    msg_fatal("fstat %s: %m", path);
	if (vstream_ferror(fp) || vstream_fclose(fp))
	    msg_fatal("read %s: %m", path);
	after = time((time_t *) 0);
	if (st.st_mtime < before - 1 || st.st_mtime > after)
	    break;
	if (msg_verbose > 1)
	    msg_info("pausing to let %s cool down", path);
	doze(300000);
    }
    return (1);
}
Ejemplo n.º 8
0
void    smtpd_proxy_free(SMTPD_STATE *state)
{
    SMTPD_PROXY *proxy = state->proxy;

    /*
     * Clean up.
     */
    if (proxy->service_stream != 0)
	(void) smtpd_proxy_close(state);
    if (proxy->request != 0)
	vstring_free(proxy->request);
    if (proxy->reply != 0)
	vstring_free(proxy->reply);
    myfree((char *) proxy);
    state->proxy = 0;

    /*
     * Reuse the replay logfile if possible. For security reasons we must
     * truncate the replay logfile before reuse. For performance reasons we
     * should truncate the replay logfile immediately after the end of a mail
     * transaction. We truncate the file here, and enforce the security
     * guarantee by requiring that no I/O happens before the file is reused.
     */
    if (smtpd_proxy_replay_stream == 0)
	return;
    if (vstream_ferror(smtpd_proxy_replay_stream)) {
	/* Errors are already reported. */
	(void) vstream_fclose(smtpd_proxy_replay_stream);
	smtpd_proxy_replay_stream = 0;
	return;
    }
    /* Flush output from aborted transaction before truncating the file!! */
    if (vstream_fseek(smtpd_proxy_replay_stream, (off_t) 0, SEEK_SET) < 0) {
	msg_warn("seek before-queue filter speed-adjust log: %m");
	(void) vstream_fclose(smtpd_proxy_replay_stream);
	smtpd_proxy_replay_stream = 0;
	return;
    }
    if (ftruncate(vstream_fileno(smtpd_proxy_replay_stream), (off_t) 0) < 0) {
	msg_warn("truncate before-queue filter speed-adjust log: %m");
	(void) vstream_fclose(smtpd_proxy_replay_stream);
	smtpd_proxy_replay_stream = 0;
	return;
    }
}
Ejemplo n.º 9
0
void    pcf_read_master(int fail_on_open_error)
{
    const char *myname = "pcf_read_master";
    char   *path;
    VSTRING *buf;
    VSTREAM *fp;
    const char *err;
    int     entry_count = 0;
    int     line_count;
    int     last_line = 0;

    /*
     * Sanity check.
     */
    if (pcf_master_table != 0)
	msg_panic("%s: master table is already initialized", myname);

    /*
     * Get the location of master.cf.
     */
    if (var_config_dir == 0)
	pcf_set_config_dir();
    path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);

    /*
     * Initialize the in-memory master table.
     */
    pcf_master_table = (PCF_MASTER_ENT *) mymalloc(sizeof(*pcf_master_table));

    /*
     * Skip blank lines and comment lines. Degrade gracefully if master.cf is
     * not available, and master.cf is not the primary target.
     */
    if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) {
	if (fail_on_open_error)
	    msg_fatal("open %s: %m", path);
	msg_warn("open %s: %m", path);
    } else {
	buf = vstring_alloc(100);
	while (readllines(buf, fp, &last_line, &line_count) != 0) {
	    pcf_master_table = (PCF_MASTER_ENT *) myrealloc((void *) pcf_master_table,
			     (entry_count + 2) * sizeof(*pcf_master_table));
	    if ((err = pcf_parse_master_entry(pcf_master_table + entry_count,
					      STR(buf))) != 0)
		msg_fatal("file %s: line %d: %s", path, line_count, err);
	    entry_count += 1;
	}
	vstream_fclose(fp);
	vstring_free(buf);
    }

    /*
     * Null-terminate the master table and clean up.
     */
    pcf_master_table[entry_count].argv = 0;
    myfree(path);
}
Ejemplo n.º 10
0
static void quit_done(int unused_event, char *context)
{
    SESSION *session = (SESSION *) context;

    (void) response(session->stream, buffer);
    event_disable_readwrite(vstream_fileno(session->stream));
    vstream_fclose(session->stream);
    session->stream = 0;
    start_another(session);
}
Ejemplo n.º 11
0
DICT   *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
{
    DICT_CIDR *dict_cidr;
    VSTREAM *map_fp;
    VSTRING *line_buffer = vstring_alloc(100);
    VSTRING *why = vstring_alloc(100);
    DICT_CIDR_ENTRY *rule;
    DICT_CIDR_ENTRY *last_rule = 0;
    int     lineno = 0;

    /*
     * Sanity checks.
     */
    if (open_flags != O_RDONLY)
	msg_fatal("%s:%s map requires O_RDONLY access mode",
		  DICT_TYPE_CIDR, mapname);

    /*
     * XXX Eliminate unnecessary queries by setting a flag that says "this
     * map matches network addresses only".
     */
    dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname,
					 sizeof(*dict_cidr));
    dict_cidr->dict.lookup = dict_cidr_lookup;
    dict_cidr->dict.close = dict_cidr_close;
    dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN;
    dict_cidr->head = 0;

    if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0)
	msg_fatal("open %s: %m", mapname);

    while (readlline(line_buffer, map_fp, &lineno)) {
	rule = dict_cidr_parse_rule(vstring_str(line_buffer), why);
	if (rule == 0) {
	    msg_warn("cidr map %s, line %d: %s: skipping this rule",
		     mapname, lineno, vstring_str(why));
	    continue;
	}
	if (last_rule == 0)
	    dict_cidr->head = rule;
	else
	    last_rule->cidr_info.next = &(rule->cidr_info);
	last_rule = rule;
    }

    /*
     * Clean up.
     */
    if (vstream_fclose(map_fp))
	msg_fatal("cidr map %s: read error: %m", mapname);
    vstring_free(line_buffer);
    vstring_free(why);

    return (DICT_DEBUG (&dict_cidr->dict));
}
Ejemplo n.º 12
0
void    edit_file_cleanup(EDIT_FILE *ep)
{

    /*
     * Don't touch the file after we lose the exclusive lock!
     */
    if (unlink(ep->tmp_path) < 0 && errno != ENOENT)
	msg_fatal("unlink %s: %m", ep->tmp_path);
    (void) vstream_fclose(ep->tmp_fp);
    EDIT_FILE_FREE(ep);
}
Ejemplo n.º 13
0
static void xsasl_dovecot_server_disconnect(XSASL_DOVECOT_SERVER_IMPL *xp)
{
    if (xp->sasl_stream) {
	(void) vstream_fclose(xp->sasl_stream);
	xp->sasl_stream = 0;
    }
    if (xp->mechanism_list) {
	xsasl_dovecot_server_mech_free(xp->mechanism_list);
	xp->mechanism_list = 0;
    }
}
Ejemplo n.º 14
0
static void dict_tcp_close(DICT *dict)
{
    DICT_TCP *dict_tcp = (DICT_TCP *) dict;

    if (dict_tcp->fp)
	(void) vstream_fclose(dict_tcp->fp);
    if (dict_tcp->raw_buf)
	vstring_free(dict_tcp->raw_buf);
    if (dict_tcp->hex_buf)
	vstring_free(dict_tcp->hex_buf);
    dict_free(dict);
}
Ejemplo n.º 15
0
main(void)
{
    VSTRING *vp = vstring_alloc(1);
    VSTREAM *fp;

    if ((fp = vstream_fopen(TEXT_VSTREAM, O_RDONLY, 0)) == 0)
	msg_fatal("open %s: %m", TEXT_VSTREAM);
    while (vstring_fgets(vp, fp))
	vstream_fprintf(VSTREAM_OUT, "%s", vstring_str(vp));
    vstream_fclose(fp);
    vstream_fflush(VSTREAM_OUT);
    vstring_free(vp);
}
Ejemplo n.º 16
0
void    event_server_disconnect(VSTREAM *stream)
{
    if (msg_verbose)
	msg_info("connection closed fd %d", vstream_fileno(stream));
    if (event_server_pre_disconn)
	event_server_pre_disconn(stream, event_server_name, event_server_argv);
    (void) vstream_fclose(stream);
    client_count--;
    /* Avoid integer wrap-around in a persistent process.  */
    if (use_count < INT_MAX)
	use_count++;
    if (client_count == 0 && var_idle_limit > 0)
	event_request_timer(event_server_timeout, (char *) 0, var_idle_limit);
}
Ejemplo n.º 17
0
void    end_master_ent()
{
    const char *myname = "end_master_ent";

    if (master_fp == 0)
	msg_panic("%s: configuration file not open", myname);
    if (vstream_fclose(master_fp) != 0)
	msg_fatal("%s: close configuration file: %m", myname);
    master_fp = 0;
    if (master_disable == 0)
	msg_panic("%s: no service disable list", myname);
    match_service_free(master_disable);
    master_disable = 0;
}
Ejemplo n.º 18
0
static void fail_connect(SESSION *session)
{
    if (session->connect_count-- == 1)
        msg_fatal("connect: %m");
    msg_warn("connect: %m");
    event_disable_readwrite(vstream_fileno(session->stream));
    vstream_fclose(session->stream);
    session->stream = 0;
#ifdef MISSING_USLEEP
    doze(10);
#else
    usleep(10);
#endif
    start_connect(session);
}
Ejemplo n.º 19
0
static int flush_add_path(const char *path, const char *queue_id)
{
    const char *myname = "flush_add_path";
    VSTREAM *log;

    /*
     * Sanity check.
     */
    if (!mail_queue_id_ok(path))
	return (FLUSH_STAT_BAD);

    /*
     * Open the logfile or bust.
     */
    if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path,
			       O_CREAT | O_APPEND | O_WRONLY, 0600)) == 0)
	msg_fatal("%s: open fast flush logfile %s: %m", myname, path);

    /*
     * We must lock the logfile, so that we don't lose information due to
     * concurrent access. If the lock takes too long, the Postfix watchdog
     * will eventually take care of the problem, but it will take a while.
     */
    if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
	msg_fatal("%s: lock fast flush logfile %s: %m", myname, path);

    /*
     * Append the queue ID. With 15 bits of microsecond time, a queue ID is
     * not recycled often enough for false hits to be a problem. If it does,
     * then we could add other signature information, such as the file size
     * in bytes.
     */
    vstream_fprintf(log, "%s\n", queue_id);
    if (vstream_fflush(log))
	msg_warn("write fast flush logfile %s: %m", path);

    /*
     * Clean up.
     */
    if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
	msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path);
    if (vstream_fclose(log) != 0)
	msg_warn("write fast flush logfile %s: %m", path);

    return (FLUSH_STAT_OK);
}
Ejemplo n.º 20
0
static VSTREAM *safe_open_create(const char *path, int flags, int mode,
	            struct stat * st, uid_t user, uid_t group, VSTRING *why)
{
    VSTREAM *fp;

    /*
     * Create a non-existing file. This relies on O_CREAT | O_EXCL to not
     * follow symbolic links.
     */
    if ((fp = vstream_fopen(path, flags | (O_CREAT | O_EXCL), mode)) == 0) {
	vstring_sprintf(why, "cannot create file exclusively: %m");
	return (0);
    }

    /*
     * Optionally change ownership after creating a new file. If there is a
     * problem we should not attempt to delete the file. Something else may
     * have opened the file in the mean time.
     */
#define CHANGE_OWNER(user, group) (user != (uid_t) -1 || group != (gid_t) -1)

    if (CHANGE_OWNER(user, group)
	&& fchown(vstream_fileno(fp), user, group) < 0) {
	msg_warn("%s: cannot change file ownership: %m", path);
    }

    /*
     * Optionally look up the file attributes.
     */
    if (st != 0 && fstat(vstream_fileno(fp), st) < 0)
	msg_fatal("%s: bad open file status: %m", path);

    /*
     * We are almost there...
     */
    else {
	return (fp);
    }

    /*
     * End up here in case of trouble.
     */
    vstream_fclose(fp);
    return (0);
}
Ejemplo n.º 21
0
int     forward_finish(DELIVER_REQUEST *request, DELIVER_ATTR attr, int cancel)
{
    HTABLE_INFO **dt_list;
    HTABLE_INFO **dt;
    HTABLE_INFO **sn_list;
    HTABLE_INFO **sn;
    HTABLE *table_snd;
    char   *delivered;
    char   *sender;
    FORWARD_INFO *info;
    int     status = cancel;

    /*
     * Sanity checks.
     */
    if (forward_dt == 0)
	msg_panic("forward_finish: missing forward_init call");

    /*
     * Walk over all delivered-to header addresses and over each envelope
     * sender address.
     */
    for (dt = dt_list = htable_list(forward_dt); *dt; dt++) {
	delivered = dt[0]->key;
	table_snd = (HTABLE *) dt[0]->value;
	for (sn = sn_list = htable_list(table_snd); *sn; sn++) {
	    sender = sn[0]->key;
	    info = (FORWARD_INFO *) sn[0]->value;
	    if (status == 0)
		status |= forward_send(info, request, attr, delivered);
	    if (msg_verbose)
		msg_info("forward_finish: delivered %s sender %s status %d",
			 delivered, sender, status);
	    (void) vstream_fclose(info->cleanup);
	    myfree(info->queue_id);
	    myfree((void *) info);
	}
	myfree((void *) sn_list);
	htable_free(table_snd, (void (*) (void *)) 0);
    }
    myfree((void *) dt_list);
    htable_free(forward_dt, (void (*) (void *)) 0);
    forward_dt = 0;
    return (status);
}
Ejemplo n.º 22
0
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);
}
Ejemplo n.º 23
0
VSTREAM *open_lock(const char *path, int flags, int mode, VSTRING *why)
{
    VSTREAM *fp;

    /*
     * Carefully create or open the file, and lock it down. Some systems
     * don't have the O_LOCK open() flag, or the flag does not do what we
     * want, so we roll our own lock.
     */
    if ((fp = safe_open(path, flags, mode, (struct stat *) 0, -1, -1, why)) == 0)
	return (0);
    if (myflock(vstream_fileno(fp), INTERNAL_LOCK,
		MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0) {
	vstring_sprintf(why, "unable to set exclusive lock: %m");
	vstream_fclose(fp);
	return (0);
    }
    return (fp);
}
Ejemplo n.º 24
0
void    smtpd_proxy_close(SMTPD_STATE *state)
{
    SMTPD_PROXY *proxy = state->proxy;

    /*
     * Specify SMTPD_PROX_WANT_NONE so that the server reply will not clobber
     * the END-OF-DATA reply.
     */
    if (proxy->service_stream != 0) {
	if (vstream_feof(proxy->service_stream) == 0
	    && vstream_ferror(proxy->service_stream) == 0)
	    (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE,
				   SMTPD_CMD_QUIT);
	(void) vstream_fclose(proxy->service_stream);
	if (proxy->stream == proxy->service_stream)
	    proxy->stream = 0;
	proxy->service_stream = 0;
    }
}
Ejemplo n.º 25
0
static void single_server_wakeup(int fd, HTABLE *attr)
{
    VSTREAM *stream;
    char   *tmp;

    /*
     * If the accept() succeeds, be sure to disable non-blocking I/O, because
     * the application is supposed to be single-threaded. Notice the master
     * of our (un)availability to service connection requests. Commit suicide
     * when the master process disconnected from us. Don't drop the already
     * accepted client request after "postfix reload"; that would be rude.
     */
    if (msg_verbose)
	msg_info("connection established");
    non_blocking(fd, BLOCKING);
    close_on_exec(fd, CLOSE_ON_EXEC);
    stream = vstream_fdopen(fd, O_RDWR);
    tmp = concatenate(single_server_name, " socket", (char *) 0);
    vstream_control(stream,
		    CA_VSTREAM_CTL_PATH(tmp),
		    CA_VSTREAM_CTL_CONTEXT((void *) attr),
		    CA_VSTREAM_CTL_END);
    myfree(tmp);
    timed_ipc_setup(stream);
    if (master_notify(var_pid, single_server_generation, MASTER_STAT_TAKEN) < 0)
	 /* void */ ;
    if (single_server_in_flow_delay && mail_flow_get(1) < 0)
	doze(var_in_flow_delay * 1000000);
    single_server_service(stream, single_server_name, single_server_argv);
    (void) vstream_fclose(stream);
    if (master_notify(var_pid, single_server_generation, MASTER_STAT_AVAIL) < 0)
	single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    if (msg_verbose)
	msg_info("connection closed");
    /* Avoid integer wrap-around in a persistent process.  */
    if (use_count < INT_MAX)
	use_count++;
    if (var_idle_limit > 0)
	event_request_timer(single_server_timeout, (void *) 0, var_idle_limit);
    if (attr)
	htable_free(attr, myfree);
}
Ejemplo n.º 26
0
static void clnt_stream_close(CLNT_STREAM *clnt_stream)
{

    /*
     * Sanity check.
     */
    if (clnt_stream->vstream == 0)
	msg_panic("clnt_stream_close: stream is closed");

    /*
     * Be sure to disable read and timer events.
     */
    if (msg_verbose)
	msg_info("%s stream disconnect", clnt_stream->service);
    event_disable_readwrite(vstream_fileno(clnt_stream->vstream));
    event_cancel_timer(clnt_stream_event, (void *) clnt_stream);
    event_cancel_timer(clnt_stream_ttl_event, (void *) clnt_stream);
    (void) vstream_fclose(clnt_stream->vstream);
    clnt_stream->vstream = 0;
}
Ejemplo n.º 27
0
void mail_conf_checkdir(const char *config_dir)
{
    VSTRING *buf;
    VSTREAM *fp;
    char   *path;
    char   *name;
    char   *value;
    char   *cp;
    int     found = 0;

    /*
     * If running set-[ug]id, require that a non-default configuration
     * directory name is blessed as a bona fide configuration directory in
     * the default main.cf file.
     */
    path = concatenate(DEF_CONFIG_DIR, "/", "main.cf", (char *) 0);
    if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
	msg_fatal("open file %s: %m", path);

    buf = vstring_alloc(1);
    while (found == 0 && readlline(buf, fp, (int *) 0)) {
	if (split_nameval(vstring_str(buf), &name, &value) == 0
	    && (strcmp(name, VAR_CONFIG_DIRS) == 0
		|| strcmp(name, VAR_MULTI_CONF_DIRS) == 0)) {
	    while (found == 0 && (cp = mystrtok(&value, CHARS_COMMA_SP)) != 0)
		if (strcmp(cp, config_dir) == 0)
		    found = 1;
	}
    }
    if (vstream_fclose(fp))
	msg_fatal("read file %s: %m", path);
    vstring_free(buf);

    if (found == 0) {
	msg_error("unauthorized configuration directory name: %s", config_dir);
	msg_fatal("specify \"%s = %s\" or \"%s = %s\" in %s",
		  VAR_CONFIG_DIRS, config_dir,
		  VAR_MULTI_CONF_DIRS, config_dir, path);
    }
    myfree(path);
}
Ejemplo n.º 28
0
int     post_mail_fclose(VSTREAM *cleanup)
{
    int     status = 0;

    /*
     * Send the message end marker only when there were no errors.
     */
    if (vstream_ferror(cleanup) != 0) {
	status = CLEANUP_STAT_WRITE;
    } else {
	rec_fputs(cleanup, REC_TYPE_XTRA, "");
	rec_fputs(cleanup, REC_TYPE_END, "");
	if (vstream_fflush(cleanup)
	    || attr_scan(cleanup, ATTR_FLAG_MISSING,
			 ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
			 ATTR_TYPE_END) != 1)
	    status = CLEANUP_STAT_WRITE;
    }
    (void) vstream_fclose(cleanup);
    return (status);
}
Ejemplo n.º 29
0
static void receive_reply(int unused_event, char *context)
{
    SESSION *session = (SESSION *) context;
    int     except;

    /*
     * Prepare for disaster.
     */
    if ((except = vstream_setjmp(session->stream)) != 0)
	msg_fatal("%s while receiving server reply", exception_text(except));

    /*
     * Receive and process the server reply.
     */
    netstring_get(session->stream, buffer, var_line_limit);
    if (msg_verbose)
	vstream_printf("<< %.*s\n", (int) LEN(buffer), STR(buffer));
    if (STR(buffer)[0] != QMQP_STAT_OK)
	msg_fatal("%s error: %.*s",
		  STR(buffer)[0] == QMQP_STAT_RETRY ? "recoverable" :
		  STR(buffer)[0] == QMQP_STAT_HARD ? "unrecoverable" :
		  "unknown", (int) LEN(buffer) - 1, STR(buffer) + 1);

    /*
     * Update the optional running counter.
     */
    if (count) {
	counter++;
	vstream_printf("%d\r", counter);
	vstream_fflush(VSTREAM_OUT);
    }

    /*
     * Finish this session. QMQP sends only one message per session.
     */
    event_disable_readwrite(vstream_fileno(session->stream));
    vstream_fclose(session->stream);
    session->stream = 0;
    start_another(session);
}
Ejemplo n.º 30
0
static void deliver_request_free(DELIVER_REQUEST *request)
{
    if (request->fp)
	vstream_fclose(request->fp);
    if (request->queue_name)
	myfree(request->queue_name);
    if (request->queue_id)
	myfree(request->queue_id);
    if (request->nexthop)
	myfree(request->nexthop);
    if (request->encoding)
	myfree(request->encoding);
    if (request->sender)
	myfree(request->sender);
    recipient_list_free(&request->rcpt_list);
    if (request->hop_status)
	dsn_free(request->hop_status);
    if (request->client_name)
	myfree(request->client_name);
    if (request->client_addr)
	myfree(request->client_addr);
    if (request->client_port)
	myfree(request->client_port);
    if (request->client_proto)
	myfree(request->client_proto);
    if (request->client_helo)
	myfree(request->client_helo);
    if (request->sasl_method)
	myfree(request->sasl_method);
    if (request->sasl_username)
	myfree(request->sasl_username);
    if (request->sasl_sender)
	myfree(request->sasl_sender);
    if (request->rewrite_context)
	myfree(request->rewrite_context);
    if (request->dsn_envid)
	myfree(request->dsn_envid);
    myfree((char *) request);
}