Example #1
0
static int bounce_verp_proto(char *service_name, VSTREAM *client)
{
    char   *myname = "bounce_verp_proto";
    int     flags;

    /*
     * Read and validate the client request.
     */
    if (mail_command_server(client,
			    ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
			    ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
			    ATTR_TYPE_END) != 6) {
	msg_warn("malformed request");
	return (-1);
    }
    if (mail_queue_name_ok(STR(queue_name)) == 0) {
	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
	return (-1);
    }
    if (mail_queue_id_ok(STR(queue_id)) == 0) {
	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
	return (-1);
    }
    if (strlen(STR(verp_delims)) != 2) {
	msg_warn("malformed verp delimiter string: %s",
		 printable(STR(verp_delims), '?'));
	return (-1);
    }
    if (msg_verbose)
	msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s delim=%s",
		 myname, flags, service_name, STR(queue_name), STR(queue_id),
		 STR(encoding), STR(sender), STR(verp_delims));

    /*
     * On request by the client, set up a trap to delete the log file in case
     * of errors.
     */
    if (flags & BOUNCE_FLAG_CLEAN)
	bounce_cleanup_register(service_name, STR(queue_id));

    /*
     * Execute the request. Fall back to traditional notification if a bounce
     * was returned as undeliverable, because we don't want to VERPify those.
     */
    if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) {
	msg_warn("request to send VERP-style notification of bounced mail");
	return (bounce_notify_service(flags, service_name, STR(queue_name),
				      STR(queue_id), STR(encoding),
				      STR(sender)));
    } else
	return (bounce_notify_verp(flags, service_name, STR(queue_name),
				   STR(queue_id), STR(encoding),
				   STR(sender), STR(verp_delims)));
}
Example #2
0
static int bounce_notify_proto(char *service_name, VSTREAM *client,
			        int (*service) (int, char *, char *, char *,
					        char *, char *, char *, int,
						        BOUNCE_TEMPLATES *))
{
    const char *myname = "bounce_notify_proto";
    int     flags;
    int     dsn_ret;

    /*
     * Read and validate the client request.
     */
    if (mail_command_server(client,
			    ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
			    ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
			    ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
			    ATTR_TYPE_END) != 7) {
	msg_warn("malformed request");
	return (-1);
    }

    /*
     * Sanitize input.
     */
    if (mail_queue_name_ok(STR(queue_name)) == 0) {
	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
	return (-1);
    }
    if (mail_queue_id_ok(STR(queue_id)) == 0) {
	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
	return (-1);
    }
    printable(STR(dsn_envid), '?');
    if (msg_verbose)
	msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s envid=%s ret=0x%x",
		 myname, flags, service_name, STR(queue_name), STR(queue_id),
		 STR(encoding), STR(sender), STR(dsn_envid), dsn_ret);

    /*
     * On request by the client, set up a trap to delete the log file in case
     * of errors.
     */
    if (flags & BOUNCE_FLAG_CLEAN)
	bounce_cleanup_register(service_name, STR(queue_id));

    /*
     * Execute the request.
     */
    return (service(flags, service_name, STR(queue_name),
		    STR(queue_id), STR(encoding),
		    STR(sender), STR(dsn_envid), dsn_ret,
		    bounce_templates));
}
Example #3
0
static int bounce_one_proto(char *service_name, VSTREAM *client)
{
    char   *myname = "bounce_one_proto";
    int     flags;
    long    offset;

    /*
     * Read and validate the client request.
     */
    if (mail_command_server(client,
			    ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
			    ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
			    ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
			    ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
			    ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
			    ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
			    ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
			    ATTR_TYPE_END) != 11) {
	msg_warn("malformed request");
	return (-1);
    }
    if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) {
	msg_warn("wrong service name \"%s\" for one-recipient bouncing",
		 service_name);
	return (-1);
    }
    if (mail_queue_name_ok(STR(queue_name)) == 0) {
	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
	return (-1);
    }
    if (mail_queue_id_ok(STR(queue_id)) == 0) {
	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
	return (-1);
    }
    if (msg_verbose)
	msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sender=%s orig_to=%s to=%s off=%ld stat=%s act=%s why=%s",
	       myname, flags, STR(queue_name), STR(queue_id), STR(encoding),
		 STR(sender), STR(orig_rcpt), STR(recipient), offset,
		 STR(dsn_status), STR(dsn_action), STR(why));

    /*
     * Execute the request.
     */
    return (bounce_one_service(flags, STR(queue_name), STR(queue_id),
			       STR(encoding), STR(sender), STR(orig_rcpt),
			       STR(recipient), offset, STR(dsn_status),
			       STR(dsn_action), STR(why)));
}
Example #4
0
int     mail_open_ok(const char *queue_name, const char *queue_id,
		             struct stat * statp, const char **path)
{
    if (mail_queue_name_ok(queue_name) == 0) {
	msg_warn("bad mail queue name: %s", queue_name);
	return (MAIL_OPEN_NO);
    }
    if (mail_queue_id_ok(queue_id) == 0)
	return (MAIL_OPEN_NO);


