1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2012-2013 The FreeBSD Foundation 5 * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org> 6 * All rights reserved. 7 * 8 * This software was developed by Pawel Jakub Dawidek under sponsorship from 9 * the FreeBSD Foundation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/nv.h> 37 #include <sys/procdesc.h> 38 39 #include <assert.h> 40 #include <errno.h> 41 #include <stdbool.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "libcasper.h" 47 #include "libcasper_impl.h" 48 49 #define CASPER_VALID_FLAGS (CASPER_NO_UNIQ) 50 51 /* 52 * Structure describing communication channel between two separated processes. 53 */ 54 #define CAP_CHANNEL_MAGIC 0xcac8a31 55 struct cap_channel { 56 /* 57 * Magic value helps to ensure that a pointer to the right structure is 58 * passed to our functions. 59 */ 60 int cch_magic; 61 /* Socket descriptor for IPC. */ 62 int cch_sock; 63 /* Process descriptor for casper. */ 64 int cch_pd; 65 /* Flags to communicate with casper. */ 66 int cch_flags; 67 }; 68 69 static bool 70 cap_add_pd(cap_channel_t *chan, int pd) 71 { 72 73 if (!fd_is_valid(pd)) 74 return (false); 75 chan->cch_pd = pd; 76 return (true); 77 } 78 79 int 80 cap_channel_flags(const cap_channel_t *chan) 81 { 82 83 return (chan->cch_flags); 84 } 85 86 cap_channel_t * 87 cap_init(void) 88 { 89 pid_t pid; 90 int sock[2], serrno, pfd; 91 bool ret; 92 cap_channel_t *chan; 93 94 if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, 95 sock) == -1) { 96 return (NULL); 97 } 98 99 pid = pdfork(&pfd, 0); 100 if (pid == 0) { 101 /* Child. */ 102 close(sock[0]); 103 casper_main_loop(sock[1]); 104 /* NOTREACHED. */ 105 } else if (pid > 0) { 106 /* Parent. */ 107 close(sock[1]); 108 chan = cap_wrap(sock[0], 0); 109 if (chan == NULL) { 110 serrno = errno; 111 close(sock[0]); 112 close(pfd); 113 errno = serrno; 114 return (NULL); 115 } 116 ret = cap_add_pd(chan, pfd); 117 assert(ret); 118 return (chan); 119 } 120 121 /* Error. */ 122 serrno = errno; 123 close(sock[0]); 124 close(sock[1]); 125 errno = serrno; 126 return (NULL); 127 } 128 129 cap_channel_t * 130 cap_wrap(int sock, int flags) 131 { 132 cap_channel_t *chan; 133 134 if (!fd_is_valid(sock)) 135 return (NULL); 136 137 if ((flags & CASPER_VALID_FLAGS) != flags) 138 return (NULL); 139 140 chan = malloc(sizeof(*chan)); 141 if (chan != NULL) { 142 chan->cch_sock = sock; 143 chan->cch_pd = -1; 144 chan->cch_flags = flags; 145 chan->cch_magic = CAP_CHANNEL_MAGIC; 146 } 147 148 return (chan); 149 } 150 151 int 152 cap_unwrap(cap_channel_t *chan, int *flags) 153 { 154 int sock; 155 156 assert(chan != NULL); 157 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 158 159 sock = chan->cch_sock; 160 if (chan->cch_pd != -1) 161 close(chan->cch_pd); 162 if (flags != NULL) 163 *flags = chan->cch_flags; 164 chan->cch_magic = 0; 165 free(chan); 166 167 return (sock); 168 } 169 170 cap_channel_t * 171 cap_clone(const cap_channel_t *chan) 172 { 173 cap_channel_t *newchan; 174 nvlist_t *nvl; 175 int newsock; 176 177 assert(chan != NULL); 178 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 179 180 nvl = nvlist_create(channel_nvlist_flags(chan)); 181 nvlist_add_string(nvl, "cmd", "clone"); 182 nvl = cap_xfer_nvlist(chan, nvl); 183 if (nvl == NULL) 184 return (NULL); 185 if (nvlist_get_number(nvl, "error") != 0) { 186 errno = (int)nvlist_get_number(nvl, "error"); 187 nvlist_destroy(nvl); 188 return (NULL); 189 } 190 newsock = nvlist_take_descriptor(nvl, "sock"); 191 nvlist_destroy(nvl); 192 newchan = cap_wrap(newsock, chan->cch_flags); 193 if (newchan == NULL) { 194 int serrno; 195 196 serrno = errno; 197 close(newsock); 198 errno = serrno; 199 } 200 201 return (newchan); 202 } 203 204 void 205 cap_close(cap_channel_t *chan) 206 { 207 208 assert(chan != NULL); 209 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 210 211 chan->cch_magic = 0; 212 if (chan->cch_pd != -1) 213 close(chan->cch_pd); 214 close(chan->cch_sock); 215 free(chan); 216 } 217 218 int 219 cap_sock(const cap_channel_t *chan) 220 { 221 222 assert(chan != NULL); 223 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 224 225 return (chan->cch_sock); 226 } 227 228 int 229 cap_limit_set(const cap_channel_t *chan, nvlist_t *limits) 230 { 231 nvlist_t *nvlmsg; 232 int error; 233 234 nvlmsg = nvlist_create(channel_nvlist_flags(chan)); 235 nvlist_add_string(nvlmsg, "cmd", "limit_set"); 236 nvlist_add_nvlist(nvlmsg, "limits", limits); 237 nvlmsg = cap_xfer_nvlist(chan, nvlmsg); 238 if (nvlmsg == NULL) { 239 nvlist_destroy(limits); 240 return (-1); 241 } 242 error = (int)nvlist_get_number(nvlmsg, "error"); 243 nvlist_destroy(nvlmsg); 244 nvlist_destroy(limits); 245 if (error != 0) { 246 errno = error; 247 return (-1); 248 } 249 return (0); 250 } 251 252 int 253 cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp) 254 { 255 nvlist_t *nvlmsg; 256 int error; 257 258 nvlmsg = nvlist_create(channel_nvlist_flags(chan)); 259 nvlist_add_string(nvlmsg, "cmd", "limit_get"); 260 nvlmsg = cap_xfer_nvlist(chan, nvlmsg); 261 if (nvlmsg == NULL) 262 return (-1); 263 error = (int)nvlist_get_number(nvlmsg, "error"); 264 if (error != 0) { 265 nvlist_destroy(nvlmsg); 266 errno = error; 267 return (-1); 268 } 269 if (nvlist_exists_null(nvlmsg, "limits")) 270 *limitsp = NULL; 271 else 272 *limitsp = nvlist_take_nvlist(nvlmsg, "limits"); 273 nvlist_destroy(nvlmsg); 274 return (0); 275 } 276 277 int 278 cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl) 279 { 280 281 assert(chan != NULL); 282 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 283 284 return (nvlist_send(chan->cch_sock, nvl)); 285 } 286 287 nvlist_t * 288 cap_recv_nvlist(const cap_channel_t *chan) 289 { 290 291 assert(chan != NULL); 292 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 293 294 return (nvlist_recv(chan->cch_sock, 295 channel_nvlist_flags(chan))); 296 } 297 298 nvlist_t * 299 cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl) 300 { 301 302 assert(chan != NULL); 303 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 304 305 return (nvlist_xfer(chan->cch_sock, nvl, 306 channel_nvlist_flags(chan))); 307 } 308 309 cap_channel_t * 310 cap_service_open(const cap_channel_t *chan, const char *name) 311 { 312 cap_channel_t *newchan; 313 nvlist_t *nvl; 314 int sock, error; 315 int flags; 316 317 sock = -1; 318 319 nvl = nvlist_create(channel_nvlist_flags(chan)); 320 nvlist_add_string(nvl, "cmd", "open"); 321 nvlist_add_string(nvl, "service", name); 322 nvl = cap_xfer_nvlist(chan, nvl); 323 if (nvl == NULL) 324 return (NULL); 325 error = (int)nvlist_get_number(nvl, "error"); 326 if (error != 0) { 327 nvlist_destroy(nvl); 328 errno = error; 329 return (NULL); 330 } 331 sock = nvlist_take_descriptor(nvl, "chanfd"); 332 flags = nvlist_take_number(nvl, "chanflags"); 333 assert(sock >= 0); 334 nvlist_destroy(nvl); 335 nvl = NULL; 336 newchan = cap_wrap(sock, flags); 337 if (newchan == NULL) 338 goto fail; 339 return (newchan); 340 fail: 341 error = errno; 342 close(sock); 343 errno = error; 344 return (NULL); 345 } 346 347 int 348 cap_service_limit(const cap_channel_t *chan, const char * const *names, 349 size_t nnames) 350 { 351 nvlist_t *limits; 352 unsigned int i; 353 354 limits = nvlist_create(channel_nvlist_flags(chan)); 355 for (i = 0; i < nnames; i++) 356 nvlist_add_null(limits, names[i]); 357 return (cap_limit_set(chan, limits)); 358 } 359