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 struct addrinfo *ai = filed->f_addr, *cur; 141 nvlist_t *nvl_addrinfo; 142 143 nvlist_add_string(nvl_filed, "f_hname", filed->f_hname); 144 if (filed->f_addr != NULL) { 145 for (cur = ai; cur != NULL; cur = cur->ai_next) { 146 nvl_addrinfo = addrinfo_pack(cur); 147 nvlist_append_nvlist_array(nvl_filed, 148 "f_addr", nvl_addrinfo); 149 nvlist_destroy(nvl_addrinfo); 150 } 151 } 152 } else if (filed->f_type == F_PIPE) { 153 nvlist_add_string(nvl_filed, "f_pname", filed->f_pname); 154 if (filed->f_procdesc >= 0) { 155 nvlist_add_descriptor(nvl_filed, "f_procdesc", 156 filed->f_procdesc); 157 } 158 } 159 160 /* 161 * Book-keeping fields are not transferred. 162 */ 163 164 return (nvl_filed); 165 } 166 167 /* 168 * Convert the given nvl_filed nvlist into a struct filed. 169 * Return a heap allocated pointer to the resulting struct 170 * filed. 171 */ 172 struct filed * 173 nvlist_to_filed(const nvlist_t *nvl_filed) 174 { 175 struct filed *filed; 176 enum f_type f_type; 177 const uint64_t *narr; 178 size_t i, sz; 179 180 filed = calloc(1, sizeof(*filed)); 181 if (filed == NULL) 182 err(1, "calloc"); 183 184 f_type = filed->f_type = nvlist_get_number(nvl_filed, "f_type"); 185 (void)strlcpy(filed->f_host, nvlist_get_string(nvl_filed, "f_host"), 186 sizeof(filed->f_host)); 187 (void)strlcpy(filed->f_program, nvlist_get_string(nvl_filed, 188 "f_program"), sizeof(filed->f_program)); 189 if (nvlist_exists_nvlist(nvl_filed, "f_prop_filter")) { 190 filed->f_prop_filter = nvlist_to_prop_filter( 191 nvlist_get_nvlist(nvl_filed, "f_prop_filter")); 192 } 193 narr = nvlist_get_number_array(nvl_filed, "f_pmask", &sz); 194 assert(sz == nitems(filed->f_pmask)); 195 for (i = 0; i < sz; ++i) 196 filed->f_pmask[i] = narr[i]; 197 narr = nvlist_get_number_array(nvl_filed, "f_pcmp", &sz); 198 assert(sz == nitems(filed->f_pcmp)); 199 for (i = 0; i < sz; ++i) 200 filed->f_pcmp[i] = narr[i]; 201 202 if (nvlist_exists_descriptor(nvl_filed, "f_file")) 203 filed->f_file = dup(nvlist_get_descriptor(nvl_filed, "f_file")); 204 else 205 filed->f_file = -1; 206 filed->f_flags = nvlist_get_number(nvl_filed, "f_flags"); 207 if (f_type == F_WALL || f_type == F_USERS) { 208 const char * const *f_uname; 209 210 f_uname = nvlist_get_string_array(nvl_filed, "f_uname", &sz); 211 assert(sz == nitems(filed->f_uname)); 212 for (i = 0; i < sz; ++i) { 213 (void)strlcpy(filed->f_uname[i], f_uname[i], 214 sizeof(filed->f_uname[i])); 215 } 216 } else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) { 217 (void)strlcpy(filed->f_fname, nvlist_get_string(nvl_filed, 218 "f_fname"), sizeof(filed->f_fname)); 219 } else if (f_type == F_FORW) { 220 const nvlist_t * const *f_addr; 221 struct addrinfo *ai, **next = NULL; 222 223 (void)strlcpy(filed->f_hname, nvlist_get_string(nvl_filed, 224 "f_hname"), sizeof(filed->f_hname)); 225 f_addr = nvlist_get_nvlist_array(nvl_filed, "f_addr", &sz); 226 for (i = 0; i < sz; ++i) { 227 ai = addrinfo_unpack(f_addr[i]); 228 if (next == NULL) 229 filed->f_addr = ai; 230 else 231 *next = ai; 232 next = &ai->ai_next; 233 } 234 } else if (filed->f_type == F_PIPE) { 235 (void)strlcpy(filed->f_pname, nvlist_get_string(nvl_filed, 236 "f_pname"), sizeof(filed->f_pname)); 237 if (nvlist_exists_descriptor(nvl_filed, "f_procdesc")) { 238 filed->f_procdesc = dup(nvlist_get_descriptor(nvl_filed, 239 "f_procdesc")); 240 } else { 241 filed->f_procdesc = -1; 242 } 243 } 244 245 /* 246 * Book-keeping fields are not transferred. 247 */ 248 249 return (filed); 250 } 251 252 nvlist_t * 253 cap_readconfigfile(cap_channel_t *chan, const char *path) 254 { 255 nvlist_t *nvl, *nvl_conf; 256 257 nvl = nvlist_create(0); 258 nvlist_add_string(nvl, "cmd", "readconfigfile"); 259 nvlist_add_string(nvl, "path", path); 260 /* It is possible that our hostname has changed. */ 261 nvlist_add_string(nvl, "LocalHostName", LocalHostName); 262 nvl = cap_xfer_nvlist(chan, nvl); 263 if (nvl == NULL) { 264 logerror("Failed to xfer configuration nvlist"); 265 exit(1); 266 } 267 nvl_conf = nvlist_take_nvlist(nvl, "nvl_conf"); 268 269 nvlist_destroy(nvl); 270 return (nvl_conf); 271 } 272 273 /* 274 * Now that we're executing as libcasper, we can obtain the 275 * resources specified in the configuration. 276 */ 277 int 278 casper_readconfigfile(nvlist_t *nvlin, nvlist_t *nvlout) 279 { 280 const nvlist_t * const *filed_list; 281 nvlist_t *nvl_conf; 282 size_t n_fileds; 283 const char *path; 284 285 /* 286 * Verify that syslogd did not manipulate the 287 * configuration file path. 288 */ 289 path = nvlist_get_string(nvlin, "path"); 290 if (strcmp(path, ConfFile) != 0) 291 err(1, "Configuration file mismatch: %s != %s", path, ConfFile); 292 293 /* Refresh our copy of LocalHostName, in case it changed. */ 294 strlcpy(LocalHostName, nvlist_get_string(nvlin, "LocalHostName"), 295 sizeof(LocalHostName)); 296 297 nvl_conf = readconfigfile(path); 298 299 /* Remove old filed data in case we are reloading. */ 300 while (!SLIST_EMPTY(&cfiled_head)) { 301 struct cap_filed *cfiled; 302 303 cfiled = SLIST_FIRST(&cfiled_head); 304 SLIST_REMOVE_HEAD(&cfiled_head, next); 305 free(cfiled); 306 } 307 /* Record F_PIPE filed data for use in p_open(). */ 308 if (!nvlist_exists_nvlist_array(nvl_conf, "filed_list")) 309 return (0); 310 filed_list = nvlist_get_nvlist_array(nvl_conf, "filed_list", &n_fileds); 311 for (size_t i = 0; i < n_fileds; ++i) { 312 if (nvlist_get_number(filed_list[i], "f_type") == F_PIPE) { 313 struct cap_filed *cfiled; 314 const char *pipe_cmd; 315 316 cfiled = malloc(sizeof(*cfiled)); 317 if (cfiled == NULL) 318 err(1, "malloc"); 319 cfiled->idx = i; 320 pipe_cmd = nvlist_get_string(filed_list[i], "f_pname"); 321 strlcpy(cfiled->pipe_cmd, pipe_cmd, sizeof(cfiled->pipe_cmd)); 322 SLIST_INSERT_HEAD(&cfiled_head, cfiled, next); 323 } 324 } 325 326 nvlist_move_nvlist(nvlout, "nvl_conf", nvl_conf); 327 return (0); 328 } 329