Postfix3.3.1
server_acl.c
[詳解]
1 /*++
2 /* NAME
3 /* server_acl 3
4 /* SUMMARY
5 /* server access list
6 /* SYNOPSIS
7 /* #include <server_acl.h>
8 /*
9 /* void server_acl_pre_jail_init(mynetworks, param_name)
10 /* const char *mynetworks;
11 /* const char *param_name;
12 /*
13 /* SERVER_ACL *server_acl_parse(extern_acl, param_name)
14 /* const char *extern_acl;
15 /* const char *param_name;
16 /*
17 /* int server_acl_eval(client_addr, intern_acl, param_name)
18 /* const char *client_addr;
19 /* SERVER_ACL *intern_acl;
20 /* const char *param_name;
21 /* DESCRIPTION
22 /* This module implements a permanent black/whitelist that
23 /* is meant to be evaluated immediately after a client connects
24 /* to a server.
25 /*
26 /* server_acl_pre_jail_init() does before-chroot initialization
27 /* for the permit_mynetworks setting.
28 /*
29 /* server_acl_parse() converts an access list from raw string
30 /* form to binary form. It should also be called as part of
31 /* before-chroot initialization.
32 /*
33 /* server_acl_eval() evaluates an access list for the specified
34 /* client address. The result is SERVER_ACL_ACT_PERMIT (permit),
35 /* SERVER_ACL_ACT_REJECT (reject), SERVER_ACL_ACT_DUNNO (no
36 /* decision), or SERVER_ACL_ACT_ERROR (error, unknown command
37 /* or database access error).
38 /*
39 /* Arguments:
40 /* .IP mynetworks
41 /* Network addresses that match "permit_mynetworks".
42 /* .IP param_name
43 /* The configuration parameter name for the access list from
44 /* main.cf. The information is used for error reporting (nested
45 /* table, unknown keyword) and to select the appropriate
46 /* behavior from parent_domain_matches_subdomains.
47 /* .IP extern_acl
48 /* External access list representation.
49 /* .IP intern_acl
50 /* Internal access list representation.
51 /* .IP client_addr
52 /* The client IP address as printable string (without []).
53 /* LICENSE
54 /* .ad
55 /* .fi
56 /* The Secure Mailer license must be distributed with this software.
57 /* AUTHOR(S)
58 /* Wietse Venema
59 /* IBM T.J. Watson Research
60 /* P.O. Box 704
61 /* Yorktown Heights, NY 10598, USA
62 /*--*/
63 
64 /* System library. */
65 
66 #include <sys_defs.h>
67 #include <string.h>
68 
69 #ifdef STRCASECMP_IN_STRINGS_H
70 #include <strings.h>
71 #endif
72 
73 /* Utility library. */
74 
75 #include <msg.h>
76 #include <mymalloc.h>
77 #include <stringops.h>
78 #include <dict.h>
79 
80 /* Global library. */
81 
82 #include <mail_params.h>
83 #include <addr_match_list.h>
84 #include <match_parent_style.h>
85 #include <mynetworks.h>
86 #include <server_acl.h>
87 
88 /* Application-specific. */
89 
90 static ADDR_MATCH_LIST *server_acl_mynetworks;
91 static ADDR_MATCH_LIST *server_acl_mynetworks_host;
92 
93 #define STR vstring_str
94 
95 /* server_acl_pre_jail_init - initialize */
96 
97 void server_acl_pre_jail_init(const char *mynetworks, const char *origin)
98 {
99  if (server_acl_mynetworks) {
100  addr_match_list_free(server_acl_mynetworks);
101  if (server_acl_mynetworks_host)
102  addr_match_list_free(server_acl_mynetworks_host);
103  }
104  server_acl_mynetworks =
106  | match_parent_style(origin), mynetworks);
108  server_acl_mynetworks_host =
110  | match_parent_style(origin), mynetworks_host());
111 }
112 
113 /* server_acl_parse - parse access list */
114 
115 SERVER_ACL *server_acl_parse(const char *extern_acl, const char *origin)
116 {
117  char *saved_acl = mystrdup(extern_acl);
118  SERVER_ACL *intern_acl = argv_alloc(1);
119  char *bp = saved_acl;
120  char *acl;
121 
122 #define STREQ(x,y) (strcasecmp((x), (y)) == 0)
123 #define STRNE(x,y) (strcasecmp((x), (y)) != 0)
124 
125  /*
126  * Nested tables are not allowed. Tables are opened before entering the
127  * chroot jail, while access lists are evaluated after entering the
128  * chroot jail.
129  */
130  while ((acl = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
131  if (strchr(acl, ':') != 0) {
132  if (strchr(origin, ':') != 0) {
133  msg_warn("table %s: lookup result \"%s\" is not allowed"
134  " -- ignoring remainder of access list",
135  origin, acl);
136  argv_add(intern_acl, SERVER_ACL_NAME_DUNNO, (char *) 0);
137  break;
138  } else {
139  if (dict_handle(acl) == 0)
140  dict_register(acl, dict_open(acl, O_RDONLY, DICT_FLAG_LOCK
143  }
144  }
145  argv_add(intern_acl, acl, (char *) 0);
146  }
147  argv_terminate(intern_acl);
148 
149  /*
150  * Cleanup.
151  */
152  myfree(saved_acl);
153  return (intern_acl);
154 }
155 
156 /* server_acl_eval - evaluate access list */
157 
158 int server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl,
159  const char *origin)
160 {
161  const char *myname = "server_acl_eval";
162  char **cpp;
163  DICT *dict;
164  SERVER_ACL *argv;
165  const char *acl;
166  const char *dict_val;
167  int ret;
168 
169  for (cpp = intern_acl->argv; (acl = *cpp) != 0; cpp++) {
170  if (msg_verbose)
171  msg_info("source=%s address=%s acl=%s",
172  origin, client_addr, acl);
173  if (STREQ(acl, SERVER_ACL_NAME_REJECT)) {
174  return (SERVER_ACL_ACT_REJECT);
175  } else if (STREQ(acl, SERVER_ACL_NAME_PERMIT)) {
176  return (SERVER_ACL_ACT_PERMIT);
177  } else if (STREQ(acl, SERVER_ACL_NAME_WL_MYNETWORKS)) {
178  if (addr_match_list_match(server_acl_mynetworks, client_addr)) {
180  && !addr_match_list_match(server_acl_mynetworks_host,
181  client_addr))
182  msg_info("using backwards-compatible default setting "
183  VAR_MYNETWORKS_STYLE "=%s to permit "
184  "request from client \"%s\"",
185  var_mynetworks_style, client_addr);
186  return (SERVER_ACL_ACT_PERMIT);
187  }
188  if (server_acl_mynetworks->error != 0) {
189  msg_warn("%s: %s: mynetworks lookup error -- ignoring the "
190  "remainder of this access list", origin, acl);
191  return (SERVER_ACL_ACT_ERROR);
192  }
193  } else if (strchr(acl, ':') != 0) {
194  if ((dict = dict_handle(acl)) == 0)
195  msg_panic("%s: unexpected dictionary: %s", myname, acl);
196  if ((dict_val = dict_get(dict, client_addr)) != 0) {
197  /* Fake up an ARGV to avoid lots of mallocs and frees. */
198  if (dict_val[strcspn(dict_val, ":" CHARS_COMMA_SP)] == 0) {
199  ARGV_FAKE_BEGIN(fake_argv, dict_val);
200  ret = server_acl_eval(client_addr, &fake_argv, acl);
202  } else {
203  argv = server_acl_parse(dict_val, acl);
204  ret = server_acl_eval(client_addr, argv, acl);
205  argv_free(argv);
206  }
207  if (ret != SERVER_ACL_ACT_DUNNO)
208  return (ret);
209  } else if (dict->error != 0) {
210  msg_warn("%s: %s: table lookup error -- ignoring the remainder "
211  "of this access list", origin, acl);
212  return (SERVER_ACL_ACT_ERROR);
213  }
214  } else if (STREQ(acl, SERVER_ACL_NAME_DUNNO)) {
215  return (SERVER_ACL_ACT_DUNNO);
216  } else {
217  msg_warn("%s: unknown command: %s -- ignoring the remainder "
218  "of this access list", origin, acl);
219  return (SERVER_ACL_ACT_ERROR);
220  }
221  }
222  if (msg_verbose)
223  msg_info("source=%s address=%s - no match",
224  origin, client_addr);
225  return (SERVER_ACL_ACT_DUNNO);
226 }
227 
228  /*
229  * Access lists need testing. Not only with good inputs; error cases must
230  * also be handled appropriately.
231  */
232 #ifdef TEST
233 #include <unistd.h>
234 #include <stdlib.h>
235 #include <vstring_vstream.h>
236 #include <name_code.h>
237 #include <split_at.h>
238 
240 char *var_mynetworks = "";
241 char *var_server_acl = "";
242 
243 #define UPDATE_VAR(s,v) do { if (*(s)) myfree(s); (s) = mystrdup(v); } while (0)
244 
245 int main(void)
246 {
247  VSTRING *buf = vstring_alloc(100);
248  SERVER_ACL *argv;
249  int ret;
250  int have_tty = isatty(0);
251  char *bufp;
252  char *cmd;
253  char *value;
254  const NAME_CODE acl_map[] = {
259  0,
260  };
261 
262 #define VAR_SERVER_ACL "server_acl"
263 
264  while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
265  bufp = STR(buf);
266  if (have_tty == 0) {
267  vstream_printf("> %s\n", bufp);
269  }
270  if (*bufp == '#')
271  continue;
272  if ((cmd = mystrtok(&bufp, " =")) == 0 || STREQ(cmd, "?")) {
273  vstream_printf("usage: %s=value|%s=value|address=value\n",
274  VAR_MYNETWORKS, VAR_SERVER_ACL);
275  } else if ((value = mystrtok(&bufp, " =")) == 0) {
276  vstream_printf("missing value\n");
277  } else if (STREQ(cmd, VAR_MYNETWORKS)) {
278  UPDATE_VAR(var_mynetworks, value);
279  } else if (STREQ(cmd, VAR_SERVER_ACL)) {
280  UPDATE_VAR(var_server_acl, value);
281  } else if (STREQ(cmd, "address")) {
283  argv = server_acl_parse(var_server_acl, VAR_SERVER_ACL);
284  ret = server_acl_eval(value, argv, VAR_SERVER_ACL);
285  argv_free(argv);
286  vstream_printf("%s: %s\n", value, str_name_code(acl_map, ret));
287  } else {
288  vstream_printf("unknown command: \"%s\"\n", cmd);
289  }
291  }
292  vstring_free(buf);
293  exit(0);
294 }
295 
296 #endif
int msg_verbose
Definition: msg.c:177
#define SERVER_ACL_ACT_ERROR
Definition: server_acl.h:36
#define VSTREAM_EOF
Definition: vstream.h:110
#define STR
Definition: server_acl.c:93
void myfree(void *ptr)
Definition: mymalloc.c:207
#define MATCH_FLAG_RETURN
Definition: match_list.h:40
int match_parent_style(const char *name)
#define CHARS_BRACE
Definition: sys_defs.h:1763
#define addr_match_list_match(l, a)
char * mystrdup(const char *str)
Definition: mymalloc.c:225
void dict_register(const char *dict_name, DICT *dict_info)
Definition: dict.c:312
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
#define SERVER_ACL_NAME_PERMIT
Definition: server_acl.h:28
char ** argv
Definition: argv.h:20
void server_acl_pre_jail_init(const char *mynetworks, const char *origin)
Definition: server_acl.c:97
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
char * mystrtokq(char **src, const char *sep, const char *parens)
Definition: mystrtok.c:80
DICT * dict_open(const char *, int, int)
Definition: dict_open.c:421
#define DICT_FLAG_UTF8_REQUEST
Definition: dict.h:130
#define VSTREAM_IN
Definition: vstream.h:66
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
#define DICT_FLAG_FOLD_FIX
Definition: dict.h:124
const char * mynetworks(void)
Definition: mynetworks.c:295
#define SERVER_ACL_ACT_PERMIT
Definition: server_acl.h:33
SERVER_ACL * server_acl_parse(const char *extern_acl, const char *origin)
Definition: server_acl.c:115
int server_acl_eval(const char *client_addr, SERVER_ACL *intern_acl, const char *origin)
Definition: server_acl.c:158
Definition: dict.h:78
const char * mynetworks_host(void)
Definition: mynetworks.c:306
int warn_compat_break_mynetworks_style
Definition: mail_params.c:358
#define ADDR_MATCH_LIST
#define VAR_MYNETWORKS
Definition: mail_params.h:2035
#define dict_get(dp, key)
Definition: dict.h:236
#define SERVER_ACL_NAME_DUNNO
Definition: server_acl.h:29
#define SERVER_ACL_NAME_REJECT
Definition: server_acl.h:30
const char * str_name_code(const NAME_CODE *table, int code)
Definition: name_code.c:83
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define SERVER_ACL_NAME_ERROR
Definition: server_acl.h:31
#define DEF_PAR_DOM_MATCH
Definition: mail_params.h:2639
DICT * dict_handle(const char *dict_name)
Definition: dict.c:333
#define DICT_FLAG_LOCK
Definition: dict.h:116
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define addr_match_list_free
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
char * var_mynetworks
Definition: mail_params.c:261
#define SERVER_ACL_ACT_DUNNO
Definition: server_acl.h:34
int error
Definition: dict.h:94
#define ARGV_FAKE_BEGIN(fake_argv, arg)
Definition: argv.h:42
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define VAR_MYNETWORKS_STYLE
Definition: mail_params.h:2038
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define addr_match_list_init(o, f, p)
#define ARGV_FAKE_END
Definition: argv.h:50
#define SERVER_ACL_ACT_REJECT
Definition: server_acl.h:35
#define SERVER_ACL_NAME_WL_MYNETWORKS
Definition: server_acl.h:27
char * var_par_dom_match
Definition: mail_params.c:292
char * var_mynetworks_style
Definition: mail_params.c:288
void argv_terminate(ARGV *argvp)
Definition: argv.c:242
#define STREQ(x, y)
void msg_info(const char *fmt,...)
Definition: msg.c:199