1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2023 The FreeBSD Foundation
5 *
6 * This software was developed by Jake Freeland <jfree@FreeBSD.org>
7 * under sponsorship from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33
34 #include <assert.h>
35 #include <err.h>
36 #include <libcasper.h>
37 #include <netdb.h>
38 #include <string.h>
39
40 #include <casper/cap_net.h>
41
42 #include "syslogd_cap.h"
43
44 /*
45 * Convert the given prop_filter structure into an nvlist.
46 * Return a heap allocated pointer to the resulting nvlist.
47 */
48 nvlist_t *
prop_filter_to_nvlist(const struct prop_filter * pfilter)49 prop_filter_to_nvlist(const struct prop_filter *pfilter)
50 {
51 nvlist_t *nvl_prop_filter = nvlist_create(0);
52
53 nvlist_add_number(nvl_prop_filter, "prop_type", pfilter->prop_type);
54 nvlist_add_number(nvl_prop_filter, "cmp_type", pfilter->cmp_type);
55 nvlist_add_number(nvl_prop_filter, "cmp_flags", pfilter->cmp_flags);
56 nvlist_add_string(nvl_prop_filter, "pflt_strval", pfilter->pflt_strval);
57 /*
58 * Do not bother adding pflt_re. It will be recompiled
59 * using pflt_strval later, if applicable.
60 */
61
62 return (nvl_prop_filter);
63 }
64
65 /*
66 * Convert the given nvlist into a prop_filter structure.
67 * Return a heap allocated pointer to the resulting prop_filter.
68 */
69 struct prop_filter *
nvlist_to_prop_filter(const nvlist_t * nvl_prop_filter)70 nvlist_to_prop_filter(const nvlist_t *nvl_prop_filter)
71 {
72 struct prop_filter *pfilter;
73
74 pfilter = calloc(1, sizeof(*pfilter));
75 if (pfilter == NULL)
76 err(1, "calloc");
77 pfilter->prop_type = nvlist_get_number(nvl_prop_filter, "prop_type");
78 pfilter->cmp_type = nvlist_get_number(nvl_prop_filter, "cmp_type");
79 pfilter->cmp_flags = nvlist_get_number(nvl_prop_filter, "cmp_flags");
80 pfilter->pflt_strval = strdup(nvlist_get_string(nvl_prop_filter,
81 "pflt_strval"));
82 if (pfilter->cmp_type == FILT_CMP_REGEX) {
83 int re_flags = REG_NOSUB;
84 pfilter->pflt_re = calloc(1, sizeof(*pfilter->pflt_re));
85 if (pfilter->pflt_re == NULL)
86 errx(1, "RE calloc() error");
87 if ((pfilter->cmp_flags & FILT_FLAG_EXTENDED) != 0)
88 re_flags |= REG_EXTENDED;
89 if ((pfilter->cmp_flags & FILT_FLAG_ICASE) != 0)
90 re_flags |= REG_ICASE;
91 if (regcomp(pfilter->pflt_re, pfilter->pflt_strval,
92 re_flags) != 0)
93 errx(1, "RE compilation error");
94 }
95
96 return (pfilter);
97 }
98
99 /*
100 * Convert the given struct filed into an nvl_filed nvlist.
101 * Return a heap allocated pointer to the resulting nvlist.
102 */
103 nvlist_t *
filed_to_nvlist(const struct filed * filed)104 filed_to_nvlist(const struct filed *filed)
105 {
106 nvlist_t *nvl_filed = nvlist_create(0);
107 enum f_type f_type = filed->f_type;
108 size_t i, sz;
109
110 nvlist_add_number(nvl_filed, "f_type", f_type);
111 nvlist_add_string(nvl_filed, "f_host", filed->f_host);
112 nvlist_add_string(nvl_filed, "f_program", filed->f_program);
113 if (filed->f_prop_filter != NULL) {
114 nvlist_add_nvlist(nvl_filed, "f_prop_filter",
115 prop_filter_to_nvlist(filed->f_prop_filter));
116 }
117 sz = nitems(filed->f_pmask);
118 for (i = 0; i < sz; ++i) {
119 nvlist_append_number_array(nvl_filed, "f_pmask",
120 filed->f_pmask[i]);
121 }
122 sz = nitems(filed->f_pcmp);
123 for (i = 0; i < sz; ++i) {
124 nvlist_append_number_array(nvl_filed, "f_pcmp",
125 filed->f_pcmp[i]);
126 }
127
128 if (filed->f_file >= 0)
129 nvlist_add_descriptor(nvl_filed, "f_file", filed->f_file);
130 nvlist_add_number(nvl_filed, "f_flags", filed->f_flags);
131 if (f_type == F_WALL || f_type == F_USERS) {
132 sz = nitems(filed->f_uname);
133 for (i = 0; i < sz; ++i) {
134 nvlist_append_string_array(nvl_filed, "f_uname",
135 filed->f_uname[i]);
136 }
137 } else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) {
138 nvlist_add_string(nvl_filed, "f_fname", filed->f_fname);
139 } else if (f_type == F_FORW) {
140 nvlist_add_string(nvl_filed, "f_hname", filed->f_hname);
141 nvlist_add_descriptor_array(nvl_filed, "f_addr_fds",
142 filed->f_addr_fds, filed->f_num_addr_fds);
143 nvlist_add_binary(nvl_filed, "f_addrs", filed->f_addrs,
144 filed->f_num_addr_fds * sizeof(*filed->f_addrs));
145 } else if (filed->f_type == F_PIPE) {
146 nvlist_add_string(nvl_filed, "f_pname", filed->f_pname);
147 if (filed->f_procdesc >= 0) {
148 nvlist_add_descriptor(nvl_filed, "f_procdesc",
149 filed->f_procdesc);
150 }
151 }
152
153 /*
154 * Book-keeping fields are not transferred.
155 */
156
157 return (nvl_filed);
158 }
159
160 /*
161 * Convert the given nvl_filed nvlist into a struct filed.
162 * Return a heap allocated pointer to the resulting struct
163 * filed.
164 */
165 struct filed *
nvlist_to_filed(const nvlist_t * nvl_filed)166 nvlist_to_filed(const nvlist_t *nvl_filed)
167 {
168 struct filed *filed;
169 enum f_type f_type;
170 const uint64_t *narr;
171 size_t i, sz;
172
173 filed = calloc(1, sizeof(*filed));
174 if (filed == NULL)
175 err(1, "calloc");
176
177 f_type = filed->f_type = nvlist_get_number(nvl_filed, "f_type");
178 (void)strlcpy(filed->f_host, nvlist_get_string(nvl_filed, "f_host"),
179 sizeof(filed->f_host));
180 (void)strlcpy(filed->f_program, nvlist_get_string(nvl_filed,
181 "f_program"), sizeof(filed->f_program));
182 if (nvlist_exists_nvlist(nvl_filed, "f_prop_filter")) {
183 filed->f_prop_filter = nvlist_to_prop_filter(
184 nvlist_get_nvlist(nvl_filed, "f_prop_filter"));
185 }
186 narr = nvlist_get_number_array(nvl_filed, "f_pmask", &sz);
187 assert(sz == nitems(filed->f_pmask));
188 for (i = 0; i < sz; ++i)
189 filed->f_pmask[i] = narr[i];
190 narr = nvlist_get_number_array(nvl_filed, "f_pcmp", &sz);
191 assert(sz == nitems(filed->f_pcmp));
192 for (i = 0; i < sz; ++i)
193 filed->f_pcmp[i] = narr[i];
194
195 if (nvlist_exists_descriptor(nvl_filed, "f_file"))
196 filed->f_file = dup(nvlist_get_descriptor(nvl_filed, "f_file"));
197 else
198 filed->f_file = -1;
199 filed->f_flags = nvlist_get_number(nvl_filed, "f_flags");
200 if (f_type == F_WALL || f_type == F_USERS) {
201 const char * const *f_uname;
202
203 f_uname = nvlist_get_string_array(nvl_filed, "f_uname", &sz);
204 assert(sz == nitems(filed->f_uname));
205 for (i = 0; i < sz; ++i) {
206 (void)strlcpy(filed->f_uname[i], f_uname[i],
207 sizeof(filed->f_uname[i]));
208 }
209 } else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) {
210 (void)strlcpy(filed->f_fname, nvlist_get_string(nvl_filed,
211 "f_fname"), sizeof(filed->f_fname));
212 } else if (f_type == F_FORW) {
213 const int *f_addr_fds;
214
215 (void)strlcpy(filed->f_hname, nvlist_get_string(nvl_filed,
216 "f_hname"), sizeof(filed->f_hname));
217
218 f_addr_fds = nvlist_get_descriptor_array(nvl_filed,
219 "f_addr_fds", &filed->f_num_addr_fds);
220 filed->f_addr_fds = calloc(filed->f_num_addr_fds,
221 sizeof(*f_addr_fds));
222 if (filed->f_addr_fds == NULL)
223 err(1, "calloc");
224 for (i = 0; i < filed->f_num_addr_fds; ++i) {
225 filed->f_addr_fds[i] = dup(f_addr_fds[i]);
226 if (filed->f_addr_fds[i] < 0)
227 err(1, "dup");
228 }
229 } else if (filed->f_type == F_PIPE) {
230 (void)strlcpy(filed->f_pname, nvlist_get_string(nvl_filed,
231 "f_pname"), sizeof(filed->f_pname));
232 if (nvlist_exists_descriptor(nvl_filed, "f_procdesc")) {
233 filed->f_procdesc = dup(nvlist_get_descriptor(nvl_filed,
234 "f_procdesc"));
235 } else {
236 filed->f_procdesc = -1;
237 }
238 }
239
240 /*
241 * Book-keeping fields are not transferred.
242 */
243
244 return (filed);
245 }
246
247 nvlist_t *
cap_readconfigfile(cap_channel_t * chan,const char * path)248 cap_readconfigfile(cap_channel_t *chan, const char *path)
249 {
250 nvlist_t *nvl, *nvl_conf;
251
252 nvl = nvlist_create(0);
253 nvlist_add_string(nvl, "cmd", "readconfigfile");
254 nvlist_add_string(nvl, "path", path);
255 /* It is possible that our hostname has changed. */
256 nvlist_add_string(nvl, "LocalHostName", LocalHostName);
257 nvl = cap_xfer_nvlist(chan, nvl);
258 if (nvl == NULL) {
259 logerror("Failed to xfer configuration nvlist");
260 exit(1);
261 }
262 nvl_conf = nvlist_take_nvlist(nvl, "nvl_conf");
263
264 nvlist_destroy(nvl);
265 return (nvl_conf);
266 }
267
268 /*
269 * Now that we're executing as libcasper, we can obtain the
270 * resources specified in the configuration.
271 */
272 int
casper_readconfigfile(nvlist_t * nvlin,nvlist_t * nvlout)273 casper_readconfigfile(nvlist_t *nvlin, nvlist_t *nvlout)
274 {
275 const nvlist_t * const *filed_list;
276 nvlist_t *nvl_conf;
277 size_t n_fileds;
278 const char *path;
279
280 /*
281 * Verify that syslogd did not manipulate the
282 * configuration file path.
283 */
284 path = nvlist_get_string(nvlin, "path");
285 if (strcmp(path, ConfFile) != 0)
286 err(1, "Configuration file mismatch: %s != %s", path, ConfFile);
287
288 /* Refresh our copy of LocalHostName, in case it changed. */
289 strlcpy(LocalHostName, nvlist_get_string(nvlin, "LocalHostName"),
290 sizeof(LocalHostName));
291
292 nvl_conf = readconfigfile(path);
293
294 /* Remove old filed data in case we are reloading. */
295 while (!SLIST_EMPTY(&cfiled_head)) {
296 struct cap_filed *cfiled;
297
298 cfiled = SLIST_FIRST(&cfiled_head);
299 SLIST_REMOVE_HEAD(&cfiled_head, next);
300 free(cfiled);
301 }
302 /* Record F_PIPE filed data for use in p_open(). */
303 if (!nvlist_exists_nvlist_array(nvl_conf, "filed_list"))
304 return (0);
305 filed_list = nvlist_get_nvlist_array(nvl_conf, "filed_list", &n_fileds);
306 for (size_t i = 0; i < n_fileds; ++i) {
307 if (nvlist_get_number(filed_list[i], "f_type") == F_PIPE) {
308 struct cap_filed *cfiled;
309 const char *pipe_cmd;
310
311 cfiled = malloc(sizeof(*cfiled));
312 if (cfiled == NULL)
313 err(1, "malloc");
314 cfiled->idx = i;
315 pipe_cmd = nvlist_get_string(filed_list[i], "f_pname");
316 strlcpy(cfiled->pipe_cmd, pipe_cmd, sizeof(cfiled->pipe_cmd));
317 SLIST_INSERT_HEAD(&cfiled_head, cfiled, next);
318 }
319 }
320
321 nvlist_move_nvlist(nvlout, "nvl_conf", nvl_conf);
322 return (0);
323 }
324