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
libvarpd_door_privileged(ucred_t * credp)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
libvarpd_door_f_create(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_activate(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_destroy(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_nprops(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_propinfo(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_getprop(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_setprop(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_lookup(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_target(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_flush(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_delete(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_get(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_set(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_f_walk(varpd_impl_t * vip,varpd_client_arg_t * vcap,ucred_t * credp)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
libvarpd_door_server(void * cookie,char * argp,size_t argsz,door_desc_t * dp,uint_t ndesc)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
libvarpd_door_server_create(varpd_handle_t * vhp,const char * path)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
libvarpd_door_server_destroy(varpd_handle_t * vhp)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