Ejemplo n.º 1
0
void    post_mail_fopen_async(const char *sender, const char *recipient,
			              int filter_class, int trace_flags,
			              VSTRING *queue_id,
			              void (*notify) (VSTREAM *, void *),
			              void *context)
{
    VSTREAM *stream;
    POST_MAIL_STATE *state;

    stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, NON_BLOCKING);
    state = (POST_MAIL_STATE *) mymalloc(sizeof(*state));
    state->sender = mystrdup(sender);
    state->recipient = mystrdup(recipient);
    state->filter_class = filter_class;
    state->trace_flags = trace_flags;
    state->notify = notify;
    state->context = context;
    state->stream = stream;
    state->queue_id = queue_id;

    /*
     * To keep interfaces as simple as possible we report all errors via the
     * same interface as all successes.
     */
    if (stream != 0) {
	event_enable_read(vstream_fileno(stream), post_mail_open_event,
			   (void *) state);
	event_request_timer(post_mail_open_event, (void *) state,
			    var_daemon_timeout);
    } else {
	event_request_timer(post_mail_open_event, (void *) state, 0);
    }
}
Ejemplo n.º 2
0
VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient,
				        int filter_class, int trace_flags,
				        VSTRING *queue_id)
{
    VSTREAM *stream;

    if ((stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service,
			       BLOCKING)) != 0)
	post_mail_init(stream, sender, recipient, filter_class, trace_flags,
		       queue_id);
    return (stream);
}
Ejemplo n.º 3
0
static void show_queue(void)
{
    const char *errstr;
    char    buf[VSTREAM_BUFSIZE];
    VSTREAM *showq;
    int     n;
    uid_t   uid = getuid();

    if (uid != 0 && uid != var_owner_uid
	&& (errstr = check_user_acl_byuid(VAR_SHOWQ_ACL, var_showq_acl,
					  uid)) != 0)
	msg_fatal_status(EX_NOPERM,
		       "User %s(%ld) is not allowed to view the mail queue",
			 errstr, (long) uid);

    /*
     * Connect to the show queue service. Terminate silently when piping into
     * a program that terminates early.
     */
    if ((showq = mail_connect(MAIL_CLASS_PUBLIC, var_showq_service, BLOCKING)) != 0) {
	while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0) {
	    if (vstream_fwrite(VSTREAM_OUT, buf, n) != n
		|| vstream_fflush(VSTREAM_OUT) != 0) {
		if (errno == EPIPE)
		    break;
		msg_fatal("write error: %m");
	    }
	}
	if (vstream_fclose(showq) && errno != EPIPE)
	    msg_warn("close: %m");
    }

    /*
     * Don't assume that the mail system is down when the user has
     * insufficient permission to access the showq socket.
     */
    else if (errno == EACCES) {
	msg_fatal_status(EX_SOFTWARE,
			 "Connect to the %s %s service: %m",
			 var_mail_name, var_showq_service);
    }

    /*
     * When the mail system is down, the superuser can still access the queue
     * directly. Just run the showq program in stand-alone mode.
     */
    else if (geteuid() == 0) {
	ARGV   *argv;
	int     stat;

	msg_warn("Mail system is down -- accessing queue directly");
	argv = argv_alloc(6);
	argv_add(argv, var_showq_service, "-u", "-S", (char *) 0);
	for (n = 0; n < msg_verbose; n++)
	    argv_add(argv, "-v", (char *) 0);
	argv_terminate(argv);
	stat = mail_run_foreground(var_daemon_dir, argv->argv);
	argv_free(argv);
	if (stat != 0)
	    msg_fatal_status(stat < 0 ? EX_OSERR : EX_SOFTWARE,
			     "Error running %s/%s",
			     var_daemon_dir, argv->argv[0]);
    }

    /*
     * When the mail system is down, unprivileged users are stuck, because by
     * design the mail system contains no set_uid programs. The only way for
     * an unprivileged user to cross protection boundaries is to talk to the
     * showq daemon.
     */
    else {
	msg_fatal_status(EX_UNAVAILABLE,
			 "Queue report unavailable - mail system is down");
    }
}
Ejemplo n.º 4
0
void    qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOTIFY notify)
{
    QMGR_TRANSPORT_ALLOC *alloc;

    /*
     * Sanity checks.
     */
    if (transport->flags & QMGR_TRANSPORT_STAT_DEAD)
	msg_panic("qmgr_transport: dead transport: %s", transport->name);
    if (transport->flags & QMGR_TRANSPORT_STAT_RATE_LOCK)
	msg_panic("qmgr_transport: rate-locked transport: %s", transport->name);
    if (transport->pending >= QMGR_TRANSPORT_MAX_PEND)
	msg_panic("qmgr_transport: excess allocation: %s", transport->name);

    /*
     * When this message delivery transport is rate-limited, do not select it
     * again before the end of a message delivery transaction.
     */
    if (transport->xport_rate_delay > 0)
	transport->flags |= QMGR_TRANSPORT_STAT_RATE_LOCK;

    /*
     * Connect to the well-known port for this delivery service, and wake up
     * when a process announces its availability. Allow only a limited number
     * of delivery process allocation attempts for this transport. In case of
     * problems, back off. Do not hose the system when it is in trouble
     * already.
     * 
     * Use non-blocking connect(), so that Linux won't block the queue manager
     * until the delivery agent calls accept().
     * 
     * When the connection to delivery agent cannot be completed, notify the
     * event handler so that it can throttle the transport and defer the todo
     * queues, just like it does when communication fails *after* connection
     * completion.
     * 
     * Before Postfix 2.4, the event handler was not invoked after connect()
     * error, and mail was not deferred. Because of this, mail would be stuck
     * in the active queue after triggering a "connection refused" condition.
     */
    alloc = (QMGR_TRANSPORT_ALLOC *) mymalloc(sizeof(*alloc));
    alloc->transport = transport;
    alloc->notify = notify;
    transport->pending += 1;
    if ((alloc->stream = mail_connect(MAIL_CLASS_PRIVATE, transport->name,
				      NON_BLOCKING)) == 0) {
	msg_warn("connect to transport %s/%s: %m",
		 MAIL_CLASS_PRIVATE, transport->name);
	event_request_timer(qmgr_transport_event, (void *) alloc, 0);
	return;
    }
#if (EVENTS_STYLE != EVENTS_STYLE_SELECT) && defined(CA_VSTREAM_CTL_DUPFD)
#ifndef THRESHOLD_FD_WORKAROUND
#define THRESHOLD_FD_WORKAROUND 128
#endif
    vstream_control(alloc->stream,
		    CA_VSTREAM_CTL_DUPFD(THRESHOLD_FD_WORKAROUND),
		    CA_VSTREAM_CTL_END);
#endif
    event_enable_read(vstream_fileno(alloc->stream), qmgr_transport_event,
		      (void *) alloc);

    /*
     * Guard against broken systems.
     */
    event_request_timer(qmgr_transport_abort, (void *) alloc,
			var_daemon_timeout);
}
Ejemplo n.º 5
0
static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
{
    VSTRING *buffer = vstring_alloc(100);
    FORWARD_INFO *info;
    VSTREAM *cleanup;

#define FORWARD_OPEN_RETURN(res) do { \
	vstring_free(buffer); \
	return (res); \
    } while (0)

    /*
     * Contact the cleanup service and save the new mail queue id. Request
     * that the cleanup service bounces bad messages to the sender so that we
     * can avoid the trouble of bounce management.
     * 
     * In case you wonder what kind of bounces, examples are "too many hops",
     * "message too large", perhaps some others. The reason not to bounce
     * ourselves is that we don't really know who the recipients are.
     */
    cleanup = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING);
    if (cleanup == 0) {
	msg_warn("connect to %s/%s: %m",
		 MAIL_CLASS_PUBLIC, var_cleanup_service);
	FORWARD_OPEN_RETURN(0);
    }
    close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC);
    if (attr_scan(cleanup, ATTR_FLAG_STRICT,
		  RECV_ATTR_STR(MAIL_ATTR_QUEUEID, buffer),
		  ATTR_TYPE_END) != 1) {
	vstream_fclose(cleanup);
	FORWARD_OPEN_RETURN(0);
    }
    info = (FORWARD_INFO *) mymalloc(sizeof(FORWARD_INFO));
    info->cleanup = cleanup;
    info->queue_id = mystrdup(STR(buffer));
    GETTIMEOFDAY(&info->posting_time);

