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
cap_p_open(cap_channel_t * chan,size_t filed_idx,const char * prog,int * procdesc)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
casper_p_open(nvlist_t * nvlin,nvlist_t * nvlout)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 *
cap_ttymsg(cap_channel_t * chan,struct iovec * iov,int iovcnt,const char * line,int tmout)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
casper_ttymsg(nvlist_t * nvlin,nvlist_t * nvlout)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
cap_wallmsg(cap_channel_t * chan,const struct filed * f,struct iovec * iov,int iovcnt)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
casper_wallmsg(nvlist_t * nvlin)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