Example #1
0
int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
{
    const char *myname = "deliver_mailbox";
    int     status;
    struct mypasswd *mbox_pwd;
    char   *path;
    static MAPS *transp_maps;
    const char *map_transport;
    static MAPS *cmd_maps;
    const char *map_command;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);

    /*
     * DUPLICATE ELIMINATION
     * 
     * Don't come here more than once, whether or not the recipient exists.
     */
    if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.local))
	return (YES);

    /*
     * Delegate mailbox delivery to another message transport.
     */
    if (*var_mbox_transp_maps && transp_maps == 0)
	transp_maps = maps_create(VAR_MBOX_TRANSP_MAPS, var_mbox_transp_maps,
				  DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
    /* The -1 is a hint for the down-stream deliver_completed() function. */
    if (transp_maps
	&& (map_transport = maps_find(transp_maps, state.msg_attr.user,
				      DICT_FLAG_NONE)) != 0) {
	state.msg_attr.rcpt.offset = -1L;
	*statusp = deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
				state.request, &state.msg_attr.rcpt);
	return (YES);
    } else if (transp_maps && transp_maps->error != 0) {
	/* Details in the logfile. */
	dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	return (YES);
    }
    if (*var_mailbox_transport) {
	state.msg_attr.rcpt.offset = -1L;
	*statusp = deliver_pass(MAIL_CLASS_PRIVATE, var_mailbox_transport,
				state.request, &state.msg_attr.rcpt);
	return (YES);
    }

    /*
     * Skip delivery when this recipient does not exist.
     */
    if ((errno = mypwnam_err(state.msg_attr.user, &mbox_pwd)) != 0) {
	msg_warn("error looking up passwd info for %s: %m",
		 state.msg_attr.user);
	dsb_simple(state.msg_attr.why, "4.0.0", "user lookup error");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	return (YES);
    }
    if (mbox_pwd == 0)
	return (NO);

    /*
     * No early returns or we have a memory leak.
     */

    /*
     * DELIVERY RIGHTS
     * 
     * Use the rights of the recipient user.
     */
    SET_USER_ATTR(usr_attr, mbox_pwd, state.level);

    /*
     * Deliver to mailbox, maildir or to external command.
     */
#define LAST_CHAR(s) (s[strlen(s) - 1])

    if (*var_mailbox_cmd_maps && cmd_maps == 0)
	cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps,
			       DICT_FLAG_LOCK | DICT_FLAG_PARANOID);

    if (cmd_maps && (map_command = maps_find(cmd_maps, state.msg_attr.user,
				    DICT_FLAG_NONE)) != 0) {
	status = deliver_command(state, usr_attr, map_command);
    } else if (cmd_maps && cmd_maps->error != 0) {
	/* Details in the logfile. */
	dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
	status = defer_append(BOUNCE_FLAGS(state.request),
			      BOUNCE_ATTR(state.msg_attr));
    } else if (*var_mailbox_command) {
	status = deliver_command(state, usr_attr, var_mailbox_command);
    } else if (*var_home_mailbox && LAST_CHAR(var_home_mailbox) == '/') {
	path = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
	status = deliver_maildir(state, usr_attr, path);
	myfree(path);
    } else if (*var_mail_spool_dir && LAST_CHAR(var_mail_spool_dir) == '/') {
	path = concatenate(var_mail_spool_dir, state.msg_attr.user,
			   "/", (char *) 0);
	status = deliver_maildir(state, usr_attr, path);
	myfree(path);
    } else
	status = deliver_mailbox_file(state, usr_attr);

    /*
     * Cleanup.
     */
    mypwfree(mbox_pwd);
    *statusp = status;
    return (YES);
}
Example #2
0
int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
{
    const char *myname = "deliver_mailbox";
    const char *mailbox_res;
    const char *uid_res;
    const char *gid_res;
    DSN_BUF *why = state.msg_attr.why;
    long    n;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);

    /*
     * Sanity check.
     */
    if (*var_virt_mailbox_base != '/')
	msg_fatal("do not specify relative pathname: %s = %s",
		  VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base);

    /*
     * Look up the mailbox location. Bounce if not found, defer in case of
     * trouble.
     */
#define IGNORE_EXTENSION ((char **) 0)

    mailbox_res = mail_addr_find(virtual_mailbox_maps, state.msg_attr.user,
				 IGNORE_EXTENSION);
    if (mailbox_res == 0) {
	if (virtual_mailbox_maps->error == 0)
	    return (NO);
	msg_warn("table %s: lookup %s: %m", virtual_mailbox_maps->title,
		 state.msg_attr.user);
	dsb_simple(why, "4.3.5", "mail system configuration error");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	return (YES);
    }
    usr_attr.mailbox = concatenate(var_virt_mailbox_base, "/",
				   mailbox_res, (char *) 0);

#define RETURN(res) { myfree(usr_attr.mailbox); return (res); }

    /*
     * Look up the mailbox owner rights. Defer in case of trouble.
     */
    uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
			     IGNORE_EXTENSION);
    if (uid_res == 0) {
	msg_warn("recipient %s: not found in %s",
		 state.msg_attr.user, virtual_uid_maps->title);
	dsb_simple(why, "4.3.5", "mail system configuration error");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	RETURN(YES);
    }
    if ((n = atol(uid_res)) < var_virt_minimum_uid) {
	msg_warn("recipient %s: bad uid %s in %s",
		 state.msg_attr.user, uid_res, virtual_uid_maps->title);
	dsb_simple(why, "4.3.5", "mail system configuration error");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	RETURN(YES);
    }
    usr_attr.uid = (uid_t) n;

    /*
     * Look up the mailbox group rights. Defer in case of trouble.
     */
    gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
			     IGNORE_EXTENSION);
    if (gid_res == 0) {
	msg_warn("recipient %s: not found in %s",
		 state.msg_attr.user, virtual_gid_maps->title);
	dsb_simple(why, "4.3.5", "mail system configuration error");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	RETURN(YES);
    }
    if ((n = atol(gid_res)) <= 0) {
	msg_warn("recipient %s: bad gid %s in %s",
		 state.msg_attr.user, gid_res, virtual_gid_maps->title);
	dsb_simple(why, "4.3.5", "mail system configuration error");
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
				BOUNCE_ATTR(state.msg_attr));
	RETURN(YES);
    }
    usr_attr.gid = (gid_t) n;

    if (msg_verbose)
	msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
		 myname, state.level, usr_attr.mailbox,
		 (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);

    /*
     * Deliver to mailbox or to maildir.
     */
#define LAST_CHAR(s) (s[strlen(s) - 1])

    if (LAST_CHAR(usr_attr.mailbox) == '/')
	*statusp = deliver_maildir(state, usr_attr);
    else
	*statusp = deliver_mailbox_file(state, usr_attr);

    /*
     * Cleanup.
     */
    RETURN(YES);
}
Example #3
0
int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
{
    const char *myname = "deliver_file";
    struct stat st;
    MBOX   *mp;
    DSN_BUF *why = state.msg_attr.why;
    int     mail_copy_status = MAIL_COPY_STAT_WRITE;
    int     deliver_status;
    int     copy_flags;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);

    /*
     * DUPLICATE ELIMINATION
     * 
     * Skip this file if it was already delivered to as this user.
     */
    if (been_here(state.dup_filter, "file %ld %s", (long) usr_attr.uid, path))
	return (0);

    /*
     * DELIVERY POLICY
     * 
     * Do we allow delivery to files?
     */
    if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0) {
	dsb_simple(why, "5.7.1", "mail to file is restricted");
	/* Account for possible owner- sender address override. */
	return (bounce_workaround(state));
    }

    /*
     * Don't deliver trace-only requests.
     */
    if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
	dsb_simple(why, "2.0.0", "delivers to file: %s", path);
	return (sent(BOUNCE_FLAGS(state.request),
		     SENT_ATTR(state.msg_attr)));
    }

    /*
     * DELIVERY RIGHTS
     * 
     * Use a default uid/gid when none are given.
     */
    if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0)
	msg_panic("privileged default user id");
    if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0)
	msg_panic("privileged default group id");

    /*
     * If the name ends in /, use maildir-style delivery instead.
     */
    if (path[strlen(path) - 1] == '/')
	return (deliver_maildir(state, usr_attr, path));

    /*
     * Deliver. From here on, no early returns or we have a memory leak.
     */
    if (msg_verbose)
	msg_info("deliver_file (%ld,%ld): %s",
		 (long) usr_attr.uid, (long) usr_attr.gid, path);
    if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
	msg_fatal("seek queue file %s: %m", state.msg_attr.queue_id);

    /*
     * As the specified user, open or create the file, lock it, and append
     * the message.
     */
    copy_flags = MAIL_COPY_MBOX;
    if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
	copy_flags &= ~MAIL_COPY_DELIVERED;

    set_eugid(usr_attr.uid, usr_attr.gid);
    mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
		   S_IRUSR | S_IWUSR, &st, -1, -1,
		   local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL,
		   "5.2.0", why);
    if (mp != 0) {
	if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
	    vstream_fclose(mp->fp);
	    dsb_simple(why, "5.7.1", "file is executable");
	} else {
	    mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
					 S_ISREG(st.st_mode) ? copy_flags :
					 (copy_flags & ~MAIL_COPY_TOFILE),
					 "\n", why);
	}
	mbox_release(mp);
    }
    set_eugid(var_owner_uid, var_owner_gid);

    /*
     * As the mail system, bounce, defer delivery, or report success.
     */
    if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
	deliver_status = DEL_STAT_DEFER;
    } else if (mail_copy_status != 0) {
	vstring_sprintf_prepend(why->reason,
				"cannot append message to file %s: ", path);
	if (STR(why->status)[0] == '4')
	    deliver_status =
		defer_append(BOUNCE_FLAGS(state.request),
			     BOUNCE_ATTR(state.msg_attr));
	else
	    /* Account for possible owner- sender address override. */
	    deliver_status = bounce_workaround(state);
    } else {
	dsb_simple(why, "2.0.0", "delivered to file: %s", path);
	deliver_status = sent(BOUNCE_FLAGS(state.request),
			      SENT_ATTR(state.msg_attr));
    }
    return (deliver_status);
}