Postfix3.3.1
command.c
[詳解]
1 /*++
2 /* NAME
3 /* command 3
4 /* SUMMARY
5 /* message delivery to shell command
6 /* SYNOPSIS
7 /* #include "local.h"
8 /*
9 /* int deliver_command(state, usr_attr, command)
10 /* LOCAL_STATE state;
11 /* USER_ATTR exp_attr;
12 /* const char *command;
13 /* DESCRIPTION
14 /* deliver_command() runs a command with a message as standard
15 /* input. A limited amount of standard output and standard error
16 /* output is captured for diagnostics purposes.
17 /* Duplicate commands for the same recipient are suppressed.
18 /* A limited amount of information is exported via the environment:
19 /* HOME, SHELL, LOGNAME, USER, EXTENSION, DOMAIN, RECIPIENT (entire
20 /* address) LOCAL (just the local part) and SENDER. The exported
21 /* information is censored with var_cmd_filter.
22 /*
23 /* Arguments:
24 /* .IP state
25 /* The attributes that specify the message, recipient and more.
26 /* Attributes describing the alias, include or forward expansion.
27 /* A table with the results from expanding aliases or lists.
28 /* .IP usr_attr
29 /* Attributes describing user rights and environment.
30 /* .IP command
31 /* The shell command to be executed. If possible, the command is
32 /* executed without actually invoking a shell. if the command is
33 /* the mailbox_command, it is subjected to $name expansion.
34 /* DIAGNOSTICS
35 /* deliver_command() returns non-zero when delivery should be
36 /* tried again,
37 /* SEE ALSO
38 /* mailbox(3) deliver to mailbox
39 /* LICENSE
40 /* .ad
41 /* .fi
42 /* The Secure Mailer license must be distributed with this software.
43 /* AUTHOR(S)
44 /* Wietse Venema
45 /* IBM T.J. Watson Research
46 /* P.O. Box 704
47 /* Yorktown Heights, NY 10598, USA
48 /*--*/
49 
50 /* System library. */
51 
52 #include <sys_defs.h>
53 #include <unistd.h>
54 #include <stdlib.h>
55 #include <stdarg.h>
56 #include <string.h>
57 
58 /* Utility library. */
59 
60 #include <msg.h>
61 #include <htable.h>
62 #include <vstring.h>
63 #include <vstream.h>
64 #include <argv.h>
65 #include <mac_parse.h>
66 
67 /* Global library. */
68 
69 #include <defer.h>
70 #include <bounce.h>
71 #include <sent.h>
72 #include <been_here.h>
73 #include <mail_params.h>
74 #include <pipe_command.h>
75 #include <mail_copy.h>
76 #include <dsn_util.h>
77 #include <mail_parm_split.h>
78 
79 /* Application-specific. */
80 
81 #include "local.h"
82 
83 /* deliver_command - deliver to shell command */
84 
85 int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *command)
86 {
87  const char *myname = "deliver_command";
88  DSN_BUF *why = state.msg_attr.why;
89  int cmd_status;
90  int deliver_status;
91  ARGV *env;
92  int copy_flags;
93  char **cpp;
94  char *cp;
95  ARGV *export_env;
96  VSTRING *exec_dir;
97  int expand_status;
98 
99  /*
100  * Make verbose logging easier to understand.
101  */
102  state.level++;
103  if (msg_verbose)
104  MSG_LOG_STATE(myname, state);
105 
106  /*
107  * DUPLICATE ELIMINATION
108  *
109  * Skip this command if it was already delivered to as this user.
110  */
111  if (been_here(state.dup_filter, "command %s:%ld %s",
112  state.msg_attr.user, (long) usr_attr.uid, command))
113  return (0);
114 
115  /*
116  * Don't deliver a trace-only request.
117  */
118  if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
119  dsb_simple(why, "2.0.0", "delivers to command: %s", command);
120  return (sent(BOUNCE_FLAGS(state.request),
121  SENT_ATTR(state.msg_attr)));
122  }
123 
124  /*
125  * DELIVERY RIGHTS
126  *
127  * Choose a default uid and gid when none have been selected (i.e. values
128  * are still zero).
129  */
130  if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0)
131  msg_panic("privileged default user id");
132  if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0)
133  msg_panic("privileged default group id");
134 
135  /*
136  * Deliver.
137  */
141  copy_flags |= MAIL_COPY_DELIVERED;
142 
143  if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
144  msg_fatal("%s: seek queue file %s: %m",
145  myname, VSTREAM_PATH(state.msg_attr.fp));
146 
147  /*
148  * Pass additional environment information. XXX This should be
149  * configurable. However, passing untrusted information via environment
150  * parameters opens up a whole can of worms. Lesson from web servers:
151  * don't let any network data even near a shell. It causes trouble.
152  */
153  env = argv_alloc(1);
154  if (usr_attr.home)
155  argv_add(env, "HOME", usr_attr.home, ARGV_END);
156  argv_add(env,
157  "LOGNAME", state.msg_attr.user,
158  "USER", state.msg_attr.user,
159  "SENDER", state.msg_attr.sender,
160  "RECIPIENT", state.msg_attr.rcpt.address,
161  "LOCAL", state.msg_attr.local,
162  ARGV_END);
163  if (usr_attr.shell)
164  argv_add(env, "SHELL", usr_attr.shell, ARGV_END);
165  if (state.msg_attr.domain)
166  argv_add(env, "DOMAIN", state.msg_attr.domain, ARGV_END);
167  if (state.msg_attr.extension)
168  argv_add(env, "EXTENSION", state.msg_attr.extension, ARGV_END);
169  if (state.msg_attr.rcpt.orig_addr && state.msg_attr.rcpt.orig_addr[0])
170  argv_add(env, "ORIGINAL_RECIPIENT", state.msg_attr.rcpt.orig_addr,
171  ARGV_END);
172 
173 #define EXPORT_REQUEST(name, value) \
174  if ((value)[0]) argv_add(env, (name), (value), ARGV_END);
175 
176  EXPORT_REQUEST("CLIENT_HOSTNAME", state.msg_attr.request->client_name);
177  EXPORT_REQUEST("CLIENT_ADDRESS", state.msg_attr.request->client_addr);
178  EXPORT_REQUEST("CLIENT_HELO", state.msg_attr.request->client_helo);
179  EXPORT_REQUEST("CLIENT_PROTOCOL", state.msg_attr.request->client_proto);
180  EXPORT_REQUEST("SASL_METHOD", state.msg_attr.request->sasl_method);
181  EXPORT_REQUEST("SASL_SENDER", state.msg_attr.request->sasl_sender);
182  EXPORT_REQUEST("SASL_USERNAME", state.msg_attr.request->sasl_username);
183 
184  argv_terminate(env);
185 
186  /*
187  * Censor out undesirable characters from exported data.
188  */
189  for (cpp = env->argv; *cpp; cpp += 2)
190  for (cp = cpp[1]; *(cp += strspn(cp, var_cmd_exp_filter)) != 0;)
191  *cp++ = '_';
192 
193  /*
194  * Evaluate the command execution directory. Defer delivery if expansion
195  * fails.
196  */
198  exec_dir = vstring_alloc(10);
199  expand_status = local_expand(exec_dir, var_exec_directory,
200  &state, &usr_attr, var_exec_exp_filter);
201 
202  if (expand_status & MAC_PARSE_ERROR) {
203  cmd_status = PIPE_STAT_DEFER;
204  dsb_simple(why, "4.3.5", "mail system configuration error");
205  msg_warn("bad parameter value syntax for %s: %s",
207  } else {
208  cmd_status = pipe_command(state.msg_attr.fp, why,
209  CA_PIPE_CMD_UID(usr_attr.uid),
210  CA_PIPE_CMD_GID(usr_attr.gid),
211  CA_PIPE_CMD_COMMAND(command),
212  CA_PIPE_CMD_COPY_FLAGS(copy_flags),
217  CA_PIPE_CMD_ENV(env->argv),
218  CA_PIPE_CMD_EXPORT(export_env->argv),
220  CA_PIPE_CMD_CWD(*STR(exec_dir) ?
221  STR(exec_dir) : (char *) 0),
223  }
224  vstring_free(exec_dir);
225  argv_free(export_env);
226  argv_free(env);
227 
228  /*
229  * Depending on the result, bounce or defer the message.
230  */
231  switch (cmd_status) {
232  case PIPE_STAT_OK:
233  dsb_simple(why, "2.0.0", "delivered to command: %s", command);
234  deliver_status = sent(BOUNCE_FLAGS(state.request),
235  SENT_ATTR(state.msg_attr));
236  break;
237  case PIPE_STAT_BOUNCE:
238  case PIPE_STAT_DEFER:
239  /* Account for possible owner- sender address override. */
240  deliver_status = bounce_workaround(state);
241  break;
242  case PIPE_STAT_CORRUPT:
243  deliver_status = DEL_STAT_DEFER;
244  break;
245  default:
246  msg_panic("%s: bad status %d", myname, cmd_status);
247  /* NOTREACHED */
248  }
249 
250  return (deliver_status);
251 }
int msg_verbose
Definition: msg.c:177
#define SENT_ATTR(attr)
Definition: local.h:142
const char * orig_addr
char * extension
Definition: local.h:83
#define CA_PIPE_CMD_DELIVERED(v)
Definition: pipe_command.h:55
#define CA_PIPE_CMD_CWD(v)
Definition: pipe_command.h:64
#define ARGV_END
Definition: argv.h:52
#define PIPE_STAT_DEFER
Definition: pipe_command.h:77
gid_t var_default_gid
Definition: mail_params.c:240
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
const char * address
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define EXPORT_REQUEST(name, value)
char * local
Definition: local.h:81
char * var_exec_directory
Definition: local.c:666
int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *command)
Definition: command.c:85
#define PIPE_STAT_OK
Definition: pipe_command.h:76
#define MAIL_COPY_RETURN_PATH
Definition: mail_copy.h:36
char ** argv
Definition: argv.h:20
#define DEL_REQ_TRACE_ONLY(f)
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
DELIVER_REQUEST * request
Definition: local.h:91
#define CA_PIPE_CMD_UID(v)
Definition: pipe_command.h:56
char * domain
Definition: local.h:80
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
#define PIPE_STAT_CORRUPT
Definition: pipe_command.h:79
#define CA_PIPE_CMD_COPY_FLAGS(v)
Definition: pipe_command.h:53
DELIVER_REQUEST * request
Definition: local.h:113
uid_t var_default_uid
Definition: mail_params.c:239
char * var_cmd_exp_filter
Definition: local.c:669
#define BOUNCE_FLAGS(request)
#define VAR_EXPORT_ENVIRON
Definition: mail_params.h:2510
int pipe_command(VSTREAM *src, DSN_BUF *why,...)
Definition: pipe_command.c:389
BH_TABLE * dup_filter
Definition: local.h:111
char * var_local_cmd_shell
Definition: local.c:658
ARGV * mail_parm_split(const char *name, const char *value)
int been_here(BH_TABLE *dup_filter, const char *fmt,...)
Definition: been_here.c:124
#define CA_PIPE_CMD_END
Definition: pipe_command.h:50
char * user
Definition: local.h:82
#define CA_PIPE_CMD_GID(v)
Definition: pipe_command.h:57
DELIVER_ATTR msg_attr
Definition: local.h:110
#define MAIL_COPY_FROM
Definition: mail_copy.h:34
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * shell
Definition: local.h:40
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define DELIVER_HDR_CMD
Definition: local.h:202
#define CA_PIPE_CMD_TIME_LIMIT(v)
Definition: pipe_command.h:58
int var_command_maxtime
Definition: local.c:653
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
#define MAIL_COPY_DELIVERED
Definition: mail_copy.h:35
char * home
Definition: local.h:38
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
VSTREAM * fp
Definition: local.h:70
#define DEL_STAT_DEFER
gid_t gid
Definition: local.h:37
int bounce_workaround(LOCAL_STATE state)
DSN_BUF * why
Definition: local.h:92
#define CA_PIPE_CMD_COMMAND(v)
Definition: pipe_command.h:51
const char * delivered
Definition: local.h:86
#define VAR_EXEC_DIRECTORY
Definition: mail_params.h:613
#define CA_PIPE_CMD_ORIG_RCPT(v)
Definition: pipe_command.h:63
int level
Definition: local.h:109
#define CA_PIPE_CMD_SHELL(v)
Definition: pipe_command.h:60
#define CA_PIPE_CMD_SENDER(v)
Definition: pipe_command.h:54
int local_expand(VSTRING *, const char *, LOCAL_STATE *, USER_ATTR *, const char *)
Definition: local_expand.c:166
uid_t uid
Definition: local.h:36
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define CA_PIPE_CMD_ENV(v)
Definition: pipe_command.h:59
const char * sender
Definition: local.h:76
char * var_export_environ
Definition: mail_params.c:297
RECIPIENT rcpt
Definition: local.h:79
#define PIPE_STAT_BOUNCE
Definition: pipe_command.h:78
#define MAIL_COPY_ORIG_RCPT
Definition: mail_copy.h:39
int sent(int flags, const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn)
Definition: sent.c:95
long offset
Definition: local.h:73
#define MSG_LOG_STATE(m, p)
Definition: local.h:150
#define CA_PIPE_CMD_EXPORT(v)
Definition: pipe_command.h:62
int local_deliver_hdr_mask
Definition: local.c:685
char * var_exec_exp_filter
Definition: local.c:667
#define MAC_PARSE_ERROR
Definition: mac_parse.h:27
void argv_terminate(ARGV *argvp)
Definition: argv.c:242