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