xref: /freebsd/usr.sbin/syslogd/syslogd_cap_log.c (revision be9f35396449129ebe952fdd1c080f7856dee030)
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 	pipedesc_w = dnvlist_take_descriptor(nvl, "pipedesc_w", -1);
56 	*procdesc = dnvlist_take_descriptor(nvl, "procdesc", -1);
57 
58 	nvlist_destroy(nvl);
59 	if (error != 0)
60 		errno = error;
61 	return (pipedesc_w);
62 }
63 
64 int
65 casper_p_open(nvlist_t *nvlin, nvlist_t *nvlout)
66 {
67 	struct cap_filed *cfiled;
68 	size_t filed_idx;
69 	int pipedesc_w, procdesc = -1;
70 	const char *prog;
71 
72 	filed_idx = nvlist_get_number(nvlin, "filed_idx");
73 	prog = nvlist_get_string(nvlin, "prog");
74 	SLIST_FOREACH(cfiled, &cfiled_head, next) {
75 		if (cfiled->idx != filed_idx)
76 			continue;
77 		if (strcmp(cfiled->pipe_cmd, prog) != 0)
78 			return (-1);
79 
80 		pipedesc_w = p_open(prog, &procdesc);
81 		if (pipedesc_w == -1)
82 			return (errno);
83 		nvlist_move_descriptor(nvlout, "pipedesc_w", pipedesc_w);
84 		nvlist_move_descriptor(nvlout, "procdesc", procdesc);
85 		return (0);
86 	}
87 	return (ECAPMODE);
88 }
89 
90 int
91 cap_ttymsg(cap_channel_t *chan, struct iovec *iov, int iovcnt,
92     const char *line, int timeout, bool shout)
93 {
94 	nvlist_t *nvl = nvlist_create(0);
95 	int error = 0;
96 
97 	nvlist_add_string(nvl, "cmd", "ttymsg");
98 	for (int i = 0; i < iovcnt; ++i)
99 		nvlist_append_string_array(nvl, "iov_strs", iov[i].iov_base);
100 	nvlist_add_string(nvl, "line", line);
101 	nvlist_add_number(nvl, "timeout", timeout);
102 	nvlist_add_bool(nvl, "shout", shout);
103 
104 	nvl = cap_xfer_nvlist(chan, nvl);
105 	if (nvl == NULL) {
106 		logerror("Failed to xfer ttymsg nvlist");
107 		exit(1);
108 	}
109 	error = nvlist_get_number(nvl, "error");
110 	nvlist_destroy(nvl);
111 	if (error != 0) {
112 		errno = error;
113 		return (-1);
114 	}
115 	return (0);
116 }
117 
118 int
119 casper_ttymsg(nvlist_t *nvlin)
120 {
121 	const char * const *nvlstrs;
122 	struct iovec *iov;
123 	const char *line;
124 	size_t iovcnt;
125 	int ret, timeout;
126 	bool shout;
127 
128 	nvlstrs = nvlist_get_string_array(nvlin, "iov_strs", &iovcnt);
129 	assert(iovcnt <= TTYMSG_IOV_MAX);
130 	iov = calloc(iovcnt, sizeof(*iov));
131 	if (iov == NULL)
132 		err(EXIT_FAILURE, "calloc");
133 	for (size_t i = 0; i < iovcnt; ++i) {
134 		iov[i].iov_base = __DECONST(char *, nvlstrs[i]);
135 		iov[i].iov_len = strlen(nvlstrs[i]);
136 	}
137 	line = nvlist_get_string(nvlin, "line");
138 	timeout = nvlist_get_number(nvlin, "timeout");
139 	shout = nvlist_get_bool(nvlin, "shout");
140 	if ((ret = ttymsg(iov, iovcnt, line, timeout, shout)) != 0)
141 		ret = errno;
142 	free(iov);
143 	return (ret);
144 }
145 
146 void
147 cap_wallmsg(cap_channel_t *chan, const struct filed *f, struct iovec *iov,
148     int iovcnt)
149 {
150 	nvlist_t *nvl = nvlist_create(0);
151 
152 	nvlist_add_string(nvl, "cmd", "wallmsg");
153 	/*
154 	 * The filed_to_nvlist() function is not needed
155 	 * here because wallmsg() only uses f_type and
156 	 * fu_uname members, which are both inline.
157 	 */
158 	nvlist_add_binary(nvl, "filed", f, sizeof(*f));
159 	for (int i = 0; i < iovcnt; ++i)
160 		nvlist_append_string_array(nvl, "iov_strs", iov[i].iov_base);
161 
162 	nvl = cap_xfer_nvlist(chan, nvl);
163 	if (nvl == NULL) {
164 		logerror("Failed to xfer wallmsg nvlist");
165 		exit(1);
166 	}
167 	nvlist_destroy(nvl);
168 }
169 
170 int
171 casper_wallmsg(nvlist_t *nvlin)
172 {
173 	const struct filed *f;
174 	const char * const *nvlstrs;
175 	struct iovec *iov;
176 	size_t sz;
177 
178 	f = nvlist_get_binary(nvlin, "filed", &sz);
179 	assert(sz == sizeof(*f));
180 	nvlstrs = nvlist_get_string_array(nvlin, "iov_strs", &sz);
181 	assert(sz <= TTYMSG_IOV_MAX);
182 	iov = calloc(sz, sizeof(*iov));
183 	if (iov == NULL)
184 		err(EXIT_FAILURE, "calloc");
185 	for (size_t i = 0; i < sz; ++i) {
186 		iov[i].iov_base = __DECONST(char *, nvlstrs[i]);
187 		iov[i].iov_len = strlen(nvlstrs[i]);
188 	}
189 	wallmsg(f, iov, sz);
190 
191 	free(iov);
192 	return (0);
193 }
194