    /*
     * I really would like to look up the file attributes *after* opening the
     * file so that we could save one directory traversal on systems without
     * name-to-inode cache. However, we don't necessarily always want to open
     * the file.
     */
    *path = mail_queue_path((VSTRING *) 0, queue_name, queue_id);

    if (lstat(*path, statp) < 0) {
	if (errno != ENOENT)
	    msg_warn("%s: %m", *path);
	return (MAIL_OPEN_NO);
    }
    if (!S_ISREG(statp->st_mode)) {
	msg_warn("%s: uid %ld: not a regular file", *path, (long) statp->st_uid);
	return (MAIL_OPEN_NO);
    }
    if ((statp->st_mode & S_IRWXU) != MAIL_QUEUE_STAT_READY)
	return (MAIL_OPEN_NO);

    /*
     * Workaround for spurious "file has 2 links" warnings in showq. As
     * kernels have evolved from non-interruptible system calls towards
     * fine-grained locks, the showq command has become likely to observe a
     * file while the queue manager is in the middle of renaming it, at a
     * time when the file has links to both the old and new name. We now log
     * the warning only when the condition appears to be persistent.
     */
#define MINUTE_SECONDS	60			/* XXX should be centralized */

    if (statp->st_nlink > 1) {
	if (msg_verbose)
	    msg_info("%s: uid %ld: file has %d links", *path,
		     (long) statp->st_uid, (int) statp->st_nlink);
	else if (statp->st_ctime < time((time_t *) 0) - MINUTE_SECONDS)
	    msg_warn("%s: uid %ld: file has %d links", *path,
		     (long) statp->st_uid, (int) statp->st_nlink);
    }
    return (MAIL_OPEN_YES);
}
Example #5
0
static void bounce_service(VSTREAM *client, char *service_name, char **argv)
{
    int     command;
    int     status;

    /*
     * Sanity check. This service takes no command-line arguments. The
     * service name should be usable as a subdirectory name.
     */
    if (argv[0])
	msg_fatal("unexpected command-line argument: %s", argv[0]);
    if (mail_queue_name_ok(service_name) == 0)
	msg_fatal("malformed service name: %s", service_name);

    /*
     * Read and validate the first parameter of the client request. Let the
     * request-specific protocol routines take care of the remainder.
     */
    if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
		  ATTR_TYPE_NUM, MAIL_ATTR_NREQ, &command, 0) != 1) {
	msg_warn("malformed request");
	status = -1;
    } else if (command == BOUNCE_CMD_VERP) {
	status = bounce_verp_proto(service_name, client);
    } else if (command == BOUNCE_CMD_FLUSH) {
	status = bounce_notify_proto(service_name, client,
				     bounce_notify_service);
    } else if (command == BOUNCE_CMD_WARN) {
	status = bounce_notify_proto(service_name, client,
				     bounce_warn_service);
    } else if (command == BOUNCE_CMD_TRACE) {
	status = bounce_notify_proto(service_name, client,
				     bounce_trace_service);
    } else if (command == BOUNCE_CMD_APPEND) {
	status = bounce_append_proto(service_name, client);
    } else if (command == BOUNCE_CMD_ONE) {
	status = bounce_one_proto(service_name, client);
    } else {
	msg_warn("unknown command: %d", command);
	status = -1;
    }

    /*
     * When the request has completed, send the completion status to the
     * client.
     */
    attr_print(client, ATTR_FLAG_NONE,
	       ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
	       ATTR_TYPE_END);
    vstream_fflush(client);

    /*
     * When a cleanup trap was set, delete the log file in case of error.
     * This includes errors while sending the completion status to the
     * client.
     */
    if (bounce_cleanup_path) {
	if (status || vstream_ferror(client))
	    bounce_cleanup_log();
	bounce_cleanup_unregister();
    }
}
Example #6
0
static int bounce_one_proto(char *service_name, VSTREAM *client)
{
    const char *myname = "bounce_one_proto";
    int     flags;
    int     dsn_ret;

    /*
     * Read and validate the client request.
     */
    if (mail_command_server(client,
			    ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
			    ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
			    ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
			    ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf,
			    ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf,
			    ATTR_TYPE_END) != 9) {
	msg_warn("malformed request");
	return (-1);
    }

    /*
     * Sanitize input.
     */
    if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) {
	msg_warn("wrong service name \"%s\" for one-recipient bouncing",
		 service_name);
	return (-1);
    }
    if (mail_queue_name_ok(STR(queue_name)) == 0) {
	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
	return (-1);
    }
    if (mail_queue_id_ok(STR(queue_id)) == 0) {
	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
	return (-1);
    }
    printable(STR(dsn_envid), '?');
    VS_NEUTER(rcpt_buf->address);
    VS_NEUTER(rcpt_buf->orig_addr);
    VS_NEUTER(rcpt_buf->dsn_orcpt);
    VS_NEUTER(dsn_buf->status);
    VS_NEUTER(dsn_buf->action);
    VS_NEUTER(dsn_buf->reason);
    VS_NEUTER(dsn_buf->dtype);
    VS_NEUTER(dsn_buf->dtext);
    VS_NEUTER(dsn_buf->mtype);
    VS_NEUTER(dsn_buf->mname);
    (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf);
    (void) DSN_FROM_DSN_BUF(dsn_buf);

    /*
     * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and
     * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and
     * RECIPIENT_FROM_RCPT_BUF().
     */
    if (msg_verbose)
	msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sender=%s envid=%s dsn_ret=0x%x orig_to=%s to=%s off=%ld dsn_orig=%s notif=0x%x stat=%s act=%s why=%s",
		 myname, flags, STR(queue_name), STR(queue_id),
		 STR(encoding), STR(sender), STR(dsn_envid), dsn_ret,
		 STR(rcpt_buf->orig_addr), STR(rcpt_buf->address),
		 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt),
		 rcpt_buf->dsn_notify, STR(dsn_buf->status),
		 STR(dsn_buf->action), STR(dsn_buf->reason));

    /*
     * Execute the request.
     */
    return (bounce_one_service(flags, STR(queue_name), STR(queue_id),
			       STR(encoding), STR(sender), STR(dsn_envid),
			     dsn_ret, rcpt_buf, dsn_buf, bounce_templates));
}
Example #7
0
static int bounce_verp_proto(char *service_name, VSTREAM *client)
{
    const char *myname = "bounce_verp_proto";
    int     flags;
    int     smtputf8;
    int     dsn_ret;

    /*
     * Read and validate the client request.
     */
    if (mail_command_server(client,
			    RECV_ATTR_INT(MAIL_ATTR_FLAGS, &flags),
			    RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
			    RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
			    RECV_ATTR_STR(MAIL_ATTR_ENCODING, encoding),
			    RECV_ATTR_INT(MAIL_ATTR_SMTPUTF8, &smtputf8),
			    RECV_ATTR_STR(MAIL_ATTR_SENDER, sender),
			    RECV_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid),
			    RECV_ATTR_INT(MAIL_ATTR_DSN_RET, &dsn_ret),
			    RECV_ATTR_STR(MAIL_ATTR_VERPDL, verp_delims),
			    ATTR_TYPE_END) != 9) {
	msg_warn("malformed request");
	return (-1);
    }

    /*
     * Sanitize input.
     */
    if (mail_queue_name_ok(STR(queue_name)) == 0) {
	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
	return (-1);
    }
    if (mail_queue_id_ok(STR(queue_id)) == 0) {
	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
	return (-1);
    }
    VS_NEUTER(encoding);
    VS_NEUTER(sender);
    VS_NEUTER(dsn_envid);
    VS_NEUTER(verp_delims);
    if (strlen(STR(verp_delims)) != 2) {
	msg_warn("malformed verp delimiter string: %s", STR(verp_delims));
	return (-1);
    }
    if (msg_verbose)
	msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s smtputf8=%d sender=%s envid=%s ret=0x%x delim=%s",
		 myname, flags, service_name, STR(queue_name),
		 STR(queue_id), STR(encoding), smtputf8, STR(sender),
		 STR(dsn_envid), dsn_ret, STR(verp_delims));

    /*
     * On request by the client, set up a trap to delete the log file in case
     * of errors.
     */
    if (flags & BOUNCE_FLAG_CLEAN)
	bounce_cleanup_register(service_name, STR(queue_id));

    /*
     * Execute the request. Fall back to traditional notification if a bounce
     * was returned as undeliverable, because we don't want to VERPify those.
     */
    if (!*STR(sender) || !strcasecmp_utf8(STR(sender),
					  mail_addr_double_bounce())) {
	msg_warn("request to send VERP-style notification of bounced mail");
	return (bounce_notify_service(flags, service_name, STR(queue_name),
				      STR(queue_id), STR(encoding), smtputf8,
				      STR(sender), STR(dsn_envid), dsn_ret,
				      bounce_templates));
    } else
	return (bounce_notify_verp(flags, service_name, STR(queue_name),
				   STR(queue_id), STR(encoding), smtputf8,
				   STR(sender), STR(dsn_envid), dsn_ret,
				   STR(verp_delims), bounce_templates));
}