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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* helper functions for using libscf with sharemgr */
28
29 #include <libscf.h>
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32 #include "libshare.h"
33 #include "libshare_impl.h"
34 #include "scfutil.h"
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <uuid/uuid.h>
39 #include <sys/param.h>
40 #include <signal.h>
41 #include <sys/time.h>
42 #include <libintl.h>
43
44 ssize_t scf_max_name_len;
45 extern struct sa_proto_plugin *sap_proto_list;
46 extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
47 static void set_transaction_tstamp(sa_handle_impl_t);
48 /*
49 * The SMF facility uses some properties that must exist. We want to
50 * skip over these when processing protocol options.
51 */
52 static char *skip_props[] = {
53 "modify_authorization",
54 "action_authorization",
55 "value_authorization",
56 NULL
57 };
58
59 /*
60 * sa_scf_fini(handle)
61 *
62 * Must be called when done. Called with the handle allocated in
63 * sa_scf_init(), it cleans up the state and frees any SCF resources
64 * still in use. Called by sa_fini().
65 */
66
67 void
sa_scf_fini(scfutilhandle_t * handle)68 sa_scf_fini(scfutilhandle_t *handle)
69 {
70 if (handle != NULL) {
71 int unbind = 0;
72 if (handle->scope != NULL) {
73 unbind = 1;
74 scf_scope_destroy(handle->scope);
75 }
76 if (handle->instance != NULL)
77 scf_instance_destroy(handle->instance);
78 if (handle->service != NULL)
79 scf_service_destroy(handle->service);
80 if (handle->pg != NULL)
81 scf_pg_destroy(handle->pg);
82 if (handle->handle != NULL) {
83 handle->scf_state = SCH_STATE_UNINIT;
84 if (unbind)
85 (void) scf_handle_unbind(handle->handle);
86 scf_handle_destroy(handle->handle);
87 }
88 free(handle);
89 }
90 }
91
92 /*
93 * sa_scf_init()
94 *
95 * Must be called before using any of the SCF functions. Called by
96 * sa_init() during the API setup.
97 */
98
99 scfutilhandle_t *
sa_scf_init(sa_handle_impl_t ihandle)100 sa_scf_init(sa_handle_impl_t ihandle)
101 {
102 scfutilhandle_t *handle;
103
104 scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
105 if (scf_max_name_len <= 0)
106 scf_max_name_len = SA_MAX_NAME_LEN + 1;
107
108 handle = calloc(1, sizeof (scfutilhandle_t));
109 if (handle == NULL)
110 return (handle);
111
112 ihandle->scfhandle = handle;
113 handle->scf_state = SCH_STATE_INITIALIZING;
114 handle->handle = scf_handle_create(SCF_VERSION);
115 if (handle->handle == NULL) {
116 free(handle);
117 handle = NULL;
118 (void) printf("libshare could not access SMF repository: %s\n",
119 scf_strerror(scf_error()));
120 return (handle);
121 }
122 if (scf_handle_bind(handle->handle) != 0)
123 goto err;
124
125 handle->scope = scf_scope_create(handle->handle);
126 handle->service = scf_service_create(handle->handle);
127 handle->pg = scf_pg_create(handle->handle);
128
129 /* Make sure we have sufficient SMF running */
130 handle->instance = scf_instance_create(handle->handle);
131 if (handle->scope == NULL || handle->service == NULL ||
132 handle->pg == NULL || handle->instance == NULL)
133 goto err;
134 if (scf_handle_get_scope(handle->handle,
135 SCF_SCOPE_LOCAL, handle->scope) != 0)
136 goto err;
137 if (scf_scope_get_service(handle->scope,
138 SA_GROUP_SVC_NAME, handle->service) != 0)
139 goto err;
140
141 handle->scf_state = SCH_STATE_INIT;
142 if (sa_get_instance(handle, "default") != SA_OK) {
143 sa_group_t defgrp;
144 defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
145 /* Only NFS enabled for "default" group. */
146 if (defgrp != NULL)
147 (void) sa_create_optionset(defgrp, "nfs");
148 }
149
150 return (handle);
151
152 /* Error handling/unwinding */
153 err:
154 (void) sa_scf_fini(handle);
155 (void) printf("libshare SMF initialization problem: %s\n",
156 scf_strerror(scf_error()));
157 return (NULL);
158 }
159
160 /*
161 * get_scf_limit(name)
162 *
163 * Since we use scf_limit a lot and do the same check and return the
164 * same value if it fails, implement as a function for code
165 * simplification. Basically, if name isn't found, return MAXPATHLEN
166 * (1024) so we have a reasonable default buffer size.
167 */
168 static ssize_t
get_scf_limit(uint32_t name)169 get_scf_limit(uint32_t name)
170 {
171 ssize_t vallen;
172
173 vallen = scf_limit(name);
174 if (vallen == (ssize_t)-1)
175 vallen = MAXPATHLEN;
176 return (vallen);
177 }
178
179 /*
180 * skip_property(name)
181 *
182 * Internal function to check to see if a property is an SMF magic
183 * property that needs to be skipped.
184 */
185 static int
skip_property(char * name)186 skip_property(char *name)
187 {
188 int i;
189
190 for (i = 0; skip_props[i] != NULL; i++)
191 if (strcmp(name, skip_props[i]) == 0)
192 return (1);
193 return (0);
194 }
195
196 /*
197 * generate_unique_sharename(sharename)
198 *
199 * Shares are represented in SMF as property groups. Due to share
200 * paths containing characters that are not allowed in SMF names and
201 * the need to be unique, we use UUIDs to construct a unique name.
202 */
203
204 static void
generate_unique_sharename(char * sharename)205 generate_unique_sharename(char *sharename)
206 {
207 uuid_t uuid;
208
209 uuid_generate(uuid);
210 (void) strcpy(sharename, "S-");
211 uuid_unparse(uuid, sharename + 2);
212 }
213
214 /*
215 * valid_protocol(proto)
216 *
217 * Check to see if the specified protocol is a valid one for the
218 * general sharemgr facility. We determine this by checking which
219 * plugin protocols were found.
220 */
221
222 static int
valid_protocol(char * proto)223 valid_protocol(char *proto)
224 {
225 struct sa_proto_plugin *plugin;
226 for (plugin = sap_proto_list; plugin != NULL;
227 plugin = plugin->plugin_next)
228 if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
229 return (1);
230 return (0);
231 }
232
233 /*
234 * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
235 *
236 * Extract the name property group and create the specified type of
237 * node on the provided group. type will be optionset or security.
238 */
239
240 static int
sa_extract_pgroup(xmlNodePtr root,scfutilhandle_t * handle,scf_propertygroup_t * pg,char * nodetype,char * proto,char * sectype)241 sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
242 scf_propertygroup_t *pg,
243 char *nodetype, char *proto, char *sectype)
244 {
245 xmlNodePtr node;
246 scf_iter_t *iter;
247 scf_property_t *prop;
248 scf_value_t *value;
249 char *name;
250 char *valuestr;
251 ssize_t vallen;
252 int ret = SA_OK;
253
254 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
255
256 node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
257 if (node == NULL)
258 return (ret);
259
260 if (proto != NULL)
261 (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
262 if (sectype != NULL)
263 (void) xmlSetProp(node, (xmlChar *)"sectype",
264 (xmlChar *)sectype);
265 /*
266 * Have node to work with so iterate over the properties
267 * in the pg and create option sub nodes.
268 */
269 iter = scf_iter_create(handle->handle);
270 value = scf_value_create(handle->handle);
271 prop = scf_property_create(handle->handle);
272 name = malloc(scf_max_name_len);
273 valuestr = malloc(vallen);
274 /*
275 * Want to iterate through the properties and add them
276 * to the base optionset.
277 */
278 if (iter == NULL || value == NULL || prop == NULL ||
279 valuestr == NULL || name == NULL) {
280 ret = SA_NO_MEMORY;
281 goto out;
282 }
283 if (scf_iter_pg_properties(iter, pg) == 0) {
284 /* Now iterate the properties in the group */
285 while (scf_iter_next_property(iter, prop) > 0) {
286 /* have a property */
287 if (scf_property_get_name(prop, name,
288 scf_max_name_len) > 0) {
289 sa_property_t saprop;
290 /* Some properties are part of the framework */
291 if (skip_property(name))
292 continue;
293 if (scf_property_get_value(prop, value) != 0)
294 continue;
295 if (scf_value_get_astring(value, valuestr,
296 vallen) < 0)
297 continue;
298 saprop = sa_create_property(name, valuestr);
299 if (saprop != NULL) {
300 /*
301 * Since in SMF, don't
302 * recurse. Use xmlAddChild
303 * directly, instead.
304 */
305 (void) xmlAddChild(node,
306 (xmlNodePtr) saprop);
307 }
308 }
309 }
310 }
311 out:
312 /* cleanup to avoid memory leaks */
313 if (value != NULL)
314 scf_value_destroy(value);
315 if (iter != NULL)
316 scf_iter_destroy(iter);
317 if (prop != NULL)
318 scf_property_destroy(prop);
319 if (name != NULL)
320 free(name);
321 if (valuestr != NULL)
322 free(valuestr);
323
324 return (ret);
325 }
326
327 /*
328 * sa_extract_attrs(root, handle, instance)
329 *
330 * Local function to extract the actual attributes/properties from the
331 * property group of the service instance. These are the well known
332 * attributes of "state" and "zfs". If additional attributes are
333 * added, they should be added here.
334 */
335
336 static void
sa_extract_attrs(xmlNodePtr root,scfutilhandle_t * handle,scf_instance_t * instance)337 sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
338 scf_instance_t *instance)
339 {
340 scf_property_t *prop;
341 scf_value_t *value;
342 char *valuestr;
343 ssize_t vallen;
344
345 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
346 prop = scf_property_create(handle->handle);
347 value = scf_value_create(handle->handle);
348 valuestr = malloc(vallen);
349 if (prop == NULL || value == NULL || valuestr == NULL ||
350 scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
351 goto out;
352 }
353 /*
354 * Have a property group with desired name so now get
355 * the known attributes.
356 */
357 if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
358 /* Found the property so get the value */
359 if (scf_property_get_value(prop, value) == 0) {
360 if (scf_value_get_astring(value, valuestr,
361 vallen) >= 0) {
362 (void) xmlSetProp(root, (xmlChar *)"state",
363 (xmlChar *)valuestr);
364 }
365 }
366 }
367 if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
368 /* Found the property so get the value */
369 if (scf_property_get_value(prop, value) == 0) {
370 if (scf_value_get_astring(value, valuestr,
371 vallen) > 0) {
372 (void) xmlSetProp(root, (xmlChar *)"zfs",
373 (xmlChar *)valuestr);
374 }
375 }
376 }
377 out:
378 if (valuestr != NULL)
379 free(valuestr);
380 if (value != NULL)
381 scf_value_destroy(value);
382 if (prop != NULL)
383 scf_property_destroy(prop);
384 }
385
386 /*
387 * List of known share attributes.
388 */
389
390 static char *share_attr[] = {
391 "path",
392 "id",
393 "drive-letter",
394 "exclude",
395 NULL,
396 };
397
398 static int
is_share_attr(char * name)399 is_share_attr(char *name)
400 {
401 int i;
402 for (i = 0; share_attr[i] != NULL; i++)
403 if (strcmp(name, share_attr[i]) == 0)
404 return (1);
405 return (0);
406 }
407
408 /*
409 * _sa_make_resource(node, valuestr)
410 *
411 * Make a resource node on the share node. The valusestr will either
412 * be old format (SMF acceptable string) or new format (pretty much an
413 * arbitrary string with "nnn:" prefixing in order to persist
414 * mapping). The input valuestr will get modified in place. This is
415 * only used in SMF repository parsing. A possible third field will be
416 * a "description" string.
417 */
418
419 static void
_sa_make_resource(xmlNodePtr node,char * valuestr)420 _sa_make_resource(xmlNodePtr node, char *valuestr)
421 {
422 char *idx;
423 char *name;
424 char *description = NULL;
425
426 idx = valuestr;
427 name = strchr(valuestr, ':');
428 if (name == NULL) {
429 /* this is old form so give an index of "0" */
430 idx = "0";
431 name = valuestr;
432 } else {
433 /* NUL the ':' and move past it */
434 *name++ = '\0';
435 /* There could also be a description string */
436 description = strchr(name, ':');
437 if (description != NULL)
438 *description++ = '\0';
439 }
440 node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
441 if (node != NULL) {
442 (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
443 (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
444 /* SMF values are always persistent */
445 (void) xmlSetProp(node, (xmlChar *)"type",
446 (xmlChar *)"persist");
447 if (description != NULL && strlen(description) > 0) {
448 (void) xmlNewChild(node, NULL, (xmlChar *)"description",
449 (xmlChar *)description);
450 }
451 }
452 }
453
454
455 /*
456 * sa_share_from_pgroup
457 *
458 * Extract the share definition from the share property group. We do
459 * some sanity checking to avoid bad data.
460 *
461 * Since this is only constructing the internal data structures, we
462 * don't use the sa_* functions most of the time.
463 */
464 void
sa_share_from_pgroup(xmlNodePtr root,scfutilhandle_t * handle,scf_propertygroup_t * pg,char * id)465 sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
466 scf_propertygroup_t *pg, char *id)
467 {
468 xmlNodePtr node;
469 char *name;
470 scf_iter_t *iter;
471 scf_property_t *prop;
472 scf_value_t *value;
473 ssize_t vallen;
474 char *valuestr;
475 int ret = SA_OK;
476 int have_path = 0;
477
478 /*
479 * While preliminary check (starts with 'S') passed before
480 * getting here. Need to make sure it is in ID syntax
481 * (Snnnnnn). Note that shares with properties have similar
482 * pgroups.
483 */
484 vallen = strlen(id);
485 if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
486 uuid_t uuid;
487 if (strncmp(id, SA_SHARE_PG_PREFIX,
488 SA_SHARE_PG_PREFIXLEN) != 0 ||
489 uuid_parse(id + 2, uuid) < 0)
490 return;
491 } else {
492 return;
493 }
494
495 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
496
497 iter = scf_iter_create(handle->handle);
498 value = scf_value_create(handle->handle);
499 prop = scf_property_create(handle->handle);
500 name = malloc(scf_max_name_len);
501 valuestr = malloc(vallen);
502
503 /*
504 * Construct the share XML node. It is similar to sa_add_share
505 * but never changes the repository. Also, there won't be any
506 * ZFS or transient shares. Root will be the group it is
507 * associated with.
508 */
509 node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
510 if (node != NULL) {
511 /*
512 * Make sure the UUID part of the property group is
513 * stored in the share "id" property. We use this
514 * later.
515 */
516 (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
517 (void) xmlSetProp(node, (xmlChar *)"type",
518 (xmlChar *)"persist");
519 }
520
521 if (iter == NULL || value == NULL || prop == NULL || name == NULL)
522 goto out;
523
524 /* Iterate over the share pg properties */
525 if (scf_iter_pg_properties(iter, pg) != 0)
526 goto out;
527
528 while (scf_iter_next_property(iter, prop) > 0) {
529 ret = SA_SYSTEM_ERR; /* assume the worst */
530 if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
531 if (scf_property_get_value(prop, value) == 0) {
532 if (scf_value_get_astring(value, valuestr,
533 vallen) >= 0) {
534 ret = SA_OK;
535 }
536 } else if (strcmp(name, "resource") == 0) {
537 ret = SA_OK;
538 }
539 }
540 if (ret != SA_OK)
541 continue;
542 /*
543 * Check that we have the "path" property in
544 * name. The string in name will always be nul
545 * terminated if scf_property_get_name()
546 * succeeded.
547 */
548 if (strcmp(name, "path") == 0)
549 have_path = 1;
550 if (is_share_attr(name)) {
551 /*
552 * If a share attr, then simple -
553 * usually path and id name
554 */
555 (void) xmlSetProp(node, (xmlChar *)name,
556 (xmlChar *)valuestr);
557 } else if (strcmp(name, "resource") == 0) {
558 /*
559 * Resource names handled differently since
560 * there can be multiple on each share. The
561 * "resource" id must be preserved since this
562 * will be used by some protocols in mapping
563 * "property spaces" to names and is always
564 * used to create SMF property groups specific
565 * to resources. CIFS needs this. The first
566 * value is present so add and then loop for
567 * any additional. Since this is new and
568 * previous values may exist, handle
569 * conversions.
570 */
571 scf_iter_t *viter;
572 viter = scf_iter_create(handle->handle);
573 if (viter != NULL &&
574 scf_iter_property_values(viter, prop) == 0) {
575 while (scf_iter_next_value(viter, value) > 0) {
576 /* Have a value so process it */
577 if (scf_value_get_ustring(value,
578 valuestr, vallen) >= 0) {
579 /* have a ustring */
580 _sa_make_resource(node,
581 valuestr);
582 } else if (scf_value_get_astring(value,
583 valuestr, vallen) >= 0) {
584 /* have an astring */
585 _sa_make_resource(node,
586 valuestr);
587 }
588 }
589 scf_iter_destroy(viter);
590 }
591 } else {
592 if (strcmp(name, "description") == 0) {
593 /* We have a description node */
594 xmlNodePtr desc;
595 desc = xmlNewChild(node, NULL,
596 (xmlChar *)"description", NULL);
597 if (desc != NULL)
598 xmlNodeSetContent(desc,
599 (xmlChar *)valuestr);
600 }
601 }
602 }
603 out:
604 /*
605 * A share without a path is broken so we want to not include
606 * these. They shouldn't happen but if you kill a sharemgr in
607 * the process of creating a share, it could happen. They
608 * should be harmless. It is also possible that another
609 * sharemgr is running and in the process of creating a share.
610 */
611 if (have_path == 0 && node != NULL) {
612 xmlUnlinkNode(node);
613 xmlFreeNode(node);
614 }
615 if (name != NULL)
616 free(name);
617 if (valuestr != NULL)
618 free(valuestr);
619 if (value != NULL)
620 scf_value_destroy(value);
621 if (iter != NULL)
622 scf_iter_destroy(iter);
623 if (prop != NULL)
624 scf_property_destroy(prop);
625 }
626
627 /*
628 * find_share_by_id(shareid)
629 *
630 * Search all shares in all groups until we find the share represented
631 * by "id".
632 */
633
634 static sa_share_t
find_share_by_id(sa_handle_t handle,char * shareid)635 find_share_by_id(sa_handle_t handle, char *shareid)
636 {
637 sa_group_t group;
638 sa_share_t share = NULL;
639 char *id = NULL;
640 int done = 0;
641
642 for (group = sa_get_group(handle, NULL);
643 group != NULL && !done;
644 group = sa_get_next_group(group)) {
645 for (share = sa_get_share(group, NULL);
646 share != NULL;
647 share = sa_get_next_share(share)) {
648 id = sa_get_share_attr(share, "id");
649 if (id != NULL && strcmp(id, shareid) == 0) {
650 sa_free_attr_string(id);
651 id = NULL;
652 done++;
653 break;
654 }
655 if (id != NULL) {
656 sa_free_attr_string(id);
657 id = NULL;
658 }
659 }
660 }
661 return (share);
662 }
663
664 /*
665 * find_resource_by_index(share, index)
666 *
667 * Search the resource records on the share for the id index.
668 */
669 static sa_resource_t
find_resource_by_index(sa_share_t share,char * index)670 find_resource_by_index(sa_share_t share, char *index)
671 {
672 sa_resource_t resource;
673 sa_resource_t found = NULL;
674 char *id;
675
676 for (resource = sa_get_share_resource(share, NULL);
677 resource != NULL && found == NULL;
678 resource = sa_get_next_resource(resource)) {
679 id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
680 if (id != NULL) {
681 if (strcmp(id, index) == 0) {
682 /* found it so save in "found" */
683 found = resource;
684 }
685 sa_free_attr_string(id);
686 }
687 }
688 return (found);
689 }
690
691 /*
692 * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
693 *
694 * Extract share properties from the SMF property group. More sanity
695 * checks are done and the share object is created. We ignore some
696 * errors that could exist in the repository and only worry about
697 * property groups that validate in naming.
698 */
699
700 static int
sa_share_props_from_pgroup(xmlNodePtr root,scfutilhandle_t * handle,scf_propertygroup_t * pg,char * id,sa_handle_t sahandle)701 sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
702 scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
703 {
704 xmlNodePtr node;
705 char *name = NULL;
706 scf_iter_t *iter = NULL;
707 scf_property_t *prop = NULL;
708 scf_value_t *value = NULL;
709 ssize_t vallen;
710 char *valuestr = NULL;
711 int ret = SA_OK;
712 char *sectype = NULL;
713 char *proto;
714 sa_share_t share;
715 uuid_t uuid;
716
717 /*
718 * While preliminary check (starts with 'S') passed before
719 * getting here. Need to make sure it is in ID syntax
720 * (Snnnnnn). Note that shares with properties have similar
721 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
722 * characters, it is likely one of the protocol/security
723 * versions.
724 */
725 vallen = strlen(id);
726 if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
727 /*
728 * It is ok to not have what we thought since someone might
729 * have added a name via SMF.
730 */
731 return (ret);
732 }
733 if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
734 proto = strchr(id, '_');
735 if (proto == NULL)
736 return (ret);
737 *proto++ = '\0';
738 if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
739 return (ret);
740 /*
741 * probably a legal optionset so check a few more
742 * syntax points below.
743 */
744 if (*proto == '\0') {
745 /* not a valid proto (null) */
746 return (ret);
747 }
748
749 sectype = strchr(proto, '_');
750 if (sectype != NULL)
751 *sectype++ = '\0';
752 if (!valid_protocol(proto))
753 return (ret);
754 }
755
756 /*
757 * To get here, we have a valid protocol and possibly a
758 * security. We now have to find the share that it is really
759 * associated with. The "id" portion of the pgroup name will
760 * match.
761 */
762
763 share = find_share_by_id(sahandle, id);
764 if (share == NULL)
765 return (SA_BAD_PATH);
766
767 root = (xmlNodePtr)share;
768
769 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
770
771 if (sectype == NULL)
772 node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
773 else {
774 if (isdigit((int)*sectype)) {
775 sa_resource_t resource;
776 /*
777 * If sectype[0] is a digit, then it is an index into
778 * the resource names. We need to find a resource
779 * record and then get the properties into an
780 * optionset. The optionset becomes the "node" and the
781 * rest is hung off of the share.
782 */
783 resource = find_resource_by_index(share, sectype);
784 if (resource != NULL) {
785 node = xmlNewChild(resource, NULL,
786 (xmlChar *)"optionset", NULL);
787 } else {
788 /* This shouldn't happen. */
789 ret = SA_SYSTEM_ERR;
790 goto out;
791 }
792 } else {
793 /*
794 * If not a digit, then it is a security type
795 * (alternate option space). Security types start with
796 * an alphabetic.
797 */
798 node = xmlNewChild(root, NULL, (xmlChar *)"security",
799 NULL);
800 if (node != NULL)
801 (void) xmlSetProp(node, (xmlChar *)"sectype",
802 (xmlChar *)sectype);
803 }
804 }
805 if (node == NULL) {
806 ret = SA_NO_MEMORY;
807 goto out;
808 }
809
810 (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
811 /* now find the properties */
812 iter = scf_iter_create(handle->handle);
813 value = scf_value_create(handle->handle);
814 prop = scf_property_create(handle->handle);
815 name = malloc(scf_max_name_len);
816 valuestr = malloc(vallen);
817
818 if (iter == NULL || value == NULL || prop == NULL || name == NULL)
819 goto out;
820
821 /* iterate over the share pg properties */
822 if (scf_iter_pg_properties(iter, pg) == 0) {
823 while (scf_iter_next_property(iter, prop) > 0) {
824 ret = SA_SYSTEM_ERR; /* assume the worst */
825 if (scf_property_get_name(prop, name,
826 scf_max_name_len) > 0) {
827 if (scf_property_get_value(prop, value) == 0) {
828 if (scf_value_get_astring(value,
829 valuestr, vallen) >= 0) {
830 ret = SA_OK;
831 }
832 }
833 } else {
834 ret = SA_SYSTEM_ERR;
835 }
836 if (ret == SA_OK) {
837 sa_property_t prop;
838 prop = sa_create_property(name, valuestr);
839 if (prop != NULL)
840 prop = (sa_property_t)xmlAddChild(node,
841 (xmlNodePtr)prop);
842 else
843 ret = SA_NO_MEMORY;
844 }
845 }
846 } else {
847 ret = SA_SYSTEM_ERR;
848 }
849 out:
850 if (iter != NULL)
851 scf_iter_destroy(iter);
852 if (value != NULL)
853 scf_value_destroy(value);
854 if (prop != NULL)
855 scf_property_destroy(prop);
856 if (name != NULL)
857 free(name);
858 if (valuestr != NULL)
859 free(valuestr);
860 return (ret);
861 }
862
863 /*
864 * sa_extract_group(root, handle, instance)
865 *
866 * Get the config info for this instance of a group and create the XML
867 * subtree from it.
868 */
869
870 static int
sa_extract_group(xmlNodePtr root,scfutilhandle_t * handle,scf_instance_t * instance,sa_handle_t sahandle)871 sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
872 scf_instance_t *instance, sa_handle_t sahandle)
873 {
874 char *buff;
875 xmlNodePtr node;
876 scf_iter_t *iter;
877 char *proto;
878 char *sectype;
879 boolean_t have_shares = B_FALSE;
880 boolean_t is_default = B_FALSE;
881 boolean_t is_nfs = B_FALSE;
882 int ret = SA_OK;
883 int err;
884
885 buff = malloc(scf_max_name_len);
886 if (buff == NULL)
887 return (SA_NO_MEMORY);
888
889 iter = scf_iter_create(handle->handle);
890 if (iter == NULL) {
891 ret = SA_NO_MEMORY;
892 goto out;
893 }
894
895 if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
896 node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
897 if (node == NULL) {
898 ret = SA_NO_MEMORY;
899 goto out;
900 }
901 (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
902 if (strcmp(buff, "default") == 0)
903 is_default = B_TRUE;
904
905 sa_extract_attrs(node, handle, instance);
906 /*
907 * Iterate through all the property groups
908 * looking for those with security or
909 * optionset prefixes. The names of the
910 * matching pgroups are parsed to get the
911 * protocol, and for security, the sectype.
912 * Syntax is as follows:
913 * optionset | optionset_<proto>
914 * security_default | security_<proto>_<sectype>
915 * "operation" is handled by
916 * sa_extract_attrs().
917 */
918 if (scf_iter_instance_pgs(iter, instance) != 0) {
919 ret = SA_NO_MEMORY;
920 goto out;
921 }
922 while (scf_iter_next_pg(iter, handle->pg) > 0) {
923 /* Have a pgroup so sort it out */
924 ret = scf_pg_get_name(handle->pg, buff,
925 scf_max_name_len);
926 if (ret <= 0)
927 continue;
928 is_nfs = B_FALSE;
929
930 if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
931 sa_share_from_pgroup(node, handle,
932 handle->pg, buff);
933 have_shares = B_TRUE;
934 } else if (strncmp(buff, "optionset", 9) == 0) {
935 char *nodetype = "optionset";
936 /* Have an optionset */
937 sectype = NULL;
938 proto = strchr(buff, '_');
939 if (proto != NULL) {
940 *proto++ = '\0';
941 sectype = strchr(proto, '_');
942 if (sectype != NULL) {
943 *sectype++ = '\0';
944 nodetype = "security";
945 }
946 is_nfs = strcmp(proto, "nfs") == 0;
947 } else if (strlen(buff) > 9) {
948 /*
949 * This can only occur if
950 * someone has made changes
951 * via an SMF command. Since
952 * this would be an unknown
953 * syntax, we just ignore it.
954 */
955 continue;
956 }
957 /*
958 * If the group is not "default" or is
959 * "default" and is_nfs, then extract the
960 * pgroup. If it is_default and !is_nfs,
961 * then we have an error and should remove
962 * the extraneous protocols. We don't care
963 * about errors on scf_pg_delete since we
964 * might not have permission during an
965 * extract only.
966 */
967 if (!is_default || is_nfs) {
968 ret = sa_extract_pgroup(node, handle,
969 handle->pg, nodetype, proto,
970 sectype);
971 } else {
972 err = scf_pg_delete(handle->pg);
973 if (err == 0)
974 (void) fprintf(stderr,
975 dgettext(TEXT_DOMAIN,
976 "Removed protocol \"%s\" "
977 "from group \"default\"\n"),
978 proto);
979 }
980 } else if (strncmp(buff, "security", 8) == 0) {
981 /*
982 * Have a security (note that
983 * this should change in the
984 * future)
985 */
986 proto = strchr(buff, '_');
987 sectype = NULL;
988 if (proto != NULL) {
989 *proto++ = '\0';
990 sectype = strchr(proto, '_');
991 if (sectype != NULL)
992 *sectype++ = '\0';
993 if (strcmp(proto, "default") == 0)
994 proto = NULL;
995 }
996 ret = sa_extract_pgroup(node, handle,
997 handle->pg, "security", proto, sectype);
998 }
999 /* Ignore everything else */
1000 }
1001 /*
1002 * Make sure we have a valid default group.
1003 * On first boot, default won't have any
1004 * protocols defined and won't be enabled (but
1005 * should be). "default" only has NFS enabled on it.
1006 */
1007 if (is_default) {
1008 char *state = sa_get_group_attr((sa_group_t)node,
1009 "state");
1010
1011 if (state == NULL) {
1012 /* set attribute to enabled */
1013 (void) sa_set_group_attr((sa_group_t)node,
1014 "state", "enabled");
1015 (void) sa_create_optionset((sa_group_t)node,
1016 "nfs");
1017 } else {
1018 sa_free_attr_string(state);
1019 }
1020 }
1021 /* Do a second pass if shares were found */
1022 if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
1023 while (scf_iter_next_pg(iter, handle->pg) > 0) {
1024 /*
1025 * Have a pgroup so see if it is a
1026 * share optionset
1027 */
1028 err = scf_pg_get_name(handle->pg, buff,
1029 scf_max_name_len);
1030 if (err <= 0)
1031 continue;
1032 if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
1033 ret = sa_share_props_from_pgroup(node,
1034 handle, handle->pg, buff,
1035 sahandle);
1036 }
1037 }
1038 }
1039 }
1040 out:
1041 if (iter != NULL)
1042 scf_iter_destroy(iter);
1043 if (buff != NULL)
1044 free(buff);
1045 return (ret);
1046 }
1047
1048 /*
1049 * sa_extract_defaults(root, handle, instance)
1050 *
1051 * Local function to find the default properties that live in the
1052 * default instance's "operation" property group.
1053 */
1054
1055 static void
sa_extract_defaults(xmlNodePtr root,scfutilhandle_t * handle,scf_instance_t * instance)1056 sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
1057 scf_instance_t *instance)
1058 {
1059 xmlNodePtr node;
1060 scf_property_t *prop;
1061 scf_value_t *value;
1062 char *valuestr;
1063 ssize_t vallen;
1064
1065 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1066 prop = scf_property_create(handle->handle);
1067 value = scf_value_create(handle->handle);
1068 valuestr = malloc(vallen);
1069
1070 if (prop == NULL || value == NULL || vallen == 0 ||
1071 scf_instance_get_pg(instance, "operation", handle->pg) != 0)
1072 goto out;
1073
1074 if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
1075 goto out;
1076
1077 /* Found the property so get the value */
1078 if (scf_property_get_value(prop, value) == 0) {
1079 if (scf_value_get_astring(value, valuestr, vallen) > 0) {
1080 node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
1081 NULL);
1082 if (node != NULL) {
1083 (void) xmlSetProp(node, (xmlChar *)"timestamp",
1084 (xmlChar *)valuestr);
1085 (void) xmlSetProp(node, (xmlChar *)"path",
1086 (xmlChar *)SA_LEGACY_DFSTAB);
1087 }
1088 }
1089 }
1090 out:
1091 if (valuestr != NULL)
1092 free(valuestr);
1093 if (value != NULL)
1094 scf_value_destroy(value);
1095 if (prop != NULL)
1096 scf_property_destroy(prop);
1097 }
1098
1099
1100 /*
1101 * sa_get_config(handle, root, doc, sahandle)
1102 *
1103 * Walk the SMF repository for /network/shares/group and find all the
1104 * instances. These become group names. Then add the XML structure
1105 * below the groups based on property groups and properties.
1106 */
1107 int
sa_get_config(scfutilhandle_t * handle,xmlNodePtr root,sa_handle_t sahandle)1108 sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
1109 {
1110 int ret = SA_OK;
1111 scf_instance_t *instance;
1112 scf_iter_t *iter;
1113 char buff[BUFSIZ * 2];
1114
1115 instance = scf_instance_create(handle->handle);
1116 iter = scf_iter_create(handle->handle);
1117 if (instance != NULL && iter != NULL) {
1118 if ((ret = scf_iter_service_instances(iter,
1119 handle->service)) == 0) {
1120 while ((ret = scf_iter_next_instance(iter,
1121 instance)) > 0) {
1122 if (scf_instance_get_name(instance, buff,
1123 sizeof (buff)) > 0) {
1124 if (strcmp(buff, "default") == 0)
1125 sa_extract_defaults(root,
1126 handle, instance);
1127 ret = sa_extract_group(root, handle,
1128 instance, sahandle);
1129 }
1130 }
1131 }
1132 }
1133
1134 /* Always cleanup these */
1135 if (instance != NULL)
1136 scf_instance_destroy(instance);
1137 if (iter != NULL)
1138 scf_iter_destroy(iter);
1139 return (ret);
1140 }
1141
1142 /*
1143 * sa_get_instance(handle, instance)
1144 *
1145 * Get the instance of the group service. This is actually the
1146 * specific group name. The instance is needed for all property and
1147 * control operations.
1148 */
1149
1150 int
sa_get_instance(scfutilhandle_t * handle,char * instname)1151 sa_get_instance(scfutilhandle_t *handle, char *instname)
1152 {
1153 if (scf_service_get_instance(handle->service, instname,
1154 handle->instance) != 0) {
1155 return (SA_NO_SUCH_GROUP);
1156 }
1157 return (SA_OK);
1158 }
1159
1160 /*
1161 * sa_create_instance(handle, instname)
1162 *
1163 * Create a new SMF service instance. There can only be one with a
1164 * given name.
1165 */
1166
1167 int
sa_create_instance(scfutilhandle_t * handle,char * instname)1168 sa_create_instance(scfutilhandle_t *handle, char *instname)
1169 {
1170 int ret = SA_OK;
1171 char instance[SA_GROUP_INST_LEN];
1172 if (scf_service_add_instance(handle->service, instname,
1173 handle->instance) != 0) {
1174 /* better error returns need to be added based on real error */
1175 if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
1176 ret = SA_NO_PERMISSION;
1177 else
1178 ret = SA_DUPLICATE_NAME;
1179 } else {
1180 /* have the service created, so enable it */
1181 (void) snprintf(instance, sizeof (instance), "%s:%s",
1182 SA_SVC_FMRI_BASE, instname);
1183 (void) smf_enable_instance(instance, 0);
1184 }
1185 return (ret);
1186 }
1187
1188 /*
1189 * sa_delete_instance(handle, instname)
1190 *
1191 * When a group goes away, we also remove the service instance.
1192 */
1193
1194 int
sa_delete_instance(scfutilhandle_t * handle,char * instname)1195 sa_delete_instance(scfutilhandle_t *handle, char *instname)
1196 {
1197 int ret;
1198
1199 if (strcmp(instname, "default") == 0) {
1200 ret = SA_NO_PERMISSION;
1201 } else {
1202 if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
1203 if (scf_instance_delete(handle->instance) != 0)
1204 /* need better analysis */
1205 ret = SA_NO_PERMISSION;
1206 }
1207 }
1208 return (ret);
1209 }
1210
1211 /*
1212 * sa_create_pgroup(handle, pgroup)
1213 *
1214 * create a new property group
1215 */
1216
1217 int
sa_create_pgroup(scfutilhandle_t * handle,char * pgroup)1218 sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
1219 {
1220 int ret = SA_OK;
1221 int persist = 0;
1222
1223 /*
1224 * Only create a handle if it doesn't exist. It is ok to exist
1225 * since the pg handle will be set as a side effect.
1226 */
1227 if (handle->pg == NULL)
1228 handle->pg = scf_pg_create(handle->handle);
1229
1230 /*
1231 * Special case for a non-persistent property group. This is
1232 * internal use only.
1233 */
1234 if (*pgroup == '*') {
1235 persist = SCF_PG_FLAG_NONPERSISTENT;
1236 pgroup++;
1237 }
1238
1239 /*
1240 * If the pgroup exists, we are done. If it doesn't, then we
1241 * need to actually add one to the service instance.
1242 */
1243 if (scf_instance_get_pg(handle->instance,
1244 pgroup, handle->pg) != 0) {
1245
1246 /* Doesn't exist so create one */
1247 if (scf_instance_add_pg(handle->instance, pgroup,
1248 SCF_GROUP_APPLICATION, persist, handle->pg) != 0) {
1249 switch (scf_error()) {
1250 case SCF_ERROR_PERMISSION_DENIED:
1251 ret = SA_NO_PERMISSION;
1252 break;
1253 default:
1254 ret = SA_SYSTEM_ERR;
1255 break;
1256 }
1257 }
1258 }
1259 return (ret);
1260 }
1261
1262 /*
1263 * sa_delete_pgroup(handle, pgroup)
1264 *
1265 * Remove the property group from the current instance of the service,
1266 * but only if it actually exists.
1267 */
1268
1269 int
sa_delete_pgroup(scfutilhandle_t * handle,char * pgroup)1270 sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
1271 {
1272 int ret = SA_OK;
1273 /*
1274 * Only delete if it does exist.
1275 */
1276 if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
1277 /* does exist so delete it */
1278 if (scf_pg_delete(handle->pg) != 0)
1279 ret = SA_SYSTEM_ERR;
1280 } else {
1281 ret = SA_SYSTEM_ERR;
1282 }
1283 if (ret == SA_SYSTEM_ERR &&
1284 scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1285 ret = SA_NO_PERMISSION;
1286 }
1287 return (ret);
1288 }
1289
1290 /*
1291 * sa_start_transaction(handle, pgroup)
1292 *
1293 * Start an SMF transaction so we can deal with properties. it would
1294 * be nice to not have to expose this, but we have to in order to
1295 * optimize.
1296 *
1297 * Basic model is to hold the transaction in the handle and allow
1298 * property adds/deletes/updates to be added then close the
1299 * transaction (or abort). There may eventually be a need to handle
1300 * other types of transaction mechanisms but we don't do that now.
1301 *
1302 * An sa_start_transaction must be followed by either an
1303 * sa_end_transaction or sa_abort_transaction before another
1304 * sa_start_transaction can be done.
1305 */
1306
1307 int
sa_start_transaction(scfutilhandle_t * handle,char * propgroup)1308 sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
1309 {
1310 int ret = SA_OK;
1311 /*
1312 * Lookup the property group and create it if it doesn't already
1313 * exist.
1314 */
1315 if (handle == NULL)
1316 return (SA_CONFIG_ERR);
1317
1318 if (handle->scf_state == SCH_STATE_INIT) {
1319 ret = sa_create_pgroup(handle, propgroup);
1320 if (ret == SA_OK) {
1321 handle->trans = scf_transaction_create(handle->handle);
1322 if (handle->trans != NULL) {
1323 if (scf_transaction_start(handle->trans,
1324 handle->pg) != 0) {
1325 ret = SA_SYSTEM_ERR;
1326 }
1327 if (ret != SA_OK) {
1328 scf_transaction_destroy(handle->trans);
1329 handle->trans = NULL;
1330 }
1331 } else {
1332 ret = SA_SYSTEM_ERR;
1333 }
1334 }
1335 }
1336 if (ret == SA_SYSTEM_ERR &&
1337 scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1338 ret = SA_NO_PERMISSION;
1339 }
1340 return (ret);
1341 }
1342
1343
1344 /*
1345 * sa_end_transaction(scfhandle, sahandle)
1346 *
1347 * Commit the changes that were added to the transaction in the
1348 * handle. Do all necessary cleanup.
1349 */
1350
1351 int
sa_end_transaction(scfutilhandle_t * handle,sa_handle_impl_t sahandle)1352 sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle)
1353 {
1354 int ret = SA_OK;
1355
1356 if (handle == NULL || handle->trans == NULL || sahandle == NULL) {
1357 ret = SA_SYSTEM_ERR;
1358 } else {
1359 if (scf_transaction_commit(handle->trans) < 0)
1360 ret = SA_SYSTEM_ERR;
1361 scf_transaction_destroy_children(handle->trans);
1362 scf_transaction_destroy(handle->trans);
1363 if (ret == SA_OK)
1364 set_transaction_tstamp(sahandle);
1365 handle->trans = NULL;
1366 }
1367 return (ret);
1368 }
1369
1370 /*
1371 * sa_abort_transaction(handle)
1372 *
1373 * Abort the changes that were added to the transaction in the
1374 * handle. Do all necessary cleanup.
1375 */
1376
1377 void
sa_abort_transaction(scfutilhandle_t * handle)1378 sa_abort_transaction(scfutilhandle_t *handle)
1379 {
1380 if (handle->trans != NULL) {
1381 scf_transaction_reset_all(handle->trans);
1382 scf_transaction_destroy_children(handle->trans);
1383 scf_transaction_destroy(handle->trans);
1384 handle->trans = NULL;
1385 }
1386 }
1387
1388 /*
1389 * set_transaction_tstamp(sahandle)
1390 *
1391 * After a successful transaction commit, update the timestamp of the
1392 * last transaction. This lets us detect changes from other processes.
1393 */
1394 static void
set_transaction_tstamp(sa_handle_impl_t sahandle)1395 set_transaction_tstamp(sa_handle_impl_t sahandle)
1396 {
1397 char tstring[32];
1398 struct timeval tv;
1399 scfutilhandle_t *scfhandle;
1400
1401 if (sahandle == NULL || sahandle->scfhandle == NULL)
1402 return;
1403
1404 scfhandle = sahandle->scfhandle;
1405
1406 if (sa_get_instance(scfhandle, "default") != SA_OK)
1407 return;
1408
1409 if (gettimeofday(&tv, NULL) != 0)
1410 return;
1411
1412 if (sa_start_transaction(scfhandle, "*state") != SA_OK)
1413 return;
1414
1415 sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv));
1416 (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans);
1417 if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) ==
1418 SA_OK) {
1419 /*
1420 * While best if it succeeds, a failure doesn't cause
1421 * problems and we will ignore it anyway.
1422 */
1423 (void) scf_transaction_commit(scfhandle->trans);
1424 scf_transaction_destroy_children(scfhandle->trans);
1425 scf_transaction_destroy(scfhandle->trans);
1426 } else {
1427 sa_abort_transaction(scfhandle);
1428 }
1429 }
1430
1431 /*
1432 * sa_set_property(handle, prop, value)
1433 *
1434 * Set a property transaction entry into the pending SMF transaction.
1435 */
1436
1437 int
sa_set_property(scfutilhandle_t * handle,char * propname,char * valstr)1438 sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
1439 {
1440 int ret = SA_OK;
1441 scf_value_t *value;
1442 scf_transaction_entry_t *entry;
1443 /*
1444 * Properties must be set in transactions and don't take
1445 * effect until the transaction has been ended/committed.
1446 */
1447 value = scf_value_create(handle->handle);
1448 entry = scf_entry_create(handle->handle);
1449 if (value != NULL && entry != NULL) {
1450 if (scf_transaction_property_change(handle->trans, entry,
1451 propname, SCF_TYPE_ASTRING) == 0 ||
1452 scf_transaction_property_new(handle->trans, entry,
1453 propname, SCF_TYPE_ASTRING) == 0) {
1454 if (scf_value_set_astring(value, valstr) == 0) {
1455 if (scf_entry_add_value(entry, value) != 0) {
1456 ret = SA_SYSTEM_ERR;
1457 scf_value_destroy(value);
1458 }
1459 /* The value is in the transaction */
1460 value = NULL;
1461 } else {
1462 /* Value couldn't be constructed */
1463 ret = SA_SYSTEM_ERR;
1464 }
1465 /* The entry is in the transaction */
1466 entry = NULL;
1467 } else {
1468 ret = SA_SYSTEM_ERR;
1469 }
1470 } else {
1471 ret = SA_SYSTEM_ERR;
1472 }
1473 if (ret == SA_SYSTEM_ERR) {
1474 switch (scf_error()) {
1475 case SCF_ERROR_PERMISSION_DENIED:
1476 ret = SA_NO_PERMISSION;
1477 break;
1478 }
1479 }
1480 /*
1481 * Cleanup if there were any errors that didn't leave these
1482 * values where they would be cleaned up later.
1483 */
1484 if (value != NULL)
1485 scf_value_destroy(value);
1486 if (entry != NULL)
1487 scf_entry_destroy(entry);
1488 return (ret);
1489 }
1490
1491 /*
1492 * check_resource(share)
1493 *
1494 * Check to see if share has any persistent resources. We don't want
1495 * to save if they are all transient.
1496 */
1497 static int
check_resource(sa_share_t share)1498 check_resource(sa_share_t share)
1499 {
1500 sa_resource_t resource;
1501 int ret = B_FALSE;
1502
1503 for (resource = sa_get_share_resource(share, NULL);
1504 resource != NULL && ret == B_FALSE;
1505 resource = sa_get_next_resource(resource)) {
1506 char *type;
1507 type = sa_get_resource_attr(resource, "type");
1508 if (type != NULL) {
1509 if (strcmp(type, "transient") != 0) {
1510 ret = B_TRUE;
1511 }
1512 sa_free_attr_string(type);
1513 }
1514 }
1515 return (ret);
1516 }
1517
1518 /*
1519 * sa_set_resource_property(handle, prop, value)
1520 *
1521 * set a property transaction entry into the pending SMF
1522 * transaction. We don't want to include any transient resources
1523 */
1524
1525 static int
sa_set_resource_property(scfutilhandle_t * handle,sa_share_t share)1526 sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
1527 {
1528 int ret = SA_OK;
1529 scf_value_t *value;
1530 scf_transaction_entry_t *entry;
1531 sa_resource_t resource;
1532 char *valstr;
1533 char *idstr;
1534 char *description;
1535 char *propstr = NULL;
1536 size_t strsize;
1537
1538 /* don't bother if no persistent resources */
1539 if (check_resource(share) == B_FALSE)
1540 return (ret);
1541
1542 /*
1543 * properties must be set in transactions and don't take
1544 * effect until the transaction has been ended/committed.
1545 */
1546 entry = scf_entry_create(handle->handle);
1547 if (entry == NULL)
1548 return (SA_SYSTEM_ERR);
1549
1550 if (scf_transaction_property_change(handle->trans, entry,
1551 "resource", SCF_TYPE_ASTRING) != 0 &&
1552 scf_transaction_property_new(handle->trans, entry,
1553 "resource", SCF_TYPE_ASTRING) != 0) {
1554 scf_entry_destroy(entry);
1555 return (SA_SYSTEM_ERR);
1556
1557 }
1558 for (resource = sa_get_share_resource(share, NULL);
1559 resource != NULL;
1560 resource = sa_get_next_resource(resource)) {
1561 value = scf_value_create(handle->handle);
1562 if (value == NULL) {
1563 ret = SA_NO_MEMORY;
1564 break;
1565 }
1566 /* Get size of complete string */
1567 valstr = sa_get_resource_attr(resource, "name");
1568 idstr = sa_get_resource_attr(resource, "id");
1569 description = sa_get_resource_description(resource);
1570 strsize = (valstr != NULL) ? strlen(valstr) : 0;
1571 strsize += (idstr != NULL) ? strlen(idstr) : 0;
1572 strsize += (description != NULL) ? strlen(description) : 0;
1573 if (strsize > 0) {
1574 strsize += 3; /* add nul and ':' */
1575 propstr = (char *)malloc(strsize);
1576 if (propstr == NULL) {
1577 scf_value_destroy(value);
1578 ret = SA_NO_MEMORY;
1579 goto err;
1580 }
1581 if (idstr == NULL)
1582 (void) snprintf(propstr, strsize, "%s",
1583 valstr ? valstr : "");
1584 else
1585 (void) snprintf(propstr, strsize, "%s:%s:%s",
1586 idstr, valstr ? valstr : "",
1587 description ? description : "");
1588 if (scf_value_set_astring(value, propstr) != 0) {
1589 ret = SA_SYSTEM_ERR;
1590 free(propstr);
1591 scf_value_destroy(value);
1592 break;
1593 }
1594 if (scf_entry_add_value(entry, value) != 0) {
1595 ret = SA_SYSTEM_ERR;
1596 free(propstr);
1597 scf_value_destroy(value);
1598 break;
1599 }
1600 /* the value is in the transaction */
1601 value = NULL;
1602 free(propstr);
1603 }
1604 err:
1605 if (valstr != NULL) {
1606 sa_free_attr_string(valstr);
1607 valstr = NULL;
1608 }
1609 if (idstr != NULL) {
1610 sa_free_attr_string(idstr);
1611 idstr = NULL;
1612 }
1613 if (description != NULL) {
1614 sa_free_share_description(description);
1615 description = NULL;
1616 }
1617 }
1618 /* the entry is in the transaction */
1619 entry = NULL;
1620
1621 if (valstr != NULL)
1622 sa_free_attr_string(valstr);
1623 if (idstr != NULL)
1624 sa_free_attr_string(idstr);
1625 if (description != NULL)
1626 sa_free_share_description(description);
1627
1628 if (ret == SA_SYSTEM_ERR) {
1629 switch (scf_error()) {
1630 case SCF_ERROR_PERMISSION_DENIED:
1631 ret = SA_NO_PERMISSION;
1632 break;
1633 }
1634 }
1635 /*
1636 * cleanup if there were any errors that didn't leave
1637 * these values where they would be cleaned up later.
1638 */
1639 if (entry != NULL)
1640 scf_entry_destroy(entry);
1641
1642 return (ret);
1643 }
1644
1645 /*
1646 * sa_commit_share(handle, group, share)
1647 *
1648 * Commit this share to the repository.
1649 * properties are added if they exist but can be added later.
1650 * Need to add to dfstab and sharetab, if appropriate.
1651 */
1652 int
sa_commit_share(scfutilhandle_t * handle,sa_group_t group,sa_share_t share)1653 sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1654 {
1655 int ret = SA_OK;
1656 char *groupname;
1657 char *name;
1658 char *description;
1659 char *sharename;
1660 ssize_t proplen;
1661 char *propstring;
1662
1663 /*
1664 * Don't commit in the zfs group. We do commit legacy
1665 * (default) and all other groups/shares. ZFS is handled
1666 * through the ZFS configuration rather than SMF.
1667 */
1668
1669 groupname = sa_get_group_attr(group, "name");
1670 if (groupname != NULL) {
1671 if (strcmp(groupname, "zfs") == 0) {
1672 /*
1673 * Adding to the ZFS group will result in the sharenfs
1674 * property being set but we don't want to do anything
1675 * SMF related at this point.
1676 */
1677 sa_free_attr_string(groupname);
1678 return (ret);
1679 }
1680 }
1681
1682 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1683 propstring = malloc(proplen);
1684 if (propstring == NULL)
1685 ret = SA_NO_MEMORY;
1686
1687 if (groupname != NULL && ret == SA_OK) {
1688 ret = sa_get_instance(handle, groupname);
1689 sa_free_attr_string(groupname);
1690 groupname = NULL;
1691 sharename = sa_get_share_attr(share, "id");
1692 if (sharename == NULL) {
1693 /* slipped by */
1694 char shname[SA_SHARE_UUID_BUFLEN];
1695 generate_unique_sharename(shname);
1696 (void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
1697 (xmlChar *)shname);
1698 sharename = strdup(shname);
1699 }
1700 if (sharename != NULL) {
1701 sigset_t old, new;
1702 /*
1703 * Have a share name allocated so create a pgroup for
1704 * it. It may already exist, but that is OK. In order
1705 * to avoid creating a share pgroup that doesn't have
1706 * a path property, block signals around the critical
1707 * region of creating the share pgroup and props.
1708 */
1709 (void) sigprocmask(SIG_BLOCK, NULL, &new);
1710 (void) sigaddset(&new, SIGHUP);
1711 (void) sigaddset(&new, SIGINT);
1712 (void) sigaddset(&new, SIGQUIT);
1713 (void) sigaddset(&new, SIGTSTP);
1714 (void) sigprocmask(SIG_SETMASK, &new, &old);
1715
1716 ret = sa_create_pgroup(handle, sharename);
1717 if (ret == SA_OK) {
1718 /*
1719 * Now start the transaction for the
1720 * properties that define this share. They may
1721 * exist so attempt to update before create.
1722 */
1723 ret = sa_start_transaction(handle, sharename);
1724 }
1725 if (ret == SA_OK) {
1726 name = sa_get_share_attr(share, "path");
1727 if (name != NULL) {
1728 /*
1729 * There needs to be a path
1730 * for a share to exist.
1731 */
1732 ret = sa_set_property(handle, "path",
1733 name);
1734 sa_free_attr_string(name);
1735 } else {
1736 ret = SA_NO_MEMORY;
1737 }
1738 }
1739 if (ret == SA_OK) {
1740 name = sa_get_share_attr(share, "drive-letter");
1741 if (name != NULL) {
1742 /* A drive letter may exist for SMB */
1743 ret = sa_set_property(handle,
1744 "drive-letter", name);
1745 sa_free_attr_string(name);
1746 }
1747 }
1748 if (ret == SA_OK) {
1749 name = sa_get_share_attr(share, "exclude");
1750 if (name != NULL) {
1751 /*
1752 * In special cases need to
1753 * exclude proto enable.
1754 */
1755 ret = sa_set_property(handle,
1756 "exclude", name);
1757 sa_free_attr_string(name);
1758 }
1759 }
1760 if (ret == SA_OK) {
1761 /*
1762 * If there are resource names, bundle them up
1763 * and save appropriately.
1764 */
1765 ret = sa_set_resource_property(handle, share);
1766 }
1767
1768 if (ret == SA_OK) {
1769 description = sa_get_share_description(share);
1770 if (description != NULL) {
1771 ret = sa_set_property(handle,
1772 "description",
1773 description);
1774 sa_free_share_description(description);
1775 }
1776 }
1777 /* Make sure we cleanup the transaction */
1778 if (ret == SA_OK) {
1779 sa_handle_impl_t sahandle;
1780 sahandle = (sa_handle_impl_t)
1781 sa_find_group_handle(group);
1782 if (sahandle != NULL)
1783 ret = sa_end_transaction(handle,
1784 sahandle);
1785 else
1786 ret = SA_SYSTEM_ERR;
1787 } else {
1788 sa_abort_transaction(handle);
1789 }
1790
1791 (void) sigprocmask(SIG_SETMASK, &old, NULL);
1792
1793 free(sharename);
1794 }
1795 }
1796 if (ret == SA_SYSTEM_ERR) {
1797 int err = scf_error();
1798 if (err == SCF_ERROR_PERMISSION_DENIED)
1799 ret = SA_NO_PERMISSION;
1800 }
1801 if (propstring != NULL)
1802 free(propstring);
1803 if (groupname != NULL)
1804 sa_free_attr_string(groupname);
1805
1806 return (ret);
1807 }
1808
1809 /*
1810 * remove_resources(handle, share, shareid)
1811 *
1812 * If the share has resources, remove all of them and their
1813 * optionsets.
1814 */
1815 static int
remove_resources(scfutilhandle_t * handle,sa_share_t share,char * shareid)1816 remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
1817 {
1818 sa_resource_t resource;
1819 sa_optionset_t opt;
1820 char *proto;
1821 char *id;
1822 ssize_t proplen;
1823 char *propstring;
1824 int ret = SA_OK;
1825
1826 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1827 propstring = malloc(proplen);
1828 if (propstring == NULL)
1829 return (SA_NO_MEMORY);
1830
1831 for (resource = sa_get_share_resource(share, NULL);
1832 resource != NULL; resource = sa_get_next_resource(resource)) {
1833 id = sa_get_resource_attr(resource, "id");
1834 if (id == NULL)
1835 continue;
1836 for (opt = sa_get_optionset(resource, NULL);
1837 opt != NULL; opt = sa_get_next_optionset(resource)) {
1838 proto = sa_get_optionset_attr(opt, "type");
1839 if (proto != NULL) {
1840 (void) snprintf(propstring, proplen,
1841 "%s_%s_%s", shareid, proto, id);
1842 ret = sa_delete_pgroup(handle, propstring);
1843 sa_free_attr_string(proto);
1844 }
1845 }
1846 sa_free_attr_string(id);
1847 }
1848 free(propstring);
1849 return (ret);
1850 }
1851
1852 /*
1853 * sa_delete_share(handle, group, share)
1854 *
1855 * Remove the specified share from the group (and service instance).
1856 */
1857
1858 int
sa_delete_share(scfutilhandle_t * handle,sa_group_t group,sa_share_t share)1859 sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1860 {
1861 int ret = SA_OK;
1862 char *groupname = NULL;
1863 char *shareid = NULL;
1864 sa_optionset_t opt;
1865 sa_security_t sec;
1866 ssize_t proplen;
1867 char *propstring;
1868
1869 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1870 propstring = malloc(proplen);
1871 if (propstring == NULL)
1872 ret = SA_NO_MEMORY;
1873
1874 if (ret == SA_OK) {
1875 groupname = sa_get_group_attr(group, "name");
1876 shareid = sa_get_share_attr(share, "id");
1877 if (groupname == NULL || shareid == NULL) {
1878 ret = SA_CONFIG_ERR;
1879 goto out;
1880 }
1881 ret = sa_get_instance(handle, groupname);
1882 if (ret == SA_OK) {
1883 /* If a share has resources, remove them */
1884 ret = remove_resources(handle, share, shareid);
1885 /* If a share has properties, remove them */
1886 ret = sa_delete_pgroup(handle, shareid);
1887 for (opt = sa_get_optionset(share, NULL);
1888 opt != NULL;
1889 opt = sa_get_next_optionset(opt)) {
1890 char *proto;
1891 proto = sa_get_optionset_attr(opt, "type");
1892 if (proto != NULL) {
1893 (void) snprintf(propstring,
1894 proplen, "%s_%s", shareid,
1895 proto);
1896 ret = sa_delete_pgroup(handle,
1897 propstring);
1898 sa_free_attr_string(proto);
1899 } else {
1900 ret = SA_NO_MEMORY;
1901 }
1902 }
1903 /*
1904 * If a share has security/negotiable
1905 * properties, remove them.
1906 */
1907 for (sec = sa_get_security(share, NULL, NULL);
1908 sec != NULL;
1909 sec = sa_get_next_security(sec)) {
1910 char *proto;
1911 char *sectype;
1912 proto = sa_get_security_attr(sec, "type");
1913 sectype = sa_get_security_attr(sec, "sectype");
1914 if (proto != NULL && sectype != NULL) {
1915 (void) snprintf(propstring, proplen,
1916 "%s_%s_%s", shareid, proto,
1917 sectype);
1918 ret = sa_delete_pgroup(handle,
1919 propstring);
1920 } else {
1921 ret = SA_NO_MEMORY;
1922 }
1923 if (proto != NULL)
1924 sa_free_attr_string(proto);
1925 if (sectype != NULL)
1926 sa_free_attr_string(sectype);
1927 }
1928 }
1929 }
1930 out:
1931 if (groupname != NULL)
1932 sa_free_attr_string(groupname);
1933 if (shareid != NULL)
1934 sa_free_attr_string(shareid);
1935 if (propstring != NULL)
1936 free(propstring);
1937
1938 return (ret);
1939 }
1940