Print this page
4095 minor cleanup up libshare


   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