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 <assert.h> 32 #include <err.h> 33 #include <string.h> 34 35 #include "syslogd_cap.h" 36 37 struct cfiled_list cfiled_head; 38 39 int 40 cap_p_open(cap_channel_t *chan, size_t filed_idx, const char *prog, 41 int *procdesc) 42 { 43 nvlist_t *nvl = nvlist_create(0); 44 int error, pipedesc_w; 45 46 nvlist_add_string(nvl, "cmd", "p_open"); 47 nvlist_add_number(nvl, "filed_idx", filed_idx); 48 nvlist_add_string(nvl, "prog", prog); 49 nvl = cap_xfer_nvlist(chan, nvl); 50 if (nvl == NULL) { 51 logerror("Failed to xfer p_open nvlist"); 52 exit(1); 53 } 54 error = nvlist_get_number(nvl, "error"); 55 if (error != 0) { 56 errno = error; 57 logerror("Failed to open piped command"); 58 } 59 pipedesc_w = dnvlist_take_descriptor(nvl, "pipedesc_w", -1); 60 *procdesc = dnvlist_take_descriptor(nvl, "procdesc", -1); 61 62 nvlist_destroy(nvl); 63 return (pipedesc_w); 64 } 65 66 int 67 casper_p_open(nvlist_t *nvlin, nvlist_t *nvlout) 68 { 69 struct cap_filed *cfiled; 70 size_t filed_idx; 71 int pipedesc_w, procdesc = -1; 72 const char *prog; 73 74 filed_idx = nvlist_get_number(nvlin, "filed_idx"); 75 prog = nvlist_get_string(nvlin, "prog"); 76 SLIST_FOREACH(cfiled, &cfiled_head, next) { 77 if (cfiled->idx != filed_idx) 78 continue; 79 if (strcmp(cfiled->pipe_cmd, prog) != 0) 80 return (-1); 81 82 pipedesc_w = p_open(prog, &procdesc); 83 if (pipedesc_w == -1) 84 return (-1); 85 nvlist_move_descriptor(nvlout, "pipedesc_w", pipedesc_w); 86 nvlist_move_descriptor(nvlout, "procdesc", procdesc); 87 return (0); 88 } 89 90 return (-1); 91 } 92 93 const char * 94 cap_ttymsg(cap_channel_t *chan, struct iovec *iov, int iovcnt, 95 const char *line, int tmout) 96 { 97 nvlist_t *nvl = nvlist_create(0); 98 int error; 99 static char errbuf[1024]; 100 char *ret = NULL; 101 102 nvlist_add_string(nvl, "cmd", "ttymsg"); 103 for (int i = 0; i < iovcnt; ++i) 104 nvlist_append_string_array(nvl, "iov_strs", iov[i].iov_base); 105 nvlist_add_string(nvl, "line", line); 106 nvlist_add_number(nvl, "tmout", tmout); 107 108 nvl = cap_xfer_nvlist(chan, nvl); 109 if (nvl == NULL) { 110 logerror("Failed to xfer ttymsg nvlist"); 111 exit(1); 112 } 113 error = nvlist_get_number(nvl, "error"); 114 if (error != 0) { 115 errno = error; 116 logerror("Failed to ttymsg"); 117 } 118 if (nvlist_exists_string(nvl, "errstr")) { 119 const char *errstr = nvlist_get_string(nvl, "errstr"); 120 (void)strlcpy(errbuf, errstr, sizeof(errbuf)); 121 ret = errbuf; 122 } 123 124 nvlist_destroy(nvl); 125 return (ret); 126 } 127 128 int 129 casper_ttymsg(nvlist_t *nvlin, nvlist_t *nvlout) 130 { 131 char **nvlstrs; 132 struct iovec *iov; 133 size_t iovcnt; 134 int tmout; 135 const char *line; 136 137 nvlstrs = nvlist_take_string_array(nvlin, "iov_strs", &iovcnt); 138 assert(iovcnt <= TTYMSG_IOV_MAX); 139 iov = calloc(iovcnt, sizeof(*iov)); 140 if (iov == NULL) 141 err(EXIT_FAILURE, "calloc"); 142 for (size_t i = 0; i < iovcnt; ++i) { 143 iov[i].iov_base = nvlstrs[i]; 144 iov[i].iov_len = strlen(nvlstrs[i]); 145 } 146 line = nvlist_get_string(nvlin, "line"); 147 tmout = nvlist_get_number(nvlin, "tmout"); 148 line = ttymsg(iov, iovcnt, line, tmout); 149 if (line != NULL) 150 nvlist_add_string(nvlout, "errstr", line); 151 152 free(iov); 153 return (0); 154 } 155 156 void 157 cap_wallmsg(cap_channel_t *chan, const struct filed *f, struct iovec *iov, 158 int iovcnt) 159 { 160 nvlist_t *nvl = nvlist_create(0); 161 int error; 162 163 nvlist_add_string(nvl, "cmd", "wallmsg"); 164 /* 165 * The filed_to_nvlist() function is not needed 166 * here because wallmsg() only uses f_type and 167 * fu_uname members, which are both inline. 168 */ 169 nvlist_add_binary(nvl, "filed", f, sizeof(*f)); 170 for (int i = 0; i < iovcnt; ++i) 171 nvlist_append_string_array(nvl, "iov_strs", iov[i].iov_base); 172 173 nvl = cap_xfer_nvlist(chan, nvl); 174 if (nvl == NULL) { 175 logerror("Failed to xfer wallmsg nvlist"); 176 exit(1); 177 } 178 error = nvlist_get_number(nvl, "error"); 179 if (error != 0) { 180 errno = error; 181 logerror("Failed to wallmsg"); 182 } 183 nvlist_destroy(nvl); 184 } 185 186 int 187 casper_wallmsg(nvlist_t *nvlin) 188 { 189 const struct filed *f; 190 char **nvlstrs; 191 struct iovec *iov; 192 size_t sz; 193 194 f = nvlist_get_binary(nvlin, "filed", &sz); 195 assert(sz == sizeof(*f)); 196 nvlstrs = nvlist_take_string_array(nvlin, "iov_strs", &sz); 197 assert(sz <= TTYMSG_IOV_MAX); 198 iov = calloc(sz, sizeof(*iov)); 199 if (iov == NULL) 200 err(EXIT_FAILURE, "calloc"); 201 for (size_t i = 0; i < sz; ++i) { 202 iov[i].iov_base = nvlstrs[i]; 203 iov[i].iov_len = strlen(nvlstrs[i]); 204 } 205 wallmsg(f, iov, sz); 206 207 for (size_t i = 0; i < sz; ++i) 208 free(iov[i].iov_base); 209 free(iov); 210 return (0); 211 } 212