#define FORWARD_CLEANUP_FLAGS \
	(CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_INTERNAL \
	| smtputf8_autodetect(MAIL_SRC_MASK_FORWARD) \
	| ((request->smtputf8 & SMTPUTF8_FLAG_REQUESTED) ? \
	CLEANUP_FLAG_SMTPUTF8 : 0))

    attr_print(cleanup, ATTR_FLAG_NONE,
	       SEND_ATTR_INT(MAIL_ATTR_FLAGS, FORWARD_CLEANUP_FLAGS),
	       ATTR_TYPE_END);

    /*
     * Send initial message envelope information. For bounces, set the
     * designated sender: mailing list owner, posting user, whatever.
     */
    rec_fprintf(cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT,
		REC_TYPE_TIME_ARG(info->posting_time));
    rec_fputs(cleanup, REC_TYPE_FROM, sender);

    /*
     * Don't send the original envelope ID or full/headers return mask if it
     * was reset due to mailing list expansion.
     */
    if (request->dsn_ret)
	rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%d",
		    MAIL_ATTR_DSN_RET, request->dsn_ret);
    if (request->dsn_envid && *(request->dsn_envid))
	rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s",
		    MAIL_ATTR_DSN_ENVID, request->dsn_envid);

    /*
     * Zero-length attribute values are place holders for unavailable
     * attribute values. See qmgr_message.c. They are not meant to be
     * propagated to queue files.
     */
#define PASS_ATTR(fp, name, value) do { \
    if ((value) && *(value)) \
	rec_fprintf((fp), REC_TYPE_ATTR, "%s=%s", (name), (value)); \
    } while (0)

    /*
     * XXX encapsulate these as one object.
     */
    PASS_ATTR(cleanup, MAIL_ATTR_LOG_CLIENT_NAME, request->client_name);
    PASS_ATTR(cleanup, MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr);
    PASS_ATTR(cleanup, MAIL_ATTR_LOG_PROTO_NAME, request->client_proto);
    PASS_ATTR(cleanup, MAIL_ATTR_LOG_HELO_NAME, request->client_helo);
    PASS_ATTR(cleanup, MAIL_ATTR_SASL_METHOD, request->sasl_method);
    PASS_ATTR(cleanup, MAIL_ATTR_SASL_USERNAME, request->sasl_username);
    PASS_ATTR(cleanup, MAIL_ATTR_SASL_SENDER, request->sasl_sender);
    PASS_ATTR(cleanup, MAIL_ATTR_LOG_IDENT, request->log_ident);
    PASS_ATTR(cleanup, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context);

    FORWARD_OPEN_RETURN(info);
}