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 <sys/resource.h>
13 #include <grp.h>
14 #include <signal.h>
15
16 /* need better way to test for this */
17 #ifndef __GLIBC__
18 # define strsignal(x) ""
19 #endif
20
21 static Vlg *vlg = NULL;
22
opt_serv_sc_tst(Conf_parse * conf,Conf_token * token,int * matches,int (* tst_func)(Conf_parse *,Conf_token *,int *,void *),void * data)23 int opt_serv_sc_tst(Conf_parse *conf, Conf_token *token, int *matches,
24 int (*tst_func)(Conf_parse *, Conf_token *,
25 int *, void *), void *data)
26 {
27 if (0) { }
28
29 else if (OPT_SERV_SYM_EQ("true") || OPT_SERV_SYM_EQ("TRUE"))
30 *matches = TRUE;
31 else if (OPT_SERV_SYM_EQ("false") || OPT_SERV_SYM_EQ("FALSE"))
32 *matches = FALSE;
33
34 else if (OPT_SERV_SYM_EQ("not") || OPT_SERV_SYM_EQ("NOT") ||
35 OPT_SERV_SYM_EQ("!"))
36 {
37 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
38 if (!(*tst_func)(conf, token, matches, data))
39 return (FALSE);
40 *matches = !*matches;
41 }
42 else if (OPT_SERV_SYM_EQ("or") || OPT_SERV_SYM_EQ("OR") ||
43 OPT_SERV_SYM_EQ("||"))
44 {
45 unsigned int depth = token->depth_num;
46
47 while (conf_token_list_num(token, depth))
48 {
49 int or_matches = TRUE;
50
51 CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
52 if (!(*tst_func)(conf, token, &or_matches, data))
53 return (FALSE);
54
55 if (or_matches)
56 {
57 conf_parse_end_token(conf, token, depth);
58 return (TRUE);
59 }
60 }
61
62 *matches = FALSE;
63 }
64 else if (OPT_SERV_SYM_EQ("and") || OPT_SERV_SYM_EQ("AND") ||
65 OPT_SERV_SYM_EQ("&&"))
66 {
67 unsigned int depth = token->depth_num;
68
69 while (conf_token_list_num(token, depth))
70 {
71 CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
72 if (!(*tst_func)(conf, token, matches, data))
73 return (FALSE);
74
75 if (!*matches)
76 {
77 conf_parse_end_token(conf, token, depth);
78 return (TRUE);
79 }
80 }
81 }
82
83 else
84 return (FALSE);
85
86 return (TRUE);
87 }
88
89
opt_serv__conf_main_policy_d1(Opt_serv_policy_opts * opts,Conf_parse * conf,Conf_token * token,int clist)90 static int opt_serv__conf_main_policy_d1(Opt_serv_policy_opts *opts,
91 Conf_parse *conf, Conf_token *token,
92 int clist)
93 {
94 unsigned int dummy;
95
96 if (0) { }
97 else if (OPT_SERV_SYM_EQ("match-init"))
98 OPT_SERV_SC_MATCH_INIT(opts->beg,
99 opt_serv__conf_main_policy_d1(opts, conf, token,
100 clist));
101
102 else if (OPT_SERV_SYM_EQ("timeout"))
103 {
104 CONF_SC_MAKE_CLIST_BEG(timeout, clist);
105
106 else if (OPT_SERV_SYM_EQ("idle"))
107 OPT_SERV_X_UINT(opts->idle_timeout);
108 else if (OPT_SERV_SYM_EQ("total"))
109 OPT_SERV_X_UINT(dummy);
110
111 CONF_SC_MAKE_CLIST_END();
112 }
113 else if (OPT_SERV_SYM_EQ("limit"))
114 {
115 CONF_SC_MAKE_CLIST_BEG(limit, clist);
116
117 else if (OPT_SERV_SYM_EQ("connections"))
118 OPT_SERV_X_UINT(opts->max_connections);
119 else if (OPT_SERV_SYM_EQ("io-r/s") ||
120 OPT_SERV_SYM_EQ("io-read/s") ||
121 OPT_SERV_SYM_EQ("io-recv/s"))
122 OPT_SERV_X_UINT(dummy);
123 else if (OPT_SERV_SYM_EQ("io-s/s") ||
124 OPT_SERV_SYM_EQ("io-w/s") ||
125 OPT_SERV_SYM_EQ("io-write/s") ||
126 OPT_SERV_SYM_EQ("io-send/s"))
127 OPT_SERV_X_UINT(dummy);
128
129 CONF_SC_MAKE_CLIST_END();
130 }
131 else
132 return (FALSE);
133
134 return (TRUE);
135 }
136
opt_serv__conf_main_policy(Opt_serv_opts * opts,Conf_parse * conf,Conf_token * token)137 static int opt_serv__conf_main_policy(Opt_serv_opts *opts,
138 Conf_parse *conf, Conf_token *token)
139 {
140 Opt_serv_policy_opts *popts = NULL;
141 unsigned int cur_depth = opt_policy_sc_conf_parse(opts, conf, token, &popts);
142 int clist = FALSE;
143
144 if (!cur_depth)
145 return (FALSE);
146
147 CONF_SC_MAKE_CLIST_MID(cur_depth, clist);
148
149 else if (opt_serv__conf_main_policy_d1(popts, conf, token, clist))
150 { }
151
152 CONF_SC_MAKE_CLIST_END();
153
154 return (TRUE);
155 }
156
157 static int opt_serv__match_init_tst_d1(struct Opt_serv_opts *opts,
158 Conf_parse *conf, Conf_token *token,
159 int *matches);
opt_serv__match_init_tst_op_d1(Conf_parse * conf,Conf_token * token,int * matches,void * passed_data)160 static int opt_serv__match_init_tst_op_d1(Conf_parse *conf, Conf_token *token,
161 int *matches, void *passed_data)
162 {
163 struct Opt_serv_opts *opts = passed_data;
164
165 return (opt_serv__match_init_tst_d1(opts, conf, token, matches));
166 }
167
opt_serv__match_init_tst_d1(struct Opt_serv_opts * opts,Conf_parse * conf,Conf_token * token,int * matches)168 static int opt_serv__match_init_tst_d1(struct Opt_serv_opts *opts,
169 Conf_parse *conf, Conf_token *token,
170 int *matches)
171 {
172 int clist = FALSE;
173
174 ASSERT(matches);
175
176 CONF_SC_TOGGLE_CLIST_VAR(clist);
177
178 if (0) {}
179
180 else if (OPT_SERV_SYM_EQ("version-compare<=") ||
181 OPT_SERV_SYM_EQ("vers-cmp<="))
182 {
183 OPT_SERV_X_VSTR(conf->tmp);
184 *matches = (vstr_cmp_vers_buf(conf->tmp, 1, conf->tmp->len,
185 opts->vers_cstr, opts->vers_len) >= 0);
186 }
187 else if (OPT_SERV_SYM_EQ("version-compare>=") ||
188 OPT_SERV_SYM_EQ("vers-cmp>="))
189 {
190 OPT_SERV_X_VSTR(conf->tmp);
191 *matches = (vstr_cmp_vers_buf(conf->tmp, 1, conf->tmp->len,
192 opts->vers_cstr, opts->vers_len) <= 0);
193 }
194 else if (OPT_SERV_SYM_EQ("version-compare-eq") ||
195 OPT_SERV_SYM_EQ("vers-cmp=="))
196 {
197 OPT_SERV_X_VSTR(conf->tmp);
198 *matches = (vstr_cmp_vers_buf(conf->tmp, 1, conf->tmp->len,
199 opts->vers_cstr, opts->vers_len) == 0);
200 }
201
202 else if (OPT_SERV_SYM_EQ("name-compare-eq") ||
203 OPT_SERV_SYM_EQ("name-cmp=="))
204 {
205 OPT_SERV_X_VSTR(conf->tmp);
206 *matches = vstr_cmp_buf_eq(conf->tmp, 1, conf->tmp->len,
207 opts->name_cstr, opts->name_len);
208 }
209
210 else if (OPT_SERV_SYM_EQ("uid-compare-eq") ||
211 OPT_SERV_SYM_EQ("uid-cmp=="))
212 {
213 unsigned int dummy = 0;
214 OPT_SERV_X_UINT(dummy);
215 *matches = (dummy == getuid());
216 }
217 else if (OPT_SERV_SYM_EQ("euid-compare-eq") ||
218 OPT_SERV_SYM_EQ("euid-cmp=="))
219 {
220 unsigned int dummy = 0;
221 OPT_SERV_X_UINT(dummy);
222 *matches = (dummy == geteuid());
223 }
224
225 else
226 return (opt_serv_sc_tst(conf, token, matches,
227 opt_serv__match_init_tst_op_d1, opts));
228
229 return (TRUE);
230 }
231
opt_serv_match_init(struct Opt_serv_opts * opts,Conf_parse * conf,Conf_token * token,int * matches)232 int opt_serv_match_init(struct Opt_serv_opts *opts,
233 Conf_parse *conf, Conf_token *token, int *matches)
234 {
235 unsigned int depth = token->depth_num;
236
237 ASSERT(matches);
238
239 *matches = TRUE;
240
241 CONF_SC_PARSE_SLIST_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
242 ++depth;
243 while (conf_token_list_num(token, depth))
244 {
245 CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
246
247 if (!opt_serv__match_init_tst_d1(opts, conf, token, matches))
248 return (FALSE);
249
250 if (!*matches)
251 return (TRUE);
252 }
253
254 return (TRUE);
255 }
256
257 #define OPT_SERV__RLIM_VAL(x, y) do { \
258 const Vstr_sect_node *pv = NULL; \
259 unsigned int val = 0; \
260 int ern = 0; \
261 \
262 (y) = TRUE; \
263 \
264 ern = conf_sc_token_parse_uint(conf, token, &val); \
265 if (ern && (ern == CONF_SC_TYPE_RET_ERR_PARSE) && \
266 !(pv = conf_token_value(token))) \
267 return (FALSE); \
268 \
269 if (!pv) \
270 (x) = val; \
271 else \
272 { \
273 if (0){ } \
274 else if (OPT_SERV_SYM_EQ("<infinity>")) (x) = RLIM_INFINITY; \
275 else if (OPT_SERV_SYM_EQ("<unlimited>")) (x) = RLIM_INFINITY; \
276 else if (OPT_SERV_SYM_EQ("<none>")) (x) = 0; \
277 else if (OPT_SERV_SYM_EQ("<zero>")) (x) = 0; \
278 else if (OPT_SERV_SYM_EQ("<default>")) (y) = FALSE; \
279 else return (FALSE); \
280 } \
281 } \
282 while (FALSE)
283
opt_serv__conf_d1(struct Opt_serv_opts * opts,Conf_parse * conf,Conf_token * token,int clist)284 static int opt_serv__conf_d1(struct Opt_serv_opts *opts,
285 Conf_parse *conf, Conf_token *token,
286 int clist)
287 {
288 if (0) { }
289
290 else if (OPT_SERV_SYM_EQ("match-init"))
291 OPT_SERV_SC_MATCH_INIT(opts, opt_serv__conf_d1(opts, conf, token, clist));
292
293 else if (OPT_SERV_SYM_EQ("policy"))
294 {
295 if (!opt_serv__conf_main_policy(opts, conf, token))
296 return (FALSE);
297 }
298
299 else if (OPT_SERV_SYM_EQ("chroot"))
300 return (opt_serv_sc_make_static_path(opts, conf, token, opts->chroot_dir));
301 else if (OPT_SERV_SYM_EQ("cntl-file") ||
302 OPT_SERV_SYM_EQ("control-file"))
303 return (opt_serv_sc_make_static_path(opts, conf, token, opts->cntl_file));
304 else if (OPT_SERV_SYM_EQ("daemonize"))
305 OPT_SERV_X_TOGGLE(opts->become_daemon);
306 else if (OPT_SERV_SYM_EQ("drop-privs"))
307 {
308 unsigned int depth = token->depth_num;
309 int val = opts->drop_privs;
310 int ern = conf_sc_token_parse_toggle(conf, token, &val);
311 unsigned int num = conf_token_list_num(token, token->depth_num);
312
313 if (ern == CONF_SC_TYPE_RET_ERR_NO_MATCH)
314 return (FALSE);
315 if (!val && num)
316 return (FALSE);
317
318 opts->drop_privs = val;
319 CONF_SC_MAKE_CLIST_MID(depth, clist);
320
321 else if (OPT_SERV_SYM_EQ("uid")) OPT_SERV_X_UINT(opts->priv_uid);
322 else if (OPT_SERV_SYM_EQ("usrname")) OPT_SERV_X_VSTR(opts->vpriv_uid);
323 else if (OPT_SERV_SYM_EQ("username")) OPT_SERV_X_VSTR(opts->vpriv_uid);
324 else if (OPT_SERV_SYM_EQ("gid")) OPT_SERV_X_UINT(opts->priv_gid);
325 else if (OPT_SERV_SYM_EQ("grpname")) OPT_SERV_X_VSTR(opts->vpriv_gid);
326 else if (OPT_SERV_SYM_EQ("groupname")) OPT_SERV_X_VSTR(opts->vpriv_gid);
327
328 CONF_SC_MAKE_CLIST_END();
329 }
330 else if (OPT_SERV_SYM_EQ("listen"))
331 {
332 Opt_serv_addr_opts *addr = opt_serv_make_addr(opts);
333 CONF_SC_MAKE_CLIST_BEG(listen, clist);
334
335 else if (!addr) return (FALSE);
336
337 else if (OPT_SERV_SYM_EQ("defer-accept"))
338 OPT_SERV_X_UINT(addr->defer_accept);
339 else if (OPT_SERV_SYM_EQ("port"))
340 OPT_SERV_X_UINT(addr->tcp_port);
341 else if (OPT_SERV_SYM_EQ("address") ||
342 OPT_SERV_SYM_EQ("addr"))
343 OPT_SERV_X_VSTR(addr->ipv4_address);
344 else if (OPT_SERV_SYM_EQ("queue-length"))
345 OPT_SERV_X_UINT(addr->q_listen_len);
346 else if (OPT_SERV_SYM_EQ("filter"))
347 {
348 if (!opt_serv_sc_make_static_path(opts, conf, token,
349 addr->acpt_filter_file))
350 return (FALSE);
351 }
352 else if (OPT_SERV_SYM_EQ("max-connections"))
353 OPT_SERV_X_UINT(addr->max_connections);
354
355 CONF_SC_MAKE_CLIST_END();
356 }
357 else if (OPT_SERV_SYM_EQ("parent-death-signal"))
358 OPT_SERV_X_TOGGLE(opts->use_pdeathsig);
359 else if (OPT_SERV_SYM_EQ("pid-file"))
360 return (opt_serv_sc_make_static_path(opts, conf, token, opts->pid_file));
361 else if (OPT_SERV_SYM_EQ("processes") ||
362 OPT_SERV_SYM_EQ("procs"))
363 {
364 unsigned int opt__val = 0;
365 unsigned int ret = conf_sc_token_parse_uint(conf, token, &opt__val);
366
367 if (ret == CONF_SC_TYPE_RET_ERR_PARSE)
368 {
369 const Vstr_sect_node *pv = NULL;
370 long sc_val = -1;
371
372 if (!(pv = conf_token_value(token)))
373 return (FALSE);
374 if (0) { }
375 else if (vstr_cmp_cstr_eq(conf->data, pv->pos, pv->len,
376 "<sysconf-number-processors-configured>") ||
377 vstr_cmp_cstr_eq(conf->data, pv->pos, pv->len,
378 "<sysconf-num-procs-configured>") ||
379 vstr_cmp_cstr_eq(conf->data, pv->pos, pv->len,
380 "<sysconf-num-procs-conf>"))
381 sc_val = sysconf(_SC_NPROCESSORS_CONF);
382 else if (vstr_cmp_cstr_eq(conf->data, pv->pos, pv->len,
383 "<sysconf-number-processors-online>") ||
384 vstr_cmp_cstr_eq(conf->data, pv->pos, pv->len,
385 "<sysconf-num-procs-online>") ||
386 vstr_cmp_cstr_eq(conf->data, pv->pos, pv->len,
387 "<sysconf-num-procs-onln>"))
388 sc_val = sysconf(_SC_NPROCESSORS_ONLN);
389 else
390 return (FALSE);
391 if (sc_val == -1)
392 sc_val = 1;
393 opt__val = sc_val;
394 }
395 else if (ret)
396 return (FALSE);
397
398 opts->num_procs = opt__val;
399 }
400 else if (OPT_SERV_SYM_EQ("resource-limits") ||
401 OPT_SERV_SYM_EQ("rlimit"))
402 {
403 CONF_SC_MAKE_CLIST_BEG(rlimit, clist);
404
405 else if (OPT_SERV_SYM_EQ("CORE") ||
406 OPT_SERV_SYM_EQ("core"))
407 OPT_SERV__RLIM_VAL(opts->rlim_core_num, opts->rlim_core_call);
408 else if (OPT_SERV_SYM_EQ("NOFILE") ||
409 OPT_SERV_SYM_EQ("file-descriptor-number") ||
410 OPT_SERV_SYM_EQ("fd-num"))
411 OPT_SERV__RLIM_VAL(opts->rlim_file_num, opts->rlim_file_call);
412
413 CONF_SC_MAKE_CLIST_END();
414 }
415 /* else if (OPT_SERV_SYM_EQ("priority"))
416 OPT_SERV_X_UINT(opts->sys_priority); */
417 else if (OPT_SERV_SYM_EQ("cache-limits"))
418 {
419 CONF_SC_MAKE_CLIST_BEG(cache_limits, clist);
420
421 else if (OPT_SERV_SYM_EQ("spare-vstr-bases"))
422 OPT_SERV_X_UINT(opts->max_spare_bases);
423 else if (OPT_SERV_SYM_EQ("spare-vstr-nodes-buf"))
424 OPT_SERV_X_UINT(opts->max_spare_buf_nodes);
425 else if (OPT_SERV_SYM_EQ("spare-vstr-nodes-ptr"))
426 OPT_SERV_X_UINT(opts->max_spare_ptr_nodes);
427 else if (OPT_SERV_SYM_EQ("spare-vstr-nodes-ref"))
428 OPT_SERV_X_UINT(opts->max_spare_ref_nodes);
429
430 CONF_SC_MAKE_CLIST_END();
431 }
432
433 else
434 return (FALSE);
435
436 return (TRUE);
437 }
438 #undef OPT_SERV__RLIM_VAL
439
opt_serv_conf(struct Opt_serv_opts * opts,Conf_parse * conf,Conf_token * token)440 int opt_serv_conf(struct Opt_serv_opts *opts,
441 Conf_parse *conf, Conf_token *token)
442 {
443 unsigned int cur_depth = token->depth_num;
444 int clist = FALSE;
445
446 ASSERT(opts && conf && token);
447
448 if (!conf_token_cmp_sym_cstr_eq(conf, token, "org.and.daemon-conf-1.0"))
449 return (FALSE);
450
451 CONF_SC_MAKE_CLIST_MID(cur_depth, clist);
452
453 else if (opt_serv__conf_d1(opts, conf, token, clist))
454 { }
455
456 CONF_SC_MAKE_CLIST_END();
457
458 /* And they all live together ... dum dum */
459 if (conf->data->conf->malloc_bad)
460 return (FALSE);
461
462 return (TRUE);
463 }
464
opt_serv_conf_parse_cstr(Vstr_base * out,Opt_serv_opts * opts,const char * data)465 int opt_serv_conf_parse_cstr(Vstr_base *out,
466 Opt_serv_opts *opts, const char *data)
467 {
468 Conf_parse *conf = conf_parse_make(NULL);
469 Conf_token token[1] = {CONF_TOKEN_INIT};
470
471 ASSERT(opts && data);
472
473 if (!conf)
474 goto conf_malloc_fail;
475
476 if (!vstr_add_cstr_ptr(conf->data, conf->data->len,
477 "(org.and.daemon-conf-1.0 "))
478 goto read_malloc_fail;
479 if (!vstr_add_cstr_ptr(conf->data, conf->data->len, data))
480 goto read_malloc_fail;
481 if (!vstr_add_cstr_ptr(conf->data, conf->data->len,
482 ")"))
483 goto read_malloc_fail;
484
485 if (!conf_parse_lex(conf, 1, conf->data->len))
486 goto conf_fail;
487
488 if (!conf_parse_token(conf, token))
489 goto conf_fail;
490
491 if ((token->type != CONF_TOKEN_TYPE_CLIST) || (token->depth_num != 1))
492 goto conf_fail;
493
494 if (!conf_parse_token(conf, token))
495 goto conf_fail;
496
497 ASSERT(conf_token_cmp_sym_cstr_eq(conf, token, "org.and.daemon-conf-1.0"));
498
499 if (!opt_serv_conf(opts, conf, token))
500 goto conf_fail;
501 if (token->num != conf->sects->num)
502 goto conf_fail;
503
504 conf_parse_free(conf);
505 return (TRUE);
506
507 conf_fail:
508 conf_parse_backtrace(out, data, conf, token);
509 read_malloc_fail:
510 conf_parse_free(conf);
511 conf_malloc_fail:
512 return (FALSE);
513 }
514
opt_serv_conf_parse_file(Vstr_base * out,Opt_serv_opts * opts,const char * fname)515 int opt_serv_conf_parse_file(Vstr_base *out,
516 Opt_serv_opts *opts, const char *fname)
517 {
518 Conf_parse *conf = conf_parse_make(NULL);
519 Conf_token token[1] = {CONF_TOKEN_INIT};
520
521 ASSERT(opts && fname);
522
523 if (!conf)
524 goto conf_malloc_fail;
525
526 if (!vstr_sc_read_len_file(conf->data, 0, fname, 0, 0, NULL))
527 goto read_malloc_fail;
528
529 if (!conf_parse_lex(conf, 1, conf->data->len))
530 goto conf_fail;
531
532 while (conf_parse_token(conf, token))
533 {
534 if ((token->type != CONF_TOKEN_TYPE_CLIST) || (token->depth_num != 1))
535 goto conf_fail;
536
537 if (!conf_parse_token(conf, token))
538 goto conf_fail;
539
540 if (!conf_token_cmp_sym_cstr_eq(conf, token, "org.and.daemon-conf-1.0"))
541 goto conf_fail;
542
543 if (!opt_serv_conf(opts, conf, token))
544 goto conf_fail;
545 }
546
547 conf_parse_free(conf);
548 return (TRUE);
549
550 conf_fail:
551 conf_parse_backtrace(out, fname, conf, token);
552 errno = 0;
553 read_malloc_fail:
554 if (errno && out) /* can't find config. file */
555 vstr_add_fmt(out, out->len, "open(%s): %m", fname);
556 conf_parse_free(conf);
557 conf_malloc_fail:
558 return (FALSE);
559 }
560
opt_serv_conf_free(struct Opt_serv_opts * opts)561 void opt_serv_conf_free(struct Opt_serv_opts *opts)
562 {
563 Opt_serv_addr_opts *scan = NULL;
564
565 if (!opts)
566 return;
567
568 vstr_free_base(opts->pid_file); opts->pid_file = NULL;
569 vstr_free_base(opts->cntl_file); opts->cntl_file = NULL;
570 vstr_free_base(opts->chroot_dir); opts->chroot_dir = NULL;
571 vstr_free_base(opts->vpriv_uid); opts->vpriv_uid = NULL;
572 vstr_free_base(opts->vpriv_gid); opts->vpriv_gid = NULL;
573
574 scan = opts->addr_beg;
575 opts->addr_beg = NULL;
576 while (scan)
577 {
578 Opt_serv_addr_opts *scan_next = scan->next;
579
580 vstr_free_base(scan->acpt_filter_file);
581 vstr_free_base(scan->ipv4_address);
582 F(scan);
583
584 scan = scan_next;
585 }
586 }
587
opt_serv_conf_init(Opt_serv_opts * opts)588 int opt_serv_conf_init(Opt_serv_opts *opts)
589 {
590 struct Opt_serv_policy_opts *popts = NULL;
591 Opt_serv_addr_opts *addr = MK(sizeof(Opt_serv_addr_opts));
592
593 ASSERT(opts && opts->make_policy && opts->copy_policy);
594
595 if (!addr)
596 goto mk_addr_fail;
597
598 if (!(popts = (*opts->make_policy)(opts)))
599 goto mk_policy_fail;
600
601 opts->def_policy = popts;
602 vstr_add_cstr_ptr(popts->policy_name, 0, OPT_POLICY_CONF_DEF_POLICY_NAME);
603
604 if (popts->policy_name->conf->malloc_bad)
605 goto policy_init_fail;
606
607 opts->pid_file = vstr_make_base(NULL);
608 opts->cntl_file = vstr_make_base(NULL);
609 opts->chroot_dir = vstr_make_base(NULL);
610 opts->vpriv_uid = vstr_make_base(NULL);
611 opts->vpriv_gid = vstr_make_base(NULL);
612 addr->acpt_filter_file = vstr_make_base(NULL);
613 addr->ipv4_address = vstr_make_base(NULL);
614
615 if (!opts->pid_file ||
616 !opts->cntl_file ||
617 !opts->chroot_dir ||
618 !opts->vpriv_uid ||
619 !opts->vpriv_gid ||
620 !addr->acpt_filter_file ||
621 !addr->ipv4_address ||
622 FALSE)
623 goto opts_init_fail;
624
625 addr->next = NULL;
626
627 addr->tcp_port = 0;
628 addr->defer_accept = OPT_SERV_CONF_DEF_TCP_DEFER_ACCEPT;
629 addr->q_listen_len = OPT_SERV_CONF_DEF_Q_LISTEN_LEN;
630 addr->max_connections = OPT_SERV_CONF_DEF_MAX_CONNECTIONS;
631
632 opts->addr_beg = addr;
633
634 opts->no_conf_listen = TRUE;
635
636 return (TRUE);
637
638 opts_init_fail:
639 opt_serv_conf_free(opts);
640 policy_init_fail:
641 vstr_ref_del(popts->ref);
642 mk_policy_fail:
643 F(addr);
644 mk_addr_fail:
645 return (FALSE);
646 }
647
648 #define OPT_SERV_ADDR_DUP_VSTR(x) \
649 vstr_dup_vstr(opts->addr_beg-> x ->conf , \
650 opts->addr_beg-> x , 1, opts->addr_beg-> x ->len, \
651 VSTR_TYPE_SUB_BUF_REF)
opt_serv_make_addr(Opt_serv_opts * opts)652 Opt_serv_addr_opts *opt_serv_make_addr(Opt_serv_opts *opts)
653 {
654 Opt_serv_addr_opts *addr = NULL;
655
656 ASSERT(opts && opts->addr_beg);
657
658 if (opts->no_conf_listen)
659 { /* use the initial one to start with */
660 opts->no_conf_listen = FALSE;
661 return (opts->addr_beg);
662 }
663
664 /* duplicate the currnet one */
665 if (!(addr = MK(sizeof(Opt_serv_addr_opts))))
666 goto mk_addr_fail;
667
668 addr->acpt_filter_file = OPT_SERV_ADDR_DUP_VSTR(acpt_filter_file);
669 addr->ipv4_address = OPT_SERV_ADDR_DUP_VSTR(ipv4_address);
670
671 if (!addr->acpt_filter_file ||
672 !addr->ipv4_address ||
673 FALSE)
674 goto addr_init_fail;
675
676 addr->next = NULL;
677
678 addr->tcp_port = opts->addr_beg->tcp_port;
679 addr->defer_accept = opts->addr_beg->defer_accept;
680 addr->q_listen_len = opts->addr_beg->q_listen_len;
681 addr->max_connections = opts->addr_beg->max_connections;
682
683 addr->next = opts->addr_beg;
684 opts->addr_beg = addr;
685
686 return (addr);
687
688 addr_init_fail:
689 F(addr);
690 mk_addr_fail:
691 return (FALSE);
692 }
693
opt_serv_logger(Vlg * passed_vlg)694 void opt_serv_logger(Vlg *passed_vlg)
695 {
696 vlg = passed_vlg;
697 }
698
opt_serv_sc_drop_privs(Opt_serv_opts * opts)699 void opt_serv_sc_drop_privs(Opt_serv_opts *opts)
700 {
701 if (setgroups(1, &opts->priv_gid) == -1)
702 vlg_err(vlg, EXIT_FAILURE, "setgroups(%ld): %m\n", (long)opts->priv_gid);
703
704 if (setgid(opts->priv_gid) == -1)
705 vlg_err(vlg, EXIT_FAILURE, "setgid(%ld): %m\n", (long)opts->priv_gid);
706
707 if (setuid(opts->priv_uid) == -1)
708 vlg_err(vlg, EXIT_FAILURE, "setuid(%ld): %m\n", (long)opts->priv_uid);
709 }
710
opt_serv__sc_rlim_num(const char * name,int resource,unsigned int num)711 static void opt_serv__sc_rlim_num(const char *name, int resource,
712 unsigned int num)
713 {
714 struct rlimit rlim[1];
715
716 if (getrlimit(resource, rlim) == -1)
717 vlg_err(vlg, EXIT_FAILURE, "getrlimit(%s): %m\n", name);
718
719
720 if (num == RLIM_INFINITY) /* only attempt upwards, if we are privilaged */
721 {
722 if ((rlim->rlim_max != RLIM_INFINITY) && !getuid())
723 rlim->rlim_max = num;
724 }
725 else
726 {
727 if ((num > rlim->rlim_max) && !getuid())
728 rlim->rlim_max = num;
729
730 if (num < rlim->rlim_max) /* can always do this ? */
731 rlim->rlim_max = num;
732 }
733
734 rlim->rlim_cur = rlim->rlim_max; /* upgrade soft to hard */
735
736 if (setrlimit(resource, rlim) == -1)
737 vlg_err(vlg, EXIT_FAILURE, "setrlimit(%s): %m\n", name);
738 }
739
opt_serv_sc_rlim_file_num(unsigned int rlim_file_num)740 void opt_serv_sc_rlim_file_num(unsigned int rlim_file_num)
741 {
742 opt_serv__sc_rlim_num("NOFILE", RLIMIT_NOFILE, rlim_file_num);
743 }
744
opt_serv_sc_rlim_core_num(unsigned int rlim_core_num)745 void opt_serv_sc_rlim_core_num(unsigned int rlim_core_num)
746 {
747 opt_serv__sc_rlim_num("CORE", RLIMIT_CORE, rlim_core_num);
748 }
749
opt_serv_sc_acpt_end(const Opt_serv_policy_opts * popts,struct Evnt * from_evnt,struct Evnt * evnt)750 int opt_serv_sc_acpt_end(const Opt_serv_policy_opts *popts,
751 struct Evnt *from_evnt, struct Evnt *evnt)
752 {
753 Acpt_listener *acpt_listener = (Acpt_listener *)from_evnt;
754 unsigned int acpt_num = acpt_listener->ref->ref - 1; /* ref +1 for itself */
755 unsigned int acpt_max = acpt_listener->max_connections;
756
757 vlg_dbg1(vlg, "acpt: %u/%u\n", acpt_num, acpt_max);
758
759 if (acpt_max && (acpt_num >= acpt_max))
760 {
761 vlg_dbg1(vlg, "ACPT DEL ($<sa:%p>,%u,%u)\n", EVNT_SA(from_evnt),
762 acpt_num, acpt_max);
763 evnt_wait_cntl_del(from_evnt, POLLIN);
764 }
765
766 if (popts->max_connections && (evnt_num_all() > popts->max_connections))
767 {
768 vlg_info(vlg, "LIMIT-BLOCKED from[$<sa:%p>]: policy $<vstr.all:%p>\n",
769 EVNT_SA(evnt), popts->policy_name);
770 return (FALSE);
771 }
772
773 vlg_info(vlg, "CONNECT from[$<sa:%p>]\n", EVNT_SA(evnt));
774
775 return (TRUE);
776 }
777
opt_serv_sc_free_beg(struct Evnt * evnt,Vstr_ref * ref)778 void opt_serv_sc_free_beg(struct Evnt *evnt, Vstr_ref *ref)
779 {
780 Acpt_data *acpt_data = ref->ptr;
781
782 if (acpt_data->evnt)
783 {
784 Acpt_listener *acpt_listener = (Acpt_listener *)acpt_data->evnt;
785 unsigned int acpt_num = acpt_listener->ref->ref - 1;
786 unsigned int acpt_max = acpt_listener->max_connections;
787
788 if (acpt_max && (acpt_num <= acpt_max)) /* note that we are going to -1 */
789 {
790 vlg_dbg1(vlg, "ACPT ADD ($<sa:%p>,%u,%u)\n", EVNT_SA(acpt_data->evnt),
791 acpt_num, acpt_max);
792 evnt_wait_cntl_add(acpt_data->evnt, POLLIN);
793 }
794
795 evnt_stats_add(acpt_data->evnt, evnt);
796 }
797
798 if (evnt->flag_fully_acpt)
799 evnt_vlg_stats_info(evnt, "FREE");
800
801 vstr_ref_del(ref);
802 }
803
804 #define OPT_SERV__SIG_OR_ERR(x) \
805 if (sigaction(x, &sa, NULL) == -1) \
806 err(EXIT_FAILURE, "signal(%d:%s)", x, strsignal(x))
807
opt_serv__sig_crash(int s_ig_num)808 static void opt_serv__sig_crash(int s_ig_num)
809 {
810 vlg_sig_abort(vlg, "SIG[%d]: %s\n", s_ig_num, strsignal(s_ig_num));
811 }
812
opt_serv__sig_raise_cont(int s_ig_num)813 static void opt_serv__sig_raise_cont(int s_ig_num)
814 {
815 struct sigaction sa;
816
817 if (sigemptyset(&sa.sa_mask) == -1)
818 err(EXIT_FAILURE, "signal init");
819
820 sa.sa_flags = SA_RESTART;
821 sa.sa_handler = SIG_DFL;
822 OPT_SERV__SIG_OR_ERR(s_ig_num);
823
824 vlg_sig_info(vlg, "SIG[%d]: %s\n", s_ig_num, strsignal(s_ig_num));
825 raise(s_ig_num);
826 }
827
opt_serv__sig_cont(int s_ig_num)828 static void opt_serv__sig_cont(int s_ig_num)
829 {
830 if (0) /* s_ig_num == SIGCONT) */
831 {
832 struct sigaction sa;
833
834 if (sigemptyset(&sa.sa_mask) == -1)
835 err(EXIT_FAILURE, "signal init");
836
837 sa.sa_flags = SA_RESTART;
838 sa.sa_handler = opt_serv__sig_raise_cont;
839 OPT_SERV__SIG_OR_ERR(SIGTSTP);
840 }
841
842 vlg_sig_info(vlg, "SIG[%d]: %s\n", s_ig_num, strsignal(s_ig_num));
843 }
844
opt_serv__sig_child(int s_ig_num)845 static void opt_serv__sig_child(int s_ig_num)
846 {
847 ASSERT(s_ig_num == SIGCHLD);
848 evnt_child_exited = TRUE;
849 }
850
opt_serv_sc_signals(void)851 void opt_serv_sc_signals(void)
852 {
853 struct sigaction sa;
854
855 if (sigemptyset(&sa.sa_mask) == -1)
856 err(EXIT_FAILURE, "signal init %s", "sigemptyset");
857
858 /* don't use SA_RESTART ... */
859 sa.sa_flags = 0;
860 /* ignore it... we don't have a use for it */
861 sa.sa_handler = SIG_IGN;
862
863 OPT_SERV__SIG_OR_ERR(SIGPIPE);
864
865 sa.sa_handler = opt_serv__sig_crash;
866
867 OPT_SERV__SIG_OR_ERR(SIGSEGV);
868 OPT_SERV__SIG_OR_ERR(SIGBUS);
869 OPT_SERV__SIG_OR_ERR(SIGILL);
870 OPT_SERV__SIG_OR_ERR(SIGFPE);
871 OPT_SERV__SIG_OR_ERR(SIGXFSZ);
872
873 sa.sa_flags = SA_RESTART;
874 sa.sa_handler = opt_serv__sig_child;
875 OPT_SERV__SIG_OR_ERR(SIGCHLD);
876
877 sa.sa_flags = SA_RESTART;
878 sa.sa_handler = opt_serv__sig_cont; /* print, and do nothing */
879
880 OPT_SERV__SIG_OR_ERR(SIGUSR1);
881 OPT_SERV__SIG_OR_ERR(SIGUSR2);
882 OPT_SERV__SIG_OR_ERR(SIGHUP);
883 OPT_SERV__SIG_OR_ERR(SIGCONT);
884
885 sa.sa_handler = opt_serv__sig_raise_cont; /* queue print, and re-raise */
886
887 OPT_SERV__SIG_OR_ERR(SIGTSTP);
888 OPT_SERV__SIG_OR_ERR(SIGTERM);
889 }
890 #undef SERV__SIG_OR_ERR
891
opt_serv_sc_check_children(void)892 void opt_serv_sc_check_children(void)
893 {
894 if (evnt_child_exited)
895 {
896 vlg_warn(vlg, "Child exited.\n");
897 evnt_acpt_close_all();
898 evnt_scan_q_close();
899 evnt_child_exited = FALSE;
900 }
901 }
902
opt_serv_sc_cntl_resources(const Opt_serv_opts * opts)903 void opt_serv_sc_cntl_resources(const Opt_serv_opts *opts)
904 { /* cap the amount of "wasted" resources we're using */
905
906 vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BASE,
907 0, opts->max_spare_bases);
908
909 vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF,
910 0, opts->max_spare_buf_nodes);
911 vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_PTR,
912 0, opts->max_spare_ptr_nodes);
913 vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_REF,
914 0, opts->max_spare_ref_nodes);
915 }
916
opt_serv_sc_append_hostname(Vstr_base * s1,size_t pos)917 int opt_serv_sc_append_hostname(Vstr_base *s1, size_t pos)
918 {
919 char buf[256];
920
921 if (gethostname(buf, sizeof(buf)) == -1)
922 err(EXIT_FAILURE, "gethostname");
923
924 buf[sizeof(buf) - 1] = 0;
925 return (vstr_add_cstr_buf(s1, pos, buf));
926 }
927
opt_serv_sc_append_cwd(Vstr_base * s1,size_t pos)928 int opt_serv_sc_append_cwd(Vstr_base *s1, size_t pos)
929 {
930 size_t sz = PATH_MAX;
931 char *ptr = MK(sz);
932 char *tmp = NULL;
933 int ret = FALSE;
934
935 if (ptr)
936 tmp = getcwd(ptr, sz);
937 while (!tmp && (errno == ERANGE))
938 {
939 sz += PATH_MAX;
940 if (!MV(ptr, tmp, sz))
941 break;
942 tmp = getcwd(ptr, sz);
943 }
944
945 if (!tmp)
946 ret = vstr_add_cstr_ptr(s1, pos, "/");
947 else
948 ret = vstr_add_cstr_buf(s1, pos, tmp);
949 F(ptr);
950
951 return (ret);
952 }
953
954 /* into conf->tmp */
opt_serv__build_static_path(struct Opt_serv_opts * EVNT__ATTR_UNUSED (opts),Conf_parse * conf,Conf_token * token)955 static int opt_serv__build_static_path(struct Opt_serv_opts *
956 EVNT__ATTR_UNUSED(opts),
957 Conf_parse *conf, Conf_token *token)
958 {
959 unsigned int cur_depth = token->depth_num;
960 int clist = FALSE;
961
962 vstr_del(conf->tmp, 1, conf->tmp->len);
963 while (conf_token_list_num(token, cur_depth))
964 {
965 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
966 CONF_SC_TOGGLE_CLIST_VAR(clist);
967
968 if (0) { }
969
970 else if (OPT_SERV_SYM_EQ("ENV") || OPT_SERV_SYM_EQ("ENVIRONMENT"))
971 {
972 const Vstr_sect_node *pv = NULL;
973 const char *env_name = NULL;
974 const char *env_data = NULL;
975
976 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
977 pv = conf_token_value(token);
978 if (!(env_name = vstr_export_cstr_ptr(conf->data, pv->pos, pv->len)))
979 return (FALSE);
980
981 env_data = getenv(env_name);
982 if (!env_data) env_data = "";
983
984 vstr_add_cstr_buf(conf->tmp, conf->tmp->len, env_data);
985 }
986 else if (OPT_SERV_SYM_EQ("<hostname>"))
987 opt_serv_sc_append_hostname(conf->tmp, conf->tmp->len);
988 else if (OPT_SERV_SYM_EQ("<cwd>"))
989 opt_serv_sc_append_cwd(conf->tmp, conf->tmp->len);
990 else if (!clist)
991 { /* unknown symbol or string */
992 size_t pos = conf->tmp->len + 1;
993 const Vstr_sect_node *pv = conf_token_value(token);
994
995 if (!pv || !vstr_add_vstr(conf->tmp, conf->tmp->len,
996 conf->data, pv->pos, pv->len,
997 VSTR_TYPE_ADD_BUF_REF))
998 return (FALSE);
999
1000 OPT_SERV_X__ESC_VSTR(conf->tmp, pos, pv->len);
1001 }
1002 else
1003 return (FALSE);
1004 }
1005
1006 return (TRUE);
1007 }
1008
opt_serv_sc_make_static_path(struct Opt_serv_opts * opts,Conf_parse * conf,Conf_token * token,Vstr_base * s1)1009 int opt_serv_sc_make_static_path(struct Opt_serv_opts *opts,
1010 Conf_parse *conf, Conf_token *token,
1011 Vstr_base *s1)
1012 {
1013 int clist = FALSE;
1014
1015 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
1016 CONF_SC_TOGGLE_CLIST_VAR(clist);
1017
1018 if (OPT_SERV_SYM_EQ("assign") || OPT_SERV_SYM_EQ("="))
1019 {
1020 if (!opt_serv__build_static_path(opts, conf, token))
1021 return (FALSE);
1022
1023 return (vstr_sub_vstr(s1, 1, s1->len,
1024 conf->tmp, 1, conf->tmp->len, VSTR_TYPE_SUB_BUF_REF));
1025 }
1026 else if (OPT_SERV_SYM_EQ("append") || OPT_SERV_SYM_EQ("+="))
1027 {
1028 if (!opt_serv__build_static_path(opts, conf, token))
1029 return (FALSE);
1030
1031 return (vstr_add_vstr(s1, s1->len,
1032 conf->tmp, 1, conf->tmp->len, VSTR_TYPE_ADD_BUF_REF));
1033 }
1034 else if (!clist)
1035 {
1036 const Vstr_sect_node *pv = conf_token_value(token);
1037
1038 if (!pv || !vstr_sub_vstr(s1, 1, s1->len, conf->data, pv->pos, pv->len,
1039 VSTR_TYPE_SUB_BUF_REF))
1040 return (FALSE);
1041 OPT_SERV_X__ESC_VSTR(s1, 1, pv->len);
1042
1043 return (TRUE);
1044 }
1045
1046 return (FALSE);
1047 }
1048