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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Share control API
28 */
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <libxml/parser.h>
37 #include <libxml/tree.h>
38 #include "libshare.h"
39 #include "libshare_impl.h"
40 #include <libscf.h>
41 #include "scfutil.h"
42 #include <ctype.h>
43 #include <libintl.h>
48 #define SA_STRSIZE 256 /* max string size for names */
49
50 /*
51 * internal object type values returned by sa_get_object_type()
52 */
53 #define SA_TYPE_UNKNOWN 0
54 #define SA_TYPE_GROUP 1
55 #define SA_TYPE_SHARE 2
56 #define SA_TYPE_RESOURCE 3
57 #define SA_TYPE_OPTIONSET 4
58 #define SA_TYPE_ALTSPACE 5
59
60 /*
61 * internal data structures
62 */
63
64 extern struct sa_proto_plugin *sap_proto_list;
65
66 /* current SMF/SVC repository handle */
67 extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
68 extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
69 extern char *sa_fstype(char *);
70 extern int sa_is_share(void *);
71 extern int sa_is_resource(void *);
72 extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
73 extern int sa_group_is_zfs(sa_group_t);
74 extern int sa_path_is_zfs(char *);
75 extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
76 extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
77 extern void update_legacy_config(sa_handle_t);
78 extern int issubdir(char *, char *);
79 extern int sa_zfs_init(sa_handle_impl_t);
80 extern void sa_zfs_fini(sa_handle_impl_t);
81 extern void sablocksigs(sigset_t *);
82 extern void saunblocksigs(sigset_t *);
83 static sa_group_t sa_get_optionset_parent(sa_optionset_t);
84 static char *get_node_attr(void *, char *);
85 extern void sa_update_sharetab_ts(sa_handle_t);
86
87 /*
88 * Data structures for finding/managing the document root to access
89 * handle mapping. The list isn't expected to grow very large so a
90 * simple list is acceptable. The purpose is to provide a way to start
91 * with a group or share and find the library handle needed for
92 * various operations.
93 */
94 mutex_t sa_global_lock;
95 struct doc2handle {
96 struct doc2handle *next;
97 xmlNodePtr root;
98 sa_handle_impl_t handle;
99 };
100
101 mutex_t sa_dfstab_lock;
102
103 /* definitions used in a couple of property functions */
104 #define SA_PROP_OP_REMOVE 1
105 #define SA_PROP_OP_ADD 2
106 #define SA_PROP_OP_UPDATE 3
107
108 static struct doc2handle *sa_global_handles = NULL;
109
110 /* helper functions */
111
112 /*
113 * sa_errorstr(err)
114 *
115 * convert an error value to an error string
116 */
117
118 char *
222 ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
223 break;
224 case SA_SHARE_EXISTS:
225 ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
226 break;
227 default:
228 (void) snprintf(errstr, sizeof (errstr),
229 dgettext(TEXT_DOMAIN, "unknown %d"), err);
230 ret = errstr;
231 }
232 return (ret);
233 }
234
235 /*
236 * Document root to active handle mapping functions. These are only
237 * used internally. A mutex is used to prevent access while the list
238 * is changing. In general, the list will be relatively short - one
239 * item per thread that has called sa_init().
240 */
241
242 sa_handle_impl_t
243 get_handle_for_root(xmlNodePtr root)
244 {
245 struct doc2handle *item;
246
247 (void) mutex_lock(&sa_global_lock);
248 for (item = sa_global_handles; item != NULL; item = item->next) {
249 if (item->root == root)
250 break;
251 }
252 (void) mutex_unlock(&sa_global_lock);
253 if (item != NULL)
254 return (item->handle);
255 return (NULL);
256 }
257
258 static int
259 add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle)
260 {
261 struct doc2handle *item;
262 int ret = SA_NO_MEMORY;
263
264 item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1);
265 if (item != NULL) {
266 item->root = root;
267 item->handle = handle;
268 (void) mutex_lock(&sa_global_lock);
269 item->next = sa_global_handles;
270 sa_global_handles = item;
271 (void) mutex_unlock(&sa_global_lock);
272 ret = SA_OK;
273 }
274 return (ret);
275 }
276
277 /*
278 * remove_handle_for_root(root)
279 *
302 prev = item;
303 }
304 (void) mutex_unlock(&sa_global_lock);
305 }
306
307 /*
308 * sa_find_group_handle(sa_group_t group)
309 *
310 * Find the sa_handle_t for the configuration associated with this
311 * group.
312 */
313 sa_handle_t
314 sa_find_group_handle(sa_group_t group)
315 {
316 xmlNodePtr node = (xmlNodePtr)group;
317 sa_handle_t handle;
318
319 while (node != NULL) {
320 if (strcmp((char *)(node->name), "sharecfg") == 0) {
321 /* have the root so get the handle */
322 handle = (sa_handle_t)get_handle_for_root(node);
323 return (handle);
324 }
325 node = node->parent;
326 }
327 return (NULL);
328 }
329
330 /*
331 * set_legacy_timestamp(root, path, timevalue)
332 *
333 * add the current timestamp value to the configuration for use in
334 * determining when to update the legacy files. For SMF, this
335 * property is kept in default/operation/legacy_timestamp
336 */
337
338 static void
339 set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval)
340 {
341 xmlNodePtr node;
342 xmlChar *lpath = NULL;
343 sa_handle_impl_t handle;
344
345 /* Have to have a handle or else we weren't initialized. */
346 handle = get_handle_for_root(root);
347 if (handle == NULL)
348 return;
349
350 for (node = root->xmlChildrenNode; node != NULL;
351 node = node->next) {
352 if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) {
353 /* a possible legacy node for this path */
354 lpath = xmlGetProp(node, (xmlChar *)"path");
355 if (lpath != NULL &&
356 xmlStrcmp(lpath, (xmlChar *)path) == 0) {
357 xmlFree(lpath);
358 break;
359 }
360 if (lpath != NULL)
361 xmlFree(lpath);
362 }
363 }
583 if (fstype != NULL && strcmp(fstype, "zfs") == 0) {
584 if (sa_zfs_is_shared(handle, path))
585 error = SA_INVALID_NAME;
586 }
587 if (fstype != NULL)
588 sa_free_fstype(fstype);
589 }
590 if (error == SA_OK)
591 error = checksubdir(handle, path, strictness);
592 }
593 return (error);
594 }
595
596 /*
597 * check to see if group/share is persistent.
598 *
599 * "group" can be either an sa_group_t or an sa_share_t. (void *)
600 * works since both thse types are also void *.
601 * If the share is a ZFS share, mark it as persistent.
602 */
603 int
604 sa_is_persistent(void *group)
605 {
606 char *type;
607 int persist = 1;
608 sa_group_t grp;
609
610 type = sa_get_group_attr((sa_group_t)group, "type");
611 if (type != NULL) {
612 if (strcmp(type, "transient") == 0)
613 persist = 0;
614 sa_free_attr_string(type);
615 }
616
617 grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group;
618 if (sa_group_is_zfs(grp))
619 persist = 1;
620
621 return (persist);
622 }
623
624 /*
625 * sa_valid_group_name(name)
626 *
627 * check that the "name" contains only valid characters and otherwise
628 * fits the required naming conventions. Valid names must start with
629 * an alphabetic and the remainder may consist of only alphanumeric
630 * plus the '-' and '_' characters. This name limitation comes from
631 * inherent limitations in SMF.
632 */
633
634 int
635 sa_valid_group_name(char *name)
636 {
637 int ret = 1;
638 ssize_t len;
639
816 * Initialize the API
817 * find all the shared objects
818 * init the tables with all objects
819 * read in the current configuration
820 */
821
822 #define GETPROP(prop) scf_simple_prop_next_astring(prop)
823 #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \
824 tval != TSTAMP(st.st_ctim)
825
826 sa_handle_t
827 sa_init(int init_service)
828 {
829 struct stat st;
830 int legacy = 0;
831 uint64_t tval = 0;
832 int lockfd;
833 sigset_t old;
834 int updatelegacy = B_FALSE;
835 scf_simple_prop_t *prop;
836 sa_handle_impl_t handle;
837 int err;
838
839 handle = calloc(sizeof (struct sa_handle_impl), 1);
840
841 if (handle != NULL) {
842 /*
843 * Get protocol specific structures, but only if this
844 * is the only handle.
845 */
846 (void) mutex_lock(&sa_global_lock);
847 if (sa_global_handles == NULL)
848 (void) proto_plugin_init();
849 (void) mutex_unlock(&sa_global_lock);
850 if (init_service & SA_INIT_SHARE_API) {
851 /*
852 * initialize access into libzfs. We use this
853 * when collecting info about ZFS datasets and
854 * shares.
855 */
856 if (sa_zfs_init(handle) == B_FALSE) {
857 free(handle);
858 (void) mutex_lock(&sa_global_lock);
859 (void) proto_plugin_fini();
972 if (updatelegacy == B_TRUE) {
973 (void) mutex_unlock(
974 &sa_dfstab_lock);
975 (void) lockf(lockfd,
976 F_ULOCK, 0);
977 (void) close(lockfd);
978 }
979 return (NULL);
980 }
981
982 if (tval == 0) {
983 /*
984 * first time so make sure
985 * default is setup
986 */
987 verifydefgroupopts(handle);
988 }
989
990 if (updatelegacy == B_TRUE) {
991 sablocksigs(&old);
992 getlegacyconfig((sa_handle_t)handle,
993 SA_LEGACY_DFSTAB, &handle->tree);
994 if (stat(SA_LEGACY_DFSTAB, &st) >= 0)
995 set_legacy_timestamp(
996 handle->tree,
997 SA_LEGACY_DFSTAB,
998 TSTAMP(st.st_ctim));
999 saunblocksigs(&old);
1000 /*
1001 * Safe to unlock now to allow
1002 * others to run
1003 */
1004 (void) mutex_unlock(&sa_dfstab_lock);
1005 (void) lockf(lockfd, F_ULOCK, 0);
1006 (void) close(lockfd);
1007 }
1008 /* Get sharetab timestamp */
1009 sa_update_sharetab_ts((sa_handle_t)handle);
1010
1011 /* Get lastupdate (transaction) timestamp */
1012 prop = scf_simple_prop_get(
1013 handle->scfhandle->handle,
1014 (const char *)SA_SVC_FMRI_BASE ":default",
1015 "state", "lastupdate");
1016 if (prop != NULL) {
1017 char *str;
1018 str =
1019 scf_simple_prop_next_astring(prop);
1020 if (str != NULL)
1021 handle->tstrans =
1022 strtoull(str, NULL, 0);
1023 else
1024 handle->tstrans = 0;
1025 scf_simple_prop_free(prop);
1026 }
1027 legacy |= sa_get_zfs_shares(handle, "zfs");
1028 legacy |= gettransients(handle, &handle->tree);
1029 }
1030 }
1031 }
1032 return ((sa_handle_t)handle);
1033 }
1034
1035 /*
1036 * sa_fini(handle)
1037 * Uninitialize the API structures including the configuration
1038 * data structures and ZFS related data.
1039 */
1040
1041 void
1042 sa_fini(sa_handle_t handle)
1043 {
1044 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
1045
1046 if (impl_handle != NULL) {
1047 /*
1048 * Free the config trees and any other data structures
1049 * used in the handle.
1050 */
1051 if (impl_handle->doc != NULL)
1052 xmlFreeDoc(impl_handle->doc);
1053
1054 /* Remove and free the entry in the global list. */
1055 remove_handle_for_root(impl_handle->tree);
1056
1057 /*
1058 * If this was the last handle to release, unload the
1059 * plugins that were loaded. Use a mutex in case
1060 * another thread is reinitializing.
1061 */
1062 (void) mutex_lock(&sa_global_lock);
1063 if (sa_global_handles == NULL)
1064 (void) proto_plugin_fini();
1065 (void) mutex_unlock(&sa_global_lock);
1066
1067 sa_scf_fini(impl_handle->scfhandle);
1068 sa_zfs_fini(impl_handle);
1069
1070 /* Make sure we free the handle */
1071 free(impl_handle);
1072
1073 }
1074 }
1075
1076 /*
1077 * sa_get_protocols(char **protocol)
1078 * Get array of protocols that are supported
1079 * Returns pointer to an allocated and NULL terminated
1080 * array of strings. Caller must free.
1081 * This really should be determined dynamically.
1082 * If there aren't any defined, return -1.
1083 * Use free() to return memory.
1084 */
1085
1086 int
1087 sa_get_protocols(char ***protocols)
1088 {
1089 int numproto = -1;
1090
1091 if (protocols != NULL) {
1138 name = NULL;
1139 }
1140 }
1141 }
1142 if (name != NULL)
1143 xmlFree(name);
1144 return (node);
1145 }
1146
1147 /*
1148 * sa_get_group(groupname)
1149 * Return the "group" specified. If groupname is NULL,
1150 * return the first group of the list of groups.
1151 */
1152 sa_group_t
1153 sa_get_group(sa_handle_t handle, char *groupname)
1154 {
1155 xmlNodePtr node = NULL;
1156 char *subgroup = NULL;
1157 char *group = NULL;
1158 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
1159
1160 if (impl_handle != NULL && impl_handle->tree != NULL) {
1161 if (groupname != NULL) {
1162 group = strdup(groupname);
1163 if (group != NULL) {
1164 subgroup = strchr(group, '/');
1165 if (subgroup != NULL)
1166 *subgroup++ = '\0';
1167 }
1168 }
1169 /*
1170 * We want to find the, possibly, named group. If
1171 * group is not NULL, then lookup the name. If it is
1172 * NULL, we only do the find if groupname is also
1173 * NULL. This allows lookup of the "first" group in
1174 * the internal list.
1175 */
1176 if (group != NULL || groupname == NULL)
1177 node = find_group_by_name(impl_handle->tree,
1178 (xmlChar *)group);
1179
1180 /* if a subgroup, find it before returning */
1181 if (subgroup != NULL && node != NULL)
1182 node = find_group_by_name(node, (xmlChar *)subgroup);
1183 }
1184 if (node != NULL && (char *)group != NULL)
1185 (void) sa_get_instance(impl_handle->scfhandle, (char *)group);
1186 if (group != NULL)
1187 free(group);
1188 return ((sa_group_t)(node));
1189 }
1190
1191 /*
1192 * sa_get_next_group(group)
1193 * Return the "next" group after the specified group from
1194 * the internal group list. NULL if there are no more.
1195 */
1196 sa_group_t
1197 sa_get_next_group(sa_group_t group)
1198 {
1199 xmlNodePtr ngroup = NULL;
1200 if (group != NULL) {
1201 for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL;
1202 ngroup = ngroup->next) {
1203 if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0)
1204 break;
1205 }
1485 (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
1486 (void) xmlSetProp(node, (xmlChar *)"type",
1487 persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
1488 if (flags != 0)
1489 mark_excluded_protos(group, node, flags);
1490 if (persist != SA_SHARE_TRANSIENT) {
1491 /*
1492 * persistent shares come in two flavors: SMF and
1493 * ZFS. Sort this one out based on target group and
1494 * path type. Both NFS and SMB are supported. First,
1495 * check to see if the protocol is enabled on the
1496 * subgroup and then setup the share appropriately.
1497 */
1498 if (sa_group_is_zfs(group) &&
1499 sa_path_is_zfs(sharepath)) {
1500 if (sa_get_optionset(group, "nfs") != NULL)
1501 err = sa_zfs_set_sharenfs(group, sharepath, 1);
1502 else if (sa_get_optionset(group, "smb") != NULL)
1503 err = sa_zfs_set_sharesmb(group, sharepath, 1);
1504 } else {
1505 sa_handle_impl_t impl_handle;
1506 impl_handle =
1507 (sa_handle_impl_t)sa_find_group_handle(group);
1508 if (impl_handle != NULL) {
1509 err = sa_commit_share(impl_handle->scfhandle,
1510 group, (sa_share_t)node);
1511 } else {
1512 err = SA_SYSTEM_ERR;
1513 }
1514 }
1515 }
1516 if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
1517 /* called by the dfstab parser so could be a show */
1518 err = SA_OK;
1519
1520 if (err != SA_OK) {
1521 /*
1522 * we couldn't commit to the repository so undo
1523 * our internal state to reflect reality.
1524 */
1525 xmlUnlinkNode(node);
1526 xmlFreeNode(node);
1527 node = NULL;
1528 }
1529
1724 type = sa_get_share_attr(share, "type");
1725 group = sa_get_parent_group(share);
1726 zfs = sa_get_group_attr(group, "zfs");
1727 groupname = sa_get_group_attr(group, "name");
1728 if (type != NULL && strcmp(type, "persist") != 0)
1729 transient = 1;
1730 if (type != NULL)
1731 sa_free_attr_string(type);
1732
1733 /* remove the node from its group then free the memory */
1734
1735 /*
1736 * need to test if "busy"
1737 */
1738 /* only do SMF action if permanent */
1739 if (!transient || zfs != NULL) {
1740 /* remove from legacy dfstab as well as possible SMF */
1741 ret = sa_delete_legacy(share, NULL);
1742 if (ret == SA_OK) {
1743 if (!sa_group_is_zfs(group)) {
1744 sa_handle_impl_t impl_handle;
1745 impl_handle = (sa_handle_impl_t)
1746 sa_find_group_handle(group);
1747 if (impl_handle != NULL) {
1748 ret = sa_delete_share(
1749 impl_handle->scfhandle, group,
1750 share);
1751 } else {
1752 ret = SA_SYSTEM_ERR;
1753 }
1754 } else {
1755 char *sharepath = sa_get_share_attr(share,
1756 "path");
1757 if (sharepath != NULL) {
1758 ret = sa_zfs_set_sharenfs(group,
1759 sharepath, 0);
1760 sa_free_attr_string(sharepath);
1761 }
1762 }
1763 }
1764 }
1765 if (groupname != NULL)
1766 sa_free_attr_string(groupname);
1767 if (zfs != NULL)
1768 sa_free_attr_string(zfs);
1769
1772 return (ret);
1773 }
1774
1775 /*
1776 * sa_move_share(group, share)
1777 *
1778 * move the specified share to the specified group. Update SMF
1779 * appropriately.
1780 */
1781
1782 int
1783 sa_move_share(sa_group_t group, sa_share_t share)
1784 {
1785 sa_group_t oldgroup;
1786 int ret = SA_OK;
1787
1788 /* remove the node from its group then free the memory */
1789
1790 oldgroup = sa_get_parent_group(share);
1791 if (oldgroup != group) {
1792 sa_handle_impl_t impl_handle;
1793 xmlUnlinkNode((xmlNodePtr)share);
1794 /*
1795 * now that the share isn't in its old group, add to
1796 * the new one
1797 */
1798 (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
1799 /* need to deal with SMF */
1800 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1801 if (impl_handle != NULL) {
1802 /*
1803 * need to remove from old group first and then add to
1804 * new group. Ideally, we would do the other order but
1805 * need to avoid having the share in two groups at the
1806 * same time.
1807 */
1808 ret = sa_delete_share(impl_handle->scfhandle, oldgroup,
1809 share);
1810 if (ret == SA_OK)
1811 ret = sa_commit_share(impl_handle->scfhandle,
1812 group, share);
1813 } else {
1814 ret = SA_SYSTEM_ERR;
1815 }
1816 }
1817 return (ret);
1818 }
1819
1820 /*
1821 * sa_get_parent_group(share)
1822 *
1823 * Return the containing group for the share. If a group was actually
1824 * passed in, we don't want a parent so return NULL.
1825 */
1826
1827 sa_group_t
1828 sa_get_parent_group(sa_share_t share)
1829 {
1830 xmlNodePtr node = NULL;
1831 if (share != NULL) {
1832 node = ((xmlNodePtr)share)->parent;
1833 /*
1834 * make sure parent is a group and not sharecfg since
1835 * we may be cheating and passing in a group.
1836 * Eventually, groups of groups might come into being.
1837 */
1838 if (node == NULL ||
1839 xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0)
1840 node = NULL;
1841 }
1842 return ((sa_group_t)node);
1843 }
1844
1845 /*
1846 * _sa_create_group(impl_handle, groupname)
1847 *
1848 * Create a group in the document. The caller will need to deal with
1849 * configuration store and activation.
1850 */
1851
1852 sa_group_t
1853 _sa_create_group(sa_handle_impl_t impl_handle, char *groupname)
1854 {
1855 xmlNodePtr node = NULL;
1856
1857 if (sa_valid_group_name(groupname)) {
1858 node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group",
1859 NULL);
1860 if (node != NULL) {
1861 (void) xmlSetProp(node, (xmlChar *)"name",
1862 (xmlChar *)groupname);
1863 (void) xmlSetProp(node, (xmlChar *)"state",
1864 (xmlChar *)"enabled");
1865 }
1866 }
1867 return ((sa_group_t)node);
1868 }
1869
1870 /*
1871 * _sa_create_zfs_group(group, groupname)
1872 *
1873 * Create a ZFS subgroup under the specified group. This may
1874 * eventually form the basis of general sub-groups, but is currently
1875 * restricted to ZFS.
1876 */
1877 sa_group_t
1878 _sa_create_zfs_group(sa_group_t group, char *groupname)
1889
1890 return ((sa_group_t)node);
1891 }
1892
1893 /*
1894 * sa_create_group(groupname, *error)
1895 *
1896 * Create a new group with groupname. Need to validate that it is a
1897 * legal name for SMF and the construct the SMF service instance of
1898 * svc:/network/shares/group to implement the group. All necessary
1899 * operational properties must be added to the group at this point
1900 * (via the SMF transaction model).
1901 */
1902 sa_group_t
1903 sa_create_group(sa_handle_t handle, char *groupname, int *error)
1904 {
1905 xmlNodePtr node = NULL;
1906 sa_group_t group;
1907 int ret;
1908 char rbacstr[SA_STRSIZE];
1909 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
1910
1911 ret = SA_OK;
1912
1913 if (impl_handle == NULL || impl_handle->scfhandle == NULL) {
1914 ret = SA_SYSTEM_ERR;
1915 goto err;
1916 }
1917
1918 group = sa_get_group(handle, groupname);
1919 if (group != NULL) {
1920 ret = SA_DUPLICATE_NAME;
1921 } else {
1922 if (sa_valid_group_name(groupname)) {
1923 node = xmlNewChild(impl_handle->tree, NULL,
1924 (xmlChar *)"group", NULL);
1925 if (node != NULL) {
1926 (void) xmlSetProp(node, (xmlChar *)"name",
1927 (xmlChar *)groupname);
1928 /* default to the group being enabled */
1929 (void) xmlSetProp(node, (xmlChar *)"state",
1930 (xmlChar *)"enabled");
1931 ret = sa_create_instance(impl_handle->scfhandle,
1932 groupname);
1933 if (ret == SA_OK) {
1934 ret = sa_start_transaction(
1935 impl_handle->scfhandle,
1936 "operation");
1937 }
1938 if (ret == SA_OK) {
1939 ret = sa_set_property(
1940 impl_handle->scfhandle,
1941 "state", "enabled");
1942 if (ret == SA_OK) {
1943 ret = sa_end_transaction(
1944 impl_handle->scfhandle,
1945 impl_handle);
1946 } else {
1947 sa_abort_transaction(
1948 impl_handle->scfhandle);
1949 }
1950 }
1951 if (ret == SA_OK) {
1952 /* initialize the RBAC strings */
1953 ret = sa_start_transaction(
1954 impl_handle->scfhandle,
1955 "general");
1956 if (ret == SA_OK) {
1957 (void) snprintf(rbacstr,
1958 sizeof (rbacstr), "%s.%s",
1959 SA_RBAC_MANAGE, groupname);
1960 ret = sa_set_property(
1961 impl_handle->scfhandle,
1962 "action_authorization",
1963 rbacstr);
1964 }
1965 if (ret == SA_OK) {
1966 (void) snprintf(rbacstr,
1967 sizeof (rbacstr), "%s.%s",
1968 SA_RBAC_VALUE, groupname);
1969 ret = sa_set_property(
1970 impl_handle->scfhandle,
1971 "value_authorization",
1972 rbacstr);
1973 }
1974 if (ret == SA_OK) {
1975 ret = sa_end_transaction(
1976 impl_handle->scfhandle,
1977 impl_handle);
1978 } else {
1979 sa_abort_transaction(
1980 impl_handle->scfhandle);
1981 }
1982 }
1983 if (ret != SA_OK) {
1984 /*
1985 * Couldn't commit the group
1986 * so we need to undo
1987 * internally.
1988 */
1989 xmlUnlinkNode(node);
1990 xmlFreeNode(node);
1991 node = NULL;
1992 }
1993 } else {
1994 ret = SA_NO_MEMORY;
1995 }
1996 } else {
1997 ret = SA_INVALID_NAME;
1998 }
1999 }
2000 err:
2001 if (error != NULL)
2002 *error = ret;
2003 return ((sa_group_t)node);
2004 }
2005
2006 /*
2007 * sa_remove_group(group)
2008 *
2009 * Remove the specified group. This deletes from the SMF repository.
2010 * All property groups and properties are removed.
2011 */
2012
2013 int
2014 sa_remove_group(sa_group_t group)
2015 {
2016 char *name;
2017 int ret = SA_OK;
2018 sa_handle_impl_t impl_handle;
2019
2020 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2021 if (impl_handle != NULL) {
2022 name = sa_get_group_attr(group, "name");
2023 if (name != NULL) {
2024 ret = sa_delete_instance(impl_handle->scfhandle, name);
2025 sa_free_attr_string(name);
2026 }
2027 xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
2028 xmlFreeNode((xmlNodePtr)group); /* now it is gone */
2029 } else {
2030 ret = SA_SYSTEM_ERR;
2031 }
2032 return (ret);
2033 }
2034
2035 /*
2036 * sa_update_config()
2037 *
2038 * Used to update legacy files that need to be updated in bulk
2039 * Currently, this is a placeholder and will go away in a future
2040 * release.
2041 */
2042
2043 int
2044 sa_update_config(sa_handle_t handle)
2101 sa_get_group_attr(sa_group_t group, char *tag)
2102 {
2103 return (get_node_attr((void *)group, tag));
2104 }
2105
2106 /*
2107 * sa_set_group_attr(group, tag, value)
2108 *
2109 * set the specified tag/attribute on the group using value as its
2110 * value.
2111 *
2112 * This will result in setting the property in the SMF repository as
2113 * well as in the internal document.
2114 */
2115
2116 int
2117 sa_set_group_attr(sa_group_t group, char *tag, char *value)
2118 {
2119 int ret;
2120 char *groupname;
2121 sa_handle_impl_t impl_handle;
2122
2123 /*
2124 * ZFS group/subgroup doesn't need the handle so shortcut.
2125 */
2126 if (sa_group_is_zfs(group)) {
2127 set_node_attr((void *)group, tag, value);
2128 return (SA_OK);
2129 }
2130
2131 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2132 if (impl_handle != NULL) {
2133 groupname = sa_get_group_attr(group, "name");
2134 ret = sa_get_instance(impl_handle->scfhandle, groupname);
2135 if (ret == SA_OK) {
2136 set_node_attr((void *)group, tag, value);
2137 ret = sa_start_transaction(impl_handle->scfhandle,
2138 "operation");
2139 if (ret == SA_OK) {
2140 ret = sa_set_property(impl_handle->scfhandle,
2141 tag, value);
2142 if (ret == SA_OK)
2143 ret = sa_end_transaction(
2144 impl_handle->scfhandle,
2145 impl_handle);
2146 else
2147 sa_abort_transaction(
2148 impl_handle->scfhandle);
2149 }
2150 if (ret == SA_SYSTEM_ERR)
2151 ret = SA_NO_PERMISSION;
2152 }
2153 if (groupname != NULL)
2154 sa_free_attr_string(groupname);
2155 } else {
2156 ret = SA_SYSTEM_ERR;
2157 }
2158 return (ret);
2159 }
2160
2161 /*
2162 * sa_get_share_attr(share, tag)
2163 *
2164 * Return the value of the tag/attribute set on the specified
2165 * share. Returns NULL if the tag doesn't exist.
2166 */
2167
2168 char *
2209
2210 /*
2211 * There are some attributes that may have specific
2212 * restrictions on them. Initially, only "resource" has
2213 * special meaning that needs to be checked. Only one instance
2214 * of a resource name may exist within a group.
2215 */
2216
2217 if (strcmp(tag, "resource") == 0) {
2218 resource = sa_get_resource(group, value);
2219 if (resource != share && resource != NULL)
2220 ret = SA_DUPLICATE_NAME;
2221 }
2222 if (ret == SA_OK) {
2223 set_node_attr((void *)share, tag, value);
2224 if (group != NULL) {
2225 char *type;
2226 /* we can probably optimize this some */
2227 type = sa_get_share_attr(share, "type");
2228 if (type == NULL || strcmp(type, "transient") != 0) {
2229 sa_handle_impl_t impl_handle;
2230 impl_handle =
2231 (sa_handle_impl_t)sa_find_group_handle(
2232 group);
2233 if (impl_handle != NULL) {
2234 ret = sa_commit_share(
2235 impl_handle->scfhandle, group,
2236 share);
2237 } else {
2238 ret = SA_SYSTEM_ERR;
2239 }
2240 }
2241 if (type != NULL)
2242 sa_free_attr_string(type);
2243 }
2244 }
2245 return (ret);
2246 }
2247
2248 /*
2249 * sa_get_property_attr(prop, tag)
2250 *
2251 * Get the value of the specified property attribute. Standard
2252 * attributes are "type" and "value".
2253 */
2254
2255 char *
2510 node = node->next) {
2511 if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
2512 break;
2513 }
2514 }
2515 /* no existing description but want to add */
2516 if (node == NULL && content != NULL) {
2517 /* add a description */
2518 node = _sa_set_share_description(share, content);
2519 } else if (node != NULL && content != NULL) {
2520 /* update a description */
2521 xmlNodeSetContent(node, (xmlChar *)content);
2522 } else if (node != NULL && content == NULL) {
2523 /* remove an existing description */
2524 xmlUnlinkNode(node);
2525 xmlFreeNode(node);
2526 }
2527 group = sa_get_parent_group(share);
2528 if (group != NULL &&
2529 sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
2530 sa_handle_impl_t impl_handle;
2531 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2532 if (impl_handle != NULL) {
2533 ret = sa_commit_share(impl_handle->scfhandle, group,
2534 share);
2535 } else {
2536 ret = SA_SYSTEM_ERR;
2537 }
2538 }
2539 return (ret);
2540 }
2541
2542 /*
2543 * fixproblemchars(string)
2544 *
2545 * don't want any newline or tab characters in the text since these
2546 * could break display of data and legacy file formats.
2547 */
2548 static void
2549 fixproblemchars(char *str)
2550 {
2551 int c;
2552 for (c = *str; c != '\0'; c = *++str) {
2553 if (c == '\t' || c == '\n')
2656 char *groupname;
2657
2658 /*
2659 * Need to get parent group in all cases, but also get
2660 * the share if this is a resource.
2661 */
2662 if (sa_is_share(group)) {
2663 parent = sa_get_parent_group((sa_share_t)group);
2664 } else if (sa_is_resource(group)) {
2665 share = sa_get_resource_parent(
2666 (sa_resource_t)group);
2667 parent = sa_get_parent_group(share);
2668 }
2669
2670 sa_set_optionset_attr(optionset, "type", proto);
2671
2672 (void) sa_optionset_name(optionset, oname,
2673 sizeof (oname), id);
2674 groupname = sa_get_group_attr(parent, "name");
2675 if (groupname != NULL && sa_is_persistent(group)) {
2676 sa_handle_impl_t impl_handle;
2677 impl_handle =
2678 (sa_handle_impl_t)sa_find_group_handle(
2679 group);
2680 assert(impl_handle != NULL);
2681 if (impl_handle != NULL) {
2682 (void) sa_get_instance(
2683 impl_handle->scfhandle, groupname);
2684 (void) sa_create_pgroup(
2685 impl_handle->scfhandle, oname);
2686 }
2687 }
2688 if (groupname != NULL)
2689 sa_free_attr_string(groupname);
2690 }
2691 }
2692
2693 if (id != NULL)
2694 sa_free_attr_string(id);
2695 return (optionset);
2696 }
2697
2698 /*
2699 * sa_get_property_parent(property)
2700 *
2701 * Given a property, return the object it is a property of. This will
2702 * be an optionset of some type.
2703 */
2704
2705 static sa_optionset_t
2764 zfs_set_update(sa_share_t share)
2765 {
2766 set_node_attr((void *)share, "changed", "true");
2767 }
2768
2769 /*
2770 * sa_commit_properties(optionset, clear)
2771 *
2772 * Check if SMF or ZFS config and either update or abort the pending
2773 * changes.
2774 */
2775
2776 int
2777 sa_commit_properties(sa_optionset_t optionset, int clear)
2778 {
2779 sa_group_t group;
2780 sa_group_t parent;
2781 int zfs = 0;
2782 int needsupdate = 0;
2783 int ret = SA_OK;
2784 sa_handle_impl_t impl_handle;
2785
2786 group = sa_get_optionset_parent(optionset);
2787 if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) {
2788 /* only update ZFS if on a share */
2789 parent = sa_get_parent_group(group);
2790 zfs++;
2791 if (parent != NULL && is_zfs_group(parent))
2792 needsupdate = zfs_needs_update(group);
2793 else
2794 zfs = 0;
2795 }
2796 if (zfs) {
2797 if (!clear && needsupdate)
2798 ret = sa_zfs_update((sa_share_t)group);
2799 } else {
2800 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2801 if (impl_handle != NULL) {
2802 if (clear) {
2803 (void) sa_abort_transaction(
2804 impl_handle->scfhandle);
2805 } else {
2806 ret = sa_end_transaction(
2807 impl_handle->scfhandle, impl_handle);
2808 }
2809 } else {
2810 ret = SA_SYSTEM_ERR;
2811 }
2812 }
2813 return (ret);
2814 }
2815
2816 /*
2817 * sa_destroy_optionset(optionset)
2818 *
2819 * Remove the optionset from its group. Update the repository to
2820 * reflect this change.
2821 */
2822
2823 int
2824 sa_destroy_optionset(sa_optionset_t optionset)
2825 {
2826 char name[SA_STRSIZE];
2827 int len;
2828 int ret;
2829 char *id = NULL;
2830 sa_group_t group;
2831 int ispersist = 1;
2832
2833 /* now delete the prop group */
2834 group = sa_get_optionset_parent(optionset);
2835 if (group != NULL) {
2836 if (sa_is_resource(group)) {
2837 sa_resource_t resource = group;
2838 sa_share_t share = sa_get_resource_parent(resource);
2839 group = sa_get_parent_group(share);
2840 id = sa_get_share_attr(share, "id");
2841 } else if (sa_is_share(group)) {
2842 id = sa_get_share_attr((sa_share_t)group, "id");
2843 }
2844 ispersist = sa_is_persistent(group);
2845 }
2846 if (ispersist) {
2847 sa_handle_impl_t impl_handle;
2848 len = sa_optionset_name(optionset, name, sizeof (name), id);
2849 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2850 if (impl_handle != NULL) {
2851 if (len > 0) {
2852 ret = sa_delete_pgroup(impl_handle->scfhandle,
2853 name);
2854 }
2855 } else {
2856 ret = SA_SYSTEM_ERR;
2857 }
2858 }
2859 xmlUnlinkNode((xmlNodePtr)optionset);
2860 xmlFreeNode((xmlNodePtr)optionset);
2861 if (id != NULL)
2862 sa_free_attr_string(id);
2863 return (ret);
2864 }
2865
2866 /* private to the implementation */
2867 int
2868 _sa_remove_optionset(sa_optionset_t optionset)
2869 {
2870 int ret = SA_OK;
2871
2872 xmlUnlinkNode((xmlNodePtr)optionset);
2896 groupname = sa_get_group_attr(parent, "name");
2897 } else if (group != NULL) {
2898 groupname = sa_get_group_attr(group, "name");
2899 }
2900
2901 security = sa_get_security(group, sectype, proto);
2902 if (security != NULL) {
2903 /* can't have a duplicate security option */
2904 security = NULL;
2905 } else {
2906 security = (sa_security_t)xmlNewChild((xmlNodePtr)group,
2907 NULL, (xmlChar *)"security", NULL);
2908 if (security != NULL) {
2909 char oname[SA_STRSIZE];
2910 sa_set_security_attr(security, "type", proto);
2911
2912 sa_set_security_attr(security, "sectype", sectype);
2913 (void) sa_security_name(security, oname,
2914 sizeof (oname), id);
2915 if (groupname != NULL && sa_is_persistent(group)) {
2916 sa_handle_impl_t impl_handle;
2917 impl_handle =
2918 (sa_handle_impl_t)sa_find_group_handle(
2919 group);
2920 if (impl_handle != NULL) {
2921 (void) sa_get_instance(
2922 impl_handle->scfhandle, groupname);
2923 (void) sa_create_pgroup(
2924 impl_handle->scfhandle, oname);
2925 }
2926 }
2927 }
2928 }
2929 if (id != NULL)
2930 sa_free_attr_string(id);
2931 if (groupname != NULL)
2932 sa_free_attr_string(groupname);
2933 return (security);
2934 }
2935
2936 /*
2937 * sa_destroy_security(security)
2938 *
2939 * Remove the specified optionset from the document and the
2940 * configuration.
2941 */
2942
2943 int
2944 sa_destroy_security(sa_security_t security)
2947 int len;
2948 int ret = SA_OK;
2949 char *id = NULL;
2950 sa_group_t group;
2951 int iszfs = 0;
2952 int ispersist = 1;
2953
2954 group = sa_get_optionset_parent(security);
2955
2956 if (group != NULL)
2957 iszfs = sa_group_is_zfs(group);
2958
2959 if (group != NULL && !iszfs) {
2960 if (sa_is_share(group))
2961 ispersist = sa_is_persistent(group);
2962 id = sa_get_share_attr((sa_share_t)group, "id");
2963 }
2964 if (ispersist) {
2965 len = sa_security_name(security, name, sizeof (name), id);
2966 if (!iszfs && len > 0) {
2967 sa_handle_impl_t impl_handle;
2968 impl_handle =
2969 (sa_handle_impl_t)sa_find_group_handle(group);
2970 if (impl_handle != NULL) {
2971 ret = sa_delete_pgroup(impl_handle->scfhandle,
2972 name);
2973 } else {
2974 ret = SA_SYSTEM_ERR;
2975 }
2976 }
2977 }
2978 xmlUnlinkNode((xmlNodePtr)security);
2979 xmlFreeNode((xmlNodePtr)security);
2980 if (iszfs)
2981 ret = sa_zfs_update(group);
2982 if (id != NULL)
2983 sa_free_attr_string(id);
2984 return (ret);
2985 }
2986
2987 /*
2988 * sa_get_security_attr(optionset, tag)
2989 *
2990 * Return the specified attribute value from the optionset.
2991 */
3060 * Add/remove/update the specified property prop into the optionset or
3061 * share. If a share, sort out which property group based on GUID. In
3062 * all cases, the appropriate transaction is set (or ZFS share is
3063 * marked as needing an update)
3064 */
3065
3066 static int
3067 sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
3068 sa_property_t prop, int type)
3069 {
3070 char *name;
3071 char *valstr;
3072 int ret = SA_OK;
3073 scf_transaction_entry_t *entry;
3074 scf_value_t *value;
3075 int opttype; /* 1 == optionset, 0 == security */
3076 char *id = NULL;
3077 int iszfs = 0;
3078 sa_group_t parent = NULL;
3079 sa_share_t share = NULL;
3080 sa_handle_impl_t impl_handle;
3081 scfutilhandle_t *scf_handle;
3082
3083 if (!sa_is_persistent(group)) {
3084 /*
3085 * if the group/share is not persistent we don't need
3086 * to do anything here
3087 */
3088 return (SA_OK);
3089 }
3090 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
3091 if (impl_handle == NULL || impl_handle->scfhandle == NULL)
3092 return (SA_SYSTEM_ERR);
3093 scf_handle = impl_handle->scfhandle;
3094 name = sa_get_property_attr(prop, "type");
3095 valstr = sa_get_property_attr(prop, "value");
3096 entry = scf_entry_create(scf_handle->handle);
3097 opttype = is_nodetype((void *)optionset, "optionset");
3098
3099 /*
3100 * Check for share vs. resource since they need slightly
3101 * different treatment given the hierarchy.
3102 */
3103 if (valstr != NULL && entry != NULL) {
3104 if (sa_is_share(group)) {
3105 parent = sa_get_parent_group(group);
3106 share = (sa_share_t)group;
3107 if (parent != NULL)
3108 iszfs = is_zfs_group(parent);
3109 } else if (sa_is_resource(group)) {
3110 share = sa_get_parent_group(group);
3111 if (share != NULL)
3112 parent = sa_get_parent_group(share);
3113 } else {
3271 /*
3272 * Resources are children of share. Need to go up two
3273 * levels to find the group but the parent needs to be
3274 * the share at this point in order to get the "id".
3275 */
3276 parent = sa_get_parent_group(parent);
3277 group = sa_get_parent_group(parent);
3278 } else if (sa_is_share(parent)) {
3279 group = sa_get_parent_group(parent);
3280 } else {
3281 group = parent;
3282 }
3283
3284 if (property == NULL) {
3285 ret = SA_NO_MEMORY;
3286 } else {
3287 char oname[SA_STRSIZE];
3288
3289 if (!is_zfs_group(group)) {
3290 char *id = NULL;
3291 sa_handle_impl_t impl_handle;
3292 scfutilhandle_t *scf_handle;
3293
3294 impl_handle = (sa_handle_impl_t)sa_find_group_handle(
3295 group);
3296 if (impl_handle == NULL ||
3297 impl_handle->scfhandle == NULL)
3298 ret = SA_SYSTEM_ERR;
3299 if (ret == SA_OK) {
3300 scf_handle = impl_handle->scfhandle;
3301 if (sa_is_share((sa_group_t)parent)) {
3302 id = sa_get_share_attr(
3303 (sa_share_t)parent, "id");
3304 }
3305 if (scf_handle->trans == NULL) {
3306 if (is_nodetype(object, "optionset")) {
3307 (void) sa_optionset_name(
3308 (sa_optionset_t)object,
3309 oname, sizeof (oname), id);
3310 } else {
3311 (void) sa_security_name(
3312 (sa_optionset_t)object,
3313 oname, sizeof (oname), id);
3314 }
3315 ret = sa_start_transaction(scf_handle,
3316 oname);
3317 }
3318 if (ret == SA_OK) {
3319 char *name;
3320 char *value;
3779 } else {
3780 node = xmlNewChild((xmlNodePtr)share, NULL,
3781 (xmlChar *)"resource", NULL);
3782 if (node != NULL) {
3783 (void) xmlSetProp(node, (xmlChar *)"name",
3784 (xmlChar *)resource);
3785 (void) xmlSetProp(node, (xmlChar *)"type", persist ?
3786 (xmlChar *)"persist" : (xmlChar *)"transient");
3787 if (persist != SA_SHARE_TRANSIENT) {
3788 index = _sa_get_next_resource_index(share);
3789 (void) snprintf(istring, sizeof (istring), "%d",
3790 index);
3791 (void) xmlSetProp(node, (xmlChar *)"id",
3792 (xmlChar *)istring);
3793
3794 if (!sa_is_persistent((sa_group_t)share))
3795 goto done;
3796
3797 if (!sa_group_is_zfs(group)) {
3798 /* ZFS doesn't use resource names */
3799 sa_handle_impl_t ihandle;
3800
3801 ihandle = (sa_handle_impl_t)
3802 sa_find_group_handle(
3803 group);
3804 if (ihandle != NULL)
3805 err = sa_commit_share(
3806 ihandle->scfhandle, group,
3807 share);
3808 else
3809 err = SA_SYSTEM_ERR;
3810 } else {
3811 err = sa_zfs_update((sa_share_t)group);
3812 }
3813 }
3814 }
3815 }
3816 done:
3817 if (error != NULL)
3818 *error = err;
3819 return ((sa_resource_t)node);
3820 }
3821
3822 /*
3823 * sa_remove_resource(resource)
3824 *
3825 * Remove the resource name from the share (and the system)
3826 */
3847 }
3848
3849 /* Disable the resource for all protocols. */
3850 (void) sa_disable_resource(resource, NULL);
3851
3852 /* Remove any optionsets from the resource. */
3853 for (opt = sa_get_optionset(resource, NULL);
3854 opt != NULL;
3855 opt = sa_get_next_optionset(opt))
3856 (void) sa_destroy_optionset(opt);
3857
3858 /* Remove from the share */
3859 xmlUnlinkNode((xmlNode *)resource);
3860 xmlFreeNode((xmlNode *)resource);
3861
3862 /* only do SMF action if permanent and not ZFS */
3863 if (transient)
3864 return (ret);
3865
3866 if (!sa_group_is_zfs(group)) {
3867 sa_handle_impl_t ihandle;
3868 ihandle = (sa_handle_impl_t)sa_find_group_handle(group);
3869 if (ihandle != NULL)
3870 ret = sa_commit_share(ihandle->scfhandle, group, share);
3871 else
3872 ret = SA_SYSTEM_ERR;
3873 } else {
3874 ret = sa_zfs_update((sa_share_t)group);
3875 }
3876
3877 return (ret);
3878 }
3879
3880 /*
3881 * proto_rename_resource(handle, group, resource, newname)
3882 *
3883 * Helper function for sa_rename_resource that notifies the protocol
3884 * of a resource name change prior to a config repository update.
3885 */
3886 static int
3887 proto_rename_resource(sa_handle_t handle, sa_group_t group,
3888 sa_resource_t resource, char *newname)
3889 {
3890 sa_optionset_t optionset;
3913 * Rename the resource to the new name, if it is unique.
3914 */
3915
3916 int
3917 sa_rename_resource(sa_resource_t resource, char *newname)
3918 {
3919 sa_share_t share;
3920 sa_group_t group = NULL;
3921 sa_resource_t target;
3922 int ret = SA_CONFIG_ERR;
3923 sa_handle_t handle = NULL;
3924
3925 share = sa_get_resource_parent(resource);
3926 if (share == NULL)
3927 return (ret);
3928
3929 group = sa_get_parent_group(share);
3930 if (group == NULL)
3931 return (ret);
3932
3933 handle = (sa_handle_impl_t)sa_find_group_handle(group);
3934 if (handle == NULL)
3935 return (ret);
3936
3937 target = sa_find_resource(handle, newname);
3938 if (target != NULL) {
3939 ret = SA_DUPLICATE_NAME;
3940 } else {
3941 /*
3942 * Everything appears to be valid at this
3943 * point. Change the name of the active share and then
3944 * update the share in the appropriate repository.
3945 */
3946 ret = proto_rename_resource(handle, group, resource, newname);
3947 set_node_attr(resource, "name", newname);
3948
3949 if (!sa_is_persistent((sa_group_t)share))
3950 return (ret);
3951
3952 if (!sa_group_is_zfs(group)) {
3953 sa_handle_impl_t ihandle = (sa_handle_impl_t)handle;
3954 ret = sa_commit_share(ihandle->scfhandle, group,
3955 share);
3956 } else {
3957 ret = sa_zfs_update((sa_share_t)group);
3958 }
3959 }
3960 return (ret);
3961 }
3962
3963 /*
3964 * sa_get_resource_attr(resource, tag)
3965 *
3966 * Get the named attribute of the resource. "name" and "id" are
3967 * currently defined. NULL if tag not defined.
3968 */
3969
3970 char *
3971 sa_get_resource_attr(sa_resource_t resource, char *tag)
3972 {
3973 return (get_node_attr((void *)resource, tag));
3974 }
4347 }
4348 }
4349
4350 /* no existing description but want to add */
4351 if (node == NULL && content != NULL) {
4352 /* add a description */
4353 node = _sa_set_share_description(resource, content);
4354 } else if (node != NULL && content != NULL) {
4355 /* update a description */
4356 xmlNodeSetContent(node, (xmlChar *)content);
4357 } else if (node != NULL && content == NULL) {
4358 /* remove an existing description */
4359 xmlUnlinkNode(node);
4360 xmlFreeNode(node);
4361 }
4362
4363 share = sa_get_resource_parent(resource);
4364 group = sa_get_parent_group(share);
4365 if (group != NULL &&
4366 sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
4367 sa_handle_impl_t impl_handle;
4368 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
4369 if (impl_handle != NULL)
4370 ret = sa_commit_share(impl_handle->scfhandle,
4371 group, share);
4372 else
4373 ret = SA_SYSTEM_ERR;
4374 }
4375 return (ret);
4376 }
4377
4378 /*
4379 * sa_get_resource_description(share)
4380 *
4381 * Return the description text for the specified share if it
4382 * exists. NULL if no description exists.
4383 */
4384
4385 char *
4386 sa_get_resource_description(sa_resource_t resource)
4387 {
4388 xmlChar *description = NULL;
4389 xmlNodePtr node;
4390
|
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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013 RackTop Systems.
25 */
26
27 /*
28 * Share control API
29 */
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <libxml/parser.h>
38 #include <libxml/tree.h>
39 #include "libshare.h"
40 #include "libshare_impl.h"
41 #include <libscf.h>
42 #include "scfutil.h"
43 #include <ctype.h>
44 #include <libintl.h>
49 #define SA_STRSIZE 256 /* max string size for names */
50
51 /*
52 * internal object type values returned by sa_get_object_type()
53 */
54 #define SA_TYPE_UNKNOWN 0
55 #define SA_TYPE_GROUP 1
56 #define SA_TYPE_SHARE 2
57 #define SA_TYPE_RESOURCE 3
58 #define SA_TYPE_OPTIONSET 4
59 #define SA_TYPE_ALTSPACE 5
60
61 /*
62 * internal data structures
63 */
64
65 extern struct sa_proto_plugin *sap_proto_list;
66
67 /* current SMF/SVC repository handle */
68 extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
69 extern int gettransients(sa_handle_t, xmlNodePtr *);
70 extern char *sa_fstype(char *);
71 extern boolean_t sa_is_share(void *);
72 extern boolean_t sa_is_resource(void *);
73 extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
74 extern boolean_t sa_group_is_zfs(sa_group_t);
75 extern boolean_t sa_path_is_zfs(char *);
76 extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
77 extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
78 extern void update_legacy_config(sa_handle_t);
79 extern int issubdir(char *, char *);
80 extern int sa_zfs_init(sa_handle_t);
81 extern void sa_zfs_fini(sa_handle_t);
82 extern void sablocksigs(sigset_t *);
83 extern void saunblocksigs(sigset_t *);
84 static sa_group_t sa_get_optionset_parent(sa_optionset_t);
85 static char *get_node_attr(void *, char *);
86 extern void sa_update_sharetab_ts(sa_handle_t);
87
88 /*
89 * Data structures for finding/managing the document root to access
90 * handle mapping. The list isn't expected to grow very large so a
91 * simple list is acceptable. The purpose is to provide a way to start
92 * with a group or share and find the library handle needed for
93 * various operations.
94 */
95 mutex_t sa_global_lock;
96 struct doc2handle {
97 struct doc2handle *next;
98 xmlNodePtr root;
99 sa_handle_t handle;
100 };
101
102 mutex_t sa_dfstab_lock;
103
104 /* definitions used in a couple of property functions */
105 #define SA_PROP_OP_REMOVE 1
106 #define SA_PROP_OP_ADD 2
107 #define SA_PROP_OP_UPDATE 3
108
109 static struct doc2handle *sa_global_handles = NULL;
110
111 /* helper functions */
112
113 /*
114 * sa_errorstr(err)
115 *
116 * convert an error value to an error string
117 */
118
119 char *
223 ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
224 break;
225 case SA_SHARE_EXISTS:
226 ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
227 break;
228 default:
229 (void) snprintf(errstr, sizeof (errstr),
230 dgettext(TEXT_DOMAIN, "unknown %d"), err);
231 ret = errstr;
232 }
233 return (ret);
234 }
235
236 /*
237 * Document root to active handle mapping functions. These are only
238 * used internally. A mutex is used to prevent access while the list
239 * is changing. In general, the list will be relatively short - one
240 * item per thread that has called sa_init().
241 */
242
243 sa_handle_t
244 get_handle_for_root(xmlNodePtr root)
245 {
246 struct doc2handle *item;
247
248 (void) mutex_lock(&sa_global_lock);
249 for (item = sa_global_handles; item != NULL; item = item->next) {
250 if (item->root == root)
251 break;
252 }
253 (void) mutex_unlock(&sa_global_lock);
254 if (item != NULL)
255 return (item->handle);
256 return (NULL);
257 }
258
259 static int
260 add_handle_for_root(xmlNodePtr root, sa_handle_t handle)
261 {
262 struct doc2handle *item;
263 int ret = SA_NO_MEMORY;
264
265 item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1);
266 if (item != NULL) {
267 item->root = root;
268 item->handle = handle;
269 (void) mutex_lock(&sa_global_lock);
270 item->next = sa_global_handles;
271 sa_global_handles = item;
272 (void) mutex_unlock(&sa_global_lock);
273 ret = SA_OK;
274 }
275 return (ret);
276 }
277
278 /*
279 * remove_handle_for_root(root)
280 *
303 prev = item;
304 }
305 (void) mutex_unlock(&sa_global_lock);
306 }
307
308 /*
309 * sa_find_group_handle(sa_group_t group)
310 *
311 * Find the sa_handle_t for the configuration associated with this
312 * group.
313 */
314 sa_handle_t
315 sa_find_group_handle(sa_group_t group)
316 {
317 xmlNodePtr node = (xmlNodePtr)group;
318 sa_handle_t handle;
319
320 while (node != NULL) {
321 if (strcmp((char *)(node->name), "sharecfg") == 0) {
322 /* have the root so get the handle */
323 handle = get_handle_for_root(node);
324 return (handle);
325 }
326 node = node->parent;
327 }
328 return (NULL);
329 }
330
331 /*
332 * set_legacy_timestamp(root, path, timevalue)
333 *
334 * add the current timestamp value to the configuration for use in
335 * determining when to update the legacy files. For SMF, this
336 * property is kept in default/operation/legacy_timestamp
337 */
338
339 static void
340 set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval)
341 {
342 xmlNodePtr node;
343 xmlChar *lpath = NULL;
344 sa_handle_t handle;
345
346 /* Have to have a handle or else we weren't initialized. */
347 handle = get_handle_for_root(root);
348 if (handle == NULL)
349 return;
350
351 for (node = root->xmlChildrenNode; node != NULL;
352 node = node->next) {
353 if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) {
354 /* a possible legacy node for this path */
355 lpath = xmlGetProp(node, (xmlChar *)"path");
356 if (lpath != NULL &&
357 xmlStrcmp(lpath, (xmlChar *)path) == 0) {
358 xmlFree(lpath);
359 break;
360 }
361 if (lpath != NULL)
362 xmlFree(lpath);
363 }
364 }
584 if (fstype != NULL && strcmp(fstype, "zfs") == 0) {
585 if (sa_zfs_is_shared(handle, path))
586 error = SA_INVALID_NAME;
587 }
588 if (fstype != NULL)
589 sa_free_fstype(fstype);
590 }
591 if (error == SA_OK)
592 error = checksubdir(handle, path, strictness);
593 }
594 return (error);
595 }
596
597 /*
598 * check to see if group/share is persistent.
599 *
600 * "group" can be either an sa_group_t or an sa_share_t. (void *)
601 * works since both thse types are also void *.
602 * If the share is a ZFS share, mark it as persistent.
603 */
604 boolean_t
605 sa_is_persistent(void *group)
606 {
607 char *type;
608 boolean_t persist = B_TRUE;
609 sa_group_t grp;
610
611 type = sa_get_group_attr((sa_group_t)group, "type");
612 if (type != NULL) {
613 if (strcmp(type, "transient") == 0)
614 persist = B_FALSE;
615 sa_free_attr_string(type);
616 }
617
618 grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group;
619 if (sa_group_is_zfs(grp))
620 persist = B_TRUE;
621
622 return (persist);
623 }
624
625 /*
626 * sa_valid_group_name(name)
627 *
628 * check that the "name" contains only valid characters and otherwise
629 * fits the required naming conventions. Valid names must start with
630 * an alphabetic and the remainder may consist of only alphanumeric
631 * plus the '-' and '_' characters. This name limitation comes from
632 * inherent limitations in SMF.
633 */
634
635 int
636 sa_valid_group_name(char *name)
637 {
638 int ret = 1;
639 ssize_t len;
640
817 * Initialize the API
818 * find all the shared objects
819 * init the tables with all objects
820 * read in the current configuration
821 */
822
823 #define GETPROP(prop) scf_simple_prop_next_astring(prop)
824 #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \
825 tval != TSTAMP(st.st_ctim)
826
827 sa_handle_t
828 sa_init(int init_service)
829 {
830 struct stat st;
831 int legacy = 0;
832 uint64_t tval = 0;
833 int lockfd;
834 sigset_t old;
835 int updatelegacy = B_FALSE;
836 scf_simple_prop_t *prop;
837 sa_handle_t handle;
838 int err;
839
840 handle = calloc(sizeof (struct sa_handle), 1);
841
842 if (handle != NULL) {
843 /*
844 * Get protocol specific structures, but only if this
845 * is the only handle.
846 */
847 (void) mutex_lock(&sa_global_lock);
848 if (sa_global_handles == NULL)
849 (void) proto_plugin_init();
850 (void) mutex_unlock(&sa_global_lock);
851 if (init_service & SA_INIT_SHARE_API) {
852 /*
853 * initialize access into libzfs. We use this
854 * when collecting info about ZFS datasets and
855 * shares.
856 */
857 if (sa_zfs_init(handle) == B_FALSE) {
858 free(handle);
859 (void) mutex_lock(&sa_global_lock);
860 (void) proto_plugin_fini();
973 if (updatelegacy == B_TRUE) {
974 (void) mutex_unlock(
975 &sa_dfstab_lock);
976 (void) lockf(lockfd,
977 F_ULOCK, 0);
978 (void) close(lockfd);
979 }
980 return (NULL);
981 }
982
983 if (tval == 0) {
984 /*
985 * first time so make sure
986 * default is setup
987 */
988 verifydefgroupopts(handle);
989 }
990
991 if (updatelegacy == B_TRUE) {
992 sablocksigs(&old);
993 getlegacyconfig(handle,
994 SA_LEGACY_DFSTAB, &handle->tree);
995 if (stat(SA_LEGACY_DFSTAB, &st) >= 0)
996 set_legacy_timestamp(
997 handle->tree,
998 SA_LEGACY_DFSTAB,
999 TSTAMP(st.st_ctim));
1000 saunblocksigs(&old);
1001 /*
1002 * Safe to unlock now to allow
1003 * others to run
1004 */
1005 (void) mutex_unlock(&sa_dfstab_lock);
1006 (void) lockf(lockfd, F_ULOCK, 0);
1007 (void) close(lockfd);
1008 }
1009 /* Get sharetab timestamp */
1010 sa_update_sharetab_ts(handle);
1011
1012 /* Get lastupdate (transaction) timestamp */
1013 prop = scf_simple_prop_get(
1014 handle->scfhandle->handle,
1015 (const char *)SA_SVC_FMRI_BASE ":default",
1016 "state", "lastupdate");
1017 if (prop != NULL) {
1018 char *str;
1019 str =
1020 scf_simple_prop_next_astring(prop);
1021 if (str != NULL)
1022 handle->tstrans =
1023 strtoull(str, NULL, 0);
1024 else
1025 handle->tstrans = 0;
1026 scf_simple_prop_free(prop);
1027 }
1028 legacy |= sa_get_zfs_shares(handle, "zfs");
1029 legacy |= gettransients(handle, &handle->tree);
1030 }
1031 }
1032 }
1033 return (handle);
1034 }
1035
1036 /*
1037 * sa_fini(handle)
1038 * Uninitialize the API structures including the configuration
1039 * data structures and ZFS related data.
1040 */
1041
1042 void
1043 sa_fini(sa_handle_t handle)
1044 {
1045 if (handle != NULL) {
1046 /*
1047 * Free the config trees and any other data structures
1048 * used in the handle.
1049 */
1050 if (handle->doc != NULL)
1051 xmlFreeDoc(handle->doc);
1052
1053 /* Remove and free the entry in the global list. */
1054 remove_handle_for_root(handle->tree);
1055
1056 /*
1057 * If this was the last handle to release, unload the
1058 * plugins that were loaded. Use a mutex in case
1059 * another thread is reinitializing.
1060 */
1061 (void) mutex_lock(&sa_global_lock);
1062 if (sa_global_handles == NULL)
1063 (void) proto_plugin_fini();
1064 (void) mutex_unlock(&sa_global_lock);
1065
1066 sa_scf_fini(handle->scfhandle);
1067 sa_zfs_fini(handle);
1068
1069 /* Make sure we free the handle */
1070 free(handle);
1071
1072 }
1073 }
1074
1075 /*
1076 * sa_get_protocols(char **protocol)
1077 * Get array of protocols that are supported
1078 * Returns pointer to an allocated and NULL terminated
1079 * array of strings. Caller must free.
1080 * This really should be determined dynamically.
1081 * If there aren't any defined, return -1.
1082 * Use free() to return memory.
1083 */
1084
1085 int
1086 sa_get_protocols(char ***protocols)
1087 {
1088 int numproto = -1;
1089
1090 if (protocols != NULL) {
1137 name = NULL;
1138 }
1139 }
1140 }
1141 if (name != NULL)
1142 xmlFree(name);
1143 return (node);
1144 }
1145
1146 /*
1147 * sa_get_group(groupname)
1148 * Return the "group" specified. If groupname is NULL,
1149 * return the first group of the list of groups.
1150 */
1151 sa_group_t
1152 sa_get_group(sa_handle_t handle, char *groupname)
1153 {
1154 xmlNodePtr node = NULL;
1155 char *subgroup = NULL;
1156 char *group = NULL;
1157
1158 if (handle != NULL && handle->tree != NULL) {
1159 if (groupname != NULL) {
1160 group = strdup(groupname);
1161 if (group != NULL) {
1162 subgroup = strchr(group, '/');
1163 if (subgroup != NULL)
1164 *subgroup++ = '\0';
1165 }
1166 }
1167 /*
1168 * We want to find the, possibly, named group. If
1169 * group is not NULL, then lookup the name. If it is
1170 * NULL, we only do the find if groupname is also
1171 * NULL. This allows lookup of the "first" group in
1172 * the internal list.
1173 */
1174 if (group != NULL || groupname == NULL)
1175 node = find_group_by_name(handle->tree,
1176 (xmlChar *)group);
1177
1178 /* if a subgroup, find it before returning */
1179 if (subgroup != NULL && node != NULL)
1180 node = find_group_by_name(node, (xmlChar *)subgroup);
1181 }
1182 if (node != NULL && (char *)group != NULL)
1183 (void) sa_get_instance(handle->scfhandle, (char *)group);
1184 if (group != NULL)
1185 free(group);
1186 return ((sa_group_t)(node));
1187 }
1188
1189 /*
1190 * sa_get_next_group(group)
1191 * Return the "next" group after the specified group from
1192 * the internal group list. NULL if there are no more.
1193 */
1194 sa_group_t
1195 sa_get_next_group(sa_group_t group)
1196 {
1197 xmlNodePtr ngroup = NULL;
1198 if (group != NULL) {
1199 for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL;
1200 ngroup = ngroup->next) {
1201 if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0)
1202 break;
1203 }
1483 (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
1484 (void) xmlSetProp(node, (xmlChar *)"type",
1485 persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
1486 if (flags != 0)
1487 mark_excluded_protos(group, node, flags);
1488 if (persist != SA_SHARE_TRANSIENT) {
1489 /*
1490 * persistent shares come in two flavors: SMF and
1491 * ZFS. Sort this one out based on target group and
1492 * path type. Both NFS and SMB are supported. First,
1493 * check to see if the protocol is enabled on the
1494 * subgroup and then setup the share appropriately.
1495 */
1496 if (sa_group_is_zfs(group) &&
1497 sa_path_is_zfs(sharepath)) {
1498 if (sa_get_optionset(group, "nfs") != NULL)
1499 err = sa_zfs_set_sharenfs(group, sharepath, 1);
1500 else if (sa_get_optionset(group, "smb") != NULL)
1501 err = sa_zfs_set_sharesmb(group, sharepath, 1);
1502 } else {
1503 sa_handle_t handle = sa_find_group_handle(group);
1504 if (handle != NULL) {
1505 err = sa_commit_share(handle->scfhandle,
1506 group, (sa_share_t)node);
1507 } else {
1508 err = SA_SYSTEM_ERR;
1509 }
1510 }
1511 }
1512 if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
1513 /* called by the dfstab parser so could be a show */
1514 err = SA_OK;
1515
1516 if (err != SA_OK) {
1517 /*
1518 * we couldn't commit to the repository so undo
1519 * our internal state to reflect reality.
1520 */
1521 xmlUnlinkNode(node);
1522 xmlFreeNode(node);
1523 node = NULL;
1524 }
1525
1720 type = sa_get_share_attr(share, "type");
1721 group = sa_get_parent_group(share);
1722 zfs = sa_get_group_attr(group, "zfs");
1723 groupname = sa_get_group_attr(group, "name");
1724 if (type != NULL && strcmp(type, "persist") != 0)
1725 transient = 1;
1726 if (type != NULL)
1727 sa_free_attr_string(type);
1728
1729 /* remove the node from its group then free the memory */
1730
1731 /*
1732 * need to test if "busy"
1733 */
1734 /* only do SMF action if permanent */
1735 if (!transient || zfs != NULL) {
1736 /* remove from legacy dfstab as well as possible SMF */
1737 ret = sa_delete_legacy(share, NULL);
1738 if (ret == SA_OK) {
1739 if (!sa_group_is_zfs(group)) {
1740 sa_handle_t handle =
1741 sa_find_group_handle(group);
1742 if (handle != NULL) {
1743 ret = sa_delete_share(
1744 handle->scfhandle, group,
1745 share);
1746 } else {
1747 ret = SA_SYSTEM_ERR;
1748 }
1749 } else {
1750 char *sharepath = sa_get_share_attr(share,
1751 "path");
1752 if (sharepath != NULL) {
1753 ret = sa_zfs_set_sharenfs(group,
1754 sharepath, 0);
1755 sa_free_attr_string(sharepath);
1756 }
1757 }
1758 }
1759 }
1760 if (groupname != NULL)
1761 sa_free_attr_string(groupname);
1762 if (zfs != NULL)
1763 sa_free_attr_string(zfs);
1764
1767 return (ret);
1768 }
1769
1770 /*
1771 * sa_move_share(group, share)
1772 *
1773 * move the specified share to the specified group. Update SMF
1774 * appropriately.
1775 */
1776
1777 int
1778 sa_move_share(sa_group_t group, sa_share_t share)
1779 {
1780 sa_group_t oldgroup;
1781 int ret = SA_OK;
1782
1783 /* remove the node from its group then free the memory */
1784
1785 oldgroup = sa_get_parent_group(share);
1786 if (oldgroup != group) {
1787 sa_handle_t handle;
1788 xmlUnlinkNode((xmlNodePtr)share);
1789 /*
1790 * now that the share isn't in its old group, add to
1791 * the new one
1792 */
1793 (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
1794 /* need to deal with SMF */
1795 handle = sa_find_group_handle(group);
1796 if (handle != NULL) {
1797 /*
1798 * need to remove from old group first and then add to
1799 * new group. Ideally, we would do the other order but
1800 * need to avoid having the share in two groups at the
1801 * same time.
1802 */
1803 ret = sa_delete_share(handle->scfhandle, oldgroup,
1804 share);
1805 if (ret == SA_OK)
1806 ret = sa_commit_share(handle->scfhandle,
1807 group, share);
1808 } else {
1809 ret = SA_SYSTEM_ERR;
1810 }
1811 }
1812 return (ret);
1813 }
1814
1815 /*
1816 * sa_get_parent_group(share)
1817 *
1818 * Return the containing group for the share. If a group was actually
1819 * passed in, we don't want a parent so return NULL.
1820 */
1821
1822 sa_group_t
1823 sa_get_parent_group(sa_share_t share)
1824 {
1825 xmlNodePtr node = NULL;
1826 if (share != NULL) {
1827 node = ((xmlNodePtr)share)->parent;
1828 /*
1829 * make sure parent is a group and not sharecfg since
1830 * we may be cheating and passing in a group.
1831 * Eventually, groups of groups might come into being.
1832 */
1833 if (node == NULL ||
1834 xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0)
1835 node = NULL;
1836 }
1837 return ((sa_group_t)node);
1838 }
1839
1840 /*
1841 * _sa_create_group(handle, groupname)
1842 *
1843 * Create a group in the document. The caller will need to deal with
1844 * configuration store and activation.
1845 */
1846
1847 sa_group_t
1848 _sa_create_group(sa_handle_t handle, char *groupname)
1849 {
1850 xmlNodePtr node = NULL;
1851
1852 if (sa_valid_group_name(groupname)) {
1853 node = xmlNewChild(handle->tree, NULL, (xmlChar *)"group",
1854 NULL);
1855 if (node != NULL) {
1856 (void) xmlSetProp(node, (xmlChar *)"name",
1857 (xmlChar *)groupname);
1858 (void) xmlSetProp(node, (xmlChar *)"state",
1859 (xmlChar *)"enabled");
1860 }
1861 }
1862 return ((sa_group_t)node);
1863 }
1864
1865 /*
1866 * _sa_create_zfs_group(group, groupname)
1867 *
1868 * Create a ZFS subgroup under the specified group. This may
1869 * eventually form the basis of general sub-groups, but is currently
1870 * restricted to ZFS.
1871 */
1872 sa_group_t
1873 _sa_create_zfs_group(sa_group_t group, char *groupname)
1884
1885 return ((sa_group_t)node);
1886 }
1887
1888 /*
1889 * sa_create_group(groupname, *error)
1890 *
1891 * Create a new group with groupname. Need to validate that it is a
1892 * legal name for SMF and the construct the SMF service instance of
1893 * svc:/network/shares/group to implement the group. All necessary
1894 * operational properties must be added to the group at this point
1895 * (via the SMF transaction model).
1896 */
1897 sa_group_t
1898 sa_create_group(sa_handle_t handle, char *groupname, int *error)
1899 {
1900 xmlNodePtr node = NULL;
1901 sa_group_t group;
1902 int ret;
1903 char rbacstr[SA_STRSIZE];
1904
1905 ret = SA_OK;
1906
1907 if (handle == NULL || handle->scfhandle == NULL) {
1908 ret = SA_SYSTEM_ERR;
1909 goto err;
1910 }
1911
1912 group = sa_get_group(handle, groupname);
1913 if (group != NULL) {
1914 ret = SA_DUPLICATE_NAME;
1915 } else {
1916 if (sa_valid_group_name(groupname)) {
1917 node = xmlNewChild(handle->tree, NULL,
1918 (xmlChar *)"group", NULL);
1919 if (node != NULL) {
1920 (void) xmlSetProp(node, (xmlChar *)"name",
1921 (xmlChar *)groupname);
1922 /* default to the group being enabled */
1923 (void) xmlSetProp(node, (xmlChar *)"state",
1924 (xmlChar *)"enabled");
1925 ret = sa_create_instance(handle->scfhandle,
1926 groupname);
1927 if (ret == SA_OK) {
1928 ret = sa_start_transaction(
1929 handle->scfhandle,
1930 "operation");
1931 }
1932 if (ret == SA_OK) {
1933 ret = sa_set_property(
1934 handle->scfhandle,
1935 "state", "enabled");
1936 if (ret == SA_OK) {
1937 ret = sa_end_transaction(
1938 handle->scfhandle,
1939 handle);
1940 } else {
1941 sa_abort_transaction(
1942 handle->scfhandle);
1943 }
1944 }
1945 if (ret == SA_OK) {
1946 /* initialize the RBAC strings */
1947 ret = sa_start_transaction(
1948 handle->scfhandle,
1949 "general");
1950 if (ret == SA_OK) {
1951 (void) snprintf(rbacstr,
1952 sizeof (rbacstr), "%s.%s",
1953 SA_RBAC_MANAGE, groupname);
1954 ret = sa_set_property(
1955 handle->scfhandle,
1956 "action_authorization",
1957 rbacstr);
1958 }
1959 if (ret == SA_OK) {
1960 (void) snprintf(rbacstr,
1961 sizeof (rbacstr), "%s.%s",
1962 SA_RBAC_VALUE, groupname);
1963 ret = sa_set_property(
1964 handle->scfhandle,
1965 "value_authorization",
1966 rbacstr);
1967 }
1968 if (ret == SA_OK) {
1969 ret = sa_end_transaction(
1970 handle->scfhandle,
1971 handle);
1972 } else {
1973 sa_abort_transaction(
1974 handle->scfhandle);
1975 }
1976 }
1977 if (ret != SA_OK) {
1978 /*
1979 * Couldn't commit the group
1980 * so we need to undo
1981 * internally.
1982 */
1983 xmlUnlinkNode(node);
1984 xmlFreeNode(node);
1985 node = NULL;
1986 }
1987 } else {
1988 ret = SA_NO_MEMORY;
1989 }
1990 } else {
1991 ret = SA_INVALID_NAME;
1992 }
1993 }
1994 err:
1995 if (error != NULL)
1996 *error = ret;
1997 return ((sa_group_t)node);
1998 }
1999
2000 /*
2001 * sa_remove_group(group)
2002 *
2003 * Remove the specified group. This deletes from the SMF repository.
2004 * All property groups and properties are removed.
2005 */
2006
2007 int
2008 sa_remove_group(sa_group_t group)
2009 {
2010 char *name;
2011 int ret = SA_OK;
2012 sa_handle_t handle;
2013
2014 handle = sa_find_group_handle(group);
2015 if (handle != NULL) {
2016 name = sa_get_group_attr(group, "name");
2017 if (name != NULL) {
2018 ret = sa_delete_instance(handle->scfhandle, name);
2019 sa_free_attr_string(name);
2020 }
2021 xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
2022 xmlFreeNode((xmlNodePtr)group); /* now it is gone */
2023 } else {
2024 ret = SA_SYSTEM_ERR;
2025 }
2026 return (ret);
2027 }
2028
2029 /*
2030 * sa_update_config()
2031 *
2032 * Used to update legacy files that need to be updated in bulk
2033 * Currently, this is a placeholder and will go away in a future
2034 * release.
2035 */
2036
2037 int
2038 sa_update_config(sa_handle_t handle)
2095 sa_get_group_attr(sa_group_t group, char *tag)
2096 {
2097 return (get_node_attr((void *)group, tag));
2098 }
2099
2100 /*
2101 * sa_set_group_attr(group, tag, value)
2102 *
2103 * set the specified tag/attribute on the group using value as its
2104 * value.
2105 *
2106 * This will result in setting the property in the SMF repository as
2107 * well as in the internal document.
2108 */
2109
2110 int
2111 sa_set_group_attr(sa_group_t group, char *tag, char *value)
2112 {
2113 int ret;
2114 char *groupname;
2115 sa_handle_t handle;
2116
2117 /*
2118 * ZFS group/subgroup doesn't need the handle so shortcut.
2119 */
2120 if (sa_group_is_zfs(group)) {
2121 set_node_attr((void *)group, tag, value);
2122 return (SA_OK);
2123 }
2124
2125 handle = sa_find_group_handle(group);
2126 if (handle != NULL) {
2127 groupname = sa_get_group_attr(group, "name");
2128 ret = sa_get_instance(handle->scfhandle, groupname);
2129 if (ret == SA_OK) {
2130 set_node_attr((void *)group, tag, value);
2131 ret = sa_start_transaction(handle->scfhandle,
2132 "operation");
2133 if (ret == SA_OK) {
2134 ret = sa_set_property(handle->scfhandle,
2135 tag, value);
2136 if (ret == SA_OK)
2137 ret = sa_end_transaction(
2138 handle->scfhandle,
2139 handle);
2140 else
2141 sa_abort_transaction(
2142 handle->scfhandle);
2143 }
2144 if (ret == SA_SYSTEM_ERR)
2145 ret = SA_NO_PERMISSION;
2146 }
2147 if (groupname != NULL)
2148 sa_free_attr_string(groupname);
2149 } else {
2150 ret = SA_SYSTEM_ERR;
2151 }
2152 return (ret);
2153 }
2154
2155 /*
2156 * sa_get_share_attr(share, tag)
2157 *
2158 * Return the value of the tag/attribute set on the specified
2159 * share. Returns NULL if the tag doesn't exist.
2160 */
2161
2162 char *
2203
2204 /*
2205 * There are some attributes that may have specific
2206 * restrictions on them. Initially, only "resource" has
2207 * special meaning that needs to be checked. Only one instance
2208 * of a resource name may exist within a group.
2209 */
2210
2211 if (strcmp(tag, "resource") == 0) {
2212 resource = sa_get_resource(group, value);
2213 if (resource != share && resource != NULL)
2214 ret = SA_DUPLICATE_NAME;
2215 }
2216 if (ret == SA_OK) {
2217 set_node_attr((void *)share, tag, value);
2218 if (group != NULL) {
2219 char *type;
2220 /* we can probably optimize this some */
2221 type = sa_get_share_attr(share, "type");
2222 if (type == NULL || strcmp(type, "transient") != 0) {
2223 sa_handle_t handle = sa_find_group_handle(
2224 group);
2225 if (handle != NULL) {
2226 ret = sa_commit_share(
2227 handle->scfhandle, group,
2228 share);
2229 } else {
2230 ret = SA_SYSTEM_ERR;
2231 }
2232 }
2233 if (type != NULL)
2234 sa_free_attr_string(type);
2235 }
2236 }
2237 return (ret);
2238 }
2239
2240 /*
2241 * sa_get_property_attr(prop, tag)
2242 *
2243 * Get the value of the specified property attribute. Standard
2244 * attributes are "type" and "value".
2245 */
2246
2247 char *
2502 node = node->next) {
2503 if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
2504 break;
2505 }
2506 }
2507 /* no existing description but want to add */
2508 if (node == NULL && content != NULL) {
2509 /* add a description */
2510 node = _sa_set_share_description(share, content);
2511 } else if (node != NULL && content != NULL) {
2512 /* update a description */
2513 xmlNodeSetContent(node, (xmlChar *)content);
2514 } else if (node != NULL && content == NULL) {
2515 /* remove an existing description */
2516 xmlUnlinkNode(node);
2517 xmlFreeNode(node);
2518 }
2519 group = sa_get_parent_group(share);
2520 if (group != NULL &&
2521 sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
2522 sa_handle_t handle = sa_find_group_handle(group);
2523 if (handle != NULL) {
2524 ret = sa_commit_share(handle->scfhandle, group,
2525 share);
2526 } else {
2527 ret = SA_SYSTEM_ERR;
2528 }
2529 }
2530 return (ret);
2531 }
2532
2533 /*
2534 * fixproblemchars(string)
2535 *
2536 * don't want any newline or tab characters in the text since these
2537 * could break display of data and legacy file formats.
2538 */
2539 static void
2540 fixproblemchars(char *str)
2541 {
2542 int c;
2543 for (c = *str; c != '\0'; c = *++str) {
2544 if (c == '\t' || c == '\n')
2647 char *groupname;
2648
2649 /*
2650 * Need to get parent group in all cases, but also get
2651 * the share if this is a resource.
2652 */
2653 if (sa_is_share(group)) {
2654 parent = sa_get_parent_group((sa_share_t)group);
2655 } else if (sa_is_resource(group)) {
2656 share = sa_get_resource_parent(
2657 (sa_resource_t)group);
2658 parent = sa_get_parent_group(share);
2659 }
2660
2661 sa_set_optionset_attr(optionset, "type", proto);
2662
2663 (void) sa_optionset_name(optionset, oname,
2664 sizeof (oname), id);
2665 groupname = sa_get_group_attr(parent, "name");
2666 if (groupname != NULL && sa_is_persistent(group)) {
2667 sa_handle_t handle = sa_find_group_handle(
2668 group);
2669 assert(handle != NULL);
2670 if (handle != NULL) {
2671 (void) sa_get_instance(
2672 handle->scfhandle, groupname);
2673 (void) sa_create_pgroup(
2674 handle->scfhandle, oname);
2675 }
2676 }
2677 if (groupname != NULL)
2678 sa_free_attr_string(groupname);
2679 }
2680 }
2681
2682 if (id != NULL)
2683 sa_free_attr_string(id);
2684 return (optionset);
2685 }
2686
2687 /*
2688 * sa_get_property_parent(property)
2689 *
2690 * Given a property, return the object it is a property of. This will
2691 * be an optionset of some type.
2692 */
2693
2694 static sa_optionset_t
2753 zfs_set_update(sa_share_t share)
2754 {
2755 set_node_attr((void *)share, "changed", "true");
2756 }
2757
2758 /*
2759 * sa_commit_properties(optionset, clear)
2760 *
2761 * Check if SMF or ZFS config and either update or abort the pending
2762 * changes.
2763 */
2764
2765 int
2766 sa_commit_properties(sa_optionset_t optionset, int clear)
2767 {
2768 sa_group_t group;
2769 sa_group_t parent;
2770 int zfs = 0;
2771 int needsupdate = 0;
2772 int ret = SA_OK;
2773 sa_handle_t handle;
2774
2775 group = sa_get_optionset_parent(optionset);
2776 if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) {
2777 /* only update ZFS if on a share */
2778 parent = sa_get_parent_group(group);
2779 zfs++;
2780 if (parent != NULL && is_zfs_group(parent))
2781 needsupdate = zfs_needs_update(group);
2782 else
2783 zfs = 0;
2784 }
2785 if (zfs) {
2786 if (!clear && needsupdate)
2787 ret = sa_zfs_update((sa_share_t)group);
2788 } else {
2789 handle = sa_find_group_handle(group);
2790 if (handle != NULL) {
2791 if (clear) {
2792 (void) sa_abort_transaction(
2793 handle->scfhandle);
2794 } else {
2795 ret = sa_end_transaction(
2796 handle->scfhandle, handle);
2797 }
2798 } else {
2799 ret = SA_SYSTEM_ERR;
2800 }
2801 }
2802 return (ret);
2803 }
2804
2805 /*
2806 * sa_destroy_optionset(optionset)
2807 *
2808 * Remove the optionset from its group. Update the repository to
2809 * reflect this change.
2810 */
2811
2812 int
2813 sa_destroy_optionset(sa_optionset_t optionset)
2814 {
2815 char name[SA_STRSIZE];
2816 int len;
2817 int ret;
2818 char *id = NULL;
2819 sa_group_t group;
2820 int ispersist = 1;
2821
2822 /* now delete the prop group */
2823 group = sa_get_optionset_parent(optionset);
2824 if (group != NULL) {
2825 if (sa_is_resource(group)) {
2826 sa_resource_t resource = group;
2827 sa_share_t share = sa_get_resource_parent(resource);
2828 group = sa_get_parent_group(share);
2829 id = sa_get_share_attr(share, "id");
2830 } else if (sa_is_share(group)) {
2831 id = sa_get_share_attr((sa_share_t)group, "id");
2832 }
2833 ispersist = sa_is_persistent(group);
2834 }
2835 if (ispersist) {
2836 sa_handle_t handle = sa_find_group_handle(group);
2837 len = sa_optionset_name(optionset, name, sizeof (name), id);
2838 if (handle != NULL) {
2839 if (len > 0) {
2840 ret = sa_delete_pgroup(handle->scfhandle,
2841 name);
2842 }
2843 } else {
2844 ret = SA_SYSTEM_ERR;
2845 }
2846 }
2847 xmlUnlinkNode((xmlNodePtr)optionset);
2848 xmlFreeNode((xmlNodePtr)optionset);
2849 if (id != NULL)
2850 sa_free_attr_string(id);
2851 return (ret);
2852 }
2853
2854 /* private to the implementation */
2855 int
2856 _sa_remove_optionset(sa_optionset_t optionset)
2857 {
2858 int ret = SA_OK;
2859
2860 xmlUnlinkNode((xmlNodePtr)optionset);
2884 groupname = sa_get_group_attr(parent, "name");
2885 } else if (group != NULL) {
2886 groupname = sa_get_group_attr(group, "name");
2887 }
2888
2889 security = sa_get_security(group, sectype, proto);
2890 if (security != NULL) {
2891 /* can't have a duplicate security option */
2892 security = NULL;
2893 } else {
2894 security = (sa_security_t)xmlNewChild((xmlNodePtr)group,
2895 NULL, (xmlChar *)"security", NULL);
2896 if (security != NULL) {
2897 char oname[SA_STRSIZE];
2898 sa_set_security_attr(security, "type", proto);
2899
2900 sa_set_security_attr(security, "sectype", sectype);
2901 (void) sa_security_name(security, oname,
2902 sizeof (oname), id);
2903 if (groupname != NULL && sa_is_persistent(group)) {
2904 sa_handle_t handle = sa_find_group_handle(
2905 group);
2906 if (handle != NULL) {
2907 (void) sa_get_instance(
2908 handle->scfhandle, groupname);
2909 (void) sa_create_pgroup(
2910 handle->scfhandle, oname);
2911 }
2912 }
2913 }
2914 }
2915 if (id != NULL)
2916 sa_free_attr_string(id);
2917 if (groupname != NULL)
2918 sa_free_attr_string(groupname);
2919 return (security);
2920 }
2921
2922 /*
2923 * sa_destroy_security(security)
2924 *
2925 * Remove the specified optionset from the document and the
2926 * configuration.
2927 */
2928
2929 int
2930 sa_destroy_security(sa_security_t security)
2933 int len;
2934 int ret = SA_OK;
2935 char *id = NULL;
2936 sa_group_t group;
2937 int iszfs = 0;
2938 int ispersist = 1;
2939
2940 group = sa_get_optionset_parent(security);
2941
2942 if (group != NULL)
2943 iszfs = sa_group_is_zfs(group);
2944
2945 if (group != NULL && !iszfs) {
2946 if (sa_is_share(group))
2947 ispersist = sa_is_persistent(group);
2948 id = sa_get_share_attr((sa_share_t)group, "id");
2949 }
2950 if (ispersist) {
2951 len = sa_security_name(security, name, sizeof (name), id);
2952 if (!iszfs && len > 0) {
2953 sa_handle_t handle = sa_find_group_handle(group);
2954 if (handle != NULL) {
2955 ret = sa_delete_pgroup(handle->scfhandle,
2956 name);
2957 } else {
2958 ret = SA_SYSTEM_ERR;
2959 }
2960 }
2961 }
2962 xmlUnlinkNode((xmlNodePtr)security);
2963 xmlFreeNode((xmlNodePtr)security);
2964 if (iszfs)
2965 ret = sa_zfs_update(group);
2966 if (id != NULL)
2967 sa_free_attr_string(id);
2968 return (ret);
2969 }
2970
2971 /*
2972 * sa_get_security_attr(optionset, tag)
2973 *
2974 * Return the specified attribute value from the optionset.
2975 */
3044 * Add/remove/update the specified property prop into the optionset or
3045 * share. If a share, sort out which property group based on GUID. In
3046 * all cases, the appropriate transaction is set (or ZFS share is
3047 * marked as needing an update)
3048 */
3049
3050 static int
3051 sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
3052 sa_property_t prop, int type)
3053 {
3054 char *name;
3055 char *valstr;
3056 int ret = SA_OK;
3057 scf_transaction_entry_t *entry;
3058 scf_value_t *value;
3059 int opttype; /* 1 == optionset, 0 == security */
3060 char *id = NULL;
3061 int iszfs = 0;
3062 sa_group_t parent = NULL;
3063 sa_share_t share = NULL;
3064 sa_handle_t handle;
3065 scfutilhandle_t *scf_handle;
3066
3067 if (!sa_is_persistent(group)) {
3068 /*
3069 * if the group/share is not persistent we don't need
3070 * to do anything here
3071 */
3072 return (SA_OK);
3073 }
3074 handle = sa_find_group_handle(group);
3075 if (handle == NULL || handle->scfhandle == NULL)
3076 return (SA_SYSTEM_ERR);
3077 scf_handle = handle->scfhandle;
3078 name = sa_get_property_attr(prop, "type");
3079 valstr = sa_get_property_attr(prop, "value");
3080 entry = scf_entry_create(scf_handle->handle);
3081 opttype = is_nodetype((void *)optionset, "optionset");
3082
3083 /*
3084 * Check for share vs. resource since they need slightly
3085 * different treatment given the hierarchy.
3086 */
3087 if (valstr != NULL && entry != NULL) {
3088 if (sa_is_share(group)) {
3089 parent = sa_get_parent_group(group);
3090 share = (sa_share_t)group;
3091 if (parent != NULL)
3092 iszfs = is_zfs_group(parent);
3093 } else if (sa_is_resource(group)) {
3094 share = sa_get_parent_group(group);
3095 if (share != NULL)
3096 parent = sa_get_parent_group(share);
3097 } else {
3255 /*
3256 * Resources are children of share. Need to go up two
3257 * levels to find the group but the parent needs to be
3258 * the share at this point in order to get the "id".
3259 */
3260 parent = sa_get_parent_group(parent);
3261 group = sa_get_parent_group(parent);
3262 } else if (sa_is_share(parent)) {
3263 group = sa_get_parent_group(parent);
3264 } else {
3265 group = parent;
3266 }
3267
3268 if (property == NULL) {
3269 ret = SA_NO_MEMORY;
3270 } else {
3271 char oname[SA_STRSIZE];
3272
3273 if (!is_zfs_group(group)) {
3274 char *id = NULL;
3275 sa_handle_t handle;
3276 scfutilhandle_t *scf_handle;
3277
3278 handle = sa_find_group_handle(group);
3279 if (handle == NULL ||
3280 handle->scfhandle == NULL)
3281 ret = SA_SYSTEM_ERR;
3282 if (ret == SA_OK) {
3283 scf_handle = handle->scfhandle;
3284 if (sa_is_share((sa_group_t)parent)) {
3285 id = sa_get_share_attr(
3286 (sa_share_t)parent, "id");
3287 }
3288 if (scf_handle->trans == NULL) {
3289 if (is_nodetype(object, "optionset")) {
3290 (void) sa_optionset_name(
3291 (sa_optionset_t)object,
3292 oname, sizeof (oname), id);
3293 } else {
3294 (void) sa_security_name(
3295 (sa_optionset_t)object,
3296 oname, sizeof (oname), id);
3297 }
3298 ret = sa_start_transaction(scf_handle,
3299 oname);
3300 }
3301 if (ret == SA_OK) {
3302 char *name;
3303 char *value;
3762 } else {
3763 node = xmlNewChild((xmlNodePtr)share, NULL,
3764 (xmlChar *)"resource", NULL);
3765 if (node != NULL) {
3766 (void) xmlSetProp(node, (xmlChar *)"name",
3767 (xmlChar *)resource);
3768 (void) xmlSetProp(node, (xmlChar *)"type", persist ?
3769 (xmlChar *)"persist" : (xmlChar *)"transient");
3770 if (persist != SA_SHARE_TRANSIENT) {
3771 index = _sa_get_next_resource_index(share);
3772 (void) snprintf(istring, sizeof (istring), "%d",
3773 index);
3774 (void) xmlSetProp(node, (xmlChar *)"id",
3775 (xmlChar *)istring);
3776
3777 if (!sa_is_persistent((sa_group_t)share))
3778 goto done;
3779
3780 if (!sa_group_is_zfs(group)) {
3781 /* ZFS doesn't use resource names */
3782 sa_handle_t handle;
3783
3784 handle = sa_find_group_handle(
3785 group);
3786 if (handle != NULL)
3787 err = sa_commit_share(
3788 handle->scfhandle, group,
3789 share);
3790 else
3791 err = SA_SYSTEM_ERR;
3792 } else {
3793 err = sa_zfs_update((sa_share_t)group);
3794 }
3795 }
3796 }
3797 }
3798 done:
3799 if (error != NULL)
3800 *error = err;
3801 return ((sa_resource_t)node);
3802 }
3803
3804 /*
3805 * sa_remove_resource(resource)
3806 *
3807 * Remove the resource name from the share (and the system)
3808 */
3829 }
3830
3831 /* Disable the resource for all protocols. */
3832 (void) sa_disable_resource(resource, NULL);
3833
3834 /* Remove any optionsets from the resource. */
3835 for (opt = sa_get_optionset(resource, NULL);
3836 opt != NULL;
3837 opt = sa_get_next_optionset(opt))
3838 (void) sa_destroy_optionset(opt);
3839
3840 /* Remove from the share */
3841 xmlUnlinkNode((xmlNode *)resource);
3842 xmlFreeNode((xmlNode *)resource);
3843
3844 /* only do SMF action if permanent and not ZFS */
3845 if (transient)
3846 return (ret);
3847
3848 if (!sa_group_is_zfs(group)) {
3849 sa_handle_t handle = sa_find_group_handle(group);
3850 if (handle != NULL)
3851 ret = sa_commit_share(handle->scfhandle, group, share);
3852 else
3853 ret = SA_SYSTEM_ERR;
3854 } else {
3855 ret = sa_zfs_update((sa_share_t)group);
3856 }
3857
3858 return (ret);
3859 }
3860
3861 /*
3862 * proto_rename_resource(handle, group, resource, newname)
3863 *
3864 * Helper function for sa_rename_resource that notifies the protocol
3865 * of a resource name change prior to a config repository update.
3866 */
3867 static int
3868 proto_rename_resource(sa_handle_t handle, sa_group_t group,
3869 sa_resource_t resource, char *newname)
3870 {
3871 sa_optionset_t optionset;
3894 * Rename the resource to the new name, if it is unique.
3895 */
3896
3897 int
3898 sa_rename_resource(sa_resource_t resource, char *newname)
3899 {
3900 sa_share_t share;
3901 sa_group_t group = NULL;
3902 sa_resource_t target;
3903 int ret = SA_CONFIG_ERR;
3904 sa_handle_t handle = NULL;
3905
3906 share = sa_get_resource_parent(resource);
3907 if (share == NULL)
3908 return (ret);
3909
3910 group = sa_get_parent_group(share);
3911 if (group == NULL)
3912 return (ret);
3913
3914 handle = sa_find_group_handle(group);
3915 if (handle == NULL)
3916 return (ret);
3917
3918 target = sa_find_resource(handle, newname);
3919 if (target != NULL) {
3920 ret = SA_DUPLICATE_NAME;
3921 } else {
3922 /*
3923 * Everything appears to be valid at this
3924 * point. Change the name of the active share and then
3925 * update the share in the appropriate repository.
3926 */
3927 ret = proto_rename_resource(handle, group, resource, newname);
3928 set_node_attr(resource, "name", newname);
3929
3930 if (!sa_is_persistent((sa_group_t)share))
3931 return (ret);
3932
3933 if (!sa_group_is_zfs(group)) {
3934 ret = sa_commit_share(handle->scfhandle, group,
3935 share);
3936 } else {
3937 ret = sa_zfs_update((sa_share_t)group);
3938 }
3939 }
3940 return (ret);
3941 }
3942
3943 /*
3944 * sa_get_resource_attr(resource, tag)
3945 *
3946 * Get the named attribute of the resource. "name" and "id" are
3947 * currently defined. NULL if tag not defined.
3948 */
3949
3950 char *
3951 sa_get_resource_attr(sa_resource_t resource, char *tag)
3952 {
3953 return (get_node_attr((void *)resource, tag));
3954 }
4327 }
4328 }
4329
4330 /* no existing description but want to add */
4331 if (node == NULL && content != NULL) {
4332 /* add a description */
4333 node = _sa_set_share_description(resource, content);
4334 } else if (node != NULL && content != NULL) {
4335 /* update a description */
4336 xmlNodeSetContent(node, (xmlChar *)content);
4337 } else if (node != NULL && content == NULL) {
4338 /* remove an existing description */
4339 xmlUnlinkNode(node);
4340 xmlFreeNode(node);
4341 }
4342
4343 share = sa_get_resource_parent(resource);
4344 group = sa_get_parent_group(share);
4345 if (group != NULL &&
4346 sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
4347 sa_handle_t handle = sa_find_group_handle(group);
4348 if (handle != NULL)
4349 ret = sa_commit_share(handle->scfhandle,
4350 group, share);
4351 else
4352 ret = SA_SYSTEM_ERR;
4353 }
4354 return (ret);
4355 }
4356
4357 /*
4358 * sa_get_resource_description(share)
4359 *
4360 * Return the description text for the specified share if it
4361 * exists. NULL if no description exists.
4362 */
4363
4364 char *
4365 sa_get_resource_description(sa_resource_t resource)
4366 {
4367 xmlChar *description = NULL;
4368 xmlNodePtr node;
4369
|