1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 __FBSDID("$FreeBSD$"); 35 36 #include <sys/types.h> 37 #include <sys/socket.h> 38 #include <sys/nv.h> 39 #include <sys/procdesc.h> 40 41 #include <assert.h> 42 #include <errno.h> 43 #include <stdbool.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "libcasper.h" 49 #include "libcasper_impl.h" 50 51 #define CASPER_VALID_FLAGS (CASPER_NO_UNIQ) 52 53 /* 54 * Structure describing communication channel between two separated processes. 55 */ 56 #define CAP_CHANNEL_MAGIC 0xcac8a31 57 struct cap_channel { 58 /* 59 * Magic value helps to ensure that a pointer to the right structure is 60 * passed to our functions. 61 */ 62 int cch_magic; 63 /* Socket descriptor for IPC. */ 64 int cch_sock; 65 /* Process descriptor for casper. */ 66 int cch_pd; 67 /* Flags to communicate with casper. */ 68 int cch_flags; 69 }; 70 71 static bool 72 cap_add_pd(cap_channel_t *chan, int pd) 73 { 74 75 if (!fd_is_valid(pd)) 76 return (false); 77 chan->cch_pd = pd; 78 return (true); 79 } 80 81 int 82 cap_channel_flags(const cap_channel_t *chan) 83 { 84 85 return (chan->cch_flags); 86 } 87 88 cap_channel_t * 89 cap_init(void) 90 { 91 pid_t pid; 92 int sock[2], serrno, pfd; 93 bool ret; 94 cap_channel_t *chan; 95 96 if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, 97 sock) == -1) { 98 return (NULL); 99 } 100 101 pid = pdfork(&pfd, 0); 102 if (pid == 0) { 103 /* Child. */ 104 close(sock[0]); 105 casper_main_loop(sock[1]); 106 /* NOTREACHED. */ 107 } else if (pid > 0) { 108 /* Parent. */ 109 close(sock[1]); 110 chan = cap_wrap(sock[0], 0); 111 if (chan == NULL) { 112 serrno = errno; 113 close(sock[0]); 114 close(pfd); 115 errno = serrno; 116 return (NULL); 117 } 118 ret = cap_add_pd(chan, pfd); 119 assert(ret); 120 return (chan); 121 } 122 123 /* Error. */ 124 serrno = errno; 125 close(sock[0]); 126 close(sock[1]); 127 errno = serrno; 128 return (NULL); 129 } 130 131 cap_channel_t * 132 cap_wrap(int sock, int flags) 133 { 134 cap_channel_t *chan; 135 136 if (!fd_is_valid(sock)) 137 return (NULL); 138 139 if ((flags & CASPER_VALID_FLAGS) != flags) 140 return (NULL); 141 142 chan = malloc(sizeof(*chan)); 143 if (chan != NULL) { 144 chan->cch_sock = sock; 145 chan->cch_pd = -1; 146 chan->cch_flags = flags; 147 chan->cch_magic = CAP_CHANNEL_MAGIC; 148 } 149 150 return (chan); 151 } 152 153 int 154 cap_unwrap(cap_channel_t *chan, int *flags) 155 { 156 int sock; 157 158 assert(chan != NULL); 159 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 160 161 sock = chan->cch_sock; 162 if (chan->cch_pd != -1) 163 close(chan->cch_pd); 164 if (flags != NULL) 165 *flags = chan->cch_flags; 166 chan->cch_magic = 0; 167 free(chan); 168 169 return (sock); 170 } 171 172 cap_channel_t * 173 cap_clone(const cap_channel_t *chan) 174 { 175 cap_channel_t *newchan; 176 nvlist_t *nvl; 177 int newsock; 178 179 assert(chan != NULL); 180 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 181 182 nvl = nvlist_create(channel_nvlist_flags(chan)); 183 nvlist_add_string(nvl, "cmd", "clone"); 184 nvl = cap_xfer_nvlist(chan, nvl); 185 if (nvl == NULL) 186 return (NULL); 187 if (nvlist_get_number(nvl, "error") != 0) { 188 errno = (int)nvlist_get_number(nvl, "error"); 189 nvlist_destroy(nvl); 190 return (NULL); 191 } 192 newsock = nvlist_take_descriptor(nvl, "sock"); 193 nvlist_destroy(nvl); 194 newchan = cap_wrap(newsock, chan->cch_flags); 195 if (newchan == NULL) { 196 int serrno; 197 198 serrno = errno; 199 close(newsock); 200 errno = serrno; 201 } 202 203 return (newchan); 204 } 205 206 void 207 cap_close(cap_channel_t *chan) 208 { 209 210 assert(chan != NULL); 211 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 212 213 chan->cch_magic = 0; 214 if (chan->cch_pd != -1) 215 close(chan->cch_pd); 216 close(chan->cch_sock); 217 free(chan); 218 } 219 220 int 221 cap_sock(const cap_channel_t *chan) 222 { 223 224 assert(chan != NULL); 225 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 226 227 return (chan->cch_sock); 228 } 229 230 int 231 cap_limit_set(const cap_channel_t *chan, nvlist_t *limits) 232 { 233 nvlist_t *nvlmsg; 234 int error; 235 236 nvlmsg = nvlist_create(channel_nvlist_flags(chan)); 237 nvlist_add_string(nvlmsg, "cmd", "limit_set"); 238 nvlist_add_nvlist(nvlmsg, "limits", limits); 239 nvlmsg = cap_xfer_nvlist(chan, nvlmsg); 240 if (nvlmsg == NULL) { 241 nvlist_destroy(limits); 242 return (-1); 243 } 244 error = (int)nvlist_get_number(nvlmsg, "error"); 245 nvlist_destroy(nvlmsg); 246 nvlist_destroy(limits); 247 if (error != 0) { 248 errno = error; 249 return (-1); 250 } 251 return (0); 252 } 253 254 int 255 cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp) 256 { 257 nvlist_t *nvlmsg; 258 int error; 259 260 nvlmsg = nvlist_create(channel_nvlist_flags(chan)); 261 nvlist_add_string(nvlmsg, "cmd", "limit_get"); 262 nvlmsg = cap_xfer_nvlist(chan, nvlmsg); 263 if (nvlmsg == NULL) 264 return (-1); 265 error = (int)nvlist_get_number(nvlmsg, "error"); 266 if (error != 0) { 267 nvlist_destroy(nvlmsg); 268 errno = error; 269 return (-1); 270 } 271 if (nvlist_exists_null(nvlmsg, "limits")) 272 *limitsp = NULL; 273 else 274 *limitsp = nvlist_take_nvlist(nvlmsg, "limits"); 275 nvlist_destroy(nvlmsg); 276 return (0); 277 } 278 279 int 280 cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl) 281 { 282 283 assert(chan != NULL); 284 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 285 286 return (nvlist_send(chan->cch_sock, nvl)); 287 } 288 289 nvlist_t * 290 cap_recv_nvlist(const cap_channel_t *chan) 291 { 292 293 assert(chan != NULL); 294 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 295 296 return (nvlist_recv(chan->cch_sock, 297 channel_nvlist_flags(chan))); 298 } 299 300 nvlist_t * 301 cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl) 302 { 303 304 assert(chan != NULL); 305 assert(chan->cch_magic == CAP_CHANNEL_MAGIC); 306 307 return (nvlist_xfer(chan->cch_sock, nvl, 308 channel_nvlist_flags(chan))); 309 } 310 311 cap_channel_t * 312 cap_service_open(const cap_channel_t *chan, const char *name) 313 { 314 cap_channel_t *newchan; 315 nvlist_t *nvl; 316 int sock, error; 317 int flags; 318 319 sock = -1; 320 321 nvl = nvlist_create(channel_nvlist_flags(chan)); 322 nvlist_add_string(nvl, "cmd", "open"); 323 nvlist_add_string(nvl, "service", name); 324 nvl = cap_xfer_nvlist(chan, nvl); 325 if (nvl == NULL) 326 return (NULL); 327 error = (int)nvlist_get_number(nvl, "error"); 328 if (error != 0) { 329 nvlist_destroy(nvl); 330 errno = error; 331 return (NULL); 332 } 333 sock = nvlist_take_descriptor(nvl, "chanfd"); 334 flags = nvlist_take_number(nvl, "chanflags"); 335 assert(sock >= 0); 336 nvlist_destroy(nvl); 337 nvl = NULL; 338 newchan = cap_wrap(sock, flags); 339 if (newchan == NULL) 340 goto fail; 341 return (newchan); 342 fail: 343 error = errno; 344 close(sock); 345 errno = error; 346 return (NULL); 347 } 348 349 int 350 cap_service_limit(const cap_channel_t *chan, const char * const *names, 351 size_t nnames) 352 { 353 nvlist_t *limits; 354 unsigned int i; 355 356 limits = nvlist_create(channel_nvlist_flags(chan)); 357 for (i = 0; i < nnames; i++) 358 nvlist_add_null(limits, names[i]); 359 return (cap_limit_set(chan, limits)); 360 } 361