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