13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 23*3348Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* 303034Sdougm * Share control API 313034Sdougm */ 323034Sdougm #include <stdio.h> 333034Sdougm #include <string.h> 343034Sdougm #include <ctype.h> 353034Sdougm #include <sys/types.h> 363034Sdougm #include <sys/stat.h> 373034Sdougm #include <unistd.h> 383034Sdougm #include <libxml/parser.h> 393034Sdougm #include <libxml/tree.h> 403034Sdougm #include "libshare.h" 413034Sdougm #include "libshare_impl.h" 423034Sdougm #include <libscf.h> 433034Sdougm #include "scfutil.h" 443034Sdougm #include <ctype.h> 453034Sdougm #include <libintl.h> 463034Sdougm 473034Sdougm #if _NOT_SMF 483034Sdougm #define CONFIG_FILE "/var/tmp/share.cfg" 493034Sdougm #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 503034Sdougm #endif 513034Sdougm #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 523034Sdougm (tm.tv_nsec & 0xffffffff)) 533034Sdougm 543034Sdougm /* 553034Sdougm * internal data structures 563034Sdougm */ 573034Sdougm 583034Sdougm static xmlNodePtr sa_config_tree; /* the current config */ 593034Sdougm static xmlDocPtr sa_config_doc = NULL; /* current config document */ 603034Sdougm extern struct sa_proto_plugin *sap_proto_list; 613034Sdougm 623034Sdougm /* current SMF/SVC repository handle */ 633034Sdougm static scfutilhandle_t *scf_handle = NULL; 643034Sdougm extern void getlegacyconfig(char *, xmlNodePtr *); 653034Sdougm extern int gettransients(xmlNodePtr *); 663034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 673034Sdougm extern char *sa_fstype(char *); 683034Sdougm extern int sa_is_share(void *); 693034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 703034Sdougm extern int sa_group_is_zfs(sa_group_t); 713034Sdougm extern int sa_path_is_zfs(char *); 723034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 733034Sdougm extern void update_legacy_config(void); 743034Sdougm extern int issubdir(char *, char *); 753218Sdougm extern void sa_zfs_init(void); 763218Sdougm extern void sa_zfs_fini(void); 773034Sdougm 783034Sdougm static int sa_initialized = 0; 793034Sdougm 803034Sdougm /* helper functions */ 813034Sdougm 823034Sdougm char * 833034Sdougm sa_errorstr(int err) 843034Sdougm { 853034Sdougm static char errstr[32]; 863034Sdougm char *ret = NULL; 873034Sdougm 883034Sdougm switch (err) { 893034Sdougm case SA_OK: 903034Sdougm ret = gettext("ok"); 913034Sdougm break; 923034Sdougm case SA_NO_SUCH_PATH: 933034Sdougm ret = gettext("path doesn't exist"); 943034Sdougm break; 953034Sdougm case SA_NO_MEMORY: 963034Sdougm ret = gettext("no memory"); 973034Sdougm break; 983034Sdougm case SA_DUPLICATE_NAME: 993034Sdougm ret = gettext("name in use"); 1003034Sdougm break; 1013034Sdougm case SA_BAD_PATH: 1023034Sdougm ret = gettext("bad path"); 1033034Sdougm break; 1043034Sdougm case SA_NO_SUCH_GROUP: 1053034Sdougm ret = gettext("no such group"); 1063034Sdougm break; 1073034Sdougm case SA_CONFIG_ERR: 1083034Sdougm ret = gettext("configuration error"); 1093034Sdougm break; 1103034Sdougm case SA_SYSTEM_ERR: 1113034Sdougm ret = gettext("system error"); 1123034Sdougm break; 1133034Sdougm case SA_SYNTAX_ERR: 1143034Sdougm ret = gettext("syntax error"); 1153034Sdougm break; 1163034Sdougm case SA_NO_PERMISSION: 1173034Sdougm ret = gettext("no permission"); 1183034Sdougm break; 1193034Sdougm case SA_BUSY: 1203034Sdougm ret = gettext("busy"); 1213034Sdougm break; 1223034Sdougm case SA_NO_SUCH_PROP: 1233034Sdougm ret = gettext("no such property"); 1243034Sdougm break; 1253034Sdougm case SA_INVALID_NAME: 1263034Sdougm ret = gettext("invalid name"); 1273034Sdougm break; 1283034Sdougm case SA_INVALID_PROTOCOL: 1293034Sdougm ret = gettext("invalid protocol"); 1303034Sdougm break; 1313034Sdougm case SA_NOT_ALLOWED: 1323034Sdougm ret = gettext("operation not allowed"); 1333034Sdougm break; 1343034Sdougm case SA_BAD_VALUE: 1353034Sdougm ret = gettext("bad property value"); 1363034Sdougm break; 1373034Sdougm case SA_INVALID_SECURITY: 1383034Sdougm ret = gettext("invalid security type"); 1393034Sdougm break; 1403034Sdougm case SA_NO_SUCH_SECURITY: 1413034Sdougm ret = gettext("security type not found"); 1423034Sdougm break; 1433034Sdougm case SA_VALUE_CONFLICT: 1443034Sdougm ret = gettext("property value conflict"); 1453034Sdougm break; 1463034Sdougm case SA_NOT_IMPLEMENTED: 1473034Sdougm ret = gettext("not implemented"); 1483034Sdougm break; 1493034Sdougm case SA_INVALID_PATH: 1503034Sdougm ret = gettext("invalid path"); 1513034Sdougm break; 1523034Sdougm case SA_NOT_SUPPORTED: 1533034Sdougm ret = gettext("operation not supported"); 1543034Sdougm break; 1553034Sdougm case SA_PROP_SHARE_ONLY: 1563034Sdougm ret = gettext("property not valid for group"); 1573034Sdougm break; 1583034Sdougm case SA_NOT_SHARED: 1593034Sdougm ret = gettext("not shared"); 1603034Sdougm break; 1613034Sdougm default: 1623034Sdougm (void) snprintf(errstr, sizeof (errstr), 1633034Sdougm gettext("unknown %d"), err); 1643034Sdougm ret = errstr; 1653034Sdougm } 1663034Sdougm return (ret); 1673034Sdougm } 1683034Sdougm 1693034Sdougm /* 1703034Sdougm * get_legacy_timestamp(root, path) 1713034Sdougm * gets the timestamp of the last time sharemgr updated the legacy 1723034Sdougm * files. This is used to determine if someone has modified them by 1733034Sdougm * hand. 1743034Sdougm */ 1753034Sdougm static uint64_t 1763034Sdougm get_legacy_timestamp(xmlNodePtr root, char *path) 1773034Sdougm { 1783034Sdougm uint64_t tval = 0; 1793034Sdougm xmlNodePtr node; 1803034Sdougm xmlChar *lpath = NULL; 1813034Sdougm xmlChar *timestamp = NULL; 1823034Sdougm 1833034Sdougm for (node = root->xmlChildrenNode; node != NULL; 1843034Sdougm node = node->next) { 1853034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 1863034Sdougm /* a possible legacy node for this path */ 1873034Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 1883034Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 1893034Sdougm /* now have the node, extract the data */ 1903034Sdougm timestamp = xmlGetProp(node, (xmlChar *)"timestamp"); 1913034Sdougm if (timestamp != NULL) { 1923034Sdougm tval = strtoull((char *)timestamp, NULL, 0); 1933034Sdougm break; 1943034Sdougm } 1953034Sdougm } 1963034Sdougm if (lpath != NULL) { 1973034Sdougm xmlFree(lpath); 1983034Sdougm lpath = NULL; 1993034Sdougm } 2003034Sdougm } 2013034Sdougm } 2023034Sdougm if (lpath != NULL) 2033034Sdougm xmlFree(lpath); 2043034Sdougm if (timestamp != NULL) 2053034Sdougm xmlFree(timestamp); 2063034Sdougm return (tval); 2073034Sdougm } 2083034Sdougm 2093034Sdougm /* 2103034Sdougm * set_legacy_timestamp(root, path, timevalue) 2113034Sdougm * 2123034Sdougm * add the current timestamp value to the configuration for use in 2133034Sdougm * determining when to update the legacy files. For SMF, this 2143034Sdougm * property is kept in default/operation/legacy_timestamp 2153034Sdougm */ 2163034Sdougm 2173034Sdougm static void 2183034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 2193034Sdougm { 2203034Sdougm xmlNodePtr node; 2213034Sdougm xmlChar *lpath = NULL; 2223034Sdougm 2233034Sdougm for (node = root->xmlChildrenNode; node != NULL; 2243034Sdougm node = node->next) { 2253034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 2263034Sdougm /* a possible legacy node for this path */ 2273034Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 2283034Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 2293034Sdougm xmlFree(lpath); 2303034Sdougm break; 2313034Sdougm } 2323034Sdougm if (lpath != NULL) 2333034Sdougm xmlFree(lpath); 2343034Sdougm } 2353034Sdougm } 2363034Sdougm if (node == NULL) { 2373034Sdougm /* need to create the first legacy timestamp node */ 2383034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 2393034Sdougm } 2403034Sdougm if (node != NULL) { 2413034Sdougm char tstring[32]; 2423034Sdougm int ret; 2433034Sdougm 2443034Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 2453034Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 2463034Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 2473034Sdougm /* now commit to SMF */ 2483034Sdougm ret = sa_get_instance(scf_handle, "default"); 2493034Sdougm if (ret == SA_OK) { 2503034Sdougm ret = sa_start_transaction(scf_handle, "operation"); 2513034Sdougm if (ret == SA_OK) { 2523034Sdougm ret = sa_set_property(scf_handle, "legacy-timestamp", 2533034Sdougm tstring); 2543034Sdougm if (ret == SA_OK) { 2553034Sdougm (void) sa_end_transaction(scf_handle); 2563034Sdougm } else { 2573034Sdougm sa_abort_transaction(scf_handle); 2583034Sdougm } 2593034Sdougm } 2603034Sdougm } 2613034Sdougm } 2623034Sdougm } 2633034Sdougm 2643034Sdougm /* 2653034Sdougm * is_shared(share) 2663034Sdougm * 2673034Sdougm * determine if the specified share is currently shared or not. 2683034Sdougm */ 2693034Sdougm static int 2703034Sdougm is_shared(sa_share_t share) 2713034Sdougm { 2723034Sdougm char *shared; 2733034Sdougm int result = 0; /* assume not */ 2743034Sdougm 2753034Sdougm shared = sa_get_share_attr(share, "shared"); 2763034Sdougm if (shared != NULL) { 2773034Sdougm if (strcmp(shared, "true") == 0) 2783034Sdougm result = 1; 2793034Sdougm sa_free_attr_string(shared); 2803034Sdougm } 2813034Sdougm return (result); 2823034Sdougm } 2833034Sdougm 2843034Sdougm /* 285*3348Sdougm * checksubdir(newpath, strictness) 286*3348Sdougm * 287*3348Sdougm * checksubdir determines if the specified path (newpath) is a 288*3348Sdougm * subdirectory of another share. It calls issubdir() from the old 289*3348Sdougm * share implementation to do the complicated work. The strictness 290*3348Sdougm * parameter determines how strict a check to make against the 291*3348Sdougm * path. The strictness values mean: 292*3348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 293*3348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 294*3348Sdougm * stored in the repository 2953034Sdougm */ 2963034Sdougm static int 297*3348Sdougm checksubdir(char *newpath, int strictness) 2983034Sdougm { 2993034Sdougm sa_group_t group; 3003034Sdougm sa_share_t share; 3013034Sdougm int issub; 3023034Sdougm char *path = NULL; 3033034Sdougm 3043034Sdougm for (issub = 0, group = sa_get_group(NULL); 3053034Sdougm group != NULL && !issub; 3063034Sdougm group = sa_get_next_group(group)) { 3073034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 3083034Sdougm share = sa_get_next_share(share)) { 3093034Sdougm /* 3103034Sdougm * The original behavior of share never checked 3113034Sdougm * against the permanent configuration 3123034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 3133034Sdougm * it depends on this older behavior even though it 3143034Sdougm * could be considered incorrect. We may tighten this 3153034Sdougm * up in the future. 3163034Sdougm */ 317*3348Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 3183034Sdougm continue; 3193034Sdougm 3203034Sdougm path = sa_get_share_attr(share, "path"); 321*3348Sdougm /* 322*3348Sdougm * If path is NULL, then a share is in the process of 323*3348Sdougm * construction or someone has modified the property 324*3348Sdougm * group inappropriately. It should be ignored. 325*3348Sdougm */ 326*3348Sdougm if (path == NULL) 327*3348Sdougm continue; 3283034Sdougm if (newpath != NULL && 3293034Sdougm (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 3303034Sdougm issubdir(path, newpath))) { 3313034Sdougm sa_free_attr_string(path); 3323034Sdougm path = NULL; 3333034Sdougm issub = SA_INVALID_PATH; 3343034Sdougm break; 3353034Sdougm } 3363034Sdougm sa_free_attr_string(path); 3373034Sdougm path = NULL; 3383034Sdougm } 3393034Sdougm } 3403034Sdougm if (path != NULL) 3413034Sdougm sa_free_attr_string(path); 3423034Sdougm return (issub); 3433034Sdougm } 3443034Sdougm 3453034Sdougm /* 346*3348Sdougm * validpath(path, strictness) 3473034Sdougm * determine if the provided path is valid for a share. It shouldn't 3483034Sdougm * be a sub-dir of an already shared path or the parent directory of a 3493034Sdougm * share path. 3503034Sdougm */ 3513034Sdougm static int 352*3348Sdougm validpath(char *path, int strictness) 3533034Sdougm { 3543034Sdougm int error = SA_OK; 3553034Sdougm struct stat st; 3563034Sdougm sa_share_t share; 3573034Sdougm char *fstype; 3583034Sdougm 3593034Sdougm if (*path != '/') { 3603034Sdougm return (SA_BAD_PATH); 3613034Sdougm } 3623034Sdougm if (stat(path, &st) < 0) { 3633034Sdougm error = SA_NO_SUCH_PATH; 3643034Sdougm } else { 3653034Sdougm share = sa_find_share(path); 3663034Sdougm if (share != NULL) { 3673034Sdougm error = SA_DUPLICATE_NAME; 3683034Sdougm } 3693034Sdougm if (error == SA_OK) { 3703034Sdougm /* 3713034Sdougm * check for special case with file system that might 3723034Sdougm * have restrictions. For now, ZFS is the only case 3733034Sdougm * since it has its own idea of how to configure 3743034Sdougm * shares. We do this before subdir checking since 3753034Sdougm * things like ZFS will do that for us. This should 3763034Sdougm * also be done via plugin interface. 3773034Sdougm */ 3783034Sdougm fstype = sa_fstype(path); 3793034Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 3803034Sdougm if (sa_zfs_is_shared(path)) 3813034Sdougm error = SA_DUPLICATE_NAME; 3823034Sdougm } 3833034Sdougm if (fstype != NULL) 3843034Sdougm sa_free_fstype(fstype); 3853034Sdougm } 3863034Sdougm if (error == SA_OK) { 387*3348Sdougm error = checksubdir(path, strictness); 3883034Sdougm } 3893034Sdougm } 3903034Sdougm return (error); 3913034Sdougm } 3923034Sdougm 3933034Sdougm /* 3943034Sdougm * check to see if group/share is persistent. 3953034Sdougm */ 3963034Sdougm static int 3973034Sdougm is_persistent(sa_group_t group) 3983034Sdougm { 3993034Sdougm char *type; 4003034Sdougm int persist = 1; 4013034Sdougm 4023034Sdougm type = sa_get_group_attr(group, "type"); 4033034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 4043034Sdougm persist = 0; 4053034Sdougm if (type != NULL) 4063034Sdougm sa_free_attr_string(type); 4073034Sdougm return (persist); 4083034Sdougm } 4093034Sdougm 4103034Sdougm /* 4113034Sdougm * sa_valid_group_name(name) 4123034Sdougm * 4133034Sdougm * check that the "name" contains only valid characters and otherwise 4143034Sdougm * fits the required naming conventions. Valid names must start with 4153034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 4163034Sdougm * plus the '-' and '_' characters. This name limitation comes from 4173034Sdougm * inherent limitations in SMF. 4183034Sdougm */ 4193034Sdougm 4203034Sdougm int 4213034Sdougm sa_valid_group_name(char *name) 4223034Sdougm { 4233034Sdougm int ret = 1; 4243034Sdougm ssize_t len; 4253034Sdougm 4263034Sdougm if (name != NULL && isalpha(*name)) { 4273034Sdougm char c; 4283034Sdougm len = strlen(name); 4293034Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 4303034Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 4313034Sdougm if (!isalnum(c) && c != '-' && c != '_') 4323034Sdougm ret = 0; 4333034Sdougm } 4343034Sdougm } else { 4353034Sdougm ret = 0; 4363034Sdougm } 4373034Sdougm } else { 4383034Sdougm ret = 0; 4393034Sdougm } 4403034Sdougm return (ret); 4413034Sdougm } 4423034Sdougm 4433034Sdougm 4443034Sdougm /* 4453034Sdougm * is_zfs_group(group) 4463034Sdougm * Determine if the specified group is a ZFS sharenfs group 4473034Sdougm */ 4483034Sdougm static int 4493034Sdougm is_zfs_group(sa_group_t group) 4503034Sdougm { 4513034Sdougm int ret = 0; 4523034Sdougm xmlNodePtr parent; 4533034Sdougm xmlChar *zfs; 4543034Sdougm 4553034Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) { 4563034Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 4573034Sdougm } else { 4583034Sdougm parent = (xmlNodePtr)group; 4593034Sdougm } 4603034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 4613034Sdougm if (zfs != NULL) { 4623034Sdougm xmlFree(zfs); 4633034Sdougm ret = 1; 4643034Sdougm } 4653034Sdougm return (ret); 4663034Sdougm } 4673034Sdougm 4683034Sdougm /* 4693034Sdougm * sa_optionset_name(optionset, oname, len, id) 4703034Sdougm * return the SMF name for the optionset. If id is not NULL, it 4713034Sdougm * will have the GUID value for a share and should be used 4723034Sdougm * instead of the keyword "optionset" which is used for 4733034Sdougm * groups. If the optionset doesn't have a protocol type 4743034Sdougm * associated with it, "default" is used. This shouldn't happen 4753034Sdougm * at this point but may be desirable in the future if there are 4763034Sdougm * protocol independent properties added. The name is returned in 4773034Sdougm * oname. 4783034Sdougm */ 4793034Sdougm 4803034Sdougm static int 4813034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 4823034Sdougm { 4833034Sdougm char *proto; 4843034Sdougm 4853034Sdougm if (id == NULL) 4863034Sdougm id = "optionset"; 4873034Sdougm 4883034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 4893034Sdougm len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 4903034Sdougm 4913034Sdougm if (proto != NULL) 4923034Sdougm sa_free_attr_string(proto); 4933034Sdougm return (len); 4943034Sdougm } 4953034Sdougm 4963034Sdougm /* 4973034Sdougm * sa_security_name(optionset, oname, len, id) 4983034Sdougm * 4993034Sdougm * return the SMF name for the security. If id is not NULL, it will 5003034Sdougm * have the GUID value for a share and should be used instead of the 5013034Sdougm * keyword "optionset" which is used for groups. If the optionset 5023034Sdougm * doesn't have a protocol type associated with it, "default" is 5033034Sdougm * used. This shouldn't happen at this point but may be desirable in 5043034Sdougm * the future if there are protocol independent properties added. The 5053034Sdougm * name is returned in oname. The security type is also encoded into 5063034Sdougm * the name. In the future, this wil *be handled a bit differently. 5073034Sdougm */ 5083034Sdougm 5093034Sdougm static int 5103034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 5113034Sdougm { 5123034Sdougm char *proto; 5133034Sdougm char *sectype; 5143034Sdougm 5153034Sdougm if (id == NULL) 5163034Sdougm id = "optionset"; 5173034Sdougm 5183034Sdougm proto = sa_get_security_attr(security, "type"); 5193034Sdougm sectype = sa_get_security_attr(security, "sectype"); 5203034Sdougm len = snprintf(oname, len, "%s_%s_%s", id, 5213034Sdougm proto ? proto : "default", 5223034Sdougm sectype ? sectype : "default"); 5233034Sdougm if (proto != NULL) 5243034Sdougm sa_free_attr_string(proto); 5253034Sdougm if (sectype != NULL) 5263034Sdougm sa_free_attr_string(sectype); 5273034Sdougm return (len); 5283034Sdougm } 5293034Sdougm 5303034Sdougm /* 531*3348Sdougm * sa_init(init_service) 5323034Sdougm * Initialize the API 5333034Sdougm * find all the shared objects 5343034Sdougm * init the tables with all objects 5353034Sdougm * read in the current configuration 5363034Sdougm */ 5373034Sdougm 5383034Sdougm void 5393034Sdougm sa_init(int init_service) 5403034Sdougm { 5413034Sdougm struct stat st; 5423034Sdougm int legacy = 0; 5433034Sdougm uint64_t tval = 0; 5443034Sdougm 5453034Sdougm if (!sa_initialized) { 5463034Sdougm /* get protocol specific structures */ 5473034Sdougm (void) proto_plugin_init(); 5483034Sdougm if (init_service & SA_INIT_SHARE_API) { 5493034Sdougm /* 5503218Sdougm * initialize access into libzfs. We use this when 5513218Sdougm * collecting info about ZFS datasets and shares. 5523218Sdougm */ 5533218Sdougm sa_zfs_init(); 5543218Sdougm /* 5553034Sdougm * since we want to use SMF, initialize an svc handle 5563034Sdougm * and find out what is there. 5573034Sdougm */ 5583034Sdougm scf_handle = sa_scf_init(); 5593034Sdougm if (scf_handle != NULL) { 5603034Sdougm (void) sa_get_config(scf_handle, &sa_config_tree, 5613034Sdougm &sa_config_doc); 5623034Sdougm tval = get_legacy_timestamp(sa_config_tree, 5633034Sdougm SA_LEGACY_DFSTAB); 5643034Sdougm if (tval == 0) { 5653034Sdougm /* first time so make sure default is setup */ 5663034Sdougm sa_group_t defgrp; 5673034Sdougm sa_optionset_t opt; 5683034Sdougm defgrp = sa_get_group("default"); 5693034Sdougm if (defgrp != NULL) { 5703034Sdougm opt = sa_get_optionset(defgrp, NULL); 5713034Sdougm if (opt == NULL) 5723034Sdougm /* NFS is the default for default */ 5733034Sdougm opt = sa_create_optionset(defgrp, "nfs"); 5743034Sdougm } 5753034Sdougm } 5763034Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0 && 5773034Sdougm tval != TSTAMP(st.st_ctim)) { 5783034Sdougm getlegacyconfig(SA_LEGACY_DFSTAB, &sa_config_tree); 5793034Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 5803034Sdougm set_legacy_timestamp(sa_config_tree, 5813034Sdougm SA_LEGACY_DFSTAB, 5823034Sdougm TSTAMP(st.st_ctim)); 5833034Sdougm } 5843034Sdougm legacy |= sa_get_zfs_shares("zfs"); 5853034Sdougm legacy |= gettransients(&sa_config_tree); 5863034Sdougm } 5873034Sdougm } 5883034Sdougm } 5893034Sdougm } 5903034Sdougm 5913034Sdougm /* 5923034Sdougm * sa_fini() 5933034Sdougm * Uninitialize the API structures including the configuration 5943218Sdougm * data structures and ZFS related data. 5953034Sdougm */ 5963034Sdougm 5973034Sdougm void 5983034Sdougm sa_fini() 5993034Sdougm { 6003034Sdougm if (sa_initialized) { 6013034Sdougm /* free the config trees */ 6023034Sdougm sa_initialized = 0; 6033034Sdougm if (sa_config_doc != NULL) 6043034Sdougm xmlFreeDoc(sa_config_doc); 6053034Sdougm sa_config_tree = NULL; 6063034Sdougm sa_config_doc = NULL; 6073034Sdougm sa_scf_fini(scf_handle); 6083218Sdougm sa_zfs_fini(); 6093034Sdougm (void) proto_plugin_init(); 6103034Sdougm } 6113034Sdougm } 6123034Sdougm 6133034Sdougm /* 6143034Sdougm * sa_get_protocols(char **protocol) 6153034Sdougm * Get array of protocols that are supported 6163034Sdougm * Returns pointer to an allocated and NULL terminated 6173034Sdougm * array of strings. Caller must free. 6183034Sdougm * This really should be determined dynamically. 6193034Sdougm * If there aren't any defined, return -1. 6203034Sdougm * Use free() to return memory. 6213034Sdougm */ 6223034Sdougm 6233034Sdougm int 6243034Sdougm sa_get_protocols(char ***protocols) 6253034Sdougm { 6263034Sdougm int numproto = -1; 6273034Sdougm 6283034Sdougm if (protocols != NULL) { 6293034Sdougm struct sa_proto_plugin *plug; 6303034Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 6313034Sdougm plug = plug->plugin_next) { 6323034Sdougm numproto++; 6333034Sdougm } 6343034Sdougm 6353034Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 6363034Sdougm if (*protocols != NULL) { 6373034Sdougm int ret = 0; 6383034Sdougm for (plug = sap_proto_list; plug != NULL; 6393034Sdougm plug = plug->plugin_next) { 6403034Sdougm /* faking for now */ 6413034Sdougm (*protocols)[ret++] = plug->plugin_ops->sa_protocol; 6423034Sdougm } 6433034Sdougm } else { 6443034Sdougm numproto = -1; 6453034Sdougm } 6463034Sdougm } 6473034Sdougm return (numproto); 6483034Sdougm } 6493034Sdougm 6503034Sdougm /* 6513034Sdougm * find_group_by_name(node, group) 6523034Sdougm * 6533034Sdougm * search the XML document subtree specified by node to find the group 6543034Sdougm * specified by group. Searching subtree allows subgroups to be 6553034Sdougm * searched for. 6563034Sdougm */ 6573034Sdougm 6583034Sdougm static xmlNodePtr 6593034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 6603034Sdougm { 6613034Sdougm xmlChar *name = NULL; 6623034Sdougm 6633034Sdougm for (node = node->xmlChildrenNode; node != NULL; 6643034Sdougm node = node->next) { 6653034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 6663034Sdougm /* if no groupname, return the first found */ 6673034Sdougm if (group == NULL) 6683034Sdougm break; 6693034Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 6703034Sdougm if (name != NULL && 6713034Sdougm xmlStrcmp(name, group) == 0) { 6723034Sdougm break; 6733034Sdougm } 6743034Sdougm if (name != NULL) { 6753034Sdougm xmlFree(name); 6763034Sdougm name = NULL; 6773034Sdougm } 6783034Sdougm } 6793034Sdougm } 6803034Sdougm if (name != NULL) 6813034Sdougm xmlFree(name); 6823034Sdougm return (node); 6833034Sdougm } 6843034Sdougm 6853034Sdougm /* 6863034Sdougm * sa_get_group(groupname) 6873034Sdougm * Return the "group" specified. If groupname is NULL, 6883034Sdougm * return the first group of the list of groups. 6893034Sdougm */ 6903034Sdougm sa_group_t 6913034Sdougm sa_get_group(char *groupname) 6923034Sdougm { 6933034Sdougm xmlNodePtr node = NULL; 6943034Sdougm char *subgroup = NULL; 6953034Sdougm char *group = NULL; 6963034Sdougm 6973034Sdougm if (sa_config_tree != NULL) { 6983034Sdougm if (groupname != NULL) { 6993034Sdougm group = strdup(groupname); 7003034Sdougm subgroup = strchr(group, '/'); 7013034Sdougm if (subgroup != NULL) 7023034Sdougm *subgroup++ = '\0'; 7033034Sdougm } 7043034Sdougm node = find_group_by_name(sa_config_tree, (xmlChar *)group); 7053034Sdougm /* if a subgroup, find it before returning */ 7063034Sdougm if (subgroup != NULL && node != NULL) { 7073034Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 7083034Sdougm } 7093034Sdougm } 7103034Sdougm if (node != NULL && (char *)group != NULL) 7113034Sdougm (void) sa_get_instance(scf_handle, (char *)group); 7123034Sdougm if (group != NULL) 7133034Sdougm free(group); 7143034Sdougm return ((sa_group_t)(node)); 7153034Sdougm } 7163034Sdougm 7173034Sdougm /* 7183034Sdougm * sa_get_next_group(group) 7193034Sdougm * Return the "next" group after the specified group from 7203034Sdougm * the internal group list. NULL if there are no more. 7213034Sdougm */ 7223034Sdougm sa_group_t 7233034Sdougm sa_get_next_group(sa_group_t group) 7243034Sdougm { 7253034Sdougm xmlNodePtr ngroup = NULL; 7263034Sdougm if (group != NULL) { 7273034Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 7283034Sdougm ngroup = ngroup->next) { 7293034Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 7303034Sdougm break; 7313034Sdougm } 7323034Sdougm } 7333034Sdougm return ((sa_group_t)ngroup); 7343034Sdougm } 7353034Sdougm 7363034Sdougm /* 7373034Sdougm * sa_get_share(group, sharepath) 7383034Sdougm * Return the share object for the share specified. The share 7393034Sdougm * must be in the specified group. Return NULL if not found. 7403034Sdougm */ 7413034Sdougm sa_share_t 7423034Sdougm sa_get_share(sa_group_t group, char *sharepath) 7433034Sdougm { 7443034Sdougm xmlNodePtr node = NULL; 7453034Sdougm xmlChar *path; 7463034Sdougm 7473034Sdougm /* 7483034Sdougm * For future scalability, this should end up building a cache 7493034Sdougm * since it will get called regularly by the mountd and info 7503034Sdougm * services. 7513034Sdougm */ 7523034Sdougm if (group != NULL) { 7533034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 7543034Sdougm node = node->next) { 7553034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 7563034Sdougm if (sharepath == NULL) { 7573034Sdougm break; 7583034Sdougm } else { 7593034Sdougm /* is it the correct share? */ 7603034Sdougm path = xmlGetProp(node, (xmlChar *)"path"); 7613034Sdougm if (path != NULL && 7623034Sdougm xmlStrcmp(path, (xmlChar *)sharepath) == 0) { 7633034Sdougm xmlFree(path); 7643034Sdougm break; 7653034Sdougm } 7663034Sdougm xmlFree(path); 7673034Sdougm } 7683034Sdougm } 7693034Sdougm } 7703034Sdougm } 7713034Sdougm return ((sa_share_t)node); 7723034Sdougm } 7733034Sdougm 7743034Sdougm /* 7753034Sdougm * sa_get_next_share(share) 7763034Sdougm * Return the next share following the specified share 7773034Sdougm * from the internal list of shares. Returns NULL if there 7783034Sdougm * are no more shares. The list is relative to the same 7793034Sdougm * group. 7803034Sdougm */ 7813034Sdougm sa_share_t 7823034Sdougm sa_get_next_share(sa_share_t share) 7833034Sdougm { 7843034Sdougm xmlNodePtr node = NULL; 7853034Sdougm 7863034Sdougm if (share != NULL) { 7873034Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 7883034Sdougm node = node->next) { 7893034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 7903034Sdougm break; 7913034Sdougm } 7923034Sdougm } 7933034Sdougm } 7943034Sdougm return ((sa_share_t)node); 7953034Sdougm } 7963034Sdougm 7973034Sdougm /* 7983034Sdougm * _sa_get_child_node(node, type) 7993034Sdougm * 8003034Sdougm * find the child node of the specified node that has "type". This is 8013034Sdougm * used to implement several internal functions. 8023034Sdougm */ 8033034Sdougm 8043034Sdougm static xmlNodePtr 8053034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 8063034Sdougm { 8073034Sdougm xmlNodePtr child; 8083034Sdougm for (child = node->xmlChildrenNode; child != NULL; 8093034Sdougm child = child->next) 8103034Sdougm if (xmlStrcmp(child->name, type) == 0) 8113034Sdougm return (child); 8123034Sdougm return ((xmlNodePtr)NULL); 8133034Sdougm } 8143034Sdougm 8153034Sdougm /* 8163034Sdougm * find_share(group, path) 8173034Sdougm * 8183034Sdougm * Search all the shares in the specified group for one that has the 8193034Sdougm * specified path. 8203034Sdougm */ 8213034Sdougm 8223034Sdougm static sa_share_t 8233034Sdougm find_share(sa_group_t group, char *sharepath) 8243034Sdougm { 8253034Sdougm sa_share_t share; 8263034Sdougm char *path; 8273034Sdougm 8283034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 8293034Sdougm share = sa_get_next_share(share)) { 8303034Sdougm path = sa_get_share_attr(share, "path"); 8313034Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 8323034Sdougm sa_free_attr_string(path); 8333034Sdougm break; 8343034Sdougm } 8353034Sdougm if (path != NULL) 8363034Sdougm sa_free_attr_string(path); 8373034Sdougm } 8383034Sdougm return (share); 8393034Sdougm } 8403034Sdougm 8413034Sdougm /* 8423034Sdougm * sa_get_sub_group(group) 8433034Sdougm * 8443034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 8453034Sdougm * can be used to get the rest. This is currently only used for ZFS 8463034Sdougm * sub-groups but could be used to implement a more general mechanism. 8473034Sdougm */ 8483034Sdougm 8493034Sdougm sa_group_t 8503034Sdougm sa_get_sub_group(sa_group_t group) 8513034Sdougm { 8523034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 8533034Sdougm (xmlChar *)"group")); 8543034Sdougm } 8553034Sdougm 8563034Sdougm /* 8573034Sdougm * sa_find_share(sharepath) 8583034Sdougm * Finds a share regardless of group. In the future, this 8593034Sdougm * function should utilize a cache and hash table of some kind. 8603034Sdougm * The current assumption is that a path will only be shared 8613034Sdougm * once. In the future, this may change as implementation of 8623034Sdougm * resource names comes into being. 8633034Sdougm */ 8643034Sdougm sa_share_t 8653034Sdougm sa_find_share(char *sharepath) 8663034Sdougm { 8673034Sdougm sa_group_t group; 8683034Sdougm sa_group_t zgroup; 8693034Sdougm sa_share_t share = NULL; 8703034Sdougm int done = 0; 8713034Sdougm 8723034Sdougm for (group = sa_get_group(NULL); group != NULL && !done; 8733034Sdougm group = sa_get_next_group(group)) { 8743034Sdougm if (is_zfs_group(group)) { 8753034Sdougm for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 8763034Sdougm (xmlChar *)"group"); 8773034Sdougm zgroup != NULL; zgroup = sa_get_next_group(zgroup)) { 8783034Sdougm share = find_share(zgroup, sharepath); 8793034Sdougm if (share != NULL) 8803034Sdougm break; 8813034Sdougm } 8823034Sdougm } else { 8833034Sdougm share = find_share(group, sharepath); 8843034Sdougm } 8853034Sdougm if (share != NULL) 8863034Sdougm break; 8873034Sdougm } 8883034Sdougm return (share); 8893034Sdougm } 8903034Sdougm 8913034Sdougm /* 892*3348Sdougm * sa_check_path(group, path, strictness) 8933034Sdougm * 8943034Sdougm * check that path is a valid path relative to the group. Currently, 8953034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 8963034Sdougm * we may want to use the group to then check against the protocols 897*3348Sdougm * enabled on the group. The strictness values mean: 898*3348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 899*3348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 900*3348Sdougm * stored in the repository 9013034Sdougm */ 9023034Sdougm 9033034Sdougm int 904*3348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 9053034Sdougm { 9063034Sdougm #ifdef lint 9073034Sdougm group = group; 9083034Sdougm #endif 909*3348Sdougm return (validpath(path, strictness)); 9103034Sdougm } 9113034Sdougm 9123034Sdougm /* 9133034Sdougm * _sa_add_share(group, sharepath, persist, *error) 9143034Sdougm * 9153034Sdougm * common code for all types of add_share. sa_add_share() is the 9163034Sdougm * public API, we also need to be able to do this when parsing legacy 9173034Sdougm * files and construction of the internal configuration while 9183034Sdougm * extracting config info from SMF. 9193034Sdougm */ 9203034Sdougm 9213034Sdougm sa_share_t 9223034Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 9233034Sdougm { 9243034Sdougm xmlNodePtr node = NULL; 9253034Sdougm int err; 9263034Sdougm 9273034Sdougm err = SA_OK; /* assume success */ 9283034Sdougm 9293034Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 9303034Sdougm (xmlChar *)"share", NULL); 9313034Sdougm if (node != NULL) { 9323034Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 9333034Sdougm xmlSetProp(node, (xmlChar *)"type", persist ? 9343034Sdougm (xmlChar *)"persist" : (xmlChar *)"transient"); 9353034Sdougm if (persist != SA_SHARE_TRANSIENT) { 9363034Sdougm /* 9373034Sdougm * persistent shares come in two flavors: SMF and 9383034Sdougm * ZFS. Sort this one out based on target group and 9393034Sdougm * path type. Currently, only NFS is supported in the 9403034Sdougm * ZFS group and it is always on. 9413034Sdougm */ 9423034Sdougm if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) { 9433034Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 9443034Sdougm } else { 9453034Sdougm err = sa_commit_share(scf_handle, group, 9463034Sdougm (sa_share_t)node); 9473034Sdougm } 9483034Sdougm } 9493034Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 9503034Sdougm /* called by the dfstab parser so could be a show */ 9513034Sdougm err = SA_OK; 9523034Sdougm } 9533034Sdougm if (err != SA_OK) { 9543034Sdougm /* 9553034Sdougm * we couldn't commit to the repository so undo 9563034Sdougm * our internal state to reflect reality. 9573034Sdougm */ 9583034Sdougm xmlUnlinkNode(node); 9593034Sdougm xmlFreeNode(node); 9603034Sdougm node = NULL; 9613034Sdougm } 9623034Sdougm } else { 9633034Sdougm err = SA_NO_MEMORY; 9643034Sdougm } 9653034Sdougm if (error != NULL) 9663034Sdougm *error = err; 9673034Sdougm return (node); 9683034Sdougm } 9693034Sdougm 9703034Sdougm /* 9713034Sdougm * sa_add_share(group, sharepath, persist, *error) 9723034Sdougm * 9733034Sdougm * Add a new share object to the specified group. The share will 9743034Sdougm * have the specified sharepath and will only be constructed if 9753034Sdougm * it is a valid path to be shared. NULL is returned on error 9763034Sdougm * and a detailed error value will be returned via the error 9773034Sdougm * pointer. 9783034Sdougm */ 9793034Sdougm sa_share_t 9803034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 9813034Sdougm { 9823034Sdougm xmlNodePtr node = NULL; 9833034Sdougm sa_share_t dup; 984*3348Sdougm int strictness = SA_CHECK_NORMAL; 985*3348Sdougm 986*3348Sdougm /* 987*3348Sdougm * If the share is to be permanent, use strict checking so a 988*3348Sdougm * bad config doesn't get created. Transient shares only need 989*3348Sdougm * to check against the currently active 990*3348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 991*3348Sdougm * indicate that we are being called by the dfstab parser and 992*3348Sdougm * that we need strict checking in all cases. Normally persist 993*3348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 994*3348Sdougm * it as an override. 995*3348Sdougm */ 996*3348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 997*3348Sdougm strictness = SA_CHECK_STRICT; 9983034Sdougm 9993034Sdougm if ((dup = sa_find_share(sharepath)) == NULL && 1000*3348Sdougm (*error = sa_check_path(group, sharepath, strictness)) == 1001*3348Sdougm SA_OK) { 10023034Sdougm node = _sa_add_share(group, sharepath, persist, error); 10033034Sdougm } 10043034Sdougm if (dup != NULL) 10053034Sdougm *error = SA_DUPLICATE_NAME; 10063034Sdougm 10073034Sdougm return ((sa_share_t)node); 10083034Sdougm } 10093034Sdougm 10103034Sdougm /* 10113034Sdougm * sa_enable_share(share, protocol) 10123034Sdougm * Enable the specified share to the specified protocol. 10133034Sdougm * If protocol is NULL, then all protocols. 10143034Sdougm */ 10153034Sdougm int 10163034Sdougm sa_enable_share(sa_share_t share, char *protocol) 10173034Sdougm { 10183034Sdougm char *sharepath; 10193034Sdougm struct stat st; 10203034Sdougm int err = 0; 10213034Sdougm 10223034Sdougm sharepath = sa_get_share_attr(share, "path"); 10233034Sdougm if (stat(sharepath, &st) < 0) { 10243034Sdougm err = SA_NO_SUCH_PATH; 10253034Sdougm } else { 10263034Sdougm /* tell the server about the share */ 10273034Sdougm if (protocol != NULL) { 10283034Sdougm /* lookup protocol specific handler */ 10293034Sdougm err = sa_proto_share(protocol, share); 10303034Sdougm if (err == SA_OK) 10313034Sdougm (void) sa_set_share_attr(share, "shared", "true"); 10323034Sdougm } else { 10333034Sdougm /* tell all protocols */ 10343034Sdougm err = sa_proto_share("nfs", share); /* only NFS for now */ 10353034Sdougm (void) sa_set_share_attr(share, "shared", "true"); 10363034Sdougm } 10373034Sdougm } 10383034Sdougm if (sharepath != NULL) 10393034Sdougm sa_free_attr_string(sharepath); 10403034Sdougm return (err); 10413034Sdougm } 10423034Sdougm 10433034Sdougm /* 10443034Sdougm * sa_disable_share(share, protocol) 10453034Sdougm * Disable the specified share to the specified protocol. 10463034Sdougm * If protocol is NULL, then all protocols. 10473034Sdougm */ 10483034Sdougm int 10493034Sdougm sa_disable_share(sa_share_t share, char *protocol) 10503034Sdougm { 10513034Sdougm char *path; 10523034Sdougm char *shared; 10533034Sdougm int ret = SA_OK; 10543034Sdougm 10553034Sdougm path = sa_get_share_attr(share, "path"); 10563034Sdougm shared = sa_get_share_attr(share, "shared"); 10573034Sdougm 10583034Sdougm if (protocol != NULL) { 10593034Sdougm ret = sa_proto_unshare(protocol, path); 10603034Sdougm } else { 10613034Sdougm /* need to do all protocols */ 10623034Sdougm ret = sa_proto_unshare("nfs", path); 10633034Sdougm } 10643034Sdougm if (ret == SA_OK) 10653034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 10663034Sdougm if (path != NULL) 10673034Sdougm sa_free_attr_string(path); 10683034Sdougm if (shared != NULL) 10693034Sdougm sa_free_attr_string(shared); 10703034Sdougm return (ret); 10713034Sdougm } 10723034Sdougm 10733034Sdougm /* 10743034Sdougm * sa_remove_share(share) 10753034Sdougm * 10763034Sdougm * remove the specified share from its containing group. 10773034Sdougm * Remove from the SMF or ZFS configuration space. 10783034Sdougm */ 10793034Sdougm 10803034Sdougm int 10813034Sdougm sa_remove_share(sa_share_t share) 10823034Sdougm { 10833034Sdougm sa_group_t group; 10843034Sdougm int ret = SA_OK; 10853034Sdougm char *type; 10863034Sdougm int transient = 0; 10873034Sdougm char *groupname; 10883034Sdougm char *zfs; 10893034Sdougm 10903034Sdougm type = sa_get_share_attr(share, "type"); 10913034Sdougm group = sa_get_parent_group(share); 10923034Sdougm zfs = sa_get_group_attr(group, "zfs"); 10933034Sdougm groupname = sa_get_group_attr(group, "name"); 10943034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 10953034Sdougm transient = 1; 10963034Sdougm if (type != NULL) 10973034Sdougm sa_free_attr_string(type); 10983034Sdougm 10993034Sdougm /* remove the node from its group then free the memory */ 11003034Sdougm 11013034Sdougm /* 11023034Sdougm * need to test if "busy" 11033034Sdougm */ 11043034Sdougm /* only do SMF action if permanent */ 11053034Sdougm if (!transient || zfs != NULL) { 11063034Sdougm /* remove from legacy dfstab as well as possible SMF */ 11073034Sdougm ret = sa_delete_legacy(share); 11083034Sdougm if (ret == SA_OK) { 11093034Sdougm if (!sa_group_is_zfs(group)) { 11103034Sdougm ret = sa_delete_share(scf_handle, group, share); 11113034Sdougm } else { 11123034Sdougm char *sharepath = sa_get_share_attr(share, "path"); 11133034Sdougm if (sharepath != NULL) { 11143034Sdougm ret = sa_zfs_set_sharenfs(group, sharepath, 0); 11153034Sdougm sa_free_attr_string(sharepath); 11163034Sdougm } 11173034Sdougm } 11183034Sdougm } 11193034Sdougm } 11203034Sdougm if (groupname != NULL) 11213034Sdougm sa_free_attr_string(groupname); 11223034Sdougm if (zfs != NULL) 11233034Sdougm sa_free_attr_string(zfs); 11243034Sdougm 11253034Sdougm xmlUnlinkNode((xmlNodePtr)share); 11263034Sdougm xmlFreeNode((xmlNodePtr)share); 11273034Sdougm return (ret); 11283034Sdougm } 11293034Sdougm 11303034Sdougm /* 11313034Sdougm * sa_move_share(group, share) 11323034Sdougm * 11333034Sdougm * move the specified share to the specified group. Update SMF 11343034Sdougm * appropriately. 11353034Sdougm */ 11363034Sdougm 11373034Sdougm int 11383034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 11393034Sdougm { 11403034Sdougm sa_group_t oldgroup; 11413034Sdougm int ret = SA_OK; 11423034Sdougm 11433034Sdougm /* remove the node from its group then free the memory */ 11443034Sdougm 11453034Sdougm oldgroup = sa_get_parent_group(share); 11463034Sdougm if (oldgroup != group) { 11473034Sdougm xmlUnlinkNode((xmlNodePtr)share); 11483034Sdougm /* now that the share isn't in its old group, add to the new one */ 11493034Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 11503034Sdougm /* need to deal with SMF */ 11513034Sdougm if (ret == SA_OK) { 11523034Sdougm /* 11533034Sdougm * need to remove from old group first and then add to 11543034Sdougm * new group. Ideally, we would do the other order but 11553034Sdougm * need to avoid having the share in two groups at the 11563034Sdougm * same time. 11573034Sdougm */ 11583034Sdougm ret = sa_delete_share(scf_handle, oldgroup, share); 11593034Sdougm } 11603034Sdougm ret = sa_commit_share(scf_handle, group, share); 11613034Sdougm } 11623034Sdougm return (ret); 11633034Sdougm } 11643034Sdougm 11653034Sdougm /* 11663034Sdougm * sa_get_parent_group(share) 11673034Sdougm * 11683034Sdougm * Return the containg group for the share. If a group was actually 11693034Sdougm * passed in, we don't want a parent so return NULL. 11703034Sdougm */ 11713034Sdougm 11723034Sdougm sa_group_t 11733034Sdougm sa_get_parent_group(sa_share_t share) 11743034Sdougm { 11753034Sdougm xmlNodePtr node = NULL; 11763034Sdougm if (share != NULL) { 11773034Sdougm node = ((xmlNodePtr)share)->parent; 11783034Sdougm /* 11793034Sdougm * make sure parent is a group and not sharecfg since 11803034Sdougm * we may be cheating and passing in a group. 11813034Sdougm * Eventually, groups of groups might come into being. 11823034Sdougm */ 11833034Sdougm if (node == NULL || 11843034Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 11853034Sdougm node = NULL; 11863034Sdougm } 11873034Sdougm return ((sa_group_t)node); 11883034Sdougm } 11893034Sdougm 11903034Sdougm /* 11913034Sdougm * _sa_create_group(groupname) 11923034Sdougm * 11933034Sdougm * Create a group in the document. The caller will need to deal with 11943034Sdougm * configuration store and activation. 11953034Sdougm */ 11963034Sdougm 11973034Sdougm sa_group_t 11983034Sdougm _sa_create_group(char *groupname) 11993034Sdougm { 12003034Sdougm xmlNodePtr node = NULL; 12013034Sdougm 12023034Sdougm if (sa_valid_group_name(groupname)) { 12033034Sdougm node = xmlNewChild(sa_config_tree, NULL, 12043034Sdougm (xmlChar *)"group", NULL); 12053034Sdougm if (node != NULL) { 12063034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 12073034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 12083034Sdougm } 12093034Sdougm } 12103034Sdougm return ((sa_group_t)node); 12113034Sdougm } 12123034Sdougm 12133034Sdougm /* 12143034Sdougm * _sa_create_zfs_group(group, groupname) 12153034Sdougm * 12163034Sdougm * Create a ZFS subgroup under the specified group. This may 12173034Sdougm * eventually form the basis of general sub-groups, but is currently 12183034Sdougm * restricted to ZFS. 12193034Sdougm */ 12203034Sdougm sa_group_t 12213034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 12223034Sdougm { 12233034Sdougm xmlNodePtr node = NULL; 12243034Sdougm 12253034Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 12263034Sdougm (xmlChar *)"group", NULL); 12273034Sdougm if (node != NULL) { 12283034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 12293034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 12303034Sdougm } 12313034Sdougm 12323034Sdougm return ((sa_group_t)node); 12333034Sdougm } 12343034Sdougm 12353034Sdougm /* 12363034Sdougm * sa_create_group(groupname, *error) 12373034Sdougm * 12383034Sdougm * Create a new group with groupname. Need to validate that it is a 12393034Sdougm * legal name for SMF and the construct the SMF service instance of 12403034Sdougm * svc:/network/shares/group to implement the group. All necessary 12413034Sdougm * operational properties must be added to the group at this point 12423034Sdougm * (via the SMF transaction model). 12433034Sdougm */ 12443034Sdougm sa_group_t 12453034Sdougm sa_create_group(char *groupname, int *error) 12463034Sdougm { 12473034Sdougm xmlNodePtr node = NULL; 12483034Sdougm sa_group_t group; 12493034Sdougm int ret; 12503034Sdougm char rbacstr[256]; 12513034Sdougm 12523034Sdougm ret = SA_OK; 12533034Sdougm 12543034Sdougm if (scf_handle == NULL) { 12553034Sdougm ret = SA_SYSTEM_ERR; 12563034Sdougm goto err; 12573034Sdougm } 12583034Sdougm 12593034Sdougm group = sa_get_group(groupname); 12603034Sdougm if (group != NULL) { 12613034Sdougm ret = SA_DUPLICATE_NAME; 12623034Sdougm } else { 12633034Sdougm if (sa_valid_group_name(groupname)) { 12643034Sdougm node = xmlNewChild(sa_config_tree, NULL, 12653034Sdougm (xmlChar *)"group", NULL); 12663034Sdougm if (node != NULL) { 12673034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 12683034Sdougm /* default to the group being enabled */ 12693034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 12703034Sdougm ret = sa_create_instance(scf_handle, groupname); 12713034Sdougm if (ret == SA_OK) { 12723034Sdougm ret = sa_start_transaction(scf_handle, "operation"); 12733034Sdougm } 12743034Sdougm if (ret == SA_OK) { 12753034Sdougm ret = sa_set_property(scf_handle, "state", "enabled"); 12763034Sdougm if (ret == SA_OK) { 12773034Sdougm ret = sa_end_transaction(scf_handle); 12783034Sdougm } else { 12793034Sdougm sa_abort_transaction(scf_handle); 12803034Sdougm } 12813034Sdougm } 12823034Sdougm if (ret == SA_OK) { 12833034Sdougm /* initialize the RBAC strings */ 12843034Sdougm ret = sa_start_transaction(scf_handle, "general"); 12853034Sdougm if (ret == SA_OK) { 12863034Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 12873034Sdougm SA_RBAC_MANAGE, groupname); 12883034Sdougm ret = sa_set_property(scf_handle, 12893034Sdougm "action_authorization", 12903034Sdougm rbacstr); 12913034Sdougm } 12923034Sdougm if (ret == SA_OK) { 12933034Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 12943034Sdougm SA_RBAC_VALUE, groupname); 12953034Sdougm ret = sa_set_property(scf_handle, 12963034Sdougm "value_authorization", 12973034Sdougm rbacstr); 12983034Sdougm } 12993034Sdougm if (ret == SA_OK) { 13003034Sdougm ret = sa_end_transaction(scf_handle); 13013034Sdougm } else { 13023034Sdougm sa_abort_transaction(scf_handle); 13033034Sdougm } 13043034Sdougm } 13053034Sdougm if (ret != SA_OK) { 13063034Sdougm /* 13073034Sdougm * Couldn't commit the group so we need to 13083034Sdougm * undo internally. 13093034Sdougm */ 13103034Sdougm xmlUnlinkNode(node); 13113034Sdougm xmlFreeNode(node); 13123034Sdougm node = NULL; 13133034Sdougm } 13143034Sdougm } else { 13153034Sdougm ret = SA_NO_MEMORY; 13163034Sdougm } 13173034Sdougm } else { 13183034Sdougm ret = SA_INVALID_NAME; 13193034Sdougm } 13203034Sdougm } 13213034Sdougm err: 13223034Sdougm if (error != NULL) 13233034Sdougm *error = ret; 13243034Sdougm return ((sa_group_t)node); 13253034Sdougm } 13263034Sdougm 13273034Sdougm /* 13283034Sdougm * sa_remove_group(group) 13293034Sdougm * 13303034Sdougm * Remove the specified group. This deletes from the SMF repository. 13313034Sdougm * All property groups and properties are removed. 13323034Sdougm */ 13333034Sdougm 13343034Sdougm int 13353034Sdougm sa_remove_group(sa_group_t group) 13363034Sdougm { 13373034Sdougm char *name; 13383034Sdougm int ret = SA_OK; 13393034Sdougm 13403034Sdougm name = sa_get_group_attr(group, "name"); 13413034Sdougm if (name != NULL) { 13423034Sdougm ret = sa_delete_instance(scf_handle, name); 13433034Sdougm sa_free_attr_string(name); 13443034Sdougm } 13453034Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 13463034Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 13473034Sdougm return (ret); 13483034Sdougm } 13493034Sdougm 13503034Sdougm /* 13513034Sdougm * sa_update_config() 13523034Sdougm * 13533034Sdougm * Used to update legacy files that need to be updated in bulk 13543034Sdougm * Currently, this is a placeholder and will go away in a future 13553034Sdougm * release. 13563034Sdougm */ 13573034Sdougm 13583034Sdougm int 13593034Sdougm sa_update_config() 13603034Sdougm { 13613034Sdougm /* 13623034Sdougm * do legacy files first so we can tell when they change. 13633034Sdougm * This will go away when we start updating individual records 13643034Sdougm * rather than the whole file. 13653034Sdougm */ 13663034Sdougm update_legacy_config(); 13673034Sdougm return (SA_OK); 13683034Sdougm } 13693034Sdougm 13703034Sdougm /* 13713034Sdougm * get_node_attr(node, tag) 13723034Sdougm * 13733034Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 13743034Sdougm * used internally by a number of attribute oriented functions. 13753034Sdougm */ 13763034Sdougm 13773034Sdougm static char * 13783034Sdougm get_node_attr(void *nodehdl, char *tag) 13793034Sdougm { 13803034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 13813034Sdougm xmlChar *name = NULL; 13823034Sdougm 13833034Sdougm if (node != NULL) { 13843034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 13853034Sdougm } 13863034Sdougm return ((char *)name); 13873034Sdougm } 13883034Sdougm 13893034Sdougm /* 13903034Sdougm * get_node_attr(node, tag) 13913034Sdougm * 13923034Sdougm * Set the speficied tag(attribute) to the specified value This is 13933034Sdougm * used internally by a number of attribute oriented functions. It 13943034Sdougm * doesn't update the repository, only the internal document state. 13953034Sdougm */ 13963034Sdougm 13973034Sdougm void 13983034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 13993034Sdougm { 14003034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 14013034Sdougm if (node != NULL && tag != NULL) { 14023034Sdougm if (value != NULL) { 14033034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 14043034Sdougm } else { 14053034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 14063034Sdougm } 14073034Sdougm } 14083034Sdougm } 14093034Sdougm 14103034Sdougm /* 14113034Sdougm * sa_get_group_attr(group, tag) 14123034Sdougm * 14133034Sdougm * Get the specied attribute, if defined, for the group. 14143034Sdougm */ 14153034Sdougm 14163034Sdougm char * 14173034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 14183034Sdougm { 14193034Sdougm return (get_node_attr((void *)group, tag)); 14203034Sdougm } 14213034Sdougm 14223034Sdougm /* 14233034Sdougm * sa_set_group_attr(group, tag, value) 14243034Sdougm * 14253034Sdougm * set the specified tag/attribute on the group using value as its 14263034Sdougm * value. 14273034Sdougm * 14283034Sdougm * This will result in setting the property in the SMF repository as 14293034Sdougm * well as in the internal document. 14303034Sdougm */ 14313034Sdougm 14323034Sdougm int 14333034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 14343034Sdougm { 14353034Sdougm int ret; 14363034Sdougm char *groupname; 14373034Sdougm 14383034Sdougm groupname = sa_get_group_attr(group, "name"); 14393034Sdougm ret = sa_get_instance(scf_handle, groupname); 14403034Sdougm if (ret == SA_OK) { 14413034Sdougm set_node_attr((void *)group, tag, value); 14423034Sdougm ret = sa_start_transaction(scf_handle, "operation"); 14433034Sdougm if (ret == SA_OK) { 14443034Sdougm ret = sa_set_property(scf_handle, tag, value); 14453034Sdougm if (ret == SA_OK) 14463034Sdougm (void) sa_end_transaction(scf_handle); 14473034Sdougm else { 14483034Sdougm sa_abort_transaction(scf_handle); 14493034Sdougm } 14503034Sdougm } 14513034Sdougm } 14523034Sdougm if (groupname != NULL) 14533034Sdougm sa_free_attr_string(groupname); 14543034Sdougm return (ret); 14553034Sdougm } 14563034Sdougm 14573034Sdougm /* 14583034Sdougm * sa_get_share_attr(share, tag) 14593034Sdougm * 14603034Sdougm * Return the value of the tag/attribute set on the specified 14613034Sdougm * share. Returns NULL if the tag doesn't exist. 14623034Sdougm */ 14633034Sdougm 14643034Sdougm char * 14653034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 14663034Sdougm { 14673034Sdougm return (get_node_attr((void *)share, tag)); 14683034Sdougm } 14693034Sdougm 14703034Sdougm /* 14713034Sdougm * sa_get_resource(group, resource) 14723034Sdougm * 14733034Sdougm * Search all the shares in the speified group for a share with a 14743034Sdougm * resource name matching the one specified. 14753034Sdougm * 14763034Sdougm * In the future, it may be advantageous to allow group to be NULL and 14773034Sdougm * search all groups but that isn't needed at present. 14783034Sdougm */ 14793034Sdougm 14803034Sdougm sa_share_t 14813034Sdougm sa_get_resource(sa_group_t group, char *resource) 14823034Sdougm { 14833034Sdougm sa_share_t share = NULL; 14843034Sdougm char *name = NULL; 14853034Sdougm 14863034Sdougm if (resource != NULL) { 14873034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 14883034Sdougm share = sa_get_next_share(share)) { 14893034Sdougm name = sa_get_share_attr(share, "resource"); 14903034Sdougm if (name != NULL) { 14913034Sdougm if (strcmp(name, resource) == 0) 14923034Sdougm break; 14933034Sdougm sa_free_attr_string(name); 14943034Sdougm name = NULL; 14953034Sdougm } 14963034Sdougm } 14973034Sdougm if (name != NULL) 14983034Sdougm sa_free_attr_string(name); 14993034Sdougm } 15003034Sdougm return ((sa_share_t)share); 15013034Sdougm } 15023034Sdougm 15033034Sdougm /* 15043034Sdougm * _sa_set_share_description(share, description) 15053034Sdougm * 15063034Sdougm * Add a description tag with text contents to the specified share. 15073034Sdougm * A separate XML tag is used rather than a property. 15083034Sdougm */ 15093034Sdougm 15103034Sdougm xmlNodePtr 15113034Sdougm _sa_set_share_description(sa_share_t share, char *content) 15123034Sdougm { 15133034Sdougm xmlNodePtr node; 15143034Sdougm node = xmlNewChild((xmlNodePtr)share, 15153034Sdougm NULL, (xmlChar *)"description", NULL); 15163034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 15173034Sdougm return (node); 15183034Sdougm } 15193034Sdougm 15203034Sdougm /* 15213034Sdougm * sa_set_share_attr(share, tag, value) 15223034Sdougm * 15233034Sdougm * Set the share attribute specified by tag to the specified value. In 15243034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 15253034Sdougm * the share is not transient, commit the changes to the repository 15263034Sdougm * else just update the share internally. 15273034Sdougm */ 15283034Sdougm 15293034Sdougm int 15303034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 15313034Sdougm { 15323034Sdougm sa_group_t group; 15333034Sdougm sa_share_t resource; 15343034Sdougm int ret = SA_OK; 15353034Sdougm 15363034Sdougm group = sa_get_parent_group(share); 15373034Sdougm 15383034Sdougm /* 15393034Sdougm * There are some attributes that may have specific 15403034Sdougm * restrictions on them. Initially, only "resource" has 15413034Sdougm * special meaning that needs to be checked. Only one instance 15423034Sdougm * of a resource name may exist within a group. 15433034Sdougm */ 15443034Sdougm 15453034Sdougm if (strcmp(tag, "resource") == 0) { 15463034Sdougm resource = sa_get_resource(group, value); 15473034Sdougm if (resource != share && resource != NULL) 15483034Sdougm ret = SA_DUPLICATE_NAME; 15493034Sdougm } 15503034Sdougm if (ret == SA_OK) { 15513034Sdougm set_node_attr((void *)share, tag, value); 15523034Sdougm if (group != NULL) { 15533034Sdougm char *type; 15543034Sdougm /* we can probably optimize this some */ 15553034Sdougm type = sa_get_share_attr(share, "type"); 15563034Sdougm if (type == NULL || strcmp(type, "transient") != 0) 15573034Sdougm ret = sa_commit_share(scf_handle, group, share); 15583034Sdougm if (type != NULL) 15593034Sdougm sa_free_attr_string(type); 15603034Sdougm } 15613034Sdougm } 15623034Sdougm return (ret); 15633034Sdougm } 15643034Sdougm 15653034Sdougm /* 15663034Sdougm * sa_get_property_attr(prop, tag) 15673034Sdougm * 15683034Sdougm * Get the value of the specified property attribute. Standard 15693034Sdougm * attributes are "type" and "value". 15703034Sdougm */ 15713034Sdougm 15723034Sdougm char * 15733034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 15743034Sdougm { 15753034Sdougm return (get_node_attr((void *)prop, tag)); 15763034Sdougm } 15773034Sdougm 15783034Sdougm /* 15793034Sdougm * sa_get_optionset_attr(prop, tag) 15803034Sdougm * 15813034Sdougm * Get the value of the specified property attribute. Standard 15823034Sdougm * attribute is "type". 15833034Sdougm */ 15843034Sdougm 15853034Sdougm char * 15863034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 15873034Sdougm { 15883034Sdougm return (get_node_attr((void *)optionset, tag)); 15893034Sdougm 15903034Sdougm } 15913034Sdougm 15923034Sdougm /* 15933034Sdougm * sa_set_optionset_attr(optionset, tag, value) 15943034Sdougm * 15953034Sdougm * Set the specified attribute(tag) to the specified value on the 15963034Sdougm * optionset. 15973034Sdougm */ 15983034Sdougm 15993034Sdougm void 16003034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 16013034Sdougm { 16023034Sdougm set_node_attr((void *)optionset, tag, value); 16033034Sdougm } 16043034Sdougm 16053034Sdougm /* 16063034Sdougm * sa_free_attr_string(string) 16073034Sdougm * 16083034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 16093034Sdougm * functions. 16103034Sdougm */ 16113034Sdougm 16123034Sdougm void 16133034Sdougm sa_free_attr_string(char *string) 16143034Sdougm { 16153034Sdougm xmlFree((xmlChar *)string); 16163034Sdougm } 16173034Sdougm 16183034Sdougm /* 16193034Sdougm * sa_get_optionset(group, proto) 16203034Sdougm * 16213034Sdougm * Return the optionset, if it exists, that is associated with the 16223034Sdougm * specified protocol. 16233034Sdougm */ 16243034Sdougm 16253034Sdougm sa_optionset_t 16263034Sdougm sa_get_optionset(void *group, char *proto) 16273034Sdougm { 16283034Sdougm xmlNodePtr node; 16293034Sdougm xmlChar *value = NULL; 16303034Sdougm 16313034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 16323034Sdougm node = node->next) { 16333034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 16343034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 16353034Sdougm if (proto != NULL) { 16363034Sdougm if (value != NULL && 16373034Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 16383034Sdougm break; 16393034Sdougm } 16403034Sdougm if (value != NULL) { 16413034Sdougm xmlFree(value); 16423034Sdougm value = NULL; 16433034Sdougm } 16443034Sdougm } else { 16453034Sdougm break; 16463034Sdougm } 16473034Sdougm } 16483034Sdougm } 16493034Sdougm if (value != NULL) 16503034Sdougm xmlFree(value); 16513034Sdougm return ((sa_optionset_t)node); 16523034Sdougm } 16533034Sdougm 16543034Sdougm /* 16553034Sdougm * sa_get_next_optionset(optionset) 16563034Sdougm * 16573034Sdougm * Return the next optionset in the group. NULL if this was the last. 16583034Sdougm */ 16593034Sdougm 16603034Sdougm sa_optionset_t 16613034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 16623034Sdougm { 16633034Sdougm xmlNodePtr node; 16643034Sdougm 16653034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 16663034Sdougm node = node->next) { 16673034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 16683034Sdougm break; 16693034Sdougm } 16703034Sdougm } 16713034Sdougm return ((sa_optionset_t)node); 16723034Sdougm } 16733034Sdougm 16743034Sdougm /* 16753034Sdougm * sa_get_security(group, sectype, proto) 16763034Sdougm * 16773034Sdougm * Return the security optionset. The internal name is a hold over 16783034Sdougm * from the implementation and will be changed before the API is 16793034Sdougm * finalized. This is really a named optionset that can be negotiated 16803034Sdougm * as a group of properties (like NFS security options). 16813034Sdougm */ 16823034Sdougm 16833034Sdougm sa_security_t 16843034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 16853034Sdougm { 16863034Sdougm xmlNodePtr node; 16873034Sdougm xmlChar *value = NULL; 16883034Sdougm 16893034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 16903034Sdougm node = node->next) { 16913034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 16923034Sdougm if (proto != NULL) { 16933034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 16943034Sdougm if (value == NULL || 16953034Sdougm (value != NULL && 16963034Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 16973034Sdougm /* it doesn't match so continue */ 16983034Sdougm xmlFree(value); 16993034Sdougm value = NULL; 17003034Sdougm continue; 17013034Sdougm } 17023034Sdougm } 17033034Sdougm if (value != NULL) { 17043034Sdougm xmlFree(value); 17053034Sdougm value = NULL; 17063034Sdougm } 17073034Sdougm /* potential match */ 17083034Sdougm if (sectype != NULL) { 17093034Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 17103034Sdougm if (value != NULL && 17113034Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 17123034Sdougm break; 17133034Sdougm } 17143034Sdougm } else { 17153034Sdougm break; 17163034Sdougm } 17173034Sdougm } 17183034Sdougm if (value != NULL) { 17193034Sdougm xmlFree(value); 17203034Sdougm value = NULL; 17213034Sdougm } 17223034Sdougm } 17233034Sdougm if (value != NULL) 17243034Sdougm xmlFree(value); 17253034Sdougm return ((sa_security_t)node); 17263034Sdougm } 17273034Sdougm 17283034Sdougm /* 17293034Sdougm * sa_get_next_security(security) 17303034Sdougm * 17313034Sdougm * Get the next security optionset if one exists. 17323034Sdougm */ 17333034Sdougm 17343034Sdougm sa_security_t 17353034Sdougm sa_get_next_security(sa_security_t security) 17363034Sdougm { 17373034Sdougm xmlNodePtr node; 17383034Sdougm 17393034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 17403034Sdougm node = node->next) { 17413034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 17423034Sdougm break; 17433034Sdougm } 17443034Sdougm } 17453034Sdougm return ((sa_security_t)node); 17463034Sdougm } 17473034Sdougm 17483034Sdougm /* 17493034Sdougm * sa_get_property(optionset, prop) 17503034Sdougm * 17513034Sdougm * Get the property object with the name specified in prop from the 17523034Sdougm * optionset. 17533034Sdougm */ 17543034Sdougm 17553034Sdougm sa_property_t 17563034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 17573034Sdougm { 17583034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 17593034Sdougm xmlChar *value = NULL; 17603034Sdougm 17613034Sdougm if (optionset == NULL) 17623034Sdougm return (NULL); 17633034Sdougm 17643034Sdougm for (node = node->children; node != NULL; 17653034Sdougm node = node->next) { 17663034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 17673034Sdougm if (prop == NULL) 17683034Sdougm break; 17693034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 17703034Sdougm if (value != NULL && xmlStrcmp(value, (xmlChar *)prop) == 0) { 17713034Sdougm break; 17723034Sdougm } 17733034Sdougm if (value != NULL) { 17743034Sdougm xmlFree(value); 17753034Sdougm value = NULL; 17763034Sdougm } 17773034Sdougm } 17783034Sdougm } 17793034Sdougm if (value != NULL) 17803034Sdougm xmlFree(value); 17813034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 17823034Sdougm /* avoid a non option node -- it is possible to be a text node */ 17833034Sdougm node = NULL; 17843034Sdougm } 17853034Sdougm return ((sa_property_t)node); 17863034Sdougm } 17873034Sdougm 17883034Sdougm /* 17893034Sdougm * sa_get_next_property(property) 17903034Sdougm * 17913034Sdougm * Get the next property following the specified property. NULL if 17923034Sdougm * this was the last. 17933034Sdougm */ 17943034Sdougm 17953034Sdougm sa_property_t 17963034Sdougm sa_get_next_property(sa_property_t property) 17973034Sdougm { 17983034Sdougm xmlNodePtr node; 17993034Sdougm 18003034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 18013034Sdougm node = node->next) { 18023034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 18033034Sdougm break; 18043034Sdougm } 18053034Sdougm } 18063034Sdougm return ((sa_property_t)node); 18073034Sdougm } 18083034Sdougm 18093034Sdougm /* 18103034Sdougm * sa_set_share_description(share, content) 18113034Sdougm * 18123034Sdougm * Set the description of share to content. 18133034Sdougm */ 18143034Sdougm 18153034Sdougm int 18163034Sdougm sa_set_share_description(sa_share_t share, char *content) 18173034Sdougm { 18183034Sdougm xmlNodePtr node; 18193034Sdougm sa_group_t group; 18203034Sdougm int ret = SA_OK; 18213034Sdougm 18223034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 18233034Sdougm node = node->next) { 18243034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 18253034Sdougm break; 18263034Sdougm } 18273034Sdougm } 18283034Sdougm group = sa_get_parent_group(share); 18293034Sdougm /* no existing description but want to add */ 18303034Sdougm if (node == NULL && content != NULL) { 18313034Sdougm /* add a description */ 18323034Sdougm node = _sa_set_share_description(share, content); 18333034Sdougm } else if (node != NULL && content != NULL) { 18343034Sdougm /* update a description */ 18353034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 18363034Sdougm } else if (node != NULL && content == NULL) { 18373034Sdougm /* remove an existing description */ 18383034Sdougm xmlUnlinkNode(node); 18393034Sdougm xmlFreeNode(node); 18403034Sdougm } 18413034Sdougm if (group != NULL && is_persistent((sa_group_t)share)) 18423034Sdougm ret = sa_commit_share(scf_handle, group, share); 18433034Sdougm return (ret); 18443034Sdougm } 18453034Sdougm 18463034Sdougm /* 18473034Sdougm * fixproblemchars(string) 18483034Sdougm * 18493034Sdougm * don't want any newline or tab characters in the text since these 18503034Sdougm * could break display of data and legacy file formats. 18513034Sdougm */ 18523034Sdougm static void 18533034Sdougm fixproblemchars(char *str) 18543034Sdougm { 18553034Sdougm int c; 18563034Sdougm for (c = *str; c != '\0'; c = *++str) { 18573034Sdougm if (c == '\t' || c == '\n') 18583034Sdougm *str = ' '; 18593034Sdougm else if (c == '"') 18603034Sdougm *str = '\''; 18613034Sdougm } 18623034Sdougm } 18633034Sdougm 18643034Sdougm /* 18653034Sdougm * sa_get_share_description(share) 18663034Sdougm * 18673034Sdougm * Return the description text for the specified share if it 18683034Sdougm * exists. NULL if no description exists. 18693034Sdougm */ 18703034Sdougm 18713034Sdougm char * 18723034Sdougm sa_get_share_description(sa_share_t share) 18733034Sdougm { 18743034Sdougm xmlChar *description = NULL; 18753034Sdougm xmlNodePtr node; 18763034Sdougm 18773034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 18783034Sdougm node = node->next) { 18793034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 18803034Sdougm break; 18813034Sdougm } 18823034Sdougm } 18833034Sdougm if (node != NULL) { 18843034Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 18853034Sdougm fixproblemchars((char *)description); 18863034Sdougm } 18873034Sdougm return ((char *)description); 18883034Sdougm } 18893034Sdougm 18903034Sdougm /* 18913034Sdougm * sa_free(share_description(description) 18923034Sdougm * 18933034Sdougm * Free the description string. 18943034Sdougm */ 18953034Sdougm 18963034Sdougm void 18973034Sdougm sa_free_share_description(char *description) 18983034Sdougm { 18993034Sdougm xmlFree((xmlChar *)description); 19003034Sdougm } 19013034Sdougm 19023034Sdougm /* 19033034Sdougm * sa_create_optionset(group, proto) 19043034Sdougm * 19053034Sdougm * Create an optionset for the specified protocol in the specied 19063034Sdougm * group. This is manifested as a property group within SMF. 19073034Sdougm */ 19083034Sdougm 19093034Sdougm sa_optionset_t 19103034Sdougm sa_create_optionset(sa_group_t group, char *proto) 19113034Sdougm { 19123034Sdougm sa_optionset_t optionset; 19133034Sdougm sa_group_t parent = group; 19143034Sdougm 19153034Sdougm optionset = sa_get_optionset(group, proto); 19163034Sdougm if (optionset != NULL) { 19173034Sdougm /* can't have a duplicate protocol */ 19183034Sdougm optionset = NULL; 19193034Sdougm } else { 19203034Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 19213034Sdougm NULL, 19223034Sdougm (xmlChar *)"optionset", 19233034Sdougm NULL); 19243034Sdougm /* 19253034Sdougm * only put to repository if on a group and we were 19263034Sdougm * able to create an optionset. 19273034Sdougm */ 19283034Sdougm if (optionset != NULL) { 19293034Sdougm char oname[256]; 19303034Sdougm char *groupname; 19313034Sdougm char *id = NULL; 19323034Sdougm 19333034Sdougm if (sa_is_share(group)) 19343034Sdougm parent = sa_get_parent_group((sa_share_t)group); 19353034Sdougm 19363034Sdougm sa_set_optionset_attr(optionset, "type", proto); 19373034Sdougm 19383034Sdougm if (sa_is_share(group)) { 19393034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 19403034Sdougm } 19413034Sdougm (void) sa_optionset_name(optionset, oname, 19423034Sdougm sizeof (oname), id); 19433034Sdougm groupname = sa_get_group_attr(parent, "name"); 19443034Sdougm if (groupname != NULL && is_persistent(group)) { 19453034Sdougm (void) sa_get_instance(scf_handle, groupname); 19463034Sdougm sa_free_attr_string(groupname); 19473034Sdougm (void) sa_create_pgroup(scf_handle, oname); 19483034Sdougm } 19493034Sdougm if (id != NULL) 19503034Sdougm sa_free_attr_string(id); 19513034Sdougm } 19523034Sdougm } 19533034Sdougm return (optionset); 19543034Sdougm } 19553034Sdougm 19563034Sdougm /* 19573034Sdougm * sa_get_property_parent(property) 19583034Sdougm * 19593034Sdougm * Given a property, return the object it is a property of. This will 19603034Sdougm * be an optionset of some type. 19613034Sdougm */ 19623034Sdougm 19633034Sdougm static sa_optionset_t 19643034Sdougm sa_get_property_parent(sa_property_t property) 19653034Sdougm { 19663034Sdougm xmlNodePtr node = NULL; 19673034Sdougm 19683034Sdougm if (property != NULL) { 19693034Sdougm node = ((xmlNodePtr)property)->parent; 19703034Sdougm } 19713034Sdougm return ((sa_optionset_t)node); 19723034Sdougm } 19733034Sdougm 19743034Sdougm /* 19753034Sdougm * sa_get_optionset_parent(optionset) 19763034Sdougm * 19773034Sdougm * Return the parent of the specified optionset. This could be a group 19783034Sdougm * or a share. 19793034Sdougm */ 19803034Sdougm 19813034Sdougm static sa_group_t 19823034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 19833034Sdougm { 19843034Sdougm xmlNodePtr node = NULL; 19853034Sdougm 19863034Sdougm if (optionset != NULL) { 19873034Sdougm node = ((xmlNodePtr)optionset)->parent; 19883034Sdougm } 19893034Sdougm return ((sa_group_t)node); 19903034Sdougm } 19913034Sdougm 19923034Sdougm /* 19933034Sdougm * zfs_needs_update(share) 19943034Sdougm * 19953034Sdougm * In order to avoid making multiple updates to a ZFS share when 19963034Sdougm * setting properties, the share attribute "changed" will be set to 19973034Sdougm * true when a property is added or modifed. When done adding 19983034Sdougm * properties, we can then detect that an update is needed. We then 19993034Sdougm * clear the state here to detect additional changes. 20003034Sdougm */ 20013034Sdougm 20023034Sdougm static int 20033034Sdougm zfs_needs_update(sa_share_t share) 20043034Sdougm { 20053034Sdougm char *attr; 20063034Sdougm int result = 0; 20073034Sdougm 20083034Sdougm attr = sa_get_share_attr(share, "changed"); 20093034Sdougm if (attr != NULL) { 20103034Sdougm sa_free_attr_string(attr); 20113034Sdougm result = 1; 20123034Sdougm } 20133034Sdougm set_node_attr((void *)share, "changed", NULL); 20143034Sdougm return (result); 20153034Sdougm } 20163034Sdougm 20173034Sdougm /* 20183034Sdougm * zfs_set_update(share) 20193034Sdougm * 20203034Sdougm * Set the changed attribute of the share to true. 20213034Sdougm */ 20223034Sdougm 20233034Sdougm static void 20243034Sdougm zfs_set_update(sa_share_t share) 20253034Sdougm { 20263034Sdougm set_node_attr((void *)share, "changed", "true"); 20273034Sdougm } 20283034Sdougm 20293034Sdougm /* 20303034Sdougm * sa_commit_properties(optionset, clear) 20313034Sdougm * 20323034Sdougm * Check if SMF or ZFS config and either update or abort the pending 20333034Sdougm * changes. 20343034Sdougm */ 20353034Sdougm 20363034Sdougm int 20373034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 20383034Sdougm { 20393034Sdougm sa_group_t group; 20403034Sdougm sa_group_t parent; 20413034Sdougm int zfs = 0; 20423034Sdougm int needsupdate = 0; 20433034Sdougm int ret = SA_OK; 20443034Sdougm 20453034Sdougm group = sa_get_optionset_parent(optionset); 20463034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 20473034Sdougm /* only update ZFS if on a share */ 20483034Sdougm parent = sa_get_parent_group(group); 20493034Sdougm zfs++; 20503034Sdougm if (parent != NULL && is_zfs_group(parent)) { 20513034Sdougm needsupdate = zfs_needs_update(group); 20523034Sdougm } else { 20533034Sdougm zfs = 0; 20543034Sdougm } 20553034Sdougm } 20563034Sdougm if (zfs) { 20573034Sdougm if (!clear && needsupdate) 20583034Sdougm ret = sa_zfs_update((sa_share_t)group); 20593034Sdougm } else { 20603034Sdougm if (clear) 20613034Sdougm (void) sa_abort_transaction(scf_handle); 20623034Sdougm else 20633034Sdougm ret = sa_end_transaction(scf_handle); 20643034Sdougm } 20653034Sdougm return (ret); 20663034Sdougm } 20673034Sdougm 20683034Sdougm /* 20693034Sdougm * sa_destroy_optionset(optionset) 20703034Sdougm * 20713034Sdougm * Remove the optionset from its group. Update the repostory to 20723034Sdougm * reflect this change. 20733034Sdougm */ 20743034Sdougm 20753034Sdougm int 20763034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 20773034Sdougm { 20783034Sdougm char name[256]; 20793034Sdougm int len; 20803034Sdougm int ret; 20813034Sdougm char *id = NULL; 20823034Sdougm sa_group_t group; 20833034Sdougm int ispersist = 1; 20843034Sdougm 20853034Sdougm /* now delete the prop group */ 20863034Sdougm group = sa_get_optionset_parent(optionset); 20873034Sdougm if (group != NULL && sa_is_share(group)) { 20883034Sdougm ispersist = is_persistent(group); 20893034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 20903034Sdougm } 20913034Sdougm if (ispersist) { 20923034Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 20933034Sdougm if (len > 0) { 20943034Sdougm ret = sa_delete_pgroup(scf_handle, name); 20953034Sdougm } 20963034Sdougm } 20973034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 20983034Sdougm xmlFreeNode((xmlNodePtr)optionset); 20993034Sdougm if (id != NULL) 21003034Sdougm sa_free_attr_string(id); 21013034Sdougm return (ret); 21023034Sdougm } 21033034Sdougm 21043034Sdougm /* private to the implementation */ 21053034Sdougm int 21063034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 21073034Sdougm { 21083034Sdougm int ret = SA_OK; 21093034Sdougm 21103034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 21113034Sdougm xmlFreeNode((xmlNodePtr)optionset); 21123034Sdougm return (ret); 21133034Sdougm } 21143034Sdougm 21153034Sdougm /* 21163034Sdougm * sa_create_security(group, sectype, proto) 21173034Sdougm * 21183034Sdougm * Create a security optionset (one that has a type name and a 21193034Sdougm * proto). Security is left over from a pure NFS implementation. The 21203034Sdougm * naming will change in the future when the API is released. 21213034Sdougm */ 21223034Sdougm sa_security_t 21233034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 21243034Sdougm { 21253034Sdougm sa_security_t security; 21263034Sdougm char *id = NULL; 21273034Sdougm sa_group_t parent; 21283034Sdougm char *groupname = NULL; 21293034Sdougm 21303034Sdougm if (group != NULL && sa_is_share(group)) { 21313034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 21323034Sdougm parent = sa_get_parent_group(group); 21333034Sdougm if (parent != NULL) 21343034Sdougm groupname = sa_get_group_attr(parent, "name"); 21353034Sdougm } else if (group != NULL) { 21363034Sdougm groupname = sa_get_group_attr(group, "name"); 21373034Sdougm } 21383034Sdougm 21393034Sdougm security = sa_get_security(group, sectype, proto); 21403034Sdougm if (security != NULL) { 21413034Sdougm /* can't have a duplicate security option */ 21423034Sdougm security = NULL; 21433034Sdougm } else { 21443034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 21453034Sdougm NULL, 21463034Sdougm (xmlChar *)"security", 21473034Sdougm NULL); 21483034Sdougm if (security != NULL) { 21493034Sdougm char oname[256]; 21503034Sdougm sa_set_security_attr(security, "type", proto); 21513034Sdougm 21523034Sdougm sa_set_security_attr(security, "sectype", sectype); 21533034Sdougm (void) sa_security_name(security, oname, 21543034Sdougm sizeof (oname), id); 21553034Sdougm if (groupname != NULL && is_persistent(group)) { 21563034Sdougm (void) sa_get_instance(scf_handle, groupname); 21573034Sdougm (void) sa_create_pgroup(scf_handle, oname); 21583034Sdougm } 21593034Sdougm } 21603034Sdougm } 21613034Sdougm if (groupname != NULL) 21623034Sdougm sa_free_attr_string(groupname); 21633034Sdougm return (security); 21643034Sdougm } 21653034Sdougm 21663034Sdougm /* 21673034Sdougm * sa_destroy_security(security) 21683034Sdougm * 21693034Sdougm * Remove the specified optionset from the document and the 21703034Sdougm * configuration. 21713034Sdougm */ 21723034Sdougm 21733034Sdougm int 21743034Sdougm sa_destroy_security(sa_security_t security) 21753034Sdougm { 21763034Sdougm char name[256]; 21773034Sdougm int len; 21783034Sdougm int ret = SA_OK; 21793034Sdougm char *id = NULL; 21803034Sdougm sa_group_t group; 21813034Sdougm int iszfs = 0; 21823034Sdougm int ispersist = 1; 21833034Sdougm 21843034Sdougm group = sa_get_optionset_parent(security); 21853034Sdougm 21863034Sdougm if (group != NULL) 21873034Sdougm iszfs = sa_group_is_zfs(group); 21883034Sdougm 21893034Sdougm if (group != NULL && !iszfs) { 21903034Sdougm if (sa_is_share(group)) 21913034Sdougm ispersist = is_persistent(group); 21923034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 21933034Sdougm } 21943034Sdougm if (ispersist) { 21953034Sdougm len = sa_security_name(security, name, sizeof (name), id); 21963034Sdougm if (!iszfs && len > 0) { 21973034Sdougm ret = sa_delete_pgroup(scf_handle, name); 21983034Sdougm } 21993034Sdougm } 22003034Sdougm xmlUnlinkNode((xmlNodePtr)security); 22013034Sdougm xmlFreeNode((xmlNodePtr)security); 22023034Sdougm if (iszfs) { 22033034Sdougm ret = sa_zfs_update(group); 22043034Sdougm } 22053034Sdougm if (id != NULL) 22063034Sdougm sa_free_attr_string(id); 22073034Sdougm return (ret); 22083034Sdougm } 22093034Sdougm 22103034Sdougm /* 22113034Sdougm * sa_get_security_attr(optionset, tag) 22123034Sdougm * 22133034Sdougm * Return the specified attribute value from the optionset. 22143034Sdougm */ 22153034Sdougm 22163034Sdougm char * 22173034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 22183034Sdougm { 22193034Sdougm return (get_node_attr((void *)optionset, tag)); 22203034Sdougm 22213034Sdougm } 22223034Sdougm 22233034Sdougm /* 22243034Sdougm * sa_set_security_attr(optionset, tag, value) 22253034Sdougm * 22263034Sdougm * Set the optioset attribute specied by tag to the specified value. 22273034Sdougm */ 22283034Sdougm 22293034Sdougm void 22303034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 22313034Sdougm { 22323034Sdougm set_node_attr((void *)optionset, tag, value); 22333034Sdougm } 22343034Sdougm 22353034Sdougm /* 22363034Sdougm * is_nodetype(node, type) 22373034Sdougm * 22383034Sdougm * Check to see if node is of the type specified. 22393034Sdougm */ 22403034Sdougm 22413034Sdougm static int 22423034Sdougm is_nodetype(void *node, char *type) 22433034Sdougm { 22443034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 22453034Sdougm } 22463034Sdougm 22473034Sdougm /* 22483034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 22493034Sdougm * 22503034Sdougm * Add/remove/update the specified property prop into the optionset or 22513034Sdougm * share. If a share, sort out which property group based on GUID. In 22523034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 22533034Sdougm * marked as needing an update) 22543034Sdougm */ 22553034Sdougm 22563034Sdougm #define SA_PROP_OP_REMOVE 1 22573034Sdougm #define SA_PROP_OP_ADD 2 22583034Sdougm #define SA_PROP_OP_UPDATE 3 22593034Sdougm static int 22603034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 22613034Sdougm sa_property_t prop, int type) 22623034Sdougm { 22633034Sdougm char *name; 22643034Sdougm char *valstr; 22653034Sdougm int ret = SA_OK; 22663034Sdougm scf_transaction_entry_t *entry; 22673034Sdougm scf_value_t *value; 22683034Sdougm int opttype; /* 1 == optionset, 0 == security */ 22693034Sdougm char *id = NULL; 22703034Sdougm int iszfs = 0; 22713034Sdougm int isshare = 0; 22723034Sdougm sa_group_t parent = NULL; 22733034Sdougm 22743034Sdougm if (!is_persistent(group)) { 22753034Sdougm /* 22763034Sdougm * if the group/share is not persistent we don't need 22773034Sdougm * to do anything here 22783034Sdougm */ 22793034Sdougm return (SA_OK); 22803034Sdougm } 22813034Sdougm name = sa_get_property_attr(prop, "type"); 22823034Sdougm valstr = sa_get_property_attr(prop, "value"); 22833034Sdougm entry = scf_entry_create(scf_handle->handle); 22843034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 22853034Sdougm 22863034Sdougm if (valstr != NULL && entry != NULL) { 22873034Sdougm if (sa_is_share(group)) { 22883034Sdougm isshare = 1; 22893034Sdougm parent = sa_get_parent_group(group); 22903034Sdougm if (parent != NULL) { 22913034Sdougm iszfs = is_zfs_group(parent); 22923034Sdougm } 22933034Sdougm } else { 22943034Sdougm iszfs = is_zfs_group(group); 22953034Sdougm } 22963034Sdougm if (!iszfs) { 22973034Sdougm if (scf_handle->trans == NULL) { 22983034Sdougm char oname[256]; 22993034Sdougm char *groupname = NULL; 23003034Sdougm if (isshare) { 23013034Sdougm if (parent != NULL) { 23023034Sdougm groupname = sa_get_group_attr(parent, "name"); 23033034Sdougm } 23043034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 23053034Sdougm } else { 23063034Sdougm groupname = sa_get_group_attr(group, "name"); 23073034Sdougm } 23083034Sdougm if (groupname != NULL) { 23093034Sdougm ret = sa_get_instance(scf_handle, groupname); 23103034Sdougm sa_free_attr_string(groupname); 23113034Sdougm } 23123034Sdougm if (opttype) 23133034Sdougm (void) sa_optionset_name(optionset, oname, 23143034Sdougm sizeof (oname), id); 23153034Sdougm else 23163034Sdougm (void) sa_security_name(optionset, oname, 23173034Sdougm sizeof (oname), id); 23183034Sdougm ret = sa_start_transaction(scf_handle, oname); 23193034Sdougm } 23203034Sdougm if (ret == SA_OK) { 23213034Sdougm switch (type) { 23223034Sdougm case SA_PROP_OP_REMOVE: 23233034Sdougm ret = scf_transaction_property_delete(scf_handle->trans, 23243034Sdougm entry, 23253034Sdougm name); 23263034Sdougm break; 23273034Sdougm case SA_PROP_OP_ADD: 23283034Sdougm case SA_PROP_OP_UPDATE: 23293034Sdougm value = scf_value_create(scf_handle->handle); 23303034Sdougm if (value != NULL) { 23313034Sdougm if (type == SA_PROP_OP_ADD) 23323034Sdougm ret = scf_transaction_property_new( 23333034Sdougm scf_handle->trans, 23343034Sdougm entry, 23353034Sdougm name, 23363034Sdougm SCF_TYPE_ASTRING); 23373034Sdougm else 23383034Sdougm ret = scf_transaction_property_change( 23393034Sdougm scf_handle->trans, 23403034Sdougm entry, 23413034Sdougm name, 23423034Sdougm SCF_TYPE_ASTRING); 23433034Sdougm if (ret == 0) { 23443034Sdougm ret = scf_value_set_astring(value, valstr); 23453034Sdougm if (ret == 0) 23463034Sdougm ret = scf_entry_add_value(entry, value); 23473034Sdougm if (ret != 0) { 23483034Sdougm scf_value_destroy(value); 23493034Sdougm ret = SA_SYSTEM_ERR; 23503034Sdougm } 23513034Sdougm } else { 23523034Sdougm scf_entry_destroy(entry); 23533034Sdougm ret = SA_SYSTEM_ERR; 23543034Sdougm } 23553034Sdougm break; 23563034Sdougm } 23573034Sdougm } 23583034Sdougm } 23593034Sdougm } else { 23603034Sdougm /* 23613034Sdougm * ZFS update. The calling function would have updated 23623034Sdougm * the internal XML structure. Just need to flag it as 23633034Sdougm * changed for ZFS. 23643034Sdougm */ 23653034Sdougm zfs_set_update((sa_share_t)group); 23663034Sdougm } 23673034Sdougm } 23683034Sdougm 23693034Sdougm if (name != NULL) 23703034Sdougm sa_free_attr_string(name); 23713034Sdougm if (valstr != NULL) 23723034Sdougm sa_free_attr_string(valstr); 23733034Sdougm else if (entry != NULL) 23743034Sdougm scf_entry_destroy(entry); 23753034Sdougm 23763034Sdougm if (ret == -1) 23773034Sdougm ret = SA_SYSTEM_ERR; 23783034Sdougm 23793034Sdougm return (ret); 23803034Sdougm } 23813034Sdougm 23823034Sdougm /* 23833034Sdougm * sa_create_property(name, value) 23843034Sdougm * 23853034Sdougm * Create a new property with the specified name and value. 23863034Sdougm */ 23873034Sdougm 23883034Sdougm sa_property_t 23893034Sdougm sa_create_property(char *name, char *value) 23903034Sdougm { 23913034Sdougm xmlNodePtr node; 23923034Sdougm 23933034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 23943034Sdougm if (node != NULL) { 23953034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 23963034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 23973034Sdougm } 23983034Sdougm return ((sa_property_t)node); 23993034Sdougm } 24003034Sdougm 24013034Sdougm /* 24023034Sdougm * sa_add_property(object, property) 24033034Sdougm * 24043034Sdougm * Add the specified property to the object. Issue the appropriate 24053034Sdougm * transaction or mark a ZFS object as needing an update. 24063034Sdougm */ 24073034Sdougm 24083034Sdougm int 24093034Sdougm sa_add_property(void *object, sa_property_t property) 24103034Sdougm { 24113034Sdougm int ret = SA_OK; 24123034Sdougm sa_group_t parent; 24133034Sdougm sa_group_t group; 24143034Sdougm char *proto; 24153034Sdougm 24163034Sdougm proto = sa_get_optionset_attr(object, "type"); 24173034Sdougm if (property != NULL) { 24183034Sdougm if ((ret = sa_valid_property(object, proto, property)) == SA_OK) { 24193034Sdougm property = (sa_property_t)xmlAddChild((xmlNodePtr)object, 24203034Sdougm (xmlNodePtr)property); 24213034Sdougm } else { 24223034Sdougm if (proto != NULL) 24233034Sdougm sa_free_attr_string(proto); 24243034Sdougm return (ret); 24253034Sdougm } 24263034Sdougm } 24273034Sdougm 24283034Sdougm if (proto != NULL) 24293034Sdougm sa_free_attr_string(proto); 24303034Sdougm 24313034Sdougm parent = sa_get_parent_group(object); 24323034Sdougm if (!is_persistent(parent)) { 24333034Sdougm return (ret); 24343034Sdougm } 24353034Sdougm 24363034Sdougm if (sa_is_share(parent)) 24373034Sdougm group = sa_get_parent_group(parent); 24383034Sdougm else 24393034Sdougm group = parent; 24403034Sdougm 24413034Sdougm if (property == NULL) 24423034Sdougm ret = SA_NO_MEMORY; 24433034Sdougm else { 24443034Sdougm char oname[256]; 24453034Sdougm 24463034Sdougm if (!is_zfs_group(group)) { 24473034Sdougm char *id = NULL; 24483034Sdougm if (sa_is_share((sa_group_t)parent)) { 24493034Sdougm id = sa_get_share_attr((sa_share_t)parent, "id"); 24503034Sdougm } 24513034Sdougm if (scf_handle->trans == NULL) { 24523034Sdougm if (is_nodetype(object, "optionset")) 24533034Sdougm (void) sa_optionset_name((sa_optionset_t)object, 24543034Sdougm oname, sizeof (oname), id); 24553034Sdougm else 24563034Sdougm (void) sa_security_name((sa_optionset_t)object, 24573034Sdougm oname, sizeof (oname), id); 24583034Sdougm ret = sa_start_transaction(scf_handle, oname); 24593034Sdougm } 24603034Sdougm if (ret == SA_OK) { 24613034Sdougm char *name; 24623034Sdougm char *value; 24633034Sdougm name = sa_get_property_attr(property, "type"); 24643034Sdougm value = sa_get_property_attr(property, "value"); 24653034Sdougm if (name != NULL && value != NULL) { 24663034Sdougm if (scf_handle->scf_state == SCH_STATE_INIT) 24673034Sdougm ret = sa_set_property(scf_handle, name, value); 24683034Sdougm } else 24693034Sdougm ret = SA_CONFIG_ERR; 24703034Sdougm if (name != NULL) 24713034Sdougm sa_free_attr_string(name); 24723034Sdougm if (value != NULL) 24733034Sdougm sa_free_attr_string(value); 24743034Sdougm } 24753034Sdougm if (id != NULL) 24763034Sdougm sa_free_attr_string(id); 24773034Sdougm } else { 24783034Sdougm /* 24793034Sdougm * ZFS is a special case. We do want to allow editing 24803034Sdougm * property/security lists since we can have a better 24813034Sdougm * syntax and we also want to keep things consistent 24823034Sdougm * when possible. 24833034Sdougm * 24843034Sdougm * Right now, we defer until the sa_commit_properties 24853034Sdougm * so we can get them all at once. We do need to mark 24863034Sdougm * the share as "changed" 24873034Sdougm */ 24883034Sdougm zfs_set_update((sa_share_t)parent); 24893034Sdougm } 24903034Sdougm } 24913034Sdougm return (ret); 24923034Sdougm } 24933034Sdougm 24943034Sdougm /* 24953034Sdougm * sa_remove_property(property) 24963034Sdougm * 24973034Sdougm * Remove the specied property from its containing object. Update the 24983034Sdougm * repository as appropriate. 24993034Sdougm */ 25003034Sdougm 25013034Sdougm int 25023034Sdougm sa_remove_property(sa_property_t property) 25033034Sdougm { 25043034Sdougm int ret = SA_OK; 25053034Sdougm 25063034Sdougm if (property != NULL) { 25073034Sdougm sa_optionset_t optionset; 25083034Sdougm sa_group_t group; 25093034Sdougm optionset = sa_get_property_parent(property); 25103034Sdougm if (optionset != NULL) { 25113034Sdougm group = sa_get_optionset_parent(optionset); 25123034Sdougm if (group != NULL) { 25133034Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 25143034Sdougm SA_PROP_OP_REMOVE); 25153034Sdougm } 25163034Sdougm } 25173034Sdougm xmlUnlinkNode((xmlNodePtr)property); 25183034Sdougm xmlFreeNode((xmlNodePtr)property); 25193034Sdougm } else { 25203034Sdougm ret = SA_NO_SUCH_PROP; 25213034Sdougm } 25223034Sdougm return (ret); 25233034Sdougm } 25243034Sdougm 25253034Sdougm /* 25263034Sdougm * sa_update_property(property, value) 25273034Sdougm * 25283034Sdougm * Update the specified property to the new value. If value is NULL, 25293034Sdougm * we currently treat this as a remove. 25303034Sdougm */ 25313034Sdougm 25323034Sdougm int 25333034Sdougm sa_update_property(sa_property_t property, char *value) 25343034Sdougm { 25353034Sdougm int ret = SA_OK; 25363034Sdougm if (value == NULL) { 25373034Sdougm return (sa_remove_property(property)); 25383034Sdougm } else { 25393034Sdougm sa_optionset_t optionset; 25403034Sdougm sa_group_t group; 25413034Sdougm set_node_attr((void *)property, "value", value); 25423034Sdougm optionset = sa_get_property_parent(property); 25433034Sdougm if (optionset != NULL) { 25443034Sdougm group = sa_get_optionset_parent(optionset); 25453034Sdougm if (group != NULL) { 25463034Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 25473034Sdougm SA_PROP_OP_UPDATE); 25483034Sdougm } 25493034Sdougm } else { 25503034Sdougm ret = SA_NO_SUCH_PROP; 25513034Sdougm } 25523034Sdougm } 25533034Sdougm return (ret); 25543034Sdougm } 25553034Sdougm 25563034Sdougm /* 25573034Sdougm * _sa_get_next_error(node) 25583034Sdougm * 25593034Sdougm * Get the next (first if node==NULL) error node in the 25603034Sdougm * document. "error" nodes are added if there were syntax errors 25613034Sdougm * during parsing of the /etc/dfs/dfstab file. They are preserved in 25623034Sdougm * comments and recreated in the doc on the next parse. 25633034Sdougm */ 25643034Sdougm 25653034Sdougm xmlNodePtr 25663034Sdougm _sa_get_next_error(xmlNodePtr node) 25673034Sdougm { 25683034Sdougm if (node == NULL) { 25693034Sdougm for (node = sa_config_tree->xmlChildrenNode; 25703034Sdougm node != NULL; node = node->next) 25713034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 25723034Sdougm return (node); 25733034Sdougm } else { 25743034Sdougm for (node = node->next; node != NULL; node = node->next) 25753034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 25763034Sdougm return (node); 25773034Sdougm } 25783034Sdougm return (node); 25793034Sdougm } 25803034Sdougm 25813034Sdougm /* 25823034Sdougm * sa_get_protocol_property(propset, prop) 25833034Sdougm * 25843034Sdougm * Get the specified protocol specific property. These are global to 25853034Sdougm * the protocol and not specific to a group or share. 25863034Sdougm */ 25873034Sdougm 25883034Sdougm sa_property_t 25893034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 25903034Sdougm { 25913034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 25923034Sdougm xmlChar *value = NULL; 25933034Sdougm 25943034Sdougm for (node = node->children; node != NULL; 25953034Sdougm node = node->next) { 25963034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 25973034Sdougm if (prop == NULL) 25983034Sdougm break; 25993034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 26003034Sdougm if (value != NULL && 26013034Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 26023034Sdougm break; 26033034Sdougm } 26043034Sdougm if (value != NULL) { 26053034Sdougm xmlFree(value); 26063034Sdougm value = NULL; 26073034Sdougm } 26083034Sdougm } 26093034Sdougm } 26103034Sdougm if (value != NULL) 26113034Sdougm xmlFree(value); 26123034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 26133034Sdougm /* avoid a non option node -- it is possible to be a text node */ 26143034Sdougm node = NULL; 26153034Sdougm } 26163034Sdougm return ((sa_property_t)node); 26173034Sdougm } 26183034Sdougm 26193034Sdougm /* 26203034Sdougm * sa_get_next_protocol_property(prop) 26213034Sdougm * 26223034Sdougm * Get the next protocol specific property in the list. 26233034Sdougm */ 26243034Sdougm 26253034Sdougm sa_property_t 26263034Sdougm sa_get_next_protocol_property(sa_property_t prop) 26273034Sdougm { 26283034Sdougm xmlNodePtr node; 26293034Sdougm 26303034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 26313034Sdougm node = node->next) { 26323034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 26333034Sdougm break; 26343034Sdougm } 26353034Sdougm } 26363034Sdougm return ((sa_property_t)node); 26373034Sdougm } 26383034Sdougm 26393034Sdougm /* 26403034Sdougm * sa_set_protocol_property(prop, value) 26413034Sdougm * 26423034Sdougm * Set the specified property to have the new value. The protocol 26433034Sdougm * specific plugin will then be called to update the property. 26443034Sdougm */ 26453034Sdougm 26463034Sdougm int 26473034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 26483034Sdougm { 26493034Sdougm sa_protocol_properties_t propset; 26503034Sdougm char *proto; 26513034Sdougm int ret = SA_INVALID_PROTOCOL; 26523034Sdougm 26533034Sdougm propset = ((xmlNodePtr)prop)->parent; 26543034Sdougm if (propset != NULL) { 26553034Sdougm proto = sa_get_optionset_attr(propset, "type"); 26563034Sdougm if (proto != NULL) { 26573034Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 26583034Sdougm ret = sa_proto_set_property(proto, prop); 26593034Sdougm sa_free_attr_string(prop); 26603034Sdougm } 26613034Sdougm } 26623034Sdougm return (ret); 26633034Sdougm } 26643034Sdougm 26653034Sdougm /* 26663034Sdougm * sa_add_protocol_property(propset, prop) 26673034Sdougm * 26683034Sdougm * Add a new property to the protocol sepcific property set. 26693034Sdougm */ 26703034Sdougm 26713034Sdougm int 26723034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 26733034Sdougm { 26743034Sdougm xmlNodePtr node; 26753034Sdougm 26763034Sdougm /* should check for legitimacy */ 26773034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 26783034Sdougm if (node != NULL) 26793034Sdougm return (SA_OK); 26803034Sdougm return (SA_NO_MEMORY); 26813034Sdougm } 26823034Sdougm 26833034Sdougm /* 26843034Sdougm * sa_create_protocol_properties(proto) 26853034Sdougm * 26863034Sdougm * Create a protocol specifity property set. 26873034Sdougm */ 26883034Sdougm 26893034Sdougm sa_protocol_properties_t 26903034Sdougm sa_create_protocol_properties(char *proto) 26913034Sdougm { 26923034Sdougm xmlNodePtr node; 26933034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 26943034Sdougm if (node != NULL) { 26953034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 26963034Sdougm } 26973034Sdougm return (node); 26983034Sdougm } 2699