1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Joyent, Inc. 14 */ 15 16 /* 17 * varpd door server logic 18 */ 19 20 #include <door.h> 21 #include <errno.h> 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <fcntl.h> 25 #include <unistd.h> 26 #include <stropts.h> 27 #include <stdlib.h> 28 #include <strings.h> 29 #include <priv.h> 30 #include <libvarpd_impl.h> 31 32 typedef int (libvarpd_door_f)(varpd_impl_t *, varpd_client_arg_t *, ucred_t *); 33 34 static boolean_t 35 libvarpd_door_privileged(ucred_t *credp) 36 { 37 const priv_set_t *ps; 38 39 ps = ucred_getprivset(credp, PRIV_EFFECTIVE); 40 if (ps == NULL) 41 return (B_FALSE); 42 43 return (priv_ismember(ps, PRIV_SYS_NET_CONFIG)); 44 } 45 46 /* ARGSUSED */ 47 static int 48 libvarpd_door_f_create(varpd_impl_t *vip, varpd_client_arg_t *vcap, 49 ucred_t *credp) 50 { 51 int ret; 52 varpd_instance_handle_t *ihdl; 53 varpd_client_create_arg_t *vccap = &vcap->vca_un.vca_create; 54 55 vccap->vcca_plugin[LIBVARPD_PROP_NAMELEN-1] = '\0'; 56 ret = libvarpd_instance_create((varpd_handle_t *)vip, 57 vccap->vcca_linkid, vccap->vcca_plugin, &ihdl); 58 if (ret == 0) 59 vccap->vcca_id = libvarpd_instance_id(ihdl); 60 61 return (ret); 62 } 63 64 /* ARGSUSED */ 65 static int 66 libvarpd_door_f_activate(varpd_impl_t *vip, varpd_client_arg_t *vcap, 67 ucred_t *credp) 68 { 69 varpd_instance_handle_t *ihp; 70 varpd_client_instance_arg_t *vciap = &vcap->vca_un.vca_instance; 71 72 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vciap->vcia_id); 73 if (ihp == NULL) 74 return (ENOENT); 75 return (libvarpd_instance_activate(ihp)); 76 } 77 78 /* ARGSUSED */ 79 static int 80 libvarpd_door_f_destroy(varpd_impl_t *vip, varpd_client_arg_t *vcap, 81 ucred_t *credp) 82 { 83 varpd_instance_handle_t *ihp; 84 varpd_client_instance_arg_t *vciap = &vcap->vca_un.vca_instance; 85 86 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vciap->vcia_id); 87 if (ihp == NULL) 88 return (ENOENT); 89 libvarpd_instance_destroy(ihp); 90 return (0); 91 } 92 93 /* ARGSUSED */ 94 static int 95 libvarpd_door_f_nprops(varpd_impl_t *vip, varpd_client_arg_t *vcap, 96 ucred_t *credp) 97 { 98 varpd_instance_handle_t *ihp; 99 varpd_client_nprops_arg_t *vcnap = &vcap->vca_un.vca_nprops; 100 101 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcnap->vcna_id); 102 if (ihp == NULL) 103 return (ENOENT); 104 105 return (libvarpd_prop_nprops(ihp, &vcnap->vcna_nprops)); 106 } 107 108 /* ARGSUSED */ 109 static int 110 libvarpd_door_f_propinfo(varpd_impl_t *vip, varpd_client_arg_t *vcap, 111 ucred_t *credp) 112 { 113 int ret; 114 varpd_instance_handle_t *ihp; 115 varpd_prop_handle_t *phdl; 116 varpd_client_propinfo_arg_t *vcfap = &vcap->vca_un.vca_info; 117 118 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcfap->vcfa_id); 119 if (ihp == NULL) 120 return (ENOENT); 121 ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl); 122 if (ret != 0) 123 return (ret); 124 125 if (vcfap->vcfa_propid != UINT_MAX) { 126 ret = libvarpd_prop_info_fill(phdl, vcfap->vcfa_propid); 127 if (ret != 0) { 128 libvarpd_prop_handle_free(phdl); 129 return (ret); 130 } 131 } else { 132 uint_t i, nprop; 133 const char *name; 134 135 vcfap->vcfa_name[LIBVARPD_PROP_NAMELEN-1] = '\0'; 136 ret = libvarpd_prop_nprops(ihp, &nprop); 137 if (ret != 0) { 138 libvarpd_prop_handle_free(phdl); 139 return (ret); 140 } 141 for (i = 0; i < nprop; i++) { 142 ret = libvarpd_prop_info_fill(phdl, i); 143 if (ret != 0) { 144 libvarpd_prop_handle_free(phdl); 145 return (ret); 146 } 147 ret = libvarpd_prop_info(phdl, &name, NULL, NULL, NULL, 148 NULL, NULL); 149 if (ret != 0) { 150 libvarpd_prop_handle_free(phdl); 151 return (ret); 152 } 153 if (strcmp(vcfap->vcfa_name, name) == 0) 154 break; 155 } 156 157 if (i == nprop) { 158 libvarpd_prop_handle_free(phdl); 159 return (ENOENT); 160 } 161 vcfap->vcfa_propid = i; 162 } 163 libvarpd_prop_door_convert(phdl, vcfap); 164 libvarpd_prop_handle_free(phdl); 165 return (0); 166 } 167 168 /* ARGSUSED */ 169 static int 170 libvarpd_door_f_getprop(varpd_impl_t *vip, varpd_client_arg_t *vcap, 171 ucred_t *credp) 172 { 173 int ret; 174 uint32_t size; 175 varpd_instance_handle_t *ihp; 176 varpd_prop_handle_t *phdl; 177 varpd_client_prop_arg_t *vcpap = &vcap->vca_un.vca_prop; 178 179 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcpap->vcpa_id); 180 if (ihp == NULL) 181 return (ENOENT); 182 ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl); 183 if (ret != 0) 184 return (ret); 185 186 ret = libvarpd_prop_info_fill(phdl, vcpap->vcpa_propid); 187 if (ret != 0) { 188 libvarpd_prop_handle_free(phdl); 189 return (ret); 190 } 191 192 ret = libvarpd_prop_get(phdl, vcpap->vcpa_buf, &size); 193 if (ret == 0) 194 vcpap->vcpa_bufsize = size; 195 libvarpd_prop_handle_free(phdl); 196 return (0); 197 } 198 199 /* ARGSUSED */ 200 static int 201 libvarpd_door_f_setprop(varpd_impl_t *vip, varpd_client_arg_t *vcap, 202 ucred_t *credp) 203 { 204 int ret; 205 varpd_instance_handle_t *ihp; 206 varpd_prop_handle_t *phdl; 207 varpd_client_prop_arg_t *vcpap = &vcap->vca_un.vca_prop; 208 209 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcpap->vcpa_id); 210 if (ihp == NULL) 211 return (ENOENT); 212 ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl); 213 if (ret != 0) 214 return (ret); 215 216 ret = libvarpd_prop_info_fill(phdl, vcpap->vcpa_propid); 217 if (ret != 0) { 218 libvarpd_prop_handle_free(phdl); 219 return (ret); 220 } 221 222 ret = libvarpd_prop_set(phdl, vcpap->vcpa_buf, vcpap->vcpa_bufsize); 223 libvarpd_prop_handle_free(phdl); 224 return (ret); 225 } 226 227 /* ARGSUSED */ 228 static int 229 libvarpd_door_f_lookup(varpd_impl_t *vip, varpd_client_arg_t *vcap, 230 ucred_t *credp) 231 { 232 varpd_instance_t *inst; 233 varpd_client_lookup_arg_t *vclap = &vcap->vca_un.vca_lookup; 234 235 inst = libvarpd_instance_lookup_by_dlid(vip, vclap->vcla_linkid); 236 if (inst == NULL) 237 return (ENOENT); 238 239 vclap->vcla_id = inst->vri_id; 240 return (0); 241 } 242 243 /* ARGSUSED */ 244 static int 245 libvarpd_door_f_target(varpd_impl_t *vip, varpd_client_arg_t *vcap, 246 ucred_t *credp) 247 { 248 varpd_instance_handle_t *ihp; 249 varpd_instance_t *inst; 250 varpd_client_target_mode_arg_t *vtmap = &vcap->vca_un.vca_mode; 251 252 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtmap->vtma_id); 253 if (ihp == NULL) 254 return (ENOENT); 255 inst = (varpd_instance_t *)ihp; 256 vtmap->vtma_dest = inst->vri_dest; 257 vtmap->vtma_mode = inst->vri_mode; 258 return (0); 259 } 260 261 static int 262 libvarpd_door_f_flush(varpd_impl_t *vip, varpd_client_arg_t *vcap, 263 ucred_t *credp) 264 { 265 varpd_instance_handle_t *ihp; 266 varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache; 267 268 if (libvarpd_door_privileged(credp) == B_FALSE) 269 return (EPERM); 270 271 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id); 272 if (ihp == NULL) 273 return (ENOENT); 274 return (libvarpd_overlay_cache_flush((varpd_instance_t *)ihp)); 275 } 276 277 static int 278 libvarpd_door_f_delete(varpd_impl_t *vip, varpd_client_arg_t *vcap, 279 ucred_t *credp) 280 { 281 varpd_instance_handle_t *ihp; 282 varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache; 283 284 if (libvarpd_door_privileged(credp) == B_FALSE) 285 return (EPERM); 286 287 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id); 288 if (ihp == NULL) 289 return (ENOENT); 290 return (libvarpd_overlay_cache_delete((varpd_instance_t *)ihp, 291 vtcap->vtca_key)); 292 } 293 294 /* ARGSUSED */ 295 static int 296 libvarpd_door_f_get(varpd_impl_t *vip, varpd_client_arg_t *vcap, 297 ucred_t *credp) 298 { 299 varpd_instance_handle_t *ihp; 300 varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache; 301 302 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id); 303 if (ihp == NULL) 304 return (ENOENT); 305 return (libvarpd_overlay_cache_get((varpd_instance_t *)ihp, 306 vtcap->vtca_key, &vtcap->vtca_entry)); 307 } 308 309 static int 310 libvarpd_door_f_set(varpd_impl_t *vip, varpd_client_arg_t *vcap, 311 ucred_t *credp) 312 { 313 varpd_instance_handle_t *ihp; 314 varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache; 315 316 if (libvarpd_door_privileged(credp) == B_FALSE) 317 return (EPERM); 318 319 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id); 320 if (ihp == NULL) 321 return (ENOENT); 322 323 return (libvarpd_overlay_cache_set((varpd_instance_t *)ihp, 324 vtcap->vtca_key, &vtcap->vtca_entry)); 325 } 326 327 /* ARGSUSED */ 328 static int 329 libvarpd_door_f_walk(varpd_impl_t *vip, varpd_client_arg_t *vcap, 330 ucred_t *credp) 331 { 332 varpd_instance_handle_t *ihp; 333 varpd_client_target_walk_arg_t *vctwp = &vcap->vca_un.vca_walk; 334 335 ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vctwp->vtcw_id); 336 if (ihp == NULL) 337 return (ENOENT); 338 339 return (libvarpd_overlay_cache_walk_fill((varpd_instance_t *)ihp, 340 &vctwp->vtcw_marker, &vctwp->vtcw_count, vctwp->vtcw_ents)); 341 } 342 343 static libvarpd_door_f *libvarpd_door_table[] = { 344 libvarpd_door_f_create, 345 libvarpd_door_f_activate, 346 libvarpd_door_f_destroy, 347 libvarpd_door_f_nprops, 348 libvarpd_door_f_propinfo, 349 libvarpd_door_f_getprop, 350 libvarpd_door_f_setprop, 351 libvarpd_door_f_lookup, 352 libvarpd_door_f_target, 353 libvarpd_door_f_flush, 354 libvarpd_door_f_delete, 355 libvarpd_door_f_get, 356 libvarpd_door_f_set, 357 libvarpd_door_f_walk 358 }; 359 360 /* ARGSUSED */ 361 static void 362 libvarpd_door_server(void *cookie, char *argp, size_t argsz, door_desc_t *dp, 363 uint_t ndesc) 364 { 365 int ret; 366 varpd_client_eresp_t err; 367 ucred_t *credp = NULL; 368 varpd_impl_t *vip = cookie; 369 varpd_client_arg_t *vcap = (varpd_client_arg_t *)argp; 370 371 err.vce_command = VARPD_CLIENT_INVALID; 372 if (argsz < sizeof (varpd_client_arg_t)) { 373 err.vce_errno = EINVAL; 374 goto errout; 375 } 376 377 if ((ret = door_ucred(&credp)) != 0) { 378 err.vce_errno = ret; 379 goto errout; 380 } 381 382 if (vcap->vca_command == VARPD_CLIENT_INVALID || 383 vcap->vca_command >= VARPD_CLIENT_MAX) { 384 err.vce_errno = EINVAL; 385 goto errout; 386 } 387 388 vcap->vca_errno = 0; 389 ret = libvarpd_door_table[vcap->vca_command - 1](vip, vcap, credp); 390 if (ret != 0) 391 vcap->vca_errno = ret; 392 393 ucred_free(credp); 394 (void) door_return(argp, argsz, NULL, 0); 395 return; 396 397 errout: 398 ucred_free(credp); 399 (void) door_return((char *)&err, sizeof (err), NULL, 0); 400 } 401 402 int 403 libvarpd_door_server_create(varpd_handle_t *vhp, const char *path) 404 { 405 int fd, ret; 406 varpd_impl_t *vip = (varpd_impl_t *)vhp; 407 408 mutex_enter(&vip->vdi_lock); 409 if (vip->vdi_doorfd >= 0) { 410 mutex_exit(&vip->vdi_lock); 411 return (EEXIST); 412 } 413 414 vip->vdi_doorfd = door_create(libvarpd_door_server, vip, 415 DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 416 if (vip->vdi_doorfd == -1) { 417 mutex_exit(&vip->vdi_lock); 418 return (errno); 419 } 420 421 if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) { 422 ret = errno; 423 if (door_revoke(vip->vdi_doorfd) != 0) 424 libvarpd_panic("failed to revoke door: %d", 425 errno); 426 mutex_exit(&vip->vdi_lock); 427 return (errno); 428 } 429 430 if (fchown(fd, UID_NETADM, GID_NETADM) != 0) { 431 ret = errno; 432 if (door_revoke(vip->vdi_doorfd) != 0) 433 libvarpd_panic("failed to revoke door: %d", 434 errno); 435 mutex_exit(&vip->vdi_lock); 436 return (ret); 437 } 438 439 if (close(fd) != 0) 440 libvarpd_panic("failed to close door fd %d: %d", 441 fd, errno); 442 (void) fdetach(path); 443 if (fattach(vip->vdi_doorfd, path) != 0) { 444 ret = errno; 445 if (door_revoke(vip->vdi_doorfd) != 0) 446 libvarpd_panic("failed to revoke door: %d", 447 errno); 448 mutex_exit(&vip->vdi_lock); 449 return (ret); 450 } 451 452 mutex_exit(&vip->vdi_lock); 453 return (0); 454 } 455 456 void 457 libvarpd_door_server_destroy(varpd_handle_t *vhp) 458 { 459 varpd_impl_t *vip = (varpd_impl_t *)vhp; 460 461 mutex_enter(&vip->vdi_lock); 462 if (vip->vdi_doorfd != 0) { 463 if (door_revoke(vip->vdi_doorfd) != 0) 464 libvarpd_panic("failed to revoke door: %d", 465 errno); 466 vip->vdi_doorfd = -1; 467 } 468 mutex_exit(&vip->vdi_lock); 469 } 470