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