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