1 : #define _GNU_SOURCE 1 /* strsignal() */
2 :
3 : #include "opt_serv.h"
4 :
5 : #define EX_UTILS_NO_FUNCS 1
6 : #include "ex_utils.h"
7 :
8 : #include "opt_policy.h"
9 :
10 : #include "mk.h"
11 :
12 : #include "opt_conf.h"
13 :
14 : #include <stddef.h> /* offsetof */
15 :
16 : #include <sys/resource.h>
17 : #include <signal.h>
18 :
19 : #include <sys/utsname.h>
20 :
21 : #ifndef CONF_FULL_STATIC
22 : # include <pwd.h>
23 : # include <grp.h>
24 : # include <sys/types.h>
25 : #endif
26 :
27 : #ifndef HAVE_STRSIGNAL
28 : # define strsignal(x) ""
29 : #endif
30 :
31 : #ifdef RLIMIT_AS /* not sure how portable this one is,
32 : * modern stuff seems to have it */
33 : # define USE_RLIMIT_AS TRUE
34 : #else
35 : # define USE_RLIMIT_AS FALSE
36 : # define RLIMIT_AS 0
37 : #endif
38 :
39 : #include <syslog.h>
40 :
41 : static Vlg *vlg = NULL;
42 :
43 :
44 : /* only called the first time, so that it can easily be used from req conf */
45 : int opt_serv_sc_append_hostname(Vstr_base *s1, size_t pos)
46 102 : {
47 : static char buf[256];
48 : static size_t len = 0;
49 :
50 102 : if (!len)
51 : {
52 64 : if (gethostname(buf, sizeof(buf)) == -1)
53 0 : err(EXIT_FAILURE, "gethostname");
54 :
55 64 : buf[sizeof(buf) - 1] = 0;
56 64 : len = strlen(buf);
57 : }
58 :
59 102 : return (vstr_add_ptr(s1, pos, buf, len));
60 : }
61 : static int opt_serv__init_append_hostname(void)
62 64 : {
63 64 : Vstr_base *tmp = vstr_make_base(NULL);
64 :
65 64 : if (!tmp)
66 0 : return (FALSE);
67 :
68 64 : opt_serv_sc_append_hostname(tmp, 0); /* ignore error */
69 :
70 64 : vstr_free_base(tmp);
71 :
72 64 : return (TRUE);
73 : }
74 :
75 : int opt_serv_sc_append_cwd(Vstr_base *s1, size_t pos)
76 4 : {
77 : static size_t sz = PATH_MAX;
78 4 : char *ptr = MK(sz);
79 4 : int ret = FALSE;
80 :
81 4 : if (ptr)
82 : {
83 4 : const size_t maxsz = 8 * PATH_MAX; /* FIXME: config. */
84 4 : char *tmp = NULL;
85 :
86 4 : tmp = getcwd(ptr, sz);
87 8 : while (!tmp && (errno == ERANGE) && (sz < maxsz))
88 : {
89 0 : sz += PATH_MAX;
90 0 : if (!MV(ptr, tmp, sz))
91 : break;
92 0 : tmp = getcwd(ptr, sz);
93 : }
94 :
95 4 : if (!tmp)
96 0 : ret = vstr_add_cstr_ptr(s1, pos, "/");
97 : else
98 4 : ret = vstr_add_cstr_buf(s1, pos, tmp);
99 : }
100 :
101 4 : F(ptr);
102 :
103 4 : return (ret);
104 : }
105 :
106 : static int opt_serv_sc_append_env(Vstr_base *s1, size_t pos,
107 : const Conf_parse *conf, Conf_token *token)
108 60 : {
109 60 : const Vstr_sect_node *pv = NULL;
110 60 : const char *env_name = NULL;
111 60 : const char *env_data = NULL;
112 :
113 60 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
114 60 : if (!(pv = conf_token_value(token)))
115 0 : return (FALSE);
116 :
117 60 : if (!(env_name = vstr_export_cstr_ptr(conf->data, pv->pos, pv->len)))
118 0 : return (FALSE);
119 :
120 60 : env_data = getenv(env_name);
121 60 : if (!env_data) env_data = "";
122 :
123 60 : return (vstr_add_cstr_buf(s1, pos, env_data));
124 : }
125 :
126 : #ifdef CONF_FULL_STATIC /* just ignore it, if using full-static */
127 : # define OPT_SERV_SC_APPEND_HOMEDIR(w, x, y, z) CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE)
128 : #else
129 : static int opt_serv_sc_append_homedir(Vstr_base *s1, size_t pos,
130 : const Conf_parse *conf, Conf_token *token)
131 4 : {
132 4 : const Vstr_sect_node *pv = NULL;
133 4 : const char *usr_name = NULL;
134 4 : const char *usr_data = "";
135 4 : struct passwd *pw = NULL;
136 :
137 4 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
138 4 : if (!(pv = conf_token_value(token)))
139 0 : return (FALSE);
140 4 : if (!(usr_name = vstr_export_cstr_ptr(conf->data, pv->pos, pv->len)))
141 0 : return (FALSE);
142 :
143 4 : if ((pw = getpwnam(usr_name)))
144 4 : usr_data = pw->pw_dir;
145 :
146 4 : return (vstr_add_cstr_buf(s1, pos, usr_data));
147 : }
148 : # define OPT_SERV_SC_APPEND_HOMEDIR(w, x, y, z) \
149 : opt_serv_sc_append_homedir(w, x, y, z)
150 : #endif
151 :
152 : #define OPT_SERV_SC_APPEND_UNAME(x) do { \
153 : if (!vstr_add_cstr_buf(conf->tmp, conf->tmp->len, utsname-> x)) \
154 : return (FALSE); \
155 : } while (FALSE)
156 :
157 :
158 : int opt_serv_sc_tst(Conf_parse *conf, Conf_token *token,
159 : int *matches, int prev_match,
160 : int (*tst_func)(Conf_parse *, Conf_token *,
161 : int *, int, void *), void *data)
162 45260 : {
163 : if (0) { }
164 :
165 45456 : else if (OPT_SERV_SYM_EQ("else") || OPT_SERV_SYM_EQ("ELSE"))
166 196 : *matches = !prev_match;
167 48036 : else if (OPT_SERV_SYM_EQ("true") || OPT_SERV_SYM_EQ("TRUE"))
168 2972 : *matches = TRUE;
169 43664 : else if (OPT_SERV_SYM_EQ("false") || OPT_SERV_SYM_EQ("FALSE"))
170 1572 : *matches = FALSE;
171 :
172 49584 : else if (OPT_SERV_SYM_EQ("not") || OPT_SERV_SYM_EQ("NOT") ||
173 : OPT_SERV_SYM_EQ("!"))
174 : {
175 9064 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
176 9064 : if (!(*tst_func)(conf, token, matches, prev_match, data))
177 0 : return (FALSE);
178 9064 : *matches = !*matches;
179 : }
180 55052 : else if (OPT_SERV_SYM_EQ("or") || OPT_SERV_SYM_EQ("OR") ||
181 : OPT_SERV_SYM_EQ("||"))
182 : {
183 31452 : unsigned int depth = token->depth_num;
184 :
185 134220 : while (conf_token_list_num(token, depth))
186 : {
187 79172 : int or_matches = TRUE;
188 :
189 79172 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
190 79172 : if (!(*tst_func)(conf, token, &or_matches, prev_match, data))
191 0 : return (FALSE);
192 :
193 79172 : if (or_matches)
194 : {
195 7856 : int ret = conf_parse_end_token(conf, token, depth);
196 3928 : ASSERT(ret);
197 7856 : return (TRUE);
198 : }
199 : }
200 :
201 23596 : *matches = FALSE;
202 : }
203 6 : else if (OPT_SERV_SYM_EQ("and") || OPT_SERV_SYM_EQ("AND") ||
204 : OPT_SERV_SYM_EQ("&&"))
205 : {
206 4 : unsigned int depth = token->depth_num;
207 :
208 12 : while (conf_token_list_num(token, depth))
209 : {
210 4 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
211 4 : if (!(*tst_func)(conf, token, matches, prev_match, data))
212 0 : return (FALSE);
213 :
214 4 : if (!*matches)
215 : {
216 0 : int ret = conf_parse_end_token(conf, token, depth);
217 0 : ASSERT(ret);
218 0 : return (TRUE);
219 : }
220 : }
221 : }
222 :
223 : else
224 0 : return (FALSE);
225 :
226 37404 : return (TRUE);
227 : }
228 :
229 : #define OPT_SERV__IOLIM_VAL(x) do { \
230 : \
231 : OPT_SERV_X_SYM_ULONG_BEG(x); \
232 : else if (OPT_SERV_SYM_EQ("<unlimited>")) (x) = 0; \
233 : else if (OPT_SERV_SYM_EQ("<default>")) (x) = 0; \
234 : OPT_SERV_X_SYM_NUM_END(); \
235 : } while (FALSE)
236 :
237 : static int opt_serv__conf_main_policy_d1(Opt_serv_policy_opts *opts,
238 : Conf_parse *conf, Conf_token *token,
239 : int clist)
240 28 : {
241 : unsigned int dummy;
242 :
243 : if (0) { }
244 28 : else if (OPT_SERV_SYM_EQ("match-init"))
245 0 : OPT_SERV_SC_MATCH_INIT(opts->beg,
246 : opt_serv__conf_main_policy_d1(opts, conf, token,
247 : clist));
248 :
249 28 : else if (OPT_SERV_SYM_EQ("timeout"))
250 : {
251 72 : CONF_SC_MAKE_CLIST_BEG(timeout, clist);
252 :
253 24 : else if (OPT_SERV_SYM_EQ("idle"))
254 24 : OPT_SERV_X_UINT(opts->idle_timeout);
255 0 : else if (OPT_SERV_SYM_EQ("total"))
256 0 : OPT_SERV_X_SINGLE_UINT(dummy);
257 :
258 0 : CONF_SC_MAKE_CLIST_END();
259 : }
260 4 : else if (OPT_SERV_SYM_EQ("instant-close"))
261 0 : OPT_SERV_X_TOGGLE(opts->use_insta_close);
262 4 : else if (OPT_SERV_SYM_EQ("lingering-close"))
263 0 : OPT_SERV_X_NEG_TOGGLE(opts->use_insta_close);
264 4 : else if (OPT_SERV_SYM_EQ("limit"))
265 : {
266 12 : CONF_SC_MAKE_CLIST_BEG(limit, clist);
267 :
268 4 : else if (OPT_SERV_SYM_EQ("connections"))
269 0 : OPT_SERV_X_UINT(opts->max_connections);
270 4 : else if (OPT_SERV_SYM_EQ("io"))
271 : {
272 4 : unsigned int clist_ioo = FALSE; /* io outer */
273 4 : unsigned int clist_ioi = FALSE; /* io inner */
274 :
275 16 : CONF_SC_MAKE_CLIST_BEG(limit_ioo, clist_ioo);
276 :
277 10 : else if (OPT_SERV_SYM_EQ("policy-process/s") ||
278 : OPT_SERV_SYM_EQ("policy-process-per-second"))
279 : {
280 12 : CONF_SC_MAKE_CLIST_BEG(limit_ioi, clist_ioi);
281 :
282 4 : else if (OPT_SERV_SYM_EQ("read") || OPT_SERV_SYM_EQ("recv"))
283 0 : OPT_SERV__IOLIM_VAL(opts->io_limit.io_r_max);
284 6 : else if (OPT_SERV_SYM_EQ("write") || OPT_SERV_SYM_EQ("send"))
285 4 : OPT_SERV__IOLIM_VAL(opts->io_limit.io_w_max);
286 :
287 0 : CONF_SC_MAKE_CLIST_END();
288 : }
289 6 : else if (OPT_SERV_SYM_EQ("policy-connection/s") ||
290 : OPT_SERV_SYM_EQ("policy-connection-per-second"))
291 : {
292 12 : CONF_SC_MAKE_CLIST_BEG(limit_ioi, clist_ioi);
293 :
294 4 : else if (OPT_SERV_SYM_EQ("read") || OPT_SERV_SYM_EQ("recv"))
295 0 : OPT_SERV__IOLIM_VAL(opts->io_nslimit.io_r_max);
296 6 : else if (OPT_SERV_SYM_EQ("write") || OPT_SERV_SYM_EQ("send"))
297 4 : OPT_SERV__IOLIM_VAL(opts->io_nslimit.io_w_max);
298 :
299 0 : CONF_SC_MAKE_CLIST_END();
300 : }
301 :
302 0 : CONF_SC_MAKE_CLIST_END();
303 : }
304 :
305 0 : CONF_SC_MAKE_CLIST_END();
306 : }
307 : else
308 0 : return (FALSE);
309 :
310 28 : return (TRUE);
311 : }
312 :
313 : static int opt_serv__conf_main_policy(Opt_serv_opts *opts,
314 : Conf_parse *conf, Conf_token *token)
315 40 : {
316 40 : Opt_serv_policy_opts *popts = NULL;
317 40 : Conf_token *ntoken = NULL;
318 : unsigned int cur_depth = opt_policy_sc_conf_parse(opts, conf, token,
319 40 : &popts, &ntoken);
320 :
321 40 : if (!cur_depth)
322 0 : return (FALSE);
323 :
324 : do
325 : {
326 40 : int clist = FALSE;
327 :
328 108 : CONF_SC_MAKE_CLIST_MID(cur_depth, clist);
329 :
330 28 : else if (opt_serv__conf_main_policy_d1(popts, conf, token, clist))
331 : { }
332 :
333 0 : CONF_SC_MAKE_CLIST_END();
334 : } while (ntoken &&
335 : (cur_depth = opt_policy_sc_conf_parse(opts, conf, token,
336 40 : &popts, &ntoken)));
337 :
338 40 : return (TRUE);
339 : }
340 :
341 : static int opt_serv__match_init_tst_d1(struct Opt_serv_opts *,
342 : Conf_parse *, Conf_token *,
343 : int *, int);
344 : static int opt_serv__match_init_tst_op_d1(Conf_parse *conf, Conf_token *token,
345 : int *matches, int prev_match,
346 : void *passed_data)
347 32 : {
348 32 : struct Opt_serv_opts *opts = passed_data;
349 :
350 32 : return (opt_serv__match_init_tst_d1(opts, conf, token, matches, prev_match));
351 : }
352 :
353 : static int opt_serv__match_init_tst_d1(struct Opt_serv_opts *opts,
354 : Conf_parse *conf, Conf_token *token,
355 : int *matches, int prev_match)
356 92 : {
357 92 : int clist = FALSE;
358 :
359 46 : ASSERT(matches);
360 :
361 92 : CONF_SC_TOGGLE_CLIST_VAR(clist);
362 :
363 : if (0) {}
364 :
365 96 : else if (OPT_SERV_SYM_EQ("version<=") || OPT_SERV_SYM_EQ("vers<="))
366 : {
367 4 : OPT_SERV_X_SINGLE_VSTR(conf->tmp);
368 4 : *matches = (vstr_cmp_vers_buf(conf->tmp, 1, conf->tmp->len,
369 : opts->vers_cstr, opts->vers_len) >= 0);
370 : }
371 92 : else if (OPT_SERV_SYM_EQ("version>=") || OPT_SERV_SYM_EQ("vers>="))
372 : {
373 4 : OPT_SERV_X_SINGLE_VSTR(conf->tmp);
374 4 : *matches = (vstr_cmp_vers_buf(conf->tmp, 1, conf->tmp->len,
375 : opts->vers_cstr, opts->vers_len) <= 0);
376 : }
377 88 : else if (OPT_SERV_SYM_EQ("version-eq") || OPT_SERV_SYM_EQ("vers=="))
378 : {
379 4 : OPT_SERV_X_SINGLE_VSTR(conf->tmp);
380 4 : *matches = (vstr_cmp_vers_buf(conf->tmp, 1, conf->tmp->len,
381 : opts->vers_cstr, opts->vers_len) == 0);
382 : }
383 :
384 84 : else if (OPT_SERV_SYM_EQ("name-eq") || OPT_SERV_SYM_EQ("name=="))
385 : {
386 4 : OPT_SERV_X_SINGLE_VSTR(conf->tmp);
387 4 : *matches = vstr_cmp_buf_eq(conf->tmp, 1, conf->tmp->len,
388 : opts->name_cstr, opts->name_len);
389 : }
390 :
391 78 : else if (OPT_SERV_SYM_EQ("hostname-eq") ||
392 : OPT_SERV_SYM_EQ("hostname=="))
393 : {
394 4 : size_t lpos = 0;
395 :
396 4 : OPT_SERV_X_SINGLE_VSTR(conf->tmp);
397 :
398 4 : lpos = conf->tmp->len;
399 4 : if (!opt_serv_sc_append_hostname(conf->tmp, lpos))
400 0 : return (FALSE);
401 :
402 4 : if (lpos == conf->tmp->len)
403 0 : *matches = !!conf->tmp->len; /* if they are both blank, they match */
404 : else
405 : {
406 4 : size_t len = vstr_sc_posdiff(lpos + 1, conf->tmp->len);
407 4 : *matches = vstr_cmp_case_eq(conf->tmp, 1, lpos, conf->tmp, lpos + 1, len);
408 : }
409 : }
410 :
411 76 : else if (OPT_SERV_SYM_EQ("uid-eq") ||
412 : OPT_SERV_SYM_EQ("uid=="))
413 : {
414 4 : unsigned int dummy = 0;
415 4 : OPT_SERV_X_SINGLE_UINT(dummy);
416 4 : *matches = (dummy == getuid());
417 : }
418 72 : else if (OPT_SERV_SYM_EQ("euid-eq") ||
419 : OPT_SERV_SYM_EQ("euid=="))
420 : {
421 4 : unsigned int dummy = 0;
422 4 : OPT_SERV_X_SINGLE_UINT(dummy);
423 4 : *matches = (dummy == geteuid());
424 : }
425 :
426 64 : else if (OPT_SERV_SYM_EQ("debug"))
427 12 : *matches = COMPILE_DEBUG;
428 :
429 : else
430 52 : return (opt_serv_sc_tst(conf, token, matches, prev_match,
431 : opt_serv__match_init_tst_op_d1, opts));
432 :
433 40 : return (TRUE);
434 : }
435 :
436 : int opt_serv_match_init(struct Opt_serv_opts *opts,
437 : Conf_parse *conf, Conf_token *token)
438 60 : {
439 : static int prev_match = TRUE;
440 60 : int matches = TRUE;
441 60 : unsigned int depth = token->depth_num;
442 :
443 60 : CONF_SC_PARSE_SLIST_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
444 60 : ++depth;
445 180 : while (conf_token_list_num(token, depth))
446 : {
447 60 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
448 :
449 60 : if (!opt_serv__match_init_tst_d1(opts, conf, token, &matches, prev_match))
450 0 : return (FALSE);
451 :
452 60 : if (!matches)
453 10 : conf_parse_end_token(conf, token, depth - 1);
454 : }
455 :
456 60 : prev_match = matches;
457 :
458 60 : return (TRUE);
459 : }
460 :
461 : #define OPT_SERV__RLIM_VAL(x, y) do { \
462 : (y) = TRUE; \
463 : \
464 : OPT_SERV_X_SYM_ULONG_BEG(x); \
465 : else if (OPT_SERV_SYM_EQ("<infinity>")) (x) = RLIM_INFINITY; \
466 : else if (OPT_SERV_SYM_EQ("<unlimited>")) (x) = RLIM_INFINITY; \
467 : else if (OPT_SERV_SYM_EQ("<default>")) (y) = FALSE; \
468 : OPT_SERV_X_SYM_NUM_END(); \
469 : } while (FALSE)
470 :
471 : #define OPT_SERV__TMP_EQ(x) vstr_cmp_cstr_eq(conf->tmp, 1, conf->tmp->len, x)
472 :
473 : #define OPT_SERV_ADDR_DUP_VSTR(x, y, z) \
474 : (((x)-> z) = vstr_dup_vstr((y)-> z ->conf , \
475 : (y)-> z , 1, (y)-> z ->len, \
476 : VSTR_TYPE_SUB_BUF_REF))
477 :
478 : static void opt_serv__free_addr(Opt_serv_addr_opts *addr)
479 130 : {
480 130 : if (!addr)
481 0 : return;
482 :
483 130 : vstr_free_base(addr->acpt_filter_file);
484 130 : vstr_free_base(addr->acpt_address);
485 130 : vstr_free_base(addr->acpt_cong);
486 130 : vstr_free_base(addr->def_policy);
487 130 : F(addr);
488 : }
489 :
490 : static Opt_serv_addr_opts *opt_serv_make_addr(Opt_serv_opts *)
491 : COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
492 : static Opt_serv_addr_opts *opt_serv_make_addr(Opt_serv_opts *opts)
493 84 : {
494 84 : Opt_serv_addr_opts *addr = NULL;
495 :
496 42 : ASSERT(opts && opts->addr_beg);
497 :
498 84 : if (opts->no_conf_listen)
499 : { /* use the initial one to start with */
500 0 : opts->no_conf_listen = FALSE;
501 0 : return (opts->addr_beg);
502 : }
503 :
504 : /* duplicate the currnet one */
505 84 : if (!(addr = MK(sizeof(Opt_serv_addr_opts))))
506 0 : goto mk_addr_fail;
507 :
508 84 : OPT_SERV_ADDR_DUP_VSTR(addr, opts->addr_beg, acpt_filter_file);
509 84 : OPT_SERV_ADDR_DUP_VSTR(addr, opts->addr_beg, acpt_address);
510 84 : OPT_SERV_ADDR_DUP_VSTR(addr, opts->addr_beg, acpt_cong);
511 84 : OPT_SERV_ADDR_DUP_VSTR(addr, opts->addr_beg, def_policy);
512 :
513 84 : if (!addr->acpt_filter_file ||
514 : !addr->acpt_address ||
515 : !addr->acpt_cong ||
516 : !addr->def_policy ||
517 : FALSE)
518 : goto addr_init_fail;
519 :
520 84 : addr->next = NULL;
521 :
522 84 : addr->tcp_port = opts->addr_beg->tcp_port;
523 84 : addr->defer_accept = opts->addr_beg->defer_accept;
524 84 : addr->q_listen_len = opts->addr_beg->q_listen_len;
525 84 : addr->max_connections = opts->addr_beg->max_connections;
526 :
527 84 : addr->next = opts->addr_beg;
528 84 : opts->addr_beg = addr;
529 :
530 84 : return (addr);
531 :
532 0 : addr_init_fail:
533 0 : F(addr);
534 0 : mk_addr_fail:
535 0 : return (FALSE);
536 : }
537 :
538 : static Opt_serv_addr_opts *opt_serv__srch_addr(Opt_serv_addr_opts *scan,
539 : Opt_serv_addr_opts *addr)
540 86 : {
541 674 : while (scan)
542 : {
543 506 : if ((scan->tcp_port == addr->tcp_port) &&
544 : vstr_cmp_eq(scan->acpt_address, 1, scan->acpt_address->len,
545 : addr->acpt_address, 1, addr->acpt_address->len))
546 4 : break;
547 :
548 502 : scan = scan->next;
549 : }
550 :
551 86 : return (scan);
552 : }
553 :
554 : #define OPT_SERV__ADDR_MERGE_VSTR(z) do { \
555 : if (!vstr_sub_vstr(oaddr-> z, 1, oaddr-> z ->len, \
556 : naddr-> z, 1, naddr-> z ->len, VSTR_TYPE_SUB_DEF)) \
557 : return (FALSE); \
558 : } while (FALSE)
559 :
560 : static int opt_serv_merge_addrs(Opt_serv_opts *)
561 : COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
562 : static int opt_serv_merge_addrs(Opt_serv_opts *opts)
563 84 : {
564 84 : Opt_serv_addr_opts *oaddr = NULL;
565 84 : Opt_serv_addr_opts *naddr = NULL;
566 :
567 42 : ASSERT(opts && opts->addr_beg);
568 :
569 84 : naddr = opts->addr_beg;
570 84 : oaddr = opt_serv__srch_addr(naddr->next, naddr);
571 :
572 84 : if (!oaddr)
573 80 : return (TRUE);
574 :
575 : /* can't match more than one */
576 2 : ASSERT(!opt_serv__srch_addr(oaddr->next, naddr));
577 :
578 4 : OPT_SERV__ADDR_MERGE_VSTR(acpt_filter_file);
579 2 : ASSERT(vstr_cmp_eq(oaddr->acpt_address, 1, oaddr->acpt_address->len,
580 : naddr->acpt_address, 1, naddr->acpt_address->len));
581 4 : OPT_SERV__ADDR_MERGE_VSTR(acpt_cong);
582 4 : OPT_SERV__ADDR_MERGE_VSTR(def_policy);
583 :
584 2 : ASSERT(oaddr->tcp_port == naddr->tcp_port);
585 4 : oaddr->defer_accept = naddr->defer_accept;
586 4 : oaddr->q_listen_len = naddr->q_listen_len;
587 4 : oaddr->max_connections = naddr->max_connections;
588 :
589 4 : opts->addr_beg = naddr->next;
590 4 : opt_serv__free_addr(naddr);
591 :
592 4 : return (TRUE);
593 : }
594 :
595 : static int opt_serv__conf_d1(struct Opt_serv_opts *opts,
596 : Conf_parse *conf, Conf_token *token,
597 : int clist)
598 328 : {
599 : if (0) { }
600 :
601 328 : else if (OPT_SERV_SYM_EQ("match-init"))
602 8 : OPT_SERV_SC_MATCH_INIT(opts, opt_serv__conf_d1(opts, conf, token, clist));
603 :
604 320 : else if (OPT_SERV_SYM_EQ("policy"))
605 : {
606 40 : if (!opt_serv__conf_main_policy(opts, conf, token))
607 0 : return (FALSE);
608 : }
609 :
610 280 : else if (OPT_SERV_SYM_EQ("chroot"))
611 4 : return (opt_serv_sc_make_static_path(opts, conf, token, opts->chroot_dir));
612 276 : else if (OPT_SERV_SYM_EQ("cntl-file") ||
613 : OPT_SERV_SYM_EQ("control-file"))
614 52 : return (opt_serv_sc_make_static_path(opts, conf, token, opts->cntl_file));
615 232 : else if (OPT_SERV_SYM_EQ("daemonize") || OPT_SERV_SYM_EQ("daemonise"))
616 8 : OPT_SERV_X_TOGGLE(opts->become_daemon);
617 216 : else if (OPT_SERV_SYM_EQ("drop-privs"))
618 : {
619 8 : unsigned int depth = token->depth_num;
620 8 : int val = opts->drop_privs;
621 8 : int ern = conf_sc_token_parse_toggle(conf, token, &val);
622 8 : unsigned int num = conf_token_list_num(token, token->depth_num);
623 :
624 8 : if (ern == CONF_SC_TYPE_RET_ERR_NO_MATCH)
625 0 : return (FALSE);
626 8 : if (!val && num)
627 0 : return (FALSE);
628 :
629 8 : opts->drop_privs = val;
630 36 : CONF_SC_MAKE_CLIST_MID(depth, clist);
631 :
632 20 : else if (OPT_SERV_SYM_EQ("uid"))
633 4 : OPT_SERV_X_SINGLE_UINT(opts->priv_uid);
634 18 : else if (OPT_SERV_SYM_EQ("usrname") ||
635 : OPT_SERV_SYM_EQ("username"))
636 4 : OPT_SERV_X_VSTR(opts, opts->vpriv_uid);
637 12 : else if (OPT_SERV_SYM_EQ("gid"))
638 4 : OPT_SERV_X_SINGLE_UINT(opts->priv_gid);
639 10 : else if (OPT_SERV_SYM_EQ("grpname") ||
640 : OPT_SERV_SYM_EQ("groupname"))
641 4 : OPT_SERV_X_VSTR(opts, opts->vpriv_gid);
642 8 : else if (OPT_SERV_SYM_EQ("keep-CAP_FOWNER") ||
643 : OPT_SERV_SYM_EQ("keep-cap-fowner"))
644 4 : OPT_SERV_X_TOGGLE(opts->keep_cap_fowner);
645 :
646 0 : CONF_SC_MAKE_CLIST_END();
647 : }
648 208 : else if (OPT_SERV_SYM_EQ("dumpable"))
649 0 : OPT_SERV_X_TOGGLE(opts->make_dumpable);
650 208 : else if (OPT_SERV_SYM_EQ("listen"))
651 : {
652 84 : Opt_serv_addr_opts *addr = opt_serv_make_addr(opts);
653 312 : CONF_SC_MAKE_CLIST_BEG(listen, clist);
654 :
655 144 : else if (!addr) return (FALSE);
656 :
657 144 : else if (OPT_SERV_SYM_EQ("defer-accept"))
658 8 : OPT_SERV_X_UINT(addr->defer_accept);
659 136 : else if (OPT_SERV_SYM_EQ("port"))
660 4 : OPT_SERV_X_UINT(addr->tcp_port);
661 174 : else if (OPT_SERV_SYM_EQ("addr") || OPT_SERV_SYM_EQ("address"))
662 84 : OPT_SERV_X_VSTR(opts, addr->acpt_address);
663 48 : else if (OPT_SERV_SYM_EQ("cong") || OPT_SERV_SYM_EQ("congestion"))
664 0 : OPT_SERV_X_VSTR(opts, addr->acpt_cong);
665 48 : else if (OPT_SERV_SYM_EQ("policy"))
666 20 : OPT_SERV_X_VSTR(opts, addr->def_policy);
667 28 : else if (OPT_SERV_SYM_EQ("queue-length"))
668 : {
669 12 : OPT_SERV_X_SYM_UINT_BEG(addr->q_listen_len);
670 4 : else if (OPT_SERV_SYM_EQ("<max>")) addr->q_listen_len = SOMAXCONN;
671 0 : OPT_SERV_X_SYM_NUM_END();
672 : }
673 16 : else if (OPT_SERV_SYM_EQ("filter"))
674 : {
675 8 : if (!opt_serv_sc_make_static_path(opts, conf, token,
676 : addr->acpt_filter_file))
677 0 : return (FALSE);
678 : }
679 8 : else if (OPT_SERV_SYM_EQ("max-connections"))
680 8 : OPT_SERV_X_UINT(addr->max_connections);
681 :
682 0 : CONF_SC_MAKE_CLIST_END();
683 :
684 84 : if (!opt_serv_merge_addrs(opts))
685 0 : return (FALSE);
686 : }
687 124 : else if (OPT_SERV_SYM_EQ("parent-death-signal"))
688 0 : OPT_SERV_X_TOGGLE(opts->use_pdeathsig);
689 124 : else if (OPT_SERV_SYM_EQ("pid-file"))
690 32 : return (opt_serv_sc_make_static_path(opts, conf, token, opts->pid_file));
691 100 : else if (OPT_SERV_SYM_EQ("processes") ||
692 : OPT_SERV_SYM_EQ("procs"))
693 : {
694 16 : OPT_SERV_X_SYM_UINT_BEG(opts->num_procs);
695 :
696 0 : else if (OPT_SERV_SYM_EQ("<sysconf-number-processors-configured>") ||
697 : OPT_SERV_SYM_EQ("<sysconf-num-procs-configured>") ||
698 : OPT_SERV_SYM_EQ("<sysconf-num-procs-conf>"))
699 0 : opts->num_procs = sysconf(_SC_NPROCESSORS_CONF);
700 0 : else if (OPT_SERV_SYM_EQ("<sysconf-number-processors-online>") ||
701 : OPT_SERV_SYM_EQ("<sysconf-num-procs-online>") ||
702 : OPT_SERV_SYM_EQ("<sysconf-num-procs-onln>"))
703 0 : opts->num_procs = sysconf(_SC_NPROCESSORS_ONLN);
704 :
705 0 : OPT_SERV_X_SYM_NUM_END();
706 : }
707 76 : else if (OPT_SERV_SYM_EQ("logging"))
708 : {
709 12 : CONF_SC_MAKE_CLIST_BEG(logging_main, clist);
710 :
711 4 : else if (OPT_SERV_SYM_EQ("syslog"))
712 : {
713 116 : CONF_SC_MAKE_CLIST_BEG(logging_syslog, clist);
714 108 : else if (OPT_SERV_SYM_EQ("native"))
715 0 : OPT_SERV_X_TOGGLE(opts->vlg_syslog_native);
716 108 : else if (OPT_SERV_SYM_EQ("limit"))
717 : {
718 0 : CONF_SC_MAKE_CLIST_BEG(logging_limit, clist);
719 :
720 0 : else if (OPT_SERV_SYM_EQ("size"))
721 : {
722 0 : opts->vlg_tweaked_size = TRUE;
723 0 : OPT_SERV_X_ULONG(opts->vlg_size);
724 : }
725 :
726 0 : CONF_SC_MAKE_CLIST_END();
727 : }
728 108 : else if (OPT_SERV_SYM_EQ("facility"))
729 : {
730 108 : OPT_SERV_X_SINGLE_VSTR(conf->tmp);
731 : if (0) { }
732 :
733 116 : else if (OPT_SERV__TMP_EQ("AUTHPRIV") ||
734 : OPT_SERV__TMP_EQ("AUTH"))
735 8 : opts->syslog_facility = LOG_AUTHPRIV;
736 100 : else if (OPT_SERV__TMP_EQ("CRON")) opts->syslog_facility = LOG_CRON;
737 96 : else if (OPT_SERV__TMP_EQ("DAEMON")) opts->syslog_facility = LOG_DAEMON;
738 92 : else if (OPT_SERV__TMP_EQ("FTP")) opts->syslog_facility = LOG_FTP;
739 84 : else if (OPT_SERV__TMP_EQ("LOCAL"))
740 : {
741 32 : unsigned int num = 0;
742 :
743 32 : OPT_SERV_X_SINGLE_UINT(num);
744 32 : switch (num)
745 : {
746 0 : default: return (FALSE);
747 4 : case 0: opts->syslog_facility = LOG_LOCAL0;
748 8 : case 1: opts->syslog_facility = LOG_LOCAL1;
749 12 : case 2: opts->syslog_facility = LOG_LOCAL2;
750 16 : case 3: opts->syslog_facility = LOG_LOCAL3;
751 20 : case 4: opts->syslog_facility = LOG_LOCAL4;
752 24 : case 5: opts->syslog_facility = LOG_LOCAL5;
753 28 : case 6: opts->syslog_facility = LOG_LOCAL6;
754 32 : case 7: opts->syslog_facility = LOG_LOCAL7;
755 : }
756 : }
757 52 : else if (OPT_SERV__TMP_EQ("LOCAL0")) opts->syslog_facility = LOG_LOCAL0;
758 48 : else if (OPT_SERV__TMP_EQ("LOCAL1")) opts->syslog_facility = LOG_LOCAL1;
759 44 : else if (OPT_SERV__TMP_EQ("LOCAL2")) opts->syslog_facility = LOG_LOCAL2;
760 40 : else if (OPT_SERV__TMP_EQ("LOCAL3")) opts->syslog_facility = LOG_LOCAL3;
761 36 : else if (OPT_SERV__TMP_EQ("LOCAL4")) opts->syslog_facility = LOG_LOCAL4;
762 32 : else if (OPT_SERV__TMP_EQ("LOCAL5")) opts->syslog_facility = LOG_LOCAL5;
763 28 : else if (OPT_SERV__TMP_EQ("LOCAL6")) opts->syslog_facility = LOG_LOCAL6;
764 24 : else if (OPT_SERV__TMP_EQ("LOCAL7")) opts->syslog_facility = LOG_LOCAL7;
765 20 : else if (OPT_SERV__TMP_EQ("LPR")) opts->syslog_facility = LOG_LPR;
766 16 : else if (OPT_SERV__TMP_EQ("MAIL")) opts->syslog_facility = LOG_MAIL;
767 12 : else if (OPT_SERV__TMP_EQ("NEWS")) opts->syslog_facility = LOG_NEWS;
768 8 : else if (OPT_SERV__TMP_EQ("USER")) opts->syslog_facility = LOG_USER;
769 4 : else if (OPT_SERV__TMP_EQ("UUCP")) opts->syslog_facility = LOG_UUCP;
770 :
771 : else
772 0 : return (FALSE);
773 :
774 : }
775 0 : CONF_SC_MAKE_CLIST_END();
776 : }
777 :
778 0 : CONF_SC_MAKE_CLIST_END();
779 : }
780 104 : else if (OPT_SERV_SYM_EQ("resource-limits") ||
781 : OPT_SERV_SYM_EQ("rlimit"))
782 : {
783 192 : CONF_SC_MAKE_CLIST_BEG(rlimit, clist);
784 :
785 64 : else if (OPT_SERV_SYM_EQ("AS") || OPT_SERV_SYM_EQ("address-space"))
786 0 : OPT_SERV__RLIM_VAL(opts->rlim_as_num, opts->rlim_as_call);
787 96 : else if (OPT_SERV_SYM_EQ("CORE") || OPT_SERV_SYM_EQ("core"))
788 64 : OPT_SERV__RLIM_VAL(opts->rlim_core_num, opts->rlim_core_call);
789 0 : else if (OPT_SERV_SYM_EQ("NOFILE") || OPT_SERV_SYM_EQ("fd-num") ||
790 : OPT_SERV_SYM_EQ("file-descriptor-number"))
791 0 : OPT_SERV__RLIM_VAL(opts->rlim_file_num, opts->rlim_file_call);
792 :
793 0 : CONF_SC_MAKE_CLIST_END();
794 : }
795 : /* else if (OPT_SERV_SYM_EQ("priority"))
796 : OPT_SERV_X_UINT(opts->sys_priority); */
797 8 : else if (OPT_SERV_SYM_EQ("cache-limits"))
798 : {
799 0 : CONF_SC_MAKE_CLIST_BEG(cache_limits, clist);
800 :
801 0 : else if (OPT_SERV_SYM_EQ("spare-vstr-bases"))
802 0 : OPT_SERV_X_UINT(opts->max_spare_bases);
803 0 : else if (OPT_SERV_SYM_EQ("spare-vstr-nodes-buf"))
804 0 : OPT_SERV_X_UINT(opts->max_spare_buf_nodes);
805 0 : else if (OPT_SERV_SYM_EQ("spare-vstr-nodes-ptr"))
806 0 : OPT_SERV_X_UINT(opts->max_spare_ptr_nodes);
807 0 : else if (OPT_SERV_SYM_EQ("spare-vstr-nodes-ref"))
808 0 : OPT_SERV_X_UINT(opts->max_spare_ref_nodes);
809 :
810 0 : CONF_SC_MAKE_CLIST_END();
811 : }
812 8 : else if (OPT_SERV_SYM_EQ("limit"))
813 : {
814 12 : CONF_SC_MAKE_CLIST_BEG(limit, clist);
815 :
816 4 : else if (OPT_SERV_SYM_EQ("io"))
817 : {
818 4 : unsigned int clist_ioo = FALSE; /* io outer */
819 4 : unsigned int clist_ioi = FALSE; /* io inner */
820 :
821 16 : CONF_SC_MAKE_CLIST_BEG(limit_ioo, clist_ioo);
822 :
823 10 : else if (OPT_SERV_SYM_EQ("process/s") ||
824 : OPT_SERV_SYM_EQ("process-per-second"))
825 : {
826 12 : CONF_SC_MAKE_CLIST_BEG(limit_ioi, clist_ioi);
827 :
828 4 : else if (OPT_SERV_SYM_EQ("read") || OPT_SERV_SYM_EQ("recv"))
829 0 : OPT_SERV__IOLIM_VAL(opts->io_limit.io_r_max);
830 6 : else if (OPT_SERV_SYM_EQ("write") || OPT_SERV_SYM_EQ("send"))
831 4 : OPT_SERV__IOLIM_VAL(opts->io_limit.io_w_max);
832 :
833 0 : CONF_SC_MAKE_CLIST_END();
834 : }
835 4 : else if (OPT_SERV_SYM_EQ("policy-process/s") ||
836 : OPT_SERV_SYM_EQ("policy-process-per-second"))
837 : {
838 0 : Opt_serv_policy_opts *popts = NULL;
839 :
840 0 : if (!(popts = opt_policy_conf_find(opts, conf, token)))
841 0 : return (FALSE);
842 :
843 0 : CONF_SC_MAKE_CLIST_BEG(limit_ioi, clist_ioi);
844 :
845 0 : else if (OPT_SERV_SYM_EQ("read") || OPT_SERV_SYM_EQ("recv"))
846 0 : OPT_SERV__IOLIM_VAL(popts->io_limit.io_r_max);
847 0 : else if (OPT_SERV_SYM_EQ("write") || OPT_SERV_SYM_EQ("send"))
848 0 : OPT_SERV__IOLIM_VAL(popts->io_limit.io_w_max);
849 :
850 0 : CONF_SC_MAKE_CLIST_END();
851 : }
852 4 : else if (OPT_SERV_SYM_EQ("policy-connection/s") ||
853 : OPT_SERV_SYM_EQ("policy-connection-per-second"))
854 : {
855 0 : Opt_serv_policy_opts *popts = NULL;
856 :
857 0 : if (!(popts = opt_policy_conf_find(opts, conf, token)))
858 0 : return (FALSE);
859 :
860 0 : CONF_SC_MAKE_CLIST_BEG(limit_ioi, clist_ioi);
861 :
862 0 : else if (OPT_SERV_SYM_EQ("read") || OPT_SERV_SYM_EQ("recv"))
863 0 : OPT_SERV__IOLIM_VAL(popts->io_nslimit.io_r_max);
864 0 : else if (OPT_SERV_SYM_EQ("write") || OPT_SERV_SYM_EQ("send"))
865 0 : OPT_SERV__IOLIM_VAL(popts->io_nslimit.io_w_max);
866 :
867 0 : CONF_SC_MAKE_CLIST_END();
868 : }
869 6 : else if (OPT_SERV_SYM_EQ("connection/s") ||
870 : OPT_SERV_SYM_EQ("connection-per-second"))
871 : {
872 12 : CONF_SC_MAKE_CLIST_BEG(limit_ioi, clist_ioi);
873 :
874 4 : else if (OPT_SERV_SYM_EQ("read") || OPT_SERV_SYM_EQ("recv"))
875 0 : OPT_SERV__IOLIM_VAL(opts->io_nslimit.io_r_max);
876 6 : else if (OPT_SERV_SYM_EQ("write") || OPT_SERV_SYM_EQ("send"))
877 4 : OPT_SERV__IOLIM_VAL(opts->io_nslimit.io_w_max);
878 :
879 0 : CONF_SC_MAKE_CLIST_END();
880 : }
881 :
882 0 : CONF_SC_MAKE_CLIST_END();
883 : }
884 :
885 0 : CONF_SC_MAKE_CLIST_END();
886 : }
887 :
888 : else
889 4 : return (FALSE);
890 :
891 236 : return (TRUE);
892 : }
893 : #undef OPT_SERV__RLIM_VAL
894 :
895 : int opt_serv_conf(struct Opt_serv_opts *opts,
896 : Conf_parse *conf, Conf_token *token)
897 108 : {
898 108 : unsigned int cur_depth = token->depth_num;
899 108 : int clist = FALSE;
900 :
901 54 : ASSERT(opts && conf && token);
902 :
903 108 : if (!conf_token_cmp_sym_cstr_eq(conf, token, "org.and.daemon-conf-1.0"))
904 0 : return (FALSE);
905 :
906 650 : CONF_SC_MAKE_CLIST_MID(cur_depth, clist);
907 :
908 328 : else if (opt_serv__conf_d1(opts, conf, token, clist))
909 : { }
910 :
911 4 : CONF_SC_MAKE_CLIST_END();
912 :
913 : /* And they all live together ... dum dum */
914 104 : if (conf->data->conf->malloc_bad)
915 0 : return (FALSE);
916 :
917 104 : return (TRUE);
918 : }
919 :
920 : int opt_serv_conf_parse_cstr(Vstr_base *out,
921 : Opt_serv_opts *opts, const char *data)
922 32 : {
923 32 : Conf_parse *conf = conf_parse_make(NULL);
924 32 : Conf_token token[1] = {CONF_TOKEN_INIT};
925 :
926 16 : ASSERT(opts && data);
927 :
928 32 : if (!conf)
929 0 : goto conf_malloc_fail;
930 :
931 32 : if (!vstr_add_cstr_ptr(conf->data, conf->data->len,
932 : "(org.and.daemon-conf-1.0 "))
933 0 : goto read_malloc_fail;
934 32 : if (!vstr_add_cstr_ptr(conf->data, conf->data->len, data))
935 0 : goto read_malloc_fail;
936 32 : if (!vstr_add_cstr_ptr(conf->data, conf->data->len,
937 : ")"))
938 0 : goto read_malloc_fail;
939 :
940 32 : if (!conf_parse_lex(conf, 1, conf->data->len))
941 0 : goto conf_fail;
942 :
943 32 : if (!conf_parse_token(conf, token))
944 0 : goto conf_fail;
945 :
946 32 : if ((token->type != CONF_TOKEN_TYPE_CLIST) || (token->depth_num != 1))
947 : goto conf_fail;
948 :
949 32 : if (!conf_parse_token(conf, token))
950 0 : goto conf_fail;
951 :
952 16 : ASSERT(conf_token_cmp_sym_cstr_eq(conf, token, "org.and.daemon-conf-1.0"));
953 :
954 32 : if (!opt_serv_conf(opts, conf, token))
955 4 : goto conf_fail;
956 28 : if (token->num != conf->sects->num)
957 0 : goto conf_fail;
958 :
959 28 : conf_parse_free(conf);
960 28 : return (TRUE);
961 :
962 4 : conf_fail:
963 4 : conf_parse_backtrace(out, data, conf, token);
964 4 : read_malloc_fail:
965 4 : conf_parse_free(conf);
966 4 : conf_malloc_fail:
967 4 : return (FALSE);
968 : }
969 :
970 : int opt_serv_conf_parse_file(Vstr_base *out,
971 : Opt_serv_opts *opts, const char *fname)
972 0 : {
973 0 : Conf_parse *conf = conf_parse_make(NULL);
974 0 : Conf_token token[1] = {CONF_TOKEN_INIT};
975 :
976 0 : ASSERT(opts && fname);
977 :
978 0 : if (!conf)
979 0 : goto conf_malloc_fail;
980 :
981 0 : if (!vstr_sc_read_len_file(conf->data, 0, fname, 0, 0, NULL))
982 0 : goto read_malloc_fail;
983 :
984 0 : if (!conf_parse_lex(conf, 1, conf->data->len))
985 0 : goto conf_fail;
986 :
987 0 : while (conf_parse_token(conf, token))
988 : {
989 0 : if ((token->type != CONF_TOKEN_TYPE_CLIST) || (token->depth_num != 1))
990 : goto conf_fail;
991 :
992 0 : if (!conf_parse_token(conf, token))
993 0 : goto conf_fail;
994 :
995 0 : if (!conf_token_cmp_sym_cstr_eq(conf, token, "org.and.daemon-conf-1.0"))
996 0 : goto conf_fail;
997 :
998 0 : if (!opt_serv_conf(opts, conf, token))
999 0 : goto conf_fail;
1000 : }
1001 :
1002 0 : conf_parse_free(conf);
1003 0 : return (TRUE);
1004 :
1005 0 : conf_fail:
1006 0 : conf_parse_backtrace(out, fname, conf, token);
1007 0 : errno = 0;
1008 0 : read_malloc_fail:
1009 0 : if (errno && out) /* can't find config. file */
1010 0 : vstr_add_fmt(out, out->len, "open(%s): %m", fname);
1011 0 : conf_parse_free(conf);
1012 0 : conf_malloc_fail:
1013 0 : return (FALSE);
1014 : }
1015 :
1016 : void opt_serv_conf_free_beg(struct Opt_serv_opts *opts)
1017 88 : {
1018 88 : Opt_serv_addr_opts *scan = NULL;
1019 :
1020 88 : if (!opts)
1021 0 : return;
1022 :
1023 88 : vstr_free_base(opts->pid_file); opts->pid_file = NULL;
1024 88 : vstr_free_base(opts->cntl_file); opts->cntl_file = NULL;
1025 88 : vstr_free_base(opts->chroot_dir); opts->chroot_dir = NULL;
1026 88 : vstr_free_base(opts->vpriv_uid); opts->vpriv_uid = NULL;
1027 88 : vstr_free_base(opts->vpriv_gid); opts->vpriv_gid = NULL;
1028 :
1029 88 : scan = opts->addr_beg;
1030 88 : opts->addr_beg = NULL;
1031 302 : while (scan)
1032 : {
1033 126 : Opt_serv_addr_opts *scan_next = scan->next;
1034 :
1035 126 : opt_serv__free_addr(scan);
1036 :
1037 126 : scan = scan_next;
1038 : }
1039 : }
1040 :
1041 : void opt_serv_conf_free_end(struct Opt_serv_opts *opts)
1042 44 : {
1043 44 : if (!opts)
1044 0 : return;
1045 :
1046 22 : ASSERT( opts->ref_io_limit);
1047 44 : vstr_ref_del(opts->ref_io_limit);
1048 22 : ASSERT(!opts->ref_io_limit);
1049 : }
1050 :
1051 : static void opt_serv__io_lim_ref_cb(struct Vstr_ref *ref)
1052 44 : {
1053 44 : Opt_serv_opts *opts = NULL;
1054 44 : struct Evnt_limit *lim = NULL;
1055 :
1056 44 : if (!ref)
1057 0 : return;
1058 :
1059 44 : lim = ref->ptr;
1060 22 : ASSERT(lim);
1061 :
1062 : /* ISO C magic, converts a ptr to io_limit into a pointer to opts */
1063 44 : opts = (Opt_serv_opts *)(((char *)lim) - offsetof(Opt_serv_opts, io_limit));
1064 44 : opts->ref_io_limit = NULL; /* more magic */
1065 : }
1066 :
1067 : int opt_serv_conf_init(Opt_serv_opts *opts)
1068 64 : {
1069 64 : struct Opt_serv_policy_opts *popts = NULL;
1070 64 : Opt_serv_addr_opts *addr = MK(sizeof(Opt_serv_addr_opts));
1071 :
1072 32 : ASSERT(opts && opts->make_policy && opts->copy_policy);
1073 :
1074 64 : if (!addr)
1075 0 : goto mk_addr_fail;
1076 :
1077 64 : if (!opt_serv__init_append_hostname())
1078 0 : goto mk_append_hostname_fail;
1079 :
1080 64 : if (!(popts = (*opts->make_policy)(opts)))
1081 0 : goto mk_policy_fail;
1082 :
1083 64 : opts->def_policy = popts;
1084 64 : vstr_add_cstr_ptr(popts->policy_name, 0, OPT_POLICY_CONF_DEF_POLICY_NAME);
1085 :
1086 64 : if (popts->policy_name->conf->malloc_bad)
1087 0 : goto policy_init_fail;
1088 :
1089 64 : opts->pid_file = vstr_make_base(NULL);
1090 64 : opts->cntl_file = vstr_make_base(NULL);
1091 64 : opts->chroot_dir = vstr_make_base(NULL);
1092 64 : opts->vpriv_uid = vstr_make_base(NULL);
1093 64 : opts->vpriv_gid = vstr_make_base(NULL);
1094 64 : addr->acpt_filter_file = vstr_make_base(NULL);
1095 64 : addr->acpt_address = vstr_make_base(NULL);
1096 64 : addr->acpt_cong = vstr_make_base(NULL);
1097 64 : addr->def_policy = vstr_make_base(NULL);
1098 64 : opts->ref_io_limit = vstr_ref_make_ptr(&opts->io_limit,
1099 : opt_serv__io_lim_ref_cb);
1100 :
1101 64 : if (!opts->pid_file ||
1102 : !opts->cntl_file ||
1103 : !opts->chroot_dir ||
1104 : !opts->vpriv_uid ||
1105 : !opts->vpriv_gid ||
1106 : !addr->acpt_filter_file ||
1107 : !addr->acpt_address ||
1108 : !addr->acpt_cong ||
1109 : !addr->def_policy ||
1110 : !opts->ref_io_limit ||
1111 : FALSE)
1112 : goto opts_init_fail;
1113 :
1114 64 : addr->next = NULL;
1115 :
1116 64 : addr->tcp_port = 0;
1117 64 : addr->defer_accept = OPT_SERV_CONF_DEF_TCP_DEFER_ACCEPT;
1118 64 : addr->q_listen_len = OPT_SERV_CONF_DEF_Q_LISTEN_LEN;
1119 64 : addr->max_connections = OPT_SERV_CONF_DEF_MAX_CONNECTIONS;
1120 :
1121 64 : opts->addr_beg = addr;
1122 :
1123 64 : opts->no_conf_listen = TRUE;
1124 :
1125 64 : if (!opts->ref_io_limit) /* we can't have this succeed, while others fail */
1126 0 : goto opts_init_fail;
1127 :
1128 64 : return (TRUE);
1129 :
1130 0 : opts_init_fail:
1131 0 : opt_serv_conf_free_beg(opts);
1132 0 : opt_serv_conf_free_end(opts);
1133 0 : policy_init_fail:
1134 0 : vstr_ref_del(popts->ref);
1135 0 : mk_policy_fail:
1136 0 : mk_append_hostname_fail:
1137 0 : F(addr);
1138 0 : mk_addr_fail:
1139 0 : return (FALSE);
1140 : }
1141 :
1142 : void opt_serv_logger(Vlg *passed_vlg)
1143 64 : {
1144 64 : vlg = passed_vlg;
1145 64 : }
1146 :
1147 : void opt_serv_sc_drop_privs(Opt_serv_opts *opts)
1148 0 : {
1149 0 : if (setgroups(1, &opts->priv_gid) == -1)
1150 0 : vlg_err(vlg, EXIT_FAILURE, "setgroups(%ld): %m\n", (long)opts->priv_gid);
1151 :
1152 0 : if (setgid(opts->priv_gid) == -1)
1153 0 : vlg_err(vlg, EXIT_FAILURE, "setgid(%ld): %m\n", (long)opts->priv_gid);
1154 :
1155 0 : if (setuid(opts->priv_uid) == -1)
1156 0 : vlg_err(vlg, EXIT_FAILURE, "setuid(%ld): %m\n", (long)opts->priv_uid);
1157 0 : }
1158 :
1159 : static void opt_serv__sc_rlim_num(const char *name, int resource,
1160 : unsigned int num)
1161 28 : {
1162 : struct rlimit rlim[1];
1163 :
1164 28 : if (getrlimit(resource, rlim) == -1)
1165 0 : vlg_err(vlg, EXIT_FAILURE, "getrlimit(RLIMIT_%s): %m\n", name);
1166 :
1167 :
1168 28 : if (num == RLIM_INFINITY) /* only attempt upwards, if we are privilaged */
1169 : {
1170 24 : if ((rlim->rlim_max != RLIM_INFINITY) && !getuid())
1171 0 : rlim->rlim_max = num;
1172 : }
1173 : else
1174 : {
1175 4 : if ((num > rlim->rlim_max) && !getuid())
1176 0 : rlim->rlim_max = num;
1177 :
1178 4 : if (num < rlim->rlim_max) /* can always do this ? */
1179 4 : rlim->rlim_max = num;
1180 : }
1181 :
1182 28 : rlim->rlim_cur = rlim->rlim_max; /* upgrade soft to hard */
1183 :
1184 28 : if (setrlimit(resource, rlim) == -1)
1185 0 : vlg_err(vlg, EXIT_FAILURE, "setrlimit(RLIMIT_%s): %m\n", name);
1186 28 : }
1187 :
1188 : void opt_serv_sc_rlim_as_num(unsigned int rlim_as_num)
1189 0 : {
1190 : if (USE_RLIMIT_AS)
1191 0 : opt_serv__sc_rlim_num("AS", RLIMIT_AS, rlim_as_num);
1192 0 : }
1193 :
1194 : void opt_serv_sc_rlim_core_num(unsigned int rlim_core_num)
1195 28 : {
1196 28 : opt_serv__sc_rlim_num("CORE", RLIMIT_CORE, rlim_core_num);
1197 28 : }
1198 :
1199 : void opt_serv_sc_rlim_file_num(unsigned int rlim_file_num)
1200 0 : {
1201 0 : opt_serv__sc_rlim_num("NOFILE", RLIMIT_NOFILE, rlim_file_num);
1202 0 : }
1203 :
1204 : int opt_serv_sc_acpt_end(const Opt_serv_policy_opts *popts,
1205 : struct Evnt *from_evnt, struct Evnt *evnt)
1206 12052 : {
1207 12052 : Acpt_listener *acpt_listener = (Acpt_listener *)from_evnt;
1208 12052 : unsigned int acpt_num = acpt_listener->ref->ref - 1; /* ref +1 for itself */
1209 12052 : unsigned int acpt_max = acpt_listener->max_connections;
1210 :
1211 12052 : vlg_dbg1(vlg, "acpt: %u/%u\n", acpt_num, acpt_max);
1212 :
1213 12052 : if (acpt_max && (acpt_num >= acpt_max))
1214 : {
1215 278 : vlg_dbg1(vlg, "ACPT DEL ($<sa:%p>,%u,%u)\n", EVNT_SA(from_evnt),
1216 : acpt_num, acpt_max);
1217 278 : evnt_wait_cntl_del(from_evnt, POLLIN);
1218 : }
1219 :
1220 12052 : if (popts->max_connections && (evnt_num_all() > popts->max_connections))
1221 : {
1222 0 : vlg_info(vlg, "LIMIT-BLOCKED from[$<sa:%p>]: policy $<vstr.all:%p>\n",
1223 : EVNT_SA(evnt), popts->policy_name);
1224 0 : return (FALSE);
1225 : }
1226 :
1227 12052 : vlg_info(vlg, "CONNECT from[$<sa:%p>]\n", EVNT_SA(evnt));
1228 :
1229 12052 : return (TRUE);
1230 : }
1231 :
1232 : void opt_serv_sc_free_beg(struct Evnt *evnt, const char *info_rep)
1233 12284 : {
1234 12284 : if (EVNT_ACPT_EXISTS(evnt) && EVNT_ACPT_DATA(evnt)->evnt)
1235 : {
1236 12244 : Acpt_data *acpt_data = EVNT_ACPT_DATA(evnt);
1237 12244 : Acpt_listener *acpt_listener = (Acpt_listener *)acpt_data->evnt;
1238 12244 : unsigned int acpt_num = acpt_listener->ref->ref - 1;
1239 12244 : unsigned int acpt_max = acpt_listener->max_connections;
1240 :
1241 12244 : if (acpt_max && (acpt_num <= acpt_max)) /* note that we are going to -1 */
1242 : {
1243 2308 : vlg_dbg1(vlg, "ACPT ADD ($<sa:%p>,%u,%u)\n", EVNT_SA(acpt_data->evnt),
1244 : acpt_num, acpt_max);
1245 2308 : evnt_wait_cntl_add(acpt_data->evnt, POLLIN);
1246 : }
1247 :
1248 12244 : evnt_stats_add(acpt_data->evnt, evnt);
1249 : }
1250 :
1251 12284 : if (evnt->flag_fully_acpt)
1252 12284 : evnt_vlg_stats_info(evnt, info_rep);
1253 12284 : }
1254 :
1255 : #define OPT_SERV__SIG_OR_ERR(x) \
1256 : if (sigaction(x, &sa, NULL) == -1) \
1257 : err(EXIT_FAILURE, "signal(%d:%s)", x, strsignal(x))
1258 :
1259 : static void opt_serv__sig_crash(int s_ig_num)
1260 0 : {
1261 0 : vlg_sig_abort(vlg, "SIG[%d]: %s\n", s_ig_num, strsignal(s_ig_num));
1262 0 : }
1263 :
1264 : static void opt_serv__sig_raise_cont(int s_ig_num)
1265 0 : {
1266 : struct sigaction sa;
1267 :
1268 0 : if (sigemptyset(&sa.sa_mask) == -1)
1269 0 : err(EXIT_FAILURE, "signal init");
1270 :
1271 0 : sa.sa_flags = SA_RESTART;
1272 0 : sa.sa_handler = SIG_DFL;
1273 0 : OPT_SERV__SIG_OR_ERR(s_ig_num);
1274 :
1275 0 : vlg_sig_warn(vlg, "SIG[%d]: %s\n", s_ig_num, strsignal(s_ig_num));
1276 0 : raise(s_ig_num);
1277 0 : }
1278 :
1279 : static void opt_serv__sig_cont(int s_ig_num)
1280 0 : {
1281 : if (0) /* s_ig_num == SIGCONT) */
1282 : {
1283 : struct sigaction sa;
1284 :
1285 : if (sigemptyset(&sa.sa_mask) == -1)
1286 : err(EXIT_FAILURE, "signal init");
1287 :
1288 : sa.sa_flags = SA_RESTART;
1289 : sa.sa_handler = opt_serv__sig_raise_cont;
1290 : OPT_SERV__SIG_OR_ERR(SIGTSTP);
1291 : }
1292 :
1293 0 : vlg_sig_info(vlg, "SIG[%d]: %s\n", s_ig_num, strsignal(s_ig_num));
1294 0 : }
1295 :
1296 : static void opt_serv__sig_child(int s_ig_num)
1297 2 : {
1298 1 : ASSERT(s_ig_num == SIGCHLD);
1299 2 : evnt_child_exited = TRUE;
1300 2 : }
1301 :
1302 : void opt_serv_sc_signals(void)
1303 64 : {
1304 : struct sigaction sa;
1305 :
1306 64 : if (sigemptyset(&sa.sa_mask) == -1)
1307 0 : err(EXIT_FAILURE, "signal init %s", "sigemptyset");
1308 :
1309 : /* don't use SA_RESTART ... */
1310 64 : sa.sa_flags = 0;
1311 : /* ignore it... we don't have a use for it */
1312 64 : sa.sa_handler = SIG_IGN;
1313 :
1314 64 : OPT_SERV__SIG_OR_ERR(SIGPIPE);
1315 :
1316 64 : sa.sa_handler = opt_serv__sig_crash;
1317 :
1318 64 : OPT_SERV__SIG_OR_ERR(SIGSEGV);
1319 64 : OPT_SERV__SIG_OR_ERR(SIGBUS);
1320 64 : OPT_SERV__SIG_OR_ERR(SIGILL);
1321 64 : OPT_SERV__SIG_OR_ERR(SIGFPE);
1322 64 : OPT_SERV__SIG_OR_ERR(SIGXFSZ);
1323 :
1324 64 : sa.sa_flags = SA_RESTART;
1325 64 : sa.sa_handler = opt_serv__sig_child;
1326 64 : OPT_SERV__SIG_OR_ERR(SIGCHLD);
1327 :
1328 64 : sa.sa_flags = SA_RESTART;
1329 64 : sa.sa_handler = opt_serv__sig_cont; /* print, and do nothing */
1330 :
1331 64 : OPT_SERV__SIG_OR_ERR(SIGUSR1);
1332 64 : OPT_SERV__SIG_OR_ERR(SIGUSR2);
1333 64 : OPT_SERV__SIG_OR_ERR(SIGHUP);
1334 64 : OPT_SERV__SIG_OR_ERR(SIGCONT);
1335 :
1336 64 : sa.sa_handler = opt_serv__sig_raise_cont; /* queue print, and re-raise */
1337 :
1338 64 : OPT_SERV__SIG_OR_ERR(SIGTSTP);
1339 64 : OPT_SERV__SIG_OR_ERR(SIGTERM);
1340 64 : }
1341 : #undef SERV__SIG_OR_ERR
1342 :
1343 : void opt_serv_sc_check_children(void)
1344 9176339 : {
1345 9176339 : if (evnt_child_exited)
1346 : {
1347 1 : vlg_warn(vlg, "Child exited.\n");
1348 1 : evnt_acpt_close_all();
1349 1 : evnt_scan_q_close();
1350 1 : evnt_child_exited = FALSE;
1351 : }
1352 9176339 : }
1353 :
1354 : void opt_serv_sc_cntl_resources(const Opt_serv_opts *opts)
1355 9176339 : { /* cap the amount of "wasted" resources we're using */
1356 :
1357 9176339 : vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BASE,
1358 : 0, opts->max_spare_bases);
1359 :
1360 9176339 : vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF,
1361 : 0, opts->max_spare_buf_nodes);
1362 9176339 : vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_PTR,
1363 : 0, opts->max_spare_ptr_nodes);
1364 9176339 : vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_REF,
1365 : 0, opts->max_spare_ref_nodes);
1366 9176339 : }
1367 :
1368 : /* appends into conf->tmp */
1369 : int opt_serv_build_single_str(struct Opt_serv_opts *opts,
1370 : const Conf_parse *conf, Conf_token *token,
1371 : int clist, int doing_init)
1372 10722 : {
1373 : if (0) { }
1374 :
1375 10752 : else if (OPT_SERV_SYM_EQ("ENV") || OPT_SERV_SYM_EQ("ENVIRONMENT") ||
1376 : OPT_SERV_SYM_EQ("<ENV>") || OPT_SERV_SYM_EQ("<ENVIRONMENT>"))
1377 : {
1378 60 : if (!opt_serv_sc_append_env(conf->tmp, conf->tmp->len, conf, token))
1379 0 : return (FALSE);
1380 : }
1381 10664 : else if (doing_init &&
1382 : (OPT_SERV_SYM_EQ("HOME") || OPT_SERV_SYM_EQ("<HOME>")))
1383 : {
1384 4 : if (!OPT_SERV_SC_APPEND_HOMEDIR(conf->tmp, conf->tmp->len, conf, token))
1385 0 : return (FALSE);
1386 : }
1387 10658 : else if (OPT_SERV_SYM_EQ("<hostname>"))
1388 4 : opt_serv_sc_append_hostname(conf->tmp, conf->tmp->len);
1389 10654 : else if (OPT_SERV_SYM_EQ("<cwd>"))
1390 4 : opt_serv_sc_append_cwd(conf->tmp, conf->tmp->len);
1391 10650 : else if (OPT_SERV_SYM_EQ("<uname>"))
1392 : {
1393 : static struct utsname utsname[1];
1394 : static int done = FALSE;
1395 :
1396 0 : if (!done && (uname(utsname) == -1)) return (FALSE);
1397 0 : done = TRUE;
1398 :
1399 0 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
1400 0 : CONF_SC_TOGGLE_CLIST_VAR(clist);
1401 :
1402 : if (0) { }
1403 :
1404 0 : else if (OPT_SERV_SYM_EQ("sysname")) OPT_SERV_SC_APPEND_UNAME(sysname);
1405 0 : else if (OPT_SERV_SYM_EQ("nodename")) OPT_SERV_SC_APPEND_UNAME(nodename);
1406 0 : else if (OPT_SERV_SYM_EQ("release")) OPT_SERV_SC_APPEND_UNAME(release);
1407 0 : else if (OPT_SERV_SYM_EQ("version")) OPT_SERV_SC_APPEND_UNAME(version);
1408 0 : else if (OPT_SERV_SYM_EQ("machine")) OPT_SERV_SC_APPEND_UNAME(machine);
1409 :
1410 : else
1411 0 : return (FALSE);
1412 : }
1413 10650 : else if (OPT_SERV_SYM_EQ("<version>") || OPT_SERV_SYM_EQ("<vers>"))
1414 : {
1415 0 : if (!vstr_add_ptr(conf->tmp, conf->tmp->len,
1416 : opts->vers_cstr, opts->vers_len))
1417 0 : return (FALSE);
1418 : }
1419 10650 : else if (OPT_SERV_SYM_EQ("<program-name>"))
1420 : {
1421 0 : if (!vstr_add_ptr(conf->tmp, conf->tmp->len,
1422 : opts->name_cstr, opts->name_len))
1423 0 : return (FALSE);
1424 : }
1425 10650 : else if (!clist)
1426 : { /* unknown symbol or string */
1427 10650 : size_t pos = conf->tmp->len + 1;
1428 10650 : const Vstr_sect_node *pv = conf_token_value(token);
1429 :
1430 10650 : if (!pv || !vstr_add_vstr(conf->tmp, conf->tmp->len,
1431 : conf->data, pv->pos, pv->len,
1432 : VSTR_TYPE_ADD_BUF_REF))
1433 0 : return (FALSE);
1434 :
1435 10650 : OPT_SERV_X__ESC_VSTR(conf->tmp, pos, pv->len);
1436 : }
1437 :
1438 : else
1439 0 : return (FALSE);
1440 :
1441 10722 : return (TRUE);
1442 : }
1443 :
1444 : static int opt_serv__build_str(struct Opt_serv_opts *opts,
1445 : Conf_parse *conf, Conf_token *token,
1446 : int doing_init)
1447 718 : {
1448 718 : unsigned int cur_depth = token->depth_num;
1449 718 : int clist = FALSE;
1450 :
1451 718 : vstr_del(conf->tmp, 1, conf->tmp->len);
1452 718 : while (conf_token_list_num(token, cur_depth))
1453 : {
1454 2082 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
1455 2082 : CONF_SC_TOGGLE_CLIST_VAR(clist);
1456 :
1457 2082 : if (!opt_serv_build_single_str(opts, conf, token, clist, doing_init))
1458 0 : return (FALSE);
1459 : }
1460 :
1461 718 : return (!conf->tmp->conf->malloc_bad);
1462 : }
1463 :
1464 : static int opt_serv__sc_make_str(struct Opt_serv_opts *opts,
1465 : Conf_parse *conf, Conf_token *token,
1466 : Vstr_base *s1, size_t pos, size_t len,
1467 : int doing_init)
1468 16972 : {
1469 16972 : int clist = FALSE;
1470 :
1471 8489 : ASSERT(s1 != conf->tmp);
1472 :
1473 16972 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
1474 16972 : CONF_SC_TOGGLE_CLIST_VAR(clist);
1475 :
1476 : if (0) { }
1477 :
1478 16972 : else if (OPT_SERV_SYM_EQ("<none>") || OPT_SERV_SYM_EQ("<empty>"))
1479 : {
1480 4 : return (vstr_del(s1, pos, len));
1481 : }
1482 16968 : else if (OPT_SERV_SYM_EQ("assign") || OPT_SERV_SYM_EQ("="))
1483 : {
1484 128 : if (!opt_serv__build_str(opts, conf, token, doing_init))
1485 0 : return (FALSE);
1486 :
1487 128 : return (vstr_sub_vstr(s1, pos, len,
1488 : conf->tmp, 1, conf->tmp->len, VSTR_TYPE_SUB_BUF_REF));
1489 : }
1490 16840 : else if (OPT_SERV_SYM_EQ("append") || OPT_SERV_SYM_EQ("+=") ||
1491 : OPT_SERV_SYM_EQ(".=") || OPT_SERV_SYM_EQ(">>="))
1492 : {
1493 590 : if (!opt_serv__build_str(opts, conf, token, doing_init))
1494 0 : return (FALSE);
1495 :
1496 590 : return (vstr_add_vstr(s1, vstr_sc_poslast(pos, len),
1497 : conf->tmp, 1, conf->tmp->len, VSTR_TYPE_ADD_BUF_REF));
1498 : }
1499 16250 : else if (OPT_SERV_SYM_EQ("prepend") || OPT_SERV_SYM_EQ("<<="))
1500 : {
1501 0 : if (!opt_serv__build_str(opts, conf, token, doing_init))
1502 0 : return (FALSE);
1503 :
1504 0 : return (vstr_add_vstr(s1, pos - 1,
1505 : conf->tmp, 1, conf->tmp->len, VSTR_TYPE_ADD_BUF_REF));
1506 : }
1507 16250 : else if (!clist)
1508 : {
1509 16250 : const Vstr_sect_node *pv = conf_token_value(token);
1510 :
1511 16250 : if (!pv || !vstr_sub_vstr(s1, pos, len, conf->data, pv->pos, pv->len,
1512 : VSTR_TYPE_SUB_BUF_REF))
1513 0 : return (FALSE);
1514 16250 : OPT_SERV_X__ESC_VSTR(s1, pos, pv->len);
1515 :
1516 16250 : return (TRUE);
1517 : }
1518 :
1519 0 : return (FALSE);
1520 : }
1521 :
1522 : int opt_serv_sc_make_str(struct Opt_serv_opts *opts,
1523 : Conf_parse *conf, Conf_token *token,
1524 : Vstr_base *s1, size_t pos, size_t len)
1525 16660 : {
1526 16660 : return (opt_serv__sc_make_str(opts, conf, token, s1, pos, len, FALSE));
1527 : }
1528 :
1529 : int opt_serv_sc_make_static_path(struct Opt_serv_opts *opts,
1530 : Conf_parse *conf, Conf_token *token,
1531 : Vstr_base *s1)
1532 312 : {
1533 312 : return (opt_serv__sc_make_str(opts, conf, token, s1, 1, s1->len, TRUE));
1534 : }
1535 :
1536 : static int opt_serv__build_uintmax(Conf_parse *conf, Conf_token *token,
1537 : uintmax_t num, uintmax_t *ret)
1538 28 : {
1539 14 : ASSERT(ret);
1540 :
1541 28 : OPT_SERV_X_SYM_SINGLE_UINTMAX_BEG(*ret);
1542 :
1543 8 : else if (OPT_SERV_SYM_EQ("<num>")) *ret = num;
1544 :
1545 0 : OPT_SERV_X_SYM_NUM_END();
1546 :
1547 28 : return (TRUE);
1548 : }
1549 :
1550 : int opt_serv_sc_make_uintmax(Conf_parse *conf, Conf_token *token,
1551 : uintmax_t *num)
1552 58484 : {
1553 58484 : OPT_SERV_X_SYM_SINGLE_UINTMAX_BEG(*num);
1554 :
1555 13724 : else if (OPT_SERV_SYM_EQ("none") || OPT_SERV_SYM_EQ("zero") ||
1556 : OPT_SERV_SYM_EQ("NONE") || OPT_SERV_SYM_EQ("ZERO") ||
1557 : OPT_SERV_SYM_EQ("<none>") || OPT_SERV_SYM_EQ("<zero>") ||
1558 : OPT_SERV_SYM_EQ("<NONE>") || OPT_SERV_SYM_EQ("<ZERO>"))
1559 : {
1560 4 : *num = 0;
1561 : }
1562 13718 : else if (OPT_SERV_SYM_EQ("assign") || OPT_SERV_SYM_EQ("="))
1563 : {
1564 4 : if (!opt_serv__build_uintmax(conf, token, *num, num))
1565 0 : return (FALSE);
1566 : }
1567 13720 : else if (OPT_SERV_SYM_EQ("add") || OPT_SERV_SYM_EQ("+="))
1568 : {
1569 8 : uintmax_t tmp = 0;
1570 :
1571 8 : if (!opt_serv__build_uintmax(conf, token, *num, &tmp))
1572 0 : return (FALSE);
1573 :
1574 8 : if ((tmp + *num) < tmp)
1575 0 : return (FALSE);
1576 :
1577 8 : *num += tmp;
1578 : }
1579 13708 : else if (OPT_SERV_SYM_EQ("remove") || OPT_SERV_SYM_EQ("-="))
1580 : {
1581 4 : uintmax_t tmp = 0;
1582 :
1583 4 : if (!opt_serv__build_uintmax(conf, token, *num, &tmp))
1584 0 : return (FALSE);
1585 :
1586 4 : if (tmp > *num)
1587 0 : return (FALSE);
1588 :
1589 4 : *num -= tmp;
1590 : }
1591 13704 : else if (OPT_SERV_SYM_EQ("multiply") || OPT_SERV_SYM_EQ("*="))
1592 : {
1593 4 : uintmax_t tmp = 0;
1594 :
1595 4 : if (!opt_serv__build_uintmax(conf, token, *num, &tmp))
1596 0 : return (FALSE);
1597 :
1598 : /* FIXME: this doesn't actually work, but it's better than nothing */
1599 4 : if ((tmp * *num) < tmp)
1600 0 : return (FALSE);
1601 :
1602 4 : *num *= tmp;
1603 : }
1604 13700 : else if (OPT_SERV_SYM_EQ("divide") || OPT_SERV_SYM_EQ("/="))
1605 : {
1606 4 : uintmax_t tmp = 0;
1607 :
1608 4 : if (!opt_serv__build_uintmax(conf, token, *num, &tmp))
1609 0 : return (FALSE);
1610 :
1611 4 : if (!tmp)
1612 0 : return (FALSE);
1613 :
1614 4 : *num /= tmp;
1615 : }
1616 13696 : else if (OPT_SERV_SYM_EQ("modulus") || OPT_SERV_SYM_EQ("%="))
1617 : {
1618 4 : uintmax_t tmp = 0;
1619 :
1620 4 : if (!opt_serv__build_uintmax(conf, token, *num, &tmp))
1621 0 : return (FALSE);
1622 :
1623 4 : if (!tmp)
1624 0 : return (FALSE);
1625 :
1626 4 : *num %= tmp;
1627 : }
1628 :
1629 13688 : OPT_SERV_X_SYM_NUM_END();
1630 :
1631 44796 : return (TRUE);
1632 : }
1633 :
1634 : int opt_serv_sc_make_uint(Conf_parse *conf, Conf_token *token,
1635 : unsigned int *num)
1636 58404 : {
1637 :
1638 58404 : uintmax_t tmp = *num;
1639 :
1640 58404 : if (!opt_serv_sc_make_uintmax(conf, token, &tmp))
1641 13660 : return (FALSE);
1642 :
1643 44744 : if (tmp > UINT_MAX)
1644 0 : return (FALSE);
1645 44744 : *num = tmp;
1646 :
1647 44744 : return (TRUE);
1648 : }
1649 :
1650 : int opt_serv_sc_make_ulong(Conf_parse *conf, Conf_token *token,
1651 : unsigned long *num)
1652 80 : {
1653 :
1654 80 : uintmax_t tmp = *num;
1655 :
1656 80 : if (!opt_serv_sc_make_uintmax(conf, token, &tmp))
1657 28 : return (FALSE);
1658 :
1659 52 : if (tmp > ULONG_MAX)
1660 0 : return (FALSE);
1661 52 : *num = tmp;
1662 :
1663 52 : return (TRUE);
1664 : }
1665 :
1666 : #ifndef CONF_FULL_STATIC
1667 : void opt_serv_sc_resolve_uid(struct Opt_serv_opts *opts,
1668 : const char *program_name,
1669 : void (*usage)(const char *, int, const char *))
1670 0 : {
1671 0 : const char *name = NULL;
1672 0 : struct passwd *pw = NULL;
1673 :
1674 0 : if (!opts->vpriv_uid->len)
1675 0 : return;
1676 :
1677 0 : OPT_SC_EXPORT_CSTR(name, opts->vpriv_uid, TRUE, "privilage uid");
1678 :
1679 0 : if (!(pw = getpwnam(name)))
1680 : {
1681 0 : Vstr_base *s1 = vstr_make_base(NULL);
1682 0 : const char *msg = NULL;
1683 :
1684 0 : if (s1 &&
1685 : vstr_add_fmt(s1, s1->len, " Username -- %s -- can't be found.\n",
1686 : name) &&
1687 : (msg = vstr_export_cstr_ptr(s1, 1, s1->len)))
1688 0 : usage(program_name, EXIT_FAILURE, msg);
1689 0 : usage(program_name, EXIT_FAILURE, " Username can't be found.\n");
1690 : }
1691 :
1692 0 : opts->priv_uid = pw->pw_uid;
1693 : }
1694 :
1695 : void opt_serv_sc_resolve_gid(struct Opt_serv_opts *opts,
1696 : const char *program_name,
1697 : void (*usage)(const char *, int, const char *))
1698 0 : {
1699 0 : const char *name = NULL;
1700 0 : struct group *gr = NULL;
1701 :
1702 0 : if (!opts->vpriv_gid->len)
1703 0 : return;
1704 :
1705 0 : OPT_SC_EXPORT_CSTR(name, opts->vpriv_gid, FALSE, "privilage gid");
1706 :
1707 0 : if (!(gr = getgrnam(name)))
1708 : {
1709 0 : Vstr_base *s1 = vstr_make_base(NULL);
1710 0 : const char *msg = NULL;
1711 :
1712 0 : if (s1 &&
1713 : vstr_add_fmt(s1, s1->len, " Groupname -- %s -- can't be found.\n",
1714 : name) &&
1715 : (msg = vstr_export_cstr_ptr(s1, 1, s1->len)))
1716 0 : usage(program_name, EXIT_FAILURE, msg);
1717 0 : usage(program_name, EXIT_FAILURE, " Groupname can't be found.\n");
1718 : }
1719 :
1720 0 : opts->priv_gid = gr->gr_gid;
1721 : }
1722 : #endif
1723 :
1724 : int opt_serv_sc_config_dir(Vstr_base *s1, void *data, const char *dir,
1725 : int (*func)(Vstr_base *, void *, const char *))
1726 6 : {
1727 6 : struct dirent **dents = NULL;
1728 6 : int num = -1;
1729 6 : int scan = 0;
1730 6 : int ret = TRUE;
1731 6 : Vstr_base *bld = vstr_make_base(s1->conf);
1732 :
1733 6 : if (!bld || bld->conf->malloc_bad)
1734 : {
1735 0 : errno = ENOMEM;
1736 0 : goto fail;
1737 : }
1738 :
1739 6 : num = opt_conf_sc_scan_dir(dir, &dents);
1740 6 : if (num == -1)
1741 4 : goto fail;
1742 :
1743 : /* *******************************************************************
1744 : * These free's are for malloc's done inside scandir, so we __MUST__
1745 : * use the normal free().
1746 : * ***************************************************************** */
1747 29 : while (scan < num)
1748 : {
1749 26 : if (ret)
1750 : { /* create the full path... */
1751 26 : const char *fname = NULL;
1752 26 : const struct dirent *dent = dents[scan];
1753 :
1754 26 : vstr_del(bld, 1, bld->len);
1755 26 : vstr_add_cstr_ptr(bld, bld->len, dir);
1756 26 : vstr_add_cstr_ptr(bld, bld->len, "/");
1757 26 : vstr_add_ptr(bld, bld->len, dent->d_name, _D_EXACT_NAMLEN(dent));
1758 :
1759 26 : if (bld->conf->malloc_bad)
1760 : {
1761 0 : bld->conf->malloc_bad = FALSE;
1762 0 : ret = FALSE;
1763 : }
1764 :
1765 26 : if (ret && !(fname = vstr_export_cstr_ptr(bld, 1, bld->len)))
1766 0 : ret = FALSE;
1767 26 : if (ret && !(*func)(s1, data, fname))
1768 0 : ret = FALSE;
1769 : }
1770 :
1771 26 : free(dents[scan]);
1772 26 : ++scan;
1773 : }
1774 :
1775 2 : free(dents);
1776 2 : vstr_free_base(bld);
1777 2 : return (ret);
1778 :
1779 4 : fail:
1780 4 : vstr_add_fmt(s1, s1->len, "scandir(%s): %m", dir);
1781 4 : vstr_free_base(bld);
1782 4 : return (FALSE);
1783 : }
|