xref: /freebsd/usr.sbin/syslogd/syslogd_cap_log.c (revision 61a29eca550b80d179934a7198c41ad4d255f81c)
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