1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This module contains the private layer API.
31 */
32
33 #include <stdio.h>
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <sys/param.h>
39 #include <libelf.h>
40 #include <gelf.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <dlfcn.h>
46 #include <glob.h>
47 #include <fcntl.h>
48 #include <libinetutil.h>
49 #include <dhcp_svc_public.h>
50 #include <dhcp_svc_private.h>
51
52 /*
53 * Threading notes for private layer consumers:
54 *
55 * The handles returned from open_dd() may be shared across multiple
56 * threads with no adverse side effects. However, it's up to that consumer
57 * to ensure that all threads have finished using an instance before
58 * closing the instance or removing the container it's referencing.
59 * Phrased differently:
60 *
61 * * Consumers must ensure all threads sharing a handle are
62 * finished before calling close_dd().
63 *
64 * * Consumers must ensure all threads referencing a container are
65 * closed before calling remove_dd().
66 */
67
68 static boolean_t validate_dd_entry(dsvc_handle_t, const void *, boolean_t);
69 static int synch_init(dsvc_handle_t, const char *, uint_t);
70 static void synch_fini(dsvc_handle_t);
71
72 /*
73 * Order here should match the function array in <dhcp_svc_private.h>
74 */
75 static char *funcnames[] = {
76 "status", "version", "mklocation",
77 "list_dt", "open_dt", "close_dt", "remove_dt",
78 "lookup_dt", "add_dt", "modify_dt", "delete_dt",
79 "list_dn", "open_dn", "close_dn", "remove_dn",
80 "lookup_dn", "add_dn", "modify_dn", "delete_dn"
81 };
82
83 extern dsvc_synch_ops_t dsvcd_synch_ops;
84
85 /*
86 * Retrieve the current version associated with the datastore named by
87 * `resource' and store in `converp'. One might think we could do this via
88 * a simple readlink(2), but on internal release builds $(ROOTLINKS)
89 * installs using hardlinks, not symlinks. For this reason and to make it
90 * harder for us to be fooled, we'll dredge up the actual soname through
91 * ELF. Close your eyes, it's gonna get ugly.
92 */
93 static int
get_conver(const char * resource,int * converp)94 get_conver(const char *resource, int *converp)
95 {
96 int elf_fd;
97 int i;
98 GElf_Shdr gelf_shdr;
99 GElf_Dyn gelf_dyn;
100 Elf_Scn *elf_scn = NULL;
101 Elf *elf_file;
102 Elf_Data *elf_data;
103 char *soname = NULL;
104 char path[MAXPATHLEN];
105
106 (void) snprintf(path, sizeof (path), "%s%s/%s_%s.so", DHCP_CONFOPT_ROOT,
107 DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX, resource);
108
109 elf_fd = open(path, O_RDONLY);
110 if (elf_fd == -1)
111 return (DSVC_MODULE_ERR);
112
113 if (elf_version(EV_CURRENT) == EV_NONE) {
114 (void) close(elf_fd);
115 return (DSVC_INTERNAL);
116 }
117
118 elf_file = elf_begin(elf_fd, ELF_C_READ, NULL);
119 if (elf_file == NULL || elf_kind(elf_file) != ELF_K_ELF) {
120 (void) close(elf_fd);
121 return (DSVC_INTERNAL);
122 }
123
124 while ((elf_scn = elf_nextscn(elf_file, elf_scn)) != NULL) {
125 if (gelf_getshdr(elf_scn, &gelf_shdr) == 0)
126 continue;
127
128 if (gelf_shdr.sh_type != SHT_DYNAMIC)
129 continue;
130
131 elf_data = elf_getdata(elf_scn, NULL);
132 if (elf_data == NULL)
133 continue;
134
135 i = 0;
136 do {
137 (void) gelf_getdyn(elf_data, i++, &gelf_dyn);
138 if (gelf_dyn.d_tag == DT_SONAME)
139 soname = elf_strptr(elf_file, gelf_shdr.sh_link,
140 gelf_dyn.d_un.d_ptr);
141 } while (gelf_dyn.d_tag != DT_NULL && soname == NULL);
142 }
143 if (soname == NULL || sscanf(soname, "%*[^.].so.%d", converp) != 1) {
144 (void) elf_end(elf_file);
145 (void) close(elf_fd);
146 return (DSVC_MODULE_ERR);
147 }
148 (void) elf_end(elf_file);
149 (void) close(elf_fd);
150
151 return (DSVC_SUCCESS);
152 }
153
154 /*
155 * Unload a public datastore module.
156 */
157 static int
unload_public_module(void ** instance,dsvc_splapi_t * api)158 unload_public_module(void **instance, dsvc_splapi_t *api)
159 {
160 static dsvc_splapi_t null_api;
161
162 if (dlclose(*instance) != 0)
163 return (DSVC_MODULE_UNLOAD_ERR);
164
165 *instance = NULL;
166 *api = null_api;
167
168 return (DSVC_SUCCESS);
169 }
170
171 /*
172 * Load public datastore module. Validates version of module. Returns
173 * instance of opened module, and populates the api argument with the
174 * function addresses exporting the API.
175 */
176 static int
load_public_module(dsvc_datastore_t * ddp,void ** instance,dsvc_splapi_t * api)177 load_public_module(dsvc_datastore_t *ddp, void **instance, dsvc_splapi_t *api)
178 {
179 int i, v;
180 dsvc_splfuncp_t configure;
181 char path[MAXPATHLEN];
182
183 (void) snprintf(path, sizeof (path), "%s%s/%s_%s.so", DHCP_CONFOPT_ROOT,
184 DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX, ddp->d_resource);
185
186 if (ddp->d_conver != DSVC_CUR_CONVER)
187 (void) snprintf(path, sizeof (path), "%s.%d", path,
188 ddp->d_conver);
189
190 *instance = dlopen(path, RTLD_LAZY|RTLD_GROUP|RTLD_WORLD);
191 if (*instance == NULL)
192 return (DSVC_MODULE_LOAD_ERR);
193
194 /*
195 * No requirement to duplicate the names - we can always reference
196 * the same set.
197 */
198 api->version = (dsvc_splfuncp_t)dlsym(*instance, "version");
199 if (api->version == NULL || api->version(&v) != DSVC_SUCCESS ||
200 v != DSVC_PUBLIC_VERSION) {
201 (void) unload_public_module(instance, api);
202 return (DSVC_MODULE_VERSION);
203 }
204
205 configure = (dsvc_splfuncp_t)dlsym(*instance, "configure");
206 if (configure != NULL) {
207 if (configure(ddp->d_config) != DSVC_SUCCESS) {
208 (void) unload_public_module(instance, api);
209 return (DSVC_MODULE_CFG_ERR);
210 }
211 }
212
213 for (i = 0; i < DSVC_NSPLFUNCS; i++) {
214 if ((((dsvc_splfuncp_t *)api)[i] =
215 (dsvc_splfuncp_t)dlsym(*instance, funcnames[i])) == NULL) {
216 (void) unload_public_module(instance, api);
217 return (DSVC_MODULE_ERR);
218 }
219 }
220
221 /*
222 * Caller requested the current version; fill in what that current
223 * version is.
224 */
225 if (ddp->d_conver == DSVC_CUR_CONVER) {
226 int error;
227 error = get_conver(ddp->d_resource, &ddp->d_conver);
228 if (error != DSVC_SUCCESS) {
229 (void) unload_public_module(instance, api);
230 return (error);
231 }
232 }
233
234 return (DSVC_SUCCESS);
235 }
236
237 /*
238 * Return a dynamically-allocated null-terminated list of the available
239 * modules stored in the module directory. A count of the available
240 * modules is stored in the num argument. Caller is responsible for
241 * freeing the list.
242 */
243 int
enumerate_dd(char *** modules,int * nump)244 enumerate_dd(char ***modules, int *nump)
245 {
246 int i, retval;
247 char *ptr;
248 glob_t globbuf;
249 char globpat[MAXPATHLEN];
250
251 if (modules == NULL || nump == NULL)
252 return (DSVC_INVAL);
253
254 (void) snprintf(globpat, sizeof (globpat), "%s%s/%s_*\\.so",
255 DHCP_CONFOPT_ROOT, DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX);
256
257 retval = glob(globpat, GLOB_NOSORT, NULL, &globbuf);
258 if (retval != 0) {
259 globfree(&globbuf);
260 switch (retval) {
261 case GLOB_NOMATCH:
262 *nump = 0;
263 *modules = NULL;
264 return (DSVC_SUCCESS);
265 case GLOB_NOSPACE:
266 return (DSVC_NO_MEMORY);
267 default:
268 return (DSVC_INTERNAL);
269 }
270 }
271
272 *modules = calloc(globbuf.gl_pathc, sizeof (char **));
273 if (*modules == NULL) {
274 globfree(&globbuf);
275 return (DSVC_NO_MEMORY);
276 }
277
278 for (i = 0; i < globbuf.gl_pathc; i++) {
279 ptr = strrchr(globbuf.gl_pathv[i], '/');
280 if (ptr == NULL)
281 ptr = globbuf.gl_pathv[i];
282 else
283 ptr++;
284 (*modules)[i] = malloc(strlen(ptr) + 1);
285 if ((*modules)[i] == NULL) {
286 while (i--)
287 free((*modules)[i]);
288 free(modules);
289 globfree(&globbuf);
290 return (DSVC_NO_MEMORY);
291 }
292
293 (void) sscanf(ptr, "%*[^_]_%[^.]", (*modules)[i]);
294 }
295
296 globfree(&globbuf);
297 *nump = i;
298 return (DSVC_SUCCESS);
299 }
300
301 /*
302 * Check the status of the underlying service supporting the data store.
303 * Caller is responsible for freeing any dynamically allocated arguments.
304 */
305 int
status_dd(dsvc_datastore_t * ddp)306 status_dd(dsvc_datastore_t *ddp)
307 {
308 void *instance;
309 dsvc_splapi_t api;
310 int error;
311
312 error = load_public_module(ddp, &instance, &api);
313 if (error != DSVC_SUCCESS)
314 return (error);
315
316 error = api.status(ddp->d_location);
317
318 (void) unload_public_module(&instance, &api);
319
320 return (error);
321 }
322
323 /*
324 * Create within the data store the "location" where containers will be
325 * stored.
326 */
327 int
mklocation_dd(dsvc_datastore_t * ddp)328 mklocation_dd(dsvc_datastore_t *ddp)
329 {
330 void *instance;
331 dsvc_splapi_t api;
332 int error;
333
334 error = load_public_module(ddp, &instance, &api);
335 if (error != DSVC_SUCCESS)
336 return (error);
337
338 error = api.mklocation(ddp->d_location);
339
340 (void) unload_public_module(&instance, &api);
341
342 return (error);
343 }
344
345 /*
346 * Return a list of the current container objects of type 'type' located at
347 * 'location' in listppp. Return the number of list elements in 'count'.
348 */
349 int
list_dd(dsvc_datastore_t * ddp,dsvc_contype_t type,char *** listppp,uint_t * count)350 list_dd(dsvc_datastore_t *ddp, dsvc_contype_t type, char ***listppp,
351 uint_t *count)
352 {
353 void *instance;
354 dsvc_splapi_t api;
355 int error;
356
357 error = load_public_module(ddp, &instance, &api);
358 if (error != DSVC_SUCCESS)
359 return (error);
360
361 if (type == DSVC_DHCPTAB)
362 error = api.list_dt(ddp->d_location, listppp, count);
363 else
364 error = api.list_dn(ddp->d_location, listppp, count);
365
366 (void) unload_public_module(&instance, &api);
367
368 return (error);
369 }
370
371 /*
372 * Creates or opens the DHCP container of type called name within the
373 * specific datastore referenced by ddp, and returns a handle to this
374 * container in the handp argument. New containers are created with
375 * the identity of the caller. Caller is responsible for freeing any
376 * dynamically allocated arguments. The returned handle instance must
377 * be released by calling close_dd().
378 */
379 int
open_dd(dsvc_handle_t * handp,dsvc_datastore_t * ddp,dsvc_contype_t type,const char * name,uint_t flags)380 open_dd(dsvc_handle_t *handp, dsvc_datastore_t *ddp, dsvc_contype_t type,
381 const char *name, uint_t flags)
382 {
383 int error;
384 dsvc_handle_t hp;
385
386 *handp = NULL;
387
388 if (type == DSVC_DHCPNETWORK && name == NULL)
389 return (DSVC_INVAL);
390
391 if (flags & DSVC_CREATE && (flags & DSVC_WRITE) == 0)
392 return (DSVC_INVAL);
393
394 if ((hp = calloc(1, sizeof (struct dsvc_handle))) == NULL)
395 return (DSVC_NO_MEMORY);
396
397 if (type == DSVC_DHCPNETWORK) {
398 hp->d_conid.c_net.s_addr = ntohl(inet_addr(name));
399 if (hp->d_conid.c_net.s_addr == INADDR_BROADCAST) {
400 free(hp);
401 return (DSVC_INVAL);
402 }
403 get_netmask4(&hp->d_conid.c_net, &hp->d_conid.c_mask);
404 }
405
406 error = load_public_module(ddp, &hp->d_instance, &hp->d_api);
407 if (error != DSVC_SUCCESS) {
408 free(hp);
409 return (error);
410 }
411
412 hp->d_type = type;
413 hp->d_desc.d_conver = ddp->d_conver;
414 hp->d_desc.d_resource = strdup(ddp->d_resource);
415 hp->d_desc.d_location = strdup(ddp->d_location);
416 if (hp->d_desc.d_resource == NULL || hp->d_desc.d_location == NULL) {
417 error = DSVC_NO_MEMORY;
418 goto error;
419 }
420
421 /*
422 * Initialize the synchronization strategy (may not be any).
423 */
424 error = synch_init(hp, name, flags);
425 if (error != DSVC_SUCCESS)
426 goto error;
427
428 if (type == DSVC_DHCPTAB)
429 error = hp->d_api.open_dt(&hp->d_hand, ddp->d_location, flags);
430 else
431 error = hp->d_api.open_dn(&hp->d_hand, ddp->d_location, flags,
432 &hp->d_conid.c_net, &hp->d_conid.c_mask);
433
434 if (error != DSVC_SUCCESS) {
435 if (hp->d_synch != NULL)
436 synch_fini(hp);
437 goto error;
438 }
439
440 *handp = hp;
441 return (DSVC_SUCCESS);
442 error:
443 (void) unload_public_module(&hp->d_instance, &hp->d_api);
444 free(hp->d_desc.d_resource);
445 free(hp->d_desc.d_location);
446 free(hp);
447 return (error);
448 }
449
450 /*
451 * Remove DHCP container called name of type within the specific datastore
452 * referenced by ddp. Caller is responsible for freeing any dynamically
453 * allocated arguments.
454 */
455 int
remove_dd(dsvc_datastore_t * ddp,dsvc_contype_t type,const char * name)456 remove_dd(dsvc_datastore_t *ddp, dsvc_contype_t type, const char *name)
457 {
458 void *instance;
459 int error;
460 dsvc_splapi_t api;
461 struct in_addr ip, mask;
462
463 if (type != DSVC_DHCPTAB) {
464 if ((ip.s_addr = inet_addr(name)) == INADDR_BROADCAST)
465 return (DSVC_INVAL);
466 ip.s_addr = ntohl(ip.s_addr);
467 get_netmask4(&ip, &mask);
468 }
469
470 error = load_public_module(ddp, &instance, &api);
471 if (error != DSVC_SUCCESS)
472 return (error);
473
474 /* remove the DHCP container */
475 if (type == DSVC_DHCPTAB)
476 error = api.remove_dt(ddp->d_location);
477 else
478 error = api.remove_dn(ddp->d_location, &ip, &mask);
479
480 (void) unload_public_module(&instance, &api);
481
482 return (error);
483 }
484
485 /*
486 * Delete the handle instance referenced by hand. Frees hand if the close
487 * operation was successful. NOTE: Caller is responsible for synchronizing
488 * multiple threads such that close_dd() is called when all consuming
489 * threads have exited.
490 */
491 int
close_dd(dsvc_handle_t * handp)492 close_dd(dsvc_handle_t *handp)
493 {
494 int error;
495
496 if (handp == NULL || DSVC_HANDLE_INVAL(*handp))
497 return (DSVC_INVAL);
498
499 if ((*handp)->d_type == DSVC_DHCPTAB)
500 error = (*handp)->d_api.close_dt(&((*handp)->d_hand));
501 else
502 error = (*handp)->d_api.close_dn(&((*handp)->d_hand));
503
504 if (error == DSVC_SUCCESS) {
505 error = unload_public_module(&(*handp)->d_instance,
506 &(*handp)->d_api);
507 if ((*handp)->d_synch != NULL)
508 synch_fini(*handp);
509 free((*handp)->d_desc.d_resource);
510 free((*handp)->d_desc.d_location);
511 free(*handp);
512 *handp = NULL;
513 }
514
515 return (error);
516 }
517
518 /*
519 * Searches hand container for records that match the query described by
520 * the combination of query and targetp. If the partial field is true, then
521 * lookup operations that have located some records but are unable to
522 * complete entirely are allowed. The query argument consists of 2 fields,
523 * each 16 bits long. The lower 16 bits selects which fields in the targetp
524 * record are to be considered in the query. The upper 16 bits identifies
525 * whether a particular field value must match (bit set) or not match (bit
526 * clear). Unused bits in both 16 bit fields must be 0. The count argument
527 * specifies the maximum number of matching records to return. A count
528 * value of -1 requests that all matching records be returned. recordsp is
529 * set to point to the resulting list of records; if recordsp is NULL then
530 * no records are actually returned. Note that these records are
531 * dynamically allocated, thus the caller is responsible for freeing them.
532 * The number of records found is returned in nrecordsp; a value of 0 means
533 * that no records matched the query.
534 */
535 int
lookup_dd(dsvc_handle_t hand,boolean_t partial,uint_t query,int count,const void * targetp,void ** recordsp,uint_t * nrecordsp)536 lookup_dd(dsvc_handle_t hand, boolean_t partial, uint_t query,
537 int count, const void *targetp, void **recordsp, uint_t *nrecordsp)
538 {
539 uint_t mask = 0;
540 int error;
541 void *unlock_cookie;
542 int (*lookup)();
543
544 if (targetp == NULL || nrecordsp == NULL || DSVC_HANDLE_INVAL(hand))
545 return (DSVC_INVAL);
546
547 if (hand->d_type == DSVC_DHCPTAB) {
548 mask = (uint_t)~DT_QALL;
549 lookup = hand->d_api.lookup_dt;
550 } else {
551 mask = (uint_t)~DN_QALL;
552 lookup = hand->d_api.lookup_dn;
553 }
554
555 /* validate query */
556 if (((query & 0xffff) & mask) || ((query >> 16) & mask))
557 return (DSVC_INVAL);
558
559 /*
560 * XXX: need to validate the `targetp' -- what a mess cuz only the
561 * fields lit in `query' need to be valid.
562 */
563
564 if (hand->d_synch != NULL) {
565 error = DSVC_SYNCH_RDLOCK(hand->d_synch, &unlock_cookie);
566 if (error != DSVC_SUCCESS)
567 return (error);
568 }
569
570 error = lookup(hand->d_hand, partial, query, count, targetp, recordsp,
571 nrecordsp);
572
573 if (hand->d_synch != NULL)
574 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
575
576 return (error);
577 }
578
579 /*
580 * Frees the record pointed to by entryp.
581 */
582 void
free_dd(dsvc_handle_t hand,void * entryp)583 free_dd(dsvc_handle_t hand, void *entryp)
584 {
585 if (DSVC_HANDLE_INVAL(hand) || entryp == NULL)
586 return;
587
588 if (hand->d_type == DSVC_DHCPTAB)
589 free_dtrec((dt_rec_t *)entryp);
590 else
591 free_dnrec((dn_rec_t *)entryp);
592 }
593
594 /*
595 * Frees the list of records pointed to by listp.
596 */
597 void
free_dd_list(dsvc_handle_t hand,void * listp)598 free_dd_list(dsvc_handle_t hand, void *listp)
599 {
600 if (DSVC_HANDLE_INVAL(hand) || listp == NULL)
601 return;
602
603 if (hand->d_type == DSVC_DHCPTAB)
604 free_dtrec_list((dt_rec_list_t *)listp);
605 else
606 free_dnrec_list((dn_rec_list_t *)listp);
607 }
608
609 /*
610 * Add the record newp to the DHCP container hand. newp's update signature
611 * will be updated by the public layer module doing the update. Caller is
612 * responsible for freeing newp if it was dynamically allocated.
613 */
614 int
add_dd_entry(dsvc_handle_t hand,void * newp)615 add_dd_entry(dsvc_handle_t hand, void *newp)
616 {
617 int error;
618 void *unlock_cookie;
619
620 if (DSVC_HANDLE_INVAL(hand))
621 return (DSVC_INVAL);
622
623 if (!validate_dd_entry(hand, newp, B_FALSE))
624 return (DSVC_INVAL);
625
626 if (hand->d_synch != NULL) {
627 error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie);
628 if (error != DSVC_SUCCESS)
629 return (error);
630 }
631
632 if (hand->d_type == DSVC_DHCPTAB)
633 error = hand->d_api.add_dt(hand->d_hand, newp);
634 else
635 error = hand->d_api.add_dn(hand->d_hand, newp);
636
637 if (hand->d_synch != NULL)
638 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
639
640 return (error);
641 }
642
643 /*
644 * Modify the record origp with the record newp in the DHCP container hand.
645 * newp's update signature will be updated by the public layer module doing
646 * the update. Caller is responsible for freeing origp and/or newp if they
647 * were dynamically allocated.
648 */
649 int
modify_dd_entry(dsvc_handle_t hand,const void * origp,void * newp)650 modify_dd_entry(dsvc_handle_t hand, const void *origp, void *newp)
651 {
652 int error;
653 void *unlock_cookie;
654
655 if (DSVC_HANDLE_INVAL(hand))
656 return (DSVC_INVAL);
657
658 if (!validate_dd_entry(hand, origp, B_TRUE))
659 return (DSVC_INVAL);
660
661 if (!validate_dd_entry(hand, newp, B_FALSE))
662 return (DSVC_INVAL);
663
664 if (hand->d_synch != NULL) {
665 error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie);
666 if (error != DSVC_SUCCESS)
667 return (error);
668 }
669
670 if (hand->d_type == DSVC_DHCPTAB)
671 error = hand->d_api.modify_dt(hand->d_hand, origp, newp);
672 else
673 error = hand->d_api.modify_dn(hand->d_hand, origp, newp);
674
675 if (hand->d_synch != NULL)
676 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
677
678 return (error);
679 }
680
681 /*
682 * Deletes the record referred to by entryp from the DHCP container hand.
683 * Caller is responsible for freeing entryp if it was dynamically
684 * allocated.
685 */
686 int
delete_dd_entry(dsvc_handle_t hand,void * entryp)687 delete_dd_entry(dsvc_handle_t hand, void *entryp)
688 {
689 int error;
690 void *unlock_cookie;
691
692 if (DSVC_HANDLE_INVAL(hand))
693 return (DSVC_INVAL);
694
695 if (!validate_dd_entry(hand, entryp, B_TRUE))
696 return (DSVC_INVAL);
697
698 if (hand->d_synch != NULL) {
699 error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie);
700 if (error != DSVC_SUCCESS)
701 return (error);
702 }
703
704 if (hand->d_type == DSVC_DHCPTAB)
705 error = hand->d_api.delete_dt(hand->d_hand, entryp);
706 else
707 error = hand->d_api.delete_dn(hand->d_hand, entryp);
708
709 if (hand->d_synch != NULL)
710 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
711
712 return (error);
713 }
714
715 /*
716 * Validate that the DHCP network record `dn' is correctly formed; returns
717 * B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then only
718 * validate the key.
719 */
720 static boolean_t
validate_dnrec(dsvc_handle_t hand,const dn_rec_t * dn,boolean_t justkey)721 validate_dnrec(dsvc_handle_t hand, const dn_rec_t *dn, boolean_t justkey)
722 {
723 /* CIP must be on container's network */
724 if (hand->d_conid.c_net.s_addr !=
725 (dn->dn_cip.s_addr & hand->d_conid.c_mask.s_addr))
726 return (B_FALSE);
727
728 if (justkey)
729 return (B_TRUE);
730
731 if (dn->dn_cid_len < 1 || dn->dn_cid_len > DN_MAX_CID_LEN)
732 return (B_FALSE);
733
734 if ((dn->dn_flags & ~DN_FALL) != 0)
735 return (B_FALSE);
736
737 return (B_TRUE);
738 }
739
740 /*
741 * Validate that the dhcptab record `dt' is correctly formed; returns
742 * B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then only
743 * validate the key.
744 */
745 /* ARGSUSED */
746 static boolean_t
validate_dtrec(dsvc_handle_t hand,const dt_rec_t * dt,boolean_t justkey)747 validate_dtrec(dsvc_handle_t hand, const dt_rec_t *dt, boolean_t justkey)
748 {
749 return (dt->dt_type == DT_SYMBOL || dt->dt_type == DT_MACRO);
750 }
751
752 /*
753 * Validate that a DHCP record of type `hand->d_type' is correctly formed;
754 * returns B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then
755 * only validate the key.
756 */
757 static boolean_t
validate_dd_entry(dsvc_handle_t hand,const void * entryp,boolean_t justkey)758 validate_dd_entry(dsvc_handle_t hand, const void *entryp, boolean_t justkey)
759 {
760 if (entryp == NULL)
761 return (B_FALSE);
762
763 if (hand->d_type == DSVC_DHCPTAB)
764 return (validate_dtrec(hand, (dt_rec_t *)entryp, justkey));
765 else if (hand->d_type == DSVC_DHCPNETWORK)
766 return (validate_dnrec(hand, (dn_rec_t *)entryp, justkey));
767
768 return (B_FALSE);
769 }
770
771 /*
772 * Get the type of synchronization needed for this module and store in
773 * `synchtypep'. Returns a DSVC_* code. This function is exported so that
774 * dsvclockd(1M) can use it.
775 */
776 int
module_synchtype(dsvc_datastore_t * ddp,dsvc_synchtype_t * synchtypep)777 module_synchtype(dsvc_datastore_t *ddp, dsvc_synchtype_t *synchtypep)
778 {
779 void *instance;
780 dsvc_splapi_t api;
781 dsvc_synchtype_t *dsvc_synchtypep;
782
783 if (load_public_module(ddp, &instance, &api) != DSVC_SUCCESS)
784 return (DSVC_INTERNAL);
785
786 dsvc_synchtypep = dlsym(instance, "dsvc_synchtype");
787 if (dsvc_synchtypep != NULL)
788 *synchtypep = *dsvc_synchtypep;
789 else
790 *synchtypep = DSVC_SYNCH_NONE;
791
792 (void) unload_public_module(&instance, &api);
793
794 return (DSVC_SUCCESS);
795 }
796
797 /*
798 * Initialize private-layer synchronization on handle `hand' for container
799 * `conname'; `flags' is the same flags passed into open_dd(). If there's
800 * no synchronization needed, always succeeds. Returns a DSVC_* code.
801 */
802 int
synch_init(dsvc_handle_t hand,const char * conname,uint_t flags)803 synch_init(dsvc_handle_t hand, const char *conname, uint_t flags)
804 {
805 dsvc_synchtype_t synchtype;
806 dsvc_synch_t *sp;
807 int error;
808 int (*mkloctoken)(const char *, char *, size_t);
809
810 error = module_synchtype(&hand->d_desc, &synchtype);
811 if (error != DSVC_SUCCESS)
812 return (error);
813
814 if (synchtype == DSVC_SYNCH_NONE)
815 return (DSVC_SUCCESS);
816
817 sp = malloc(sizeof (dsvc_synch_t));
818 if (sp == NULL)
819 return (DSVC_NO_MEMORY);
820
821 sp->s_conname = strdup(conname);
822 if (sp->s_conname == NULL) {
823 free(sp);
824 return (DSVC_NO_MEMORY);
825 }
826 sp->s_nonblock = flags & DSVC_NONBLOCK;
827 sp->s_datastore = &hand->d_desc;
828
829 mkloctoken = (int (*)())dlsym(hand->d_instance, "mkloctoken");
830 if (mkloctoken == NULL) {
831 (void) strlcpy(sp->s_loctoken, sp->s_datastore->d_location,
832 sizeof (sp->s_loctoken));
833 } else {
834 error = mkloctoken(sp->s_datastore->d_location, sp->s_loctoken,
835 sizeof (sp->s_loctoken));
836 if (error != DSVC_SUCCESS) {
837 free(sp->s_conname);
838 free(sp);
839 return (error);
840 }
841 }
842
843 /*
844 * The only synchtype supported is DSVC_SYNCH_DSVCD; if this
845 * changes, we'll need to enhance this.
846 */
847 assert((synchtype & DSVC_SYNCH_STRATMASK) == DSVC_SYNCH_DSVCD);
848 sp->s_ops = &dsvcd_synch_ops;
849
850 error = DSVC_SYNCH_INIT(sp, synchtype & DSVC_SYNCH_FLAGMASK);
851 if (error != DSVC_SUCCESS) {
852 free(sp->s_conname);
853 free(sp);
854 return (error);
855 }
856
857 hand->d_synch = sp;
858 return (DSVC_SUCCESS);
859 }
860
861 /*
862 * Finish using private-layer synchronization on handle `hand'.
863 */
864 void
synch_fini(dsvc_handle_t hand)865 synch_fini(dsvc_handle_t hand)
866 {
867 DSVC_SYNCH_FINI(hand->d_synch);
868 free(hand->d_synch->s_conname);
869 free(hand->d_synch);
870 hand->d_synch = NULL;
871 }
872