xref: /NextBSD/lib/libcapsicum/libcapsicum.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
1 /*-
2  * Copyright (c) 2012-2013 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <sys/nv.h>
37 
38 #include <assert.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include "libcapsicum.h"
47 #include "libcapsicum_impl.h"
48 
49 /*
50  * Structure describing communication channel between two separated processes.
51  */
52 #define	CAP_CHANNEL_MAGIC	0xcac8a31
53 struct cap_channel {
54 	/*
55 	 * Magic value helps to ensure that a pointer to the right structure is
56 	 * passed to our functions.
57 	 */
58 	int	cch_magic;
59 	/* Socket descriptor for IPC. */
60 	int	cch_sock;
61 };
62 
63 bool
fd_is_valid(int fd)64 fd_is_valid(int fd)
65 {
66 
67 	return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
68 }
69 
70 cap_channel_t *
cap_init(void)71 cap_init(void)
72 {
73 	cap_channel_t *chan;
74 	struct sockaddr_un sun;
75 	int serrno, sock;
76 
77 	bzero(&sun, sizeof(sun));
78 	sun.sun_family = AF_UNIX;
79 	strlcpy(sun.sun_path, CASPER_SOCKPATH, sizeof(sun.sun_path));
80 	sun.sun_len = SUN_LEN(&sun);
81 
82 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
83 	if (sock == -1)
84 		return (NULL);
85 	if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
86 		serrno = errno;
87 		close(sock);
88 		errno = serrno;
89 		return (NULL);
90 	}
91 	chan = cap_wrap(sock);
92 	if (chan == NULL) {
93 		serrno = errno;
94 		close(sock);
95 		errno = serrno;
96 		return (NULL);
97 	}
98 	return (chan);
99 }
100 
101 cap_channel_t *
cap_wrap(int sock)102 cap_wrap(int sock)
103 {
104 	cap_channel_t *chan;
105 
106 	if (!fd_is_valid(sock))
107 		return (NULL);
108 
109 	chan = malloc(sizeof(*chan));
110 	if (chan != NULL) {
111 		chan->cch_sock = sock;
112 		chan->cch_magic = CAP_CHANNEL_MAGIC;
113 	}
114 
115 	return (chan);
116 }
117 
118 int
cap_unwrap(cap_channel_t * chan)119 cap_unwrap(cap_channel_t *chan)
120 {
121 	int sock;
122 
123 	assert(chan != NULL);
124 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
125 
126 	sock = chan->cch_sock;
127 	chan->cch_magic = 0;
128 	free(chan);
129 
130 	return (sock);
131 }
132 
133 cap_channel_t *
cap_clone(const cap_channel_t * chan)134 cap_clone(const cap_channel_t *chan)
135 {
136 	cap_channel_t *newchan;
137 	nvlist_t *nvl;
138 	int newsock;
139 
140 	assert(chan != NULL);
141 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
142 
143 	nvl = nvlist_create(0);
144 	nvlist_add_string(nvl, "cmd", "clone");
145 	nvl = cap_xfer_nvlist(chan, nvl, 0);
146 	if (nvl == NULL)
147 		return (NULL);
148 	if (nvlist_get_number(nvl, "error") != 0) {
149 		errno = (int)nvlist_get_number(nvl, "error");
150 		nvlist_destroy(nvl);
151 		return (NULL);
152 	}
153 	newsock = nvlist_take_descriptor(nvl, "sock");
154 	nvlist_destroy(nvl);
155 	newchan = cap_wrap(newsock);
156 	if (newchan == NULL) {
157 		int serrno;
158 
159 		serrno = errno;
160 		close(newsock);
161 		errno = serrno;
162 	}
163 
164 	return (newchan);
165 }
166 
167 void
cap_close(cap_channel_t * chan)168 cap_close(cap_channel_t *chan)
169 {
170 
171 	assert(chan != NULL);
172 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
173 
174 	chan->cch_magic = 0;
175 	close(chan->cch_sock);
176 	free(chan);
177 }
178 
179 int
cap_sock(const cap_channel_t * chan)180 cap_sock(const cap_channel_t *chan)
181 {
182 
183 	assert(chan != NULL);
184 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
185 
186 	return (chan->cch_sock);
187 }
188 
189 int
cap_limit_set(const cap_channel_t * chan,nvlist_t * limits)190 cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
191 {
192 	nvlist_t *nvlmsg;
193 	int error;
194 
195 	nvlmsg = nvlist_create(0);
196 	nvlist_add_string(nvlmsg, "cmd", "limit_set");
197 	nvlist_add_nvlist(nvlmsg, "limits", limits);
198 	nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
199 	if (nvlmsg == NULL) {
200 		nvlist_destroy(limits);
201 		return (-1);
202 	}
203 	error = (int)nvlist_get_number(nvlmsg, "error");
204 	nvlist_destroy(nvlmsg);
205 	nvlist_destroy(limits);
206 	if (error != 0) {
207 		errno = error;
208 		return (-1);
209 	}
210 	return (0);
211 }
212 
213 int
cap_limit_get(const cap_channel_t * chan,nvlist_t ** limitsp)214 cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
215 {
216 	nvlist_t *nvlmsg;
217 	int error;
218 
219 	nvlmsg = nvlist_create(0);
220 	nvlist_add_string(nvlmsg, "cmd", "limit_get");
221 	nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
222 	if (nvlmsg == NULL)
223 		return (-1);
224 	error = (int)nvlist_get_number(nvlmsg, "error");
225 	if (error != 0) {
226 		nvlist_destroy(nvlmsg);
227 		errno = error;
228 		return (-1);
229 	}
230 	if (nvlist_exists_null(nvlmsg, "limits"))
231 		*limitsp = NULL;
232 	else
233 		*limitsp = nvlist_take_nvlist(nvlmsg, "limits");
234 	nvlist_destroy(nvlmsg);
235 	return (0);
236 }
237 
238 int
cap_send_nvlist(const cap_channel_t * chan,const nvlist_t * nvl)239 cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
240 {
241 
242 	assert(chan != NULL);
243 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
244 
245 	return (nvlist_send(chan->cch_sock, nvl));
246 }
247 
248 nvlist_t *
cap_recv_nvlist(const cap_channel_t * chan,int flags)249 cap_recv_nvlist(const cap_channel_t *chan, int flags)
250 {
251 
252 	assert(chan != NULL);
253 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
254 
255 	return (nvlist_recv(chan->cch_sock, flags));
256 }
257 
258 nvlist_t *
cap_xfer_nvlist(const cap_channel_t * chan,nvlist_t * nvl,int flags)259 cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
260 {
261 
262 	assert(chan != NULL);
263 	assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
264 
265 	return (nvlist_xfer(chan->cch_sock, nvl, flags));
266 }
267