]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcapsicum/libcapsicum.c
Bring LLVM libunwind snapshot into contrib/llvm/projects
[FreeBSD/FreeBSD.git] / lib / libcapsicum / libcapsicum.c
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
64 fd_is_valid(int fd)
65 {
66
67         return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
68 }
69
70 cap_channel_t *
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 *
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
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 *
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
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
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
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
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
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 *
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 *
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 }