Home | History | Annotate | Line # | Download | only in local
      1 /*	$NetBSD: file.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	file 3
      6 /* SUMMARY
      7 /*	mail delivery to arbitrary file
      8 /* SYNOPSIS
      9 /*	#include "local.h"
     10 /*
     11 /*	int	deliver_file(state, usr_attr, path)
     12 /*	LOCAL_STATE state;
     13 /*	USER_ATTR usr_attr;
     14 /*	char	*path;
     15 /* DESCRIPTION
     16 /*	deliver_file() appends a message to a file, UNIX mailbox format,
     17 /*	or qmail maildir format,
     18 /*	with duplicate suppression. It will deliver only to non-executable
     19 /*	regular files.
     20 /*
     21 /*	Arguments:
     22 /* .IP state
     23 /*	The attributes that specify the message, recipient and more.
     24 /*	Attributes describing alias, include or forward expansion.
     25 /*	A table with the results from expanding aliases or lists.
     26 /* .IP usr_attr
     27 /*	Attributes describing user rights and environment information.
     28 /* .IP path
     29 /*	The file to deliver to. If the name ends in '/', delivery is done
     30 /*	in qmail maildir format, otherwise delivery is done in UNIX mailbox
     31 /*	format.
     32 /* DIAGNOSTICS
     33 /*	deliver_file() returns non-zero when delivery should be tried again.
     34 /* SEE ALSO
     35 /*	defer(3)
     36 /*	bounce(3)
     37 /* LICENSE
     38 /* .ad
     39 /* .fi
     40 /*	The Secure Mailer license must be distributed with this software.
     41 /* AUTHOR(S)
     42 /*	Wietse Venema
     43 /*	IBM T.J. Watson Research
     44 /*	P.O. Box 704
     45 /*	Yorktown Heights, NY 10598, USA
     46 /*--*/
     47 
     48 /* System library. */
     49 
     50 #include <sys_defs.h>
     51 #include <sys/stat.h>
     52 #include <unistd.h>
     53 #include <fcntl.h>
     54 #include <errno.h>
     55 #include <string.h>
     56 
     57 /* Utility library. */
     58 
     59 #include <msg.h>
     60 #include <htable.h>
     61 #include <vstring.h>
     62 #include <vstream.h>
     63 #include <deliver_flock.h>
     64 #include <set_eugid.h>
     65 
     66 /* Global library. */
     67 
     68 #include <mail_copy.h>
     69 #include <bounce.h>
     70 #include <defer.h>
     71 #include <sent.h>
     72 #include <been_here.h>
     73 #include <mail_params.h>
     74 #include <mbox_conf.h>
     75 #include <mbox_open.h>
     76 #include <dsn_util.h>
     77 
     78 /* Application-specific. */
     79 
     80 #include "local.h"
     81 
     82 /* deliver_file - deliver to file */
     83 
     84 int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     85 {
     86     const char *myname = "deliver_file";
     87     struct stat st;
     88     MBOX   *mp;
     89     DSN_BUF *why = state.msg_attr.why;
     90     int     mail_copy_status = MAIL_COPY_STAT_WRITE;
     91     int     deliver_status;
     92     int     copy_flags;
     93 
     94     /*
     95      * Make verbose logging easier to understand.
     96      */
     97     state.level++;
     98     if (msg_verbose)
     99 	MSG_LOG_STATE(myname, state);
    100 
    101     /*
    102      * DUPLICATE ELIMINATION
    103      *
    104      * Skip this file if it was already delivered to as this user.
    105      */
    106     if (been_here(state.dup_filter, "file %ld %s", (long) usr_attr.uid, path))
    107 	return (0);
    108 
    109     /*
    110      * DELIVERY POLICY
    111      *
    112      * Do we allow delivery to files?
    113      */
    114     if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0) {
    115 	dsb_simple(why, "5.7.1", "mail to file is restricted");
    116 	/* Account for possible owner- sender address override. */
    117 	return (bounce_workaround(state));
    118     }
    119 
    120     /*
    121      * Don't deliver trace-only requests.
    122      */
    123     if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
    124 	dsb_simple(why, "2.0.0", "delivers to file: %s", path);
    125 	return (sent(BOUNCE_FLAGS(state.request),
    126 		     SENT_ATTR(state.msg_attr)));
    127     }
    128 
    129     /*
    130      * DELIVERY RIGHTS
    131      *
    132      * Use a default uid/gid when none are given.
    133      */
    134     if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0)
    135 	msg_panic("privileged default user id");
    136     if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0)
    137 	msg_panic("privileged default group id");
    138 
    139     /*
    140      * If the name ends in /, use maildir-style delivery instead.
    141      */
    142     if (path[strlen(path) - 1] == '/')
    143 	return (deliver_maildir(state, usr_attr, path));
    144 
    145     /*
    146      * Deliver. From here on, no early returns or we have a memory leak.
    147      */
    148     if (msg_verbose)
    149 	msg_info("deliver_file (%ld,%ld): %s",
    150 		 (long) usr_attr.uid, (long) usr_attr.gid, path);
    151     if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
    152 	msg_fatal("seek queue file %s: %m", state.msg_attr.queue_id);
    153 
    154     /*
    155      * As the specified user, open or create the file, lock it, and append
    156      * the message.
    157      */
    158     copy_flags = MAIL_COPY_MBOX;
    159     if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
    160 	copy_flags &= ~MAIL_COPY_DELIVERED;
    161 
    162     set_eugid(usr_attr.uid, usr_attr.gid);
    163     mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
    164 		   S_IRUSR | S_IWUSR, &st, -1, -1,
    165 		   local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL,
    166 		   "5.2.0", why);
    167     if (mp != 0) {
    168 	if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
    169 	    vstream_fclose(mp->fp);
    170 	    dsb_simple(why, "5.7.1", "file is executable");
    171 	} else {
    172 	    mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
    173 					 S_ISREG(st.st_mode) ? copy_flags :
    174 					 (copy_flags & ~MAIL_COPY_TOFILE),
    175 					 "\n", why);
    176 	}
    177 	mbox_release(mp);
    178     }
    179     set_eugid(var_owner_uid, var_owner_gid);
    180 
    181     /*
    182      * As the mail system, bounce, defer delivery, or report success.
    183      */
    184     if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
    185 	deliver_status = DEL_STAT_DEFER;
    186     } else if (mail_copy_status != 0) {
    187 	vstring_sprintf_prepend(why->reason,
    188 				"cannot append message to file %s: ", path);
    189 	/* Account for possible owner- sender address override. */
    190 	deliver_status = bounce_workaround(state);
    191     } else {
    192 	dsb_simple(why, "2.0.0", "delivered to file: %s", path);
    193 	deliver_status = sent(BOUNCE_FLAGS(state.request),
    194 			      SENT_ATTR(state.msg_attr));
    195     }
    196     return (deliver_status);
    197 }
    198