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 * 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 * 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 * 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 * 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 * 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 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