1 /* $NetBSD: file.c,v 1.1.1.2 2010/06/17 18:06:53 tron 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 if (STR(why->status)[0] == '4') 190 deliver_status = 191 defer_append(BOUNCE_FLAGS(state.request), 192 BOUNCE_ATTR(state.msg_attr)); 193 else 194 /* Account for possible owner- sender address override. */ 195 deliver_status = bounce_workaround(state); 196 } else { 197 dsb_simple(why, "2.0.0", "delivered to file: %s", path); 198 deliver_status = sent(BOUNCE_FLAGS(state.request), 199 SENT_ATTR(state.msg_attr)); 200 } 201 return (deliver_status); 202 } 203