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 /* 233348Sdougm * 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> 373663Sdougm #include <fcntl.h> 383034Sdougm #include <unistd.h> 393034Sdougm #include <libxml/parser.h> 403034Sdougm #include <libxml/tree.h> 413034Sdougm #include "libshare.h" 423034Sdougm #include "libshare_impl.h" 433034Sdougm #include <libscf.h> 443034Sdougm #include "scfutil.h" 453034Sdougm #include <ctype.h> 463034Sdougm #include <libintl.h> 473910Sdougm #include <thread.h> 483910Sdougm #include <synch.h> 493034Sdougm 503034Sdougm #if _NOT_SMF 513034Sdougm #define CONFIG_FILE "/var/tmp/share.cfg" 523034Sdougm #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 533034Sdougm #endif 543034Sdougm #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 553034Sdougm (tm.tv_nsec & 0xffffffff)) 563034Sdougm 573663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 58*4327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 593663Sdougm 603034Sdougm /* 613034Sdougm * internal data structures 623034Sdougm */ 633034Sdougm 643034Sdougm extern struct sa_proto_plugin *sap_proto_list; 653034Sdougm 663034Sdougm /* current SMF/SVC repository handle */ 673910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 683910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 693034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 703034Sdougm extern char *sa_fstype(char *); 713034Sdougm extern int sa_is_share(void *); 723034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 733034Sdougm extern int sa_group_is_zfs(sa_group_t); 743034Sdougm extern int sa_path_is_zfs(char *); 753034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 763910Sdougm extern void update_legacy_config(sa_handle_t); 773034Sdougm extern int issubdir(char *, char *); 78*4327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 793910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 803663Sdougm extern void sablocksigs(sigset_t *); 813663Sdougm extern void saunblocksigs(sigset_t *); 823034Sdougm 833910Sdougm /* 843910Sdougm * Data structures for finding/managing the document root to access 853910Sdougm * handle mapping. The list isn't expected to grow very large so a 863910Sdougm * simple list is acceptable. The purpose is to provide a way to start 873910Sdougm * with a group or share and find the library handle needed for 883910Sdougm * various operations. 893910Sdougm */ 903910Sdougm mutex_t sa_global_lock; 913910Sdougm struct doc2handle { 923910Sdougm struct doc2handle *next; 933910Sdougm xmlNodePtr root; 943910Sdougm sa_handle_impl_t handle; 953910Sdougm }; 963910Sdougm 97*4327Sdougm /* definitions used in a couple of property functions */ 98*4327Sdougm #define SA_PROP_OP_REMOVE 1 99*4327Sdougm #define SA_PROP_OP_ADD 2 100*4327Sdougm #define SA_PROP_OP_UPDATE 3 101*4327Sdougm 1023910Sdougm static struct doc2handle *sa_global_handles = NULL; 1033034Sdougm 1043034Sdougm /* helper functions */ 1053034Sdougm 1063910Sdougm /* 1073910Sdougm * sa_errorstr(err) 1083910Sdougm * 1093910Sdougm * convert an error value to an error string 1103910Sdougm */ 1113910Sdougm 1123034Sdougm char * 1133034Sdougm sa_errorstr(int err) 1143034Sdougm { 1153034Sdougm static char errstr[32]; 1163034Sdougm char *ret = NULL; 1173034Sdougm 1183034Sdougm switch (err) { 1193034Sdougm case SA_OK: 120*4327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 121*4327Sdougm break; 1223034Sdougm case SA_NO_SUCH_PATH: 123*4327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 124*4327Sdougm break; 1253034Sdougm case SA_NO_MEMORY: 126*4327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 127*4327Sdougm break; 1283034Sdougm case SA_DUPLICATE_NAME: 129*4327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 130*4327Sdougm break; 1313034Sdougm case SA_BAD_PATH: 132*4327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 133*4327Sdougm break; 1343034Sdougm case SA_NO_SUCH_GROUP: 135*4327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 136*4327Sdougm break; 1373034Sdougm case SA_CONFIG_ERR: 138*4327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 139*4327Sdougm break; 1403034Sdougm case SA_SYSTEM_ERR: 141*4327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 142*4327Sdougm break; 1433034Sdougm case SA_SYNTAX_ERR: 144*4327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 145*4327Sdougm break; 1463034Sdougm case SA_NO_PERMISSION: 147*4327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 148*4327Sdougm break; 1493034Sdougm case SA_BUSY: 150*4327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 151*4327Sdougm break; 1523034Sdougm case SA_NO_SUCH_PROP: 153*4327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 154*4327Sdougm break; 1553034Sdougm case SA_INVALID_NAME: 156*4327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 157*4327Sdougm break; 1583034Sdougm case SA_INVALID_PROTOCOL: 159*4327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 160*4327Sdougm break; 1613034Sdougm case SA_NOT_ALLOWED: 162*4327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 163*4327Sdougm break; 1643034Sdougm case SA_BAD_VALUE: 165*4327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 166*4327Sdougm break; 1673034Sdougm case SA_INVALID_SECURITY: 168*4327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 169*4327Sdougm break; 1703034Sdougm case SA_NO_SUCH_SECURITY: 171*4327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 172*4327Sdougm break; 1733034Sdougm case SA_VALUE_CONFLICT: 174*4327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 175*4327Sdougm break; 1763034Sdougm case SA_NOT_IMPLEMENTED: 177*4327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 178*4327Sdougm break; 1793034Sdougm case SA_INVALID_PATH: 180*4327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 181*4327Sdougm break; 1823034Sdougm case SA_NOT_SUPPORTED: 183*4327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 184*4327Sdougm break; 1853034Sdougm case SA_PROP_SHARE_ONLY: 186*4327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 187*4327Sdougm break; 1883034Sdougm case SA_NOT_SHARED: 189*4327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 190*4327Sdougm break; 1913034Sdougm default: 192*4327Sdougm (void) snprintf(errstr, sizeof (errstr), 193*4327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 194*4327Sdougm ret = errstr; 1953034Sdougm } 1963034Sdougm return (ret); 1973034Sdougm } 1983034Sdougm 1993034Sdougm /* 2003910Sdougm * Document root to active handle mapping functions. These are only 2013910Sdougm * used internally. A mutex is used to prevent access while the list 2023910Sdougm * is changing. In general, the list will be relatively short - one 2033910Sdougm * item per thread that has called sa_init(). 2043910Sdougm */ 2053910Sdougm 2063910Sdougm sa_handle_impl_t 2073910Sdougm get_handle_for_root(xmlNodePtr root) 2083910Sdougm { 2093910Sdougm struct doc2handle *item; 2103910Sdougm 2113910Sdougm (void) mutex_lock(&sa_global_lock); 2123910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 213*4327Sdougm if (item->root == root) 214*4327Sdougm break; 2153910Sdougm } 2163910Sdougm (void) mutex_unlock(&sa_global_lock); 2173910Sdougm if (item != NULL) 218*4327Sdougm return (item->handle); 2193910Sdougm return (NULL); 2203910Sdougm } 2213910Sdougm 2223910Sdougm static int 2233910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2243910Sdougm { 2253910Sdougm struct doc2handle *item; 2263910Sdougm int ret = SA_NO_MEMORY; 2273910Sdougm 2283910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2293910Sdougm if (item != NULL) { 230*4327Sdougm item->root = root; 231*4327Sdougm item->handle = handle; 232*4327Sdougm (void) mutex_lock(&sa_global_lock); 233*4327Sdougm item->next = sa_global_handles; 234*4327Sdougm sa_global_handles = item; 235*4327Sdougm (void) mutex_unlock(&sa_global_lock); 236*4327Sdougm ret = SA_OK; 2373910Sdougm } 2383910Sdougm return (ret); 2393910Sdougm } 2403910Sdougm 2413910Sdougm /* 2423910Sdougm * remove_handle_for_root(root) 2433910Sdougm * 2443910Sdougm * Walks the list of handles and removes the one for this "root" from 2453910Sdougm * the list. It is up to the caller to free the data. 2463910Sdougm */ 2473910Sdougm 2483910Sdougm static void 2493910Sdougm remove_handle_for_root(xmlNodePtr root) 2503910Sdougm { 2513910Sdougm struct doc2handle *item, *prev; 2523910Sdougm 2533910Sdougm (void) mutex_lock(&sa_global_lock); 2543910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 255*4327Sdougm item = item->next) { 256*4327Sdougm if (item->root == root) { 257*4327Sdougm /* first in the list */ 258*4327Sdougm if (prev == NULL) 259*4327Sdougm sa_global_handles = sa_global_handles->next; 260*4327Sdougm else 261*4327Sdougm prev->next = item->next; 262*4327Sdougm /* Item is out of the list so free the list structure */ 263*4327Sdougm free(item); 264*4327Sdougm break; 2653910Sdougm } 266*4327Sdougm prev = item; 2673910Sdougm } 2683910Sdougm (void) mutex_unlock(&sa_global_lock); 2693910Sdougm } 2703910Sdougm 2713910Sdougm /* 2723910Sdougm * sa_find_group_handle(sa_group_t group) 2733910Sdougm * 2743910Sdougm * Find the sa_handle_t for the configuration associated with this 2753910Sdougm * group. 2763910Sdougm */ 2773910Sdougm sa_handle_t 2783910Sdougm sa_find_group_handle(sa_group_t group) 2793910Sdougm { 2803910Sdougm xmlNodePtr node = (xmlNodePtr)group; 2813910Sdougm sa_handle_t handle; 2823910Sdougm 2833910Sdougm while (node != NULL) { 284*4327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 285*4327Sdougm /* have the root so get the handle */ 286*4327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 287*4327Sdougm return (handle); 288*4327Sdougm } 289*4327Sdougm node = node->parent; 2903910Sdougm } 2913910Sdougm return (NULL); 2923910Sdougm } 2933910Sdougm 2943910Sdougm /* 2953034Sdougm * set_legacy_timestamp(root, path, timevalue) 2963034Sdougm * 2973034Sdougm * add the current timestamp value to the configuration for use in 2983034Sdougm * determining when to update the legacy files. For SMF, this 2993034Sdougm * property is kept in default/operation/legacy_timestamp 3003034Sdougm */ 3013034Sdougm 3023034Sdougm static void 3033034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3043034Sdougm { 3053034Sdougm xmlNodePtr node; 3063034Sdougm xmlChar *lpath = NULL; 3073910Sdougm sa_handle_impl_t handle; 3083910Sdougm 3093910Sdougm /* Have to have a handle or else we weren't initialized. */ 3103910Sdougm handle = get_handle_for_root(root); 3113910Sdougm if (handle == NULL) 312*4327Sdougm return; 3133034Sdougm 3143034Sdougm for (node = root->xmlChildrenNode; node != NULL; 315*4327Sdougm node = node->next) { 316*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 317*4327Sdougm /* a possible legacy node for this path */ 318*4327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 319*4327Sdougm if (lpath != NULL && 320*4327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 321*4327Sdougm xmlFree(lpath); 322*4327Sdougm break; 323*4327Sdougm } 324*4327Sdougm if (lpath != NULL) 325*4327Sdougm xmlFree(lpath); 3263034Sdougm } 3273034Sdougm } 3283034Sdougm if (node == NULL) { 329*4327Sdougm /* need to create the first legacy timestamp node */ 330*4327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3313034Sdougm } 3323034Sdougm if (node != NULL) { 333*4327Sdougm char tstring[32]; 334*4327Sdougm int ret; 3353034Sdougm 336*4327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 337*4327Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 338*4327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 339*4327Sdougm /* now commit to SMF */ 340*4327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3413034Sdougm if (ret == SA_OK) { 342*4327Sdougm ret = sa_start_transaction(handle->scfhandle, 343*4327Sdougm "operation"); 344*4327Sdougm if (ret == SA_OK) { 345*4327Sdougm ret = sa_set_property(handle->scfhandle, 346*4327Sdougm "legacy-timestamp", tstring); 347*4327Sdougm if (ret == SA_OK) { 348*4327Sdougm (void) sa_end_transaction( 349*4327Sdougm handle->scfhandle); 350*4327Sdougm } else { 351*4327Sdougm sa_abort_transaction(handle->scfhandle); 352*4327Sdougm } 353*4327Sdougm } 3543034Sdougm } 3553034Sdougm } 3563034Sdougm } 3573034Sdougm 3583034Sdougm /* 3593034Sdougm * is_shared(share) 3603034Sdougm * 3613034Sdougm * determine if the specified share is currently shared or not. 3623034Sdougm */ 3633034Sdougm static int 3643034Sdougm is_shared(sa_share_t share) 3653034Sdougm { 3663034Sdougm char *shared; 3673034Sdougm int result = 0; /* assume not */ 3683034Sdougm 3693034Sdougm shared = sa_get_share_attr(share, "shared"); 3703034Sdougm if (shared != NULL) { 371*4327Sdougm if (strcmp(shared, "true") == 0) 372*4327Sdougm result = 1; 373*4327Sdougm sa_free_attr_string(shared); 3743034Sdougm } 3753034Sdougm return (result); 3763034Sdougm } 3773034Sdougm 3783034Sdougm /* 3793663Sdougm * checksubdirgroup(group, newpath, strictness) 3803348Sdougm * 3813663Sdougm * check all the specified newpath against all the paths in the 3823663Sdougm * group. This is a helper function for checksubdir to make it easier 3833663Sdougm * to also check ZFS subgroups. 3843663Sdougm * The strictness values mean: 3853348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 3863348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 3873348Sdougm * stored in the repository 3883034Sdougm */ 3893034Sdougm static int 3903663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 3913034Sdougm { 3923034Sdougm sa_share_t share; 3933663Sdougm char *path; 3943663Sdougm int issub = SA_OK; 3953034Sdougm 3963663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 3973663Sdougm share = sa_get_next_share(share)) { 3983034Sdougm /* 3993034Sdougm * The original behavior of share never checked 4003034Sdougm * against the permanent configuration 4013034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4023034Sdougm * it depends on this older behavior even though it 4033034Sdougm * could be considered incorrect. We may tighten this 4043034Sdougm * up in the future. 4053034Sdougm */ 406*4327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 407*4327Sdougm continue; 4083034Sdougm 409*4327Sdougm path = sa_get_share_attr(share, "path"); 4103348Sdougm /* 4113348Sdougm * If path is NULL, then a share is in the process of 4123348Sdougm * construction or someone has modified the property 4133663Sdougm * group inappropriately. It should be 4143663Sdougm * ignored. issubdir() comes from the original share 4153663Sdougm * implementation and does the difficult part of 4163663Sdougm * checking subdirectories. 4173348Sdougm */ 418*4327Sdougm if (path == NULL) 419*4327Sdougm continue; 420*4327Sdougm if (newpath != NULL && 421*4327Sdougm (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 422*4327Sdougm issubdir(path, newpath))) { 423*4327Sdougm sa_free_attr_string(path); 424*4327Sdougm path = NULL; 425*4327Sdougm issub = SA_INVALID_PATH; 426*4327Sdougm break; 427*4327Sdougm } 4283034Sdougm sa_free_attr_string(path); 4293034Sdougm path = NULL; 4303663Sdougm } 4313663Sdougm return (issub); 4323663Sdougm } 4333663Sdougm 4343663Sdougm /* 4353663Sdougm * checksubdir(newpath, strictness) 4363663Sdougm * 4373663Sdougm * checksubdir determines if the specified path (newpath) is a 4383663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 4393663Sdougm * the complicated work. The strictness parameter determines how 4403663Sdougm * strict a check to make against the path. The strictness values 4413663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 4423663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 4433663Sdougm * and those * stored in the repository 4443663Sdougm */ 4453663Sdougm static int 4463910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 4473663Sdougm { 4483663Sdougm sa_group_t group; 4493663Sdougm int issub; 4503663Sdougm char *path = NULL; 4513663Sdougm 4523910Sdougm for (issub = 0, group = sa_get_group(handle, NULL); 453*4327Sdougm group != NULL && !issub; group = sa_get_next_group(group)) { 454*4327Sdougm if (sa_group_is_zfs(group)) { 455*4327Sdougm sa_group_t subgroup; 456*4327Sdougm for (subgroup = sa_get_sub_group(group); 457*4327Sdougm subgroup != NULL && !issub; 458*4327Sdougm subgroup = sa_get_next_group(subgroup)) 459*4327Sdougm issub = checksubdirgroup(subgroup, newpath, 460*4327Sdougm strictness); 461*4327Sdougm } else { 462*4327Sdougm issub = checksubdirgroup(group, newpath, strictness); 463*4327Sdougm } 4643034Sdougm } 4653034Sdougm if (path != NULL) 466*4327Sdougm sa_free_attr_string(path); 4673034Sdougm return (issub); 4683034Sdougm } 4693034Sdougm 4703034Sdougm /* 4713348Sdougm * validpath(path, strictness) 4723034Sdougm * determine if the provided path is valid for a share. It shouldn't 4733034Sdougm * be a sub-dir of an already shared path or the parent directory of a 4743034Sdougm * share path. 4753034Sdougm */ 4763034Sdougm static int 4773910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 4783034Sdougm { 4793034Sdougm int error = SA_OK; 4803034Sdougm struct stat st; 4813034Sdougm sa_share_t share; 4823034Sdougm char *fstype; 4833034Sdougm 484*4327Sdougm if (*path != '/') 485*4327Sdougm return (SA_BAD_PATH); 486*4327Sdougm 4873034Sdougm if (stat(path, &st) < 0) { 488*4327Sdougm error = SA_NO_SUCH_PATH; 4893034Sdougm } else { 490*4327Sdougm share = sa_find_share(handle, path); 491*4327Sdougm if (share != NULL) 492*4327Sdougm error = SA_DUPLICATE_NAME; 493*4327Sdougm 494*4327Sdougm if (error == SA_OK) { 495*4327Sdougm /* 496*4327Sdougm * check for special case with file system 497*4327Sdougm * that might have restrictions. For now, ZFS 498*4327Sdougm * is the only case since it has its own idea 499*4327Sdougm * of how to configure shares. We do this 500*4327Sdougm * before subdir checking since things like 501*4327Sdougm * ZFS will do that for us. This should also 502*4327Sdougm * be done via plugin interface. 503*4327Sdougm */ 504*4327Sdougm fstype = sa_fstype(path); 505*4327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 506*4327Sdougm if (sa_zfs_is_shared(handle, path)) 507*4327Sdougm error = SA_INVALID_NAME; 508*4327Sdougm } 509*4327Sdougm if (fstype != NULL) 510*4327Sdougm sa_free_fstype(fstype); 5113034Sdougm } 512*4327Sdougm if (error == SA_OK) 513*4327Sdougm error = checksubdir(handle, path, strictness); 5143034Sdougm } 5153034Sdougm return (error); 5163034Sdougm } 5173034Sdougm 5183034Sdougm /* 5193034Sdougm * check to see if group/share is persistent. 5203034Sdougm */ 5213034Sdougm static int 5223034Sdougm is_persistent(sa_group_t group) 5233034Sdougm { 5243034Sdougm char *type; 5253034Sdougm int persist = 1; 5263034Sdougm 5273034Sdougm type = sa_get_group_attr(group, "type"); 5283034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 529*4327Sdougm persist = 0; 5303034Sdougm if (type != NULL) 531*4327Sdougm sa_free_attr_string(type); 5323034Sdougm return (persist); 5333034Sdougm } 5343034Sdougm 5353034Sdougm /* 5363034Sdougm * sa_valid_group_name(name) 5373034Sdougm * 5383034Sdougm * check that the "name" contains only valid characters and otherwise 5393034Sdougm * fits the required naming conventions. Valid names must start with 5403034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 5413034Sdougm * plus the '-' and '_' characters. This name limitation comes from 5423034Sdougm * inherent limitations in SMF. 5433034Sdougm */ 5443034Sdougm 5453034Sdougm int 5463034Sdougm sa_valid_group_name(char *name) 5473034Sdougm { 5483034Sdougm int ret = 1; 5493034Sdougm ssize_t len; 5503034Sdougm 5513034Sdougm if (name != NULL && isalpha(*name)) { 552*4327Sdougm char c; 553*4327Sdougm len = strlen(name); 554*4327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 555*4327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 556*4327Sdougm if (!isalnum(c) && c != '-' && c != '_') 557*4327Sdougm ret = 0; 558*4327Sdougm } 559*4327Sdougm } else { 5603034Sdougm ret = 0; 5613034Sdougm } 562*4327Sdougm } else { 5633034Sdougm ret = 0; 5643034Sdougm } 5653034Sdougm return (ret); 5663034Sdougm } 5673034Sdougm 5683034Sdougm 5693034Sdougm /* 5703034Sdougm * is_zfs_group(group) 5713034Sdougm * Determine if the specified group is a ZFS sharenfs group 5723034Sdougm */ 5733034Sdougm static int 5743034Sdougm is_zfs_group(sa_group_t group) 5753034Sdougm { 5763034Sdougm int ret = 0; 5773034Sdougm xmlNodePtr parent; 5783034Sdougm xmlChar *zfs; 5793034Sdougm 580*4327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 581*4327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 582*4327Sdougm else 583*4327Sdougm parent = (xmlNodePtr)group; 5843034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 5853034Sdougm if (zfs != NULL) { 586*4327Sdougm xmlFree(zfs); 587*4327Sdougm ret = 1; 5883034Sdougm } 5893034Sdougm return (ret); 5903034Sdougm } 5913034Sdougm 5923034Sdougm /* 5933034Sdougm * sa_optionset_name(optionset, oname, len, id) 5943034Sdougm * return the SMF name for the optionset. If id is not NULL, it 5953034Sdougm * will have the GUID value for a share and should be used 5963034Sdougm * instead of the keyword "optionset" which is used for 5973034Sdougm * groups. If the optionset doesn't have a protocol type 5983034Sdougm * associated with it, "default" is used. This shouldn't happen 5993034Sdougm * at this point but may be desirable in the future if there are 6003034Sdougm * protocol independent properties added. The name is returned in 6013034Sdougm * oname. 6023034Sdougm */ 6033034Sdougm 6043034Sdougm static int 6053034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 6063034Sdougm { 6073034Sdougm char *proto; 6083034Sdougm 6093034Sdougm if (id == NULL) 610*4327Sdougm id = "optionset"; 6113034Sdougm 6123034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 6133034Sdougm len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 6143034Sdougm 6153034Sdougm if (proto != NULL) 616*4327Sdougm sa_free_attr_string(proto); 6173034Sdougm return (len); 6183034Sdougm } 6193034Sdougm 6203034Sdougm /* 6213034Sdougm * sa_security_name(optionset, oname, len, id) 6223034Sdougm * 6233034Sdougm * return the SMF name for the security. If id is not NULL, it will 6243034Sdougm * have the GUID value for a share and should be used instead of the 6253034Sdougm * keyword "optionset" which is used for groups. If the optionset 6263034Sdougm * doesn't have a protocol type associated with it, "default" is 6273034Sdougm * used. This shouldn't happen at this point but may be desirable in 6283034Sdougm * the future if there are protocol independent properties added. The 6293034Sdougm * name is returned in oname. The security type is also encoded into 6303034Sdougm * the name. In the future, this wil *be handled a bit differently. 6313034Sdougm */ 6323034Sdougm 6333034Sdougm static int 6343034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 6353034Sdougm { 6363034Sdougm char *proto; 6373034Sdougm char *sectype; 6383034Sdougm 6393034Sdougm if (id == NULL) 640*4327Sdougm id = "optionset"; 6413034Sdougm 6423034Sdougm proto = sa_get_security_attr(security, "type"); 6433034Sdougm sectype = sa_get_security_attr(security, "sectype"); 644*4327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 645*4327Sdougm sectype ? sectype : "default"); 6463034Sdougm if (proto != NULL) 647*4327Sdougm sa_free_attr_string(proto); 6483034Sdougm if (sectype != NULL) 649*4327Sdougm sa_free_attr_string(sectype); 6503034Sdougm return (len); 6513034Sdougm } 6523034Sdougm 6533034Sdougm /* 654*4327Sdougm * verifydefgroupopts(handle) 655*4327Sdougm * 656*4327Sdougm * Make sure a "default" group exists and has default protocols enabled. 657*4327Sdougm */ 658*4327Sdougm static void 659*4327Sdougm verifydefgroupopts(sa_handle_t handle) 660*4327Sdougm { 661*4327Sdougm sa_group_t defgrp; 662*4327Sdougm sa_optionset_t opt; 663*4327Sdougm defgrp = sa_get_group(handle, "default"); 664*4327Sdougm if (defgrp != NULL) { 665*4327Sdougm opt = sa_get_optionset(defgrp, NULL); 666*4327Sdougm /* 667*4327Sdougm * NFS is the default for default group 668*4327Sdougm */ 669*4327Sdougm if (opt == NULL) 670*4327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 671*4327Sdougm } 672*4327Sdougm } 673*4327Sdougm 674*4327Sdougm /* 6753348Sdougm * sa_init(init_service) 6763034Sdougm * Initialize the API 6773034Sdougm * find all the shared objects 6783034Sdougm * init the tables with all objects 6793034Sdougm * read in the current configuration 6803034Sdougm */ 6813034Sdougm 682*4327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 683*4327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 684*4327Sdougm tval != TSTAMP(st.st_ctim) 685*4327Sdougm 6863910Sdougm sa_handle_t 6873034Sdougm sa_init(int init_service) 6883034Sdougm { 6893034Sdougm struct stat st; 6903034Sdougm int legacy = 0; 6913034Sdougm uint64_t tval = 0; 6923663Sdougm int lockfd; 6933663Sdougm sigset_t old; 6943663Sdougm int updatelegacy = B_FALSE; 6953663Sdougm scf_simple_prop_t *prop; 6963910Sdougm sa_handle_impl_t handle; 6973910Sdougm int err; 6983034Sdougm 6993910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 7003910Sdougm 7013910Sdougm if (handle != NULL) { 702*4327Sdougm /* get protocol specific structures */ 703*4327Sdougm (void) proto_plugin_init(); 704*4327Sdougm if (init_service & SA_INIT_SHARE_API) { 7053663Sdougm /* 706*4327Sdougm * initialize access into libzfs. We use this 707*4327Sdougm * when collecting info about ZFS datasets and 708*4327Sdougm * shares. 7093663Sdougm */ 710*4327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 711*4327Sdougm free(handle); 712*4327Sdougm (void) proto_plugin_fini(); 713*4327Sdougm return (NULL); 714*4327Sdougm } 7153663Sdougm /* 716*4327Sdougm * since we want to use SMF, initialize an svc handle 717*4327Sdougm * and find out what is there. 7183663Sdougm */ 719*4327Sdougm handle->scfhandle = sa_scf_init(handle); 720*4327Sdougm if (handle->scfhandle != NULL) { 721*4327Sdougm /* 722*4327Sdougm * Need to lock the extraction of the 723*4327Sdougm * configuration if the dfstab file has 724*4327Sdougm * changed. Lock everything now and release if 725*4327Sdougm * not needed. Use a file that isn't being 726*4327Sdougm * manipulated by other parts of the system in 727*4327Sdougm * order to not interfere with locking. Using 728*4327Sdougm * dfstab doesn't work. 729*4327Sdougm */ 730*4327Sdougm sablocksigs(&old); 731*4327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 732*4327Sdougm if (lockfd >= 0) { 733*4327Sdougm extern int errno; 734*4327Sdougm errno = 0; 735*4327Sdougm (void) lockf(lockfd, F_LOCK, 0); 736*4327Sdougm /* 737*4327Sdougm * Check whether we are going to need 738*4327Sdougm * to merge any dfstab changes. This 739*4327Sdougm * is done by comparing the value of 740*4327Sdougm * legacy-timestamp with the current 741*4327Sdougm * st_ctim of the file. If they are 742*4327Sdougm * different, an update is needed and 743*4327Sdougm * the file must remain locked until 744*4327Sdougm * the merge is done in order to 745*4327Sdougm * prevent multiple startups from 746*4327Sdougm * changing the SMF repository at the 747*4327Sdougm * same time. The first to get the 748*4327Sdougm * lock will make any changes before 749*4327Sdougm * the others can read the repository. 750*4327Sdougm */ 751*4327Sdougm prop = scf_simple_prop_get 752*4327Sdougm (handle->scfhandle->handle, 753*4327Sdougm (const char *)SA_SVC_FMRI_BASE 754*4327Sdougm ":default", "operation", 755*4327Sdougm "legacy-timestamp"); 756*4327Sdougm if (prop != NULL) { 757*4327Sdougm char *i64; 758*4327Sdougm i64 = GETPROP(prop); 759*4327Sdougm if (i64 != NULL) 760*4327Sdougm tval = strtoull(i64, 761*4327Sdougm NULL, 0); 762*4327Sdougm if (CHECKTSTAMP(st, tval)) 763*4327Sdougm updatelegacy = B_TRUE; 764*4327Sdougm scf_simple_prop_free(prop); 765*4327Sdougm } else { 766*4327Sdougm /* 767*4327Sdougm * We haven't set the 768*4327Sdougm * timestamp before so do it. 769*4327Sdougm */ 770*4327Sdougm updatelegacy = B_TRUE; 771*4327Sdougm } 772*4327Sdougm } 773*4327Sdougm if (updatelegacy == B_FALSE) { 774*4327Sdougm /* Don't need the lock anymore */ 775*4327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 776*4327Sdougm (void) close(lockfd); 777*4327Sdougm } 7783973Sdougm 779*4327Sdougm /* 780*4327Sdougm * It is essential that the document tree and 781*4327Sdougm * the internal list of roots to handles be 782*4327Sdougm * setup before anything that might try to 783*4327Sdougm * create a new object is called. The document 784*4327Sdougm * tree is the combination of handle->doc and 785*4327Sdougm * handle->tree. This allows searches, 786*4327Sdougm * etc. when all you have is an object in the 787*4327Sdougm * tree. 788*4327Sdougm */ 789*4327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 790*4327Sdougm handle->tree = xmlNewNode(NULL, 791*4327Sdougm (xmlChar *)"sharecfg"); 792*4327Sdougm if (handle->doc != NULL && 793*4327Sdougm handle->tree != NULL) { 794*4327Sdougm xmlDocSetRootElement(handle->doc, 795*4327Sdougm handle->tree); 796*4327Sdougm err = add_handle_for_root(handle->tree, 797*4327Sdougm handle); 798*4327Sdougm if (err == SA_OK) 799*4327Sdougm err = sa_get_config( 800*4327Sdougm handle->scfhandle, 8013973Sdougm handle->tree, handle); 802*4327Sdougm } else { 803*4327Sdougm if (handle->doc != NULL) 804*4327Sdougm xmlFreeDoc(handle->doc); 805*4327Sdougm if (handle->tree != NULL) 806*4327Sdougm xmlFreeNode(handle->tree); 807*4327Sdougm err = SA_NO_MEMORY; 808*4327Sdougm } 8093973Sdougm 810*4327Sdougm saunblocksigs(&old); 8113910Sdougm 812*4327Sdougm if (err != SA_OK) { 813*4327Sdougm /* 814*4327Sdougm * If we couldn't add the tree handle 815*4327Sdougm * to the list, then things are going 816*4327Sdougm * to fail badly. Might as well undo 817*4327Sdougm * everything now and fail the 818*4327Sdougm * sa_init(). 819*4327Sdougm */ 820*4327Sdougm sa_fini(handle); 821*4327Sdougm return (NULL); 822*4327Sdougm } 8233910Sdougm 824*4327Sdougm if (tval == 0) { 825*4327Sdougm /* 826*4327Sdougm * first time so make sure 827*4327Sdougm * default is setup 828*4327Sdougm */ 829*4327Sdougm verifydefgroupopts(handle); 830*4327Sdougm } 8313973Sdougm 832*4327Sdougm if (updatelegacy == B_TRUE) { 833*4327Sdougm sablocksigs(&old); 834*4327Sdougm getlegacyconfig((sa_handle_t)handle, 835*4327Sdougm SA_LEGACY_DFSTAB, &handle->tree); 836*4327Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 837*4327Sdougm set_legacy_timestamp(handle->tree, 838*4327Sdougm SA_LEGACY_DFSTAB, 839*4327Sdougm TSTAMP(st.st_ctim)); 840*4327Sdougm saunblocksigs(&old); 841*4327Sdougm /* Safe to unlock now to allow others to run */ 842*4327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 843*4327Sdougm (void) close(lockfd); 844*4327Sdougm } 845*4327Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 846*4327Sdougm legacy |= gettransients(handle, &handle->tree); 8473034Sdougm } 848*4327Sdougm } 8493034Sdougm } 8503910Sdougm return ((sa_handle_t)handle); 8513034Sdougm } 8523034Sdougm 8533034Sdougm /* 8543910Sdougm * sa_fini(handle) 8553034Sdougm * Uninitialize the API structures including the configuration 8563218Sdougm * data structures and ZFS related data. 8573034Sdougm */ 8583034Sdougm 8593034Sdougm void 8603910Sdougm sa_fini(sa_handle_t handle) 8613034Sdougm { 8623910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 8633910Sdougm 8643910Sdougm if (impl_handle != NULL) { 8653910Sdougm /* 8663910Sdougm * Free the config trees and any other data structures 8673910Sdougm * used in the handle. 8683910Sdougm */ 8693910Sdougm if (impl_handle->doc != NULL) 8703910Sdougm xmlFreeDoc(impl_handle->doc); 8713910Sdougm sa_scf_fini(impl_handle->scfhandle); 8723910Sdougm sa_zfs_fini(impl_handle); 8733910Sdougm 8743910Sdougm /* Remove and free the entry in the global list. */ 8753910Sdougm remove_handle_for_root(impl_handle->tree); 8763910Sdougm 8773910Sdougm /* Make sure we free the handle */ 8783910Sdougm free(impl_handle); 8793910Sdougm 8803910Sdougm /* 8813910Sdougm * If this was the last handle to release, unload the 8823910Sdougm * plugins that were loaded. 8833910Sdougm */ 8843910Sdougm if (sa_global_handles == NULL) 885*4327Sdougm (void) proto_plugin_fini(); 8863910Sdougm 8873034Sdougm } 8883034Sdougm } 8893034Sdougm 8903034Sdougm /* 8913034Sdougm * sa_get_protocols(char **protocol) 8923034Sdougm * Get array of protocols that are supported 8933034Sdougm * Returns pointer to an allocated and NULL terminated 8943034Sdougm * array of strings. Caller must free. 8953034Sdougm * This really should be determined dynamically. 8963034Sdougm * If there aren't any defined, return -1. 8973034Sdougm * Use free() to return memory. 8983034Sdougm */ 8993034Sdougm 9003034Sdougm int 9013034Sdougm sa_get_protocols(char ***protocols) 9023034Sdougm { 9033034Sdougm int numproto = -1; 9043034Sdougm 9053034Sdougm if (protocols != NULL) { 906*4327Sdougm struct sa_proto_plugin *plug; 907*4327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 908*4327Sdougm plug = plug->plugin_next) { 909*4327Sdougm numproto++; 910*4327Sdougm } 9113034Sdougm 912*4327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 913*4327Sdougm if (*protocols != NULL) { 914*4327Sdougm int ret = 0; 915*4327Sdougm for (plug = sap_proto_list; plug != NULL; 916*4327Sdougm plug = plug->plugin_next) { 917*4327Sdougm /* faking for now */ 918*4327Sdougm (*protocols)[ret++] = 919*4327Sdougm plug->plugin_ops->sa_protocol; 920*4327Sdougm } 921*4327Sdougm } else { 922*4327Sdougm numproto = -1; 9233034Sdougm } 9243034Sdougm } 9253034Sdougm return (numproto); 9263034Sdougm } 9273034Sdougm 9283034Sdougm /* 9293034Sdougm * find_group_by_name(node, group) 9303034Sdougm * 9313034Sdougm * search the XML document subtree specified by node to find the group 9323034Sdougm * specified by group. Searching subtree allows subgroups to be 9333034Sdougm * searched for. 9343034Sdougm */ 9353034Sdougm 9363034Sdougm static xmlNodePtr 9373034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 9383034Sdougm { 9393034Sdougm xmlChar *name = NULL; 9403034Sdougm 9413034Sdougm for (node = node->xmlChildrenNode; node != NULL; 9423034Sdougm node = node->next) { 943*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 944*4327Sdougm /* if no groupname, return the first found */ 945*4327Sdougm if (group == NULL) 946*4327Sdougm break; 947*4327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 948*4327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 949*4327Sdougm break; 950*4327Sdougm if (name != NULL) { 951*4327Sdougm xmlFree(name); 952*4327Sdougm name = NULL; 953*4327Sdougm } 9543034Sdougm } 9553034Sdougm } 9563034Sdougm if (name != NULL) 957*4327Sdougm xmlFree(name); 9583034Sdougm return (node); 9593034Sdougm } 9603034Sdougm 9613034Sdougm /* 9623034Sdougm * sa_get_group(groupname) 9633034Sdougm * Return the "group" specified. If groupname is NULL, 9643034Sdougm * return the first group of the list of groups. 9653034Sdougm */ 9663034Sdougm sa_group_t 9673910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 9683034Sdougm { 9693034Sdougm xmlNodePtr node = NULL; 9703034Sdougm char *subgroup = NULL; 9713034Sdougm char *group = NULL; 9723910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 9733034Sdougm 9743910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 975*4327Sdougm if (groupname != NULL) { 976*4327Sdougm group = strdup(groupname); 977*4327Sdougm subgroup = strchr(group, '/'); 978*4327Sdougm if (subgroup != NULL) 979*4327Sdougm *subgroup++ = '\0'; 980*4327Sdougm } 981*4327Sdougm node = find_group_by_name(impl_handle->tree, (xmlChar *)group); 982*4327Sdougm /* if a subgroup, find it before returning */ 983*4327Sdougm if (subgroup != NULL && node != NULL) 984*4327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 9853034Sdougm } 9863034Sdougm if (node != NULL && (char *)group != NULL) 987*4327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 9883034Sdougm if (group != NULL) 989*4327Sdougm free(group); 9903034Sdougm return ((sa_group_t)(node)); 9913034Sdougm } 9923034Sdougm 9933034Sdougm /* 9943034Sdougm * sa_get_next_group(group) 9953034Sdougm * Return the "next" group after the specified group from 9963034Sdougm * the internal group list. NULL if there are no more. 9973034Sdougm */ 9983034Sdougm sa_group_t 9993034Sdougm sa_get_next_group(sa_group_t group) 10003034Sdougm { 10013034Sdougm xmlNodePtr ngroup = NULL; 10023034Sdougm if (group != NULL) { 1003*4327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 10043034Sdougm ngroup = ngroup->next) { 1005*4327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 1006*4327Sdougm break; 1007*4327Sdougm } 10083034Sdougm } 10093034Sdougm return ((sa_group_t)ngroup); 10103034Sdougm } 10113034Sdougm 10123034Sdougm /* 10133034Sdougm * sa_get_share(group, sharepath) 10143034Sdougm * Return the share object for the share specified. The share 10153034Sdougm * must be in the specified group. Return NULL if not found. 10163034Sdougm */ 10173034Sdougm sa_share_t 10183034Sdougm sa_get_share(sa_group_t group, char *sharepath) 10193034Sdougm { 10203034Sdougm xmlNodePtr node = NULL; 10213034Sdougm xmlChar *path; 10223034Sdougm 10233034Sdougm /* 10243034Sdougm * For future scalability, this should end up building a cache 10253034Sdougm * since it will get called regularly by the mountd and info 10263034Sdougm * services. 10273034Sdougm */ 10283034Sdougm if (group != NULL) { 1029*4327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 10303034Sdougm node = node->next) { 1031*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 1032*4327Sdougm if (sharepath == NULL) { 1033*4327Sdougm break; 1034*4327Sdougm } else { 1035*4327Sdougm /* is it the correct share? */ 1036*4327Sdougm path = xmlGetProp(node, 1037*4327Sdougm (xmlChar *)"path"); 1038*4327Sdougm if (path != NULL && 1039*4327Sdougm xmlStrcmp(path, 1040*4327Sdougm (xmlChar *)sharepath) == 0) { 1041*4327Sdougm xmlFree(path); 1042*4327Sdougm break; 1043*4327Sdougm } 1044*4327Sdougm xmlFree(path); 1045*4327Sdougm } 10463034Sdougm } 10473034Sdougm } 10483034Sdougm } 10493034Sdougm return ((sa_share_t)node); 10503034Sdougm } 10513034Sdougm 10523034Sdougm /* 10533034Sdougm * sa_get_next_share(share) 10543034Sdougm * Return the next share following the specified share 10553034Sdougm * from the internal list of shares. Returns NULL if there 10563034Sdougm * are no more shares. The list is relative to the same 10573034Sdougm * group. 10583034Sdougm */ 10593034Sdougm sa_share_t 10603034Sdougm sa_get_next_share(sa_share_t share) 10613034Sdougm { 10623034Sdougm xmlNodePtr node = NULL; 10633034Sdougm 10643034Sdougm if (share != NULL) { 1065*4327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 10663034Sdougm node = node->next) { 1067*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 1068*4327Sdougm break; 1069*4327Sdougm } 10703034Sdougm } 10713034Sdougm } 10723034Sdougm return ((sa_share_t)node); 10733034Sdougm } 10743034Sdougm 10753034Sdougm /* 10763034Sdougm * _sa_get_child_node(node, type) 10773034Sdougm * 10783034Sdougm * find the child node of the specified node that has "type". This is 10793034Sdougm * used to implement several internal functions. 10803034Sdougm */ 10813034Sdougm 10823034Sdougm static xmlNodePtr 10833034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 10843034Sdougm { 10853034Sdougm xmlNodePtr child; 10863034Sdougm for (child = node->xmlChildrenNode; child != NULL; 10873034Sdougm child = child->next) 1088*4327Sdougm if (xmlStrcmp(child->name, type) == 0) 1089*4327Sdougm return (child); 10903034Sdougm return ((xmlNodePtr)NULL); 10913034Sdougm } 10923034Sdougm 10933034Sdougm /* 10943034Sdougm * find_share(group, path) 10953034Sdougm * 10963034Sdougm * Search all the shares in the specified group for one that has the 10973034Sdougm * specified path. 10983034Sdougm */ 10993034Sdougm 11003034Sdougm static sa_share_t 11013034Sdougm find_share(sa_group_t group, char *sharepath) 11023034Sdougm { 11033034Sdougm sa_share_t share; 11043034Sdougm char *path; 11053034Sdougm 11063034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 11073034Sdougm share = sa_get_next_share(share)) { 1108*4327Sdougm path = sa_get_share_attr(share, "path"); 1109*4327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 1110*4327Sdougm sa_free_attr_string(path); 1111*4327Sdougm break; 1112*4327Sdougm } 1113*4327Sdougm if (path != NULL) 1114*4327Sdougm sa_free_attr_string(path); 11153034Sdougm } 11163034Sdougm return (share); 11173034Sdougm } 11183034Sdougm 11193034Sdougm /* 11203034Sdougm * sa_get_sub_group(group) 11213034Sdougm * 11223034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 11233034Sdougm * can be used to get the rest. This is currently only used for ZFS 11243034Sdougm * sub-groups but could be used to implement a more general mechanism. 11253034Sdougm */ 11263034Sdougm 11273034Sdougm sa_group_t 11283034Sdougm sa_get_sub_group(sa_group_t group) 11293034Sdougm { 11303034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 1131*4327Sdougm (xmlChar *)"group")); 11323034Sdougm } 11333034Sdougm 11343034Sdougm /* 11353034Sdougm * sa_find_share(sharepath) 11363034Sdougm * Finds a share regardless of group. In the future, this 11373034Sdougm * function should utilize a cache and hash table of some kind. 11383034Sdougm * The current assumption is that a path will only be shared 11393034Sdougm * once. In the future, this may change as implementation of 11403034Sdougm * resource names comes into being. 11413034Sdougm */ 11423034Sdougm sa_share_t 11433910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 11443034Sdougm { 11453034Sdougm sa_group_t group; 11463034Sdougm sa_group_t zgroup; 11473034Sdougm sa_share_t share = NULL; 11483034Sdougm int done = 0; 11493034Sdougm 11503910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 1151*4327Sdougm group = sa_get_next_group(group)) { 1152*4327Sdougm if (is_zfs_group(group)) { 1153*4327Sdougm for (zgroup = 1154*4327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 1155*4327Sdougm (xmlChar *)"group"); 1156*4327Sdougm zgroup != NULL; 1157*4327Sdougm zgroup = sa_get_next_group(zgroup)) { 1158*4327Sdougm share = find_share(zgroup, sharepath); 1159*4327Sdougm if (share != NULL) 1160*4327Sdougm break; 1161*4327Sdougm } 1162*4327Sdougm } else { 1163*4327Sdougm share = find_share(group, sharepath); 1164*4327Sdougm } 1165*4327Sdougm if (share != NULL) 11663034Sdougm break; 11673034Sdougm } 11683034Sdougm return (share); 11693034Sdougm } 11703034Sdougm 11713034Sdougm /* 11723348Sdougm * sa_check_path(group, path, strictness) 11733034Sdougm * 11743034Sdougm * check that path is a valid path relative to the group. Currently, 11753034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 11763034Sdougm * we may want to use the group to then check against the protocols 11773348Sdougm * enabled on the group. The strictness values mean: 11783348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 11793348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 11803348Sdougm * stored in the repository 11813034Sdougm */ 11823034Sdougm 11833034Sdougm int 11843348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 11853034Sdougm { 11863910Sdougm sa_handle_t handle; 11873910Sdougm 11883910Sdougm handle = sa_find_group_handle(group); 11893910Sdougm return (validpath(handle, path, strictness)); 11903034Sdougm } 11913034Sdougm 11923034Sdougm /* 11933034Sdougm * _sa_add_share(group, sharepath, persist, *error) 11943034Sdougm * 11953034Sdougm * common code for all types of add_share. sa_add_share() is the 11963034Sdougm * public API, we also need to be able to do this when parsing legacy 11973034Sdougm * files and construction of the internal configuration while 11983034Sdougm * extracting config info from SMF. 11993034Sdougm */ 12003034Sdougm 12013034Sdougm sa_share_t 12023034Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12033034Sdougm { 12043034Sdougm xmlNodePtr node = NULL; 12053034Sdougm int err; 12063034Sdougm 12073034Sdougm err = SA_OK; /* assume success */ 12083034Sdougm 1209*4327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 12103034Sdougm if (node != NULL) { 1211*4327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 1212*4327Sdougm xmlSetProp(node, (xmlChar *)"type", 1213*4327Sdougm persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 1214*4327Sdougm if (persist != SA_SHARE_TRANSIENT) { 1215*4327Sdougm /* 1216*4327Sdougm * persistent shares come in two flavors: SMF and 1217*4327Sdougm * ZFS. Sort this one out based on target group and 1218*4327Sdougm * path type. Currently, only NFS is supported in the 1219*4327Sdougm * ZFS group and it is always on. 1220*4327Sdougm */ 1221*4327Sdougm if (sa_group_is_zfs(group) && 1222*4327Sdougm sa_path_is_zfs(sharepath)) { 1223*4327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 1224*4327Sdougm } else { 1225*4327Sdougm sa_handle_impl_t impl_handle; 1226*4327Sdougm impl_handle = 1227*4327Sdougm (sa_handle_impl_t)sa_find_group_handle( 1228*4327Sdougm group); 1229*4327Sdougm if (impl_handle != NULL) { 1230*4327Sdougm err = sa_commit_share( 1231*4327Sdougm impl_handle->scfhandle, group, 1232*4327Sdougm (sa_share_t)node); 1233*4327Sdougm } else { 1234*4327Sdougm err = SA_SYSTEM_ERR; 1235*4327Sdougm } 1236*4327Sdougm } 12373034Sdougm } 1238*4327Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 1239*4327Sdougm /* called by the dfstab parser so could be a show */ 1240*4327Sdougm err = SA_OK; 1241*4327Sdougm } 1242*4327Sdougm if (err != SA_OK) { 1243*4327Sdougm /* 1244*4327Sdougm * we couldn't commit to the repository so undo 1245*4327Sdougm * our internal state to reflect reality. 1246*4327Sdougm */ 1247*4327Sdougm xmlUnlinkNode(node); 1248*4327Sdougm xmlFreeNode(node); 1249*4327Sdougm node = NULL; 1250*4327Sdougm } 12513034Sdougm } else { 1252*4327Sdougm err = SA_NO_MEMORY; 12533034Sdougm } 12543034Sdougm if (error != NULL) 1255*4327Sdougm *error = err; 12563034Sdougm return (node); 12573034Sdougm } 12583034Sdougm 12593034Sdougm /* 12603034Sdougm * sa_add_share(group, sharepath, persist, *error) 12613034Sdougm * 12623034Sdougm * Add a new share object to the specified group. The share will 12633034Sdougm * have the specified sharepath and will only be constructed if 12643034Sdougm * it is a valid path to be shared. NULL is returned on error 12653034Sdougm * and a detailed error value will be returned via the error 12663034Sdougm * pointer. 12673034Sdougm */ 12683034Sdougm sa_share_t 12693034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12703034Sdougm { 12713034Sdougm xmlNodePtr node = NULL; 12723034Sdougm sa_share_t dup; 12733348Sdougm int strictness = SA_CHECK_NORMAL; 12743910Sdougm sa_handle_t handle; 12753348Sdougm 12763348Sdougm /* 12773348Sdougm * If the share is to be permanent, use strict checking so a 12783348Sdougm * bad config doesn't get created. Transient shares only need 12793348Sdougm * to check against the currently active 12803348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 12813348Sdougm * indicate that we are being called by the dfstab parser and 12823348Sdougm * that we need strict checking in all cases. Normally persist 12833348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 12843348Sdougm * it as an override. 12853348Sdougm */ 12863348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 1287*4327Sdougm strictness = SA_CHECK_STRICT; 12883034Sdougm 12893910Sdougm handle = sa_find_group_handle(group); 12903910Sdougm 12913910Sdougm if ((dup = sa_find_share(handle, sharepath)) == NULL && 1292*4327Sdougm (*error = sa_check_path(group, sharepath, strictness)) == SA_OK) { 1293*4327Sdougm node = _sa_add_share(group, sharepath, persist, error); 12943034Sdougm } 12953034Sdougm if (dup != NULL) 1296*4327Sdougm *error = SA_DUPLICATE_NAME; 12973034Sdougm 12983034Sdougm return ((sa_share_t)node); 12993034Sdougm } 13003034Sdougm 13013034Sdougm /* 13023034Sdougm * sa_enable_share(share, protocol) 13033034Sdougm * Enable the specified share to the specified protocol. 13043034Sdougm * If protocol is NULL, then all protocols. 13053034Sdougm */ 13063034Sdougm int 13073034Sdougm sa_enable_share(sa_share_t share, char *protocol) 13083034Sdougm { 13093034Sdougm char *sharepath; 13103034Sdougm struct stat st; 13113034Sdougm int err = 0; 13123034Sdougm 13133034Sdougm sharepath = sa_get_share_attr(share, "path"); 13143034Sdougm if (stat(sharepath, &st) < 0) { 1315*4327Sdougm err = SA_NO_SUCH_PATH; 13163034Sdougm } else { 1317*4327Sdougm /* tell the server about the share */ 1318*4327Sdougm if (protocol != NULL) { 1319*4327Sdougm /* lookup protocol specific handler */ 1320*4327Sdougm err = sa_proto_share(protocol, share); 1321*4327Sdougm if (err == SA_OK) 1322*4327Sdougm (void) sa_set_share_attr(share, "shared", 1323*4327Sdougm "true"); 1324*4327Sdougm } else { 1325*4327Sdougm /* 1326*4327Sdougm * Tell all protocols. Only NFS for now but 1327*4327Sdougm * SMB is coming. 1328*4327Sdougm */ 1329*4327Sdougm err = sa_proto_share("nfs", share); 1330*4327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 1331*4327Sdougm } 13323034Sdougm } 13333034Sdougm if (sharepath != NULL) 1334*4327Sdougm sa_free_attr_string(sharepath); 13353034Sdougm return (err); 13363034Sdougm } 13373034Sdougm 13383034Sdougm /* 13393034Sdougm * sa_disable_share(share, protocol) 13403034Sdougm * Disable the specified share to the specified protocol. 13413034Sdougm * If protocol is NULL, then all protocols. 13423034Sdougm */ 13433034Sdougm int 13443034Sdougm sa_disable_share(sa_share_t share, char *protocol) 13453034Sdougm { 13463034Sdougm char *path; 13473034Sdougm char *shared; 13483034Sdougm int ret = SA_OK; 13493034Sdougm 13503034Sdougm path = sa_get_share_attr(share, "path"); 13513034Sdougm shared = sa_get_share_attr(share, "shared"); 13523034Sdougm 13533034Sdougm if (protocol != NULL) { 1354*4327Sdougm ret = sa_proto_unshare(protocol, path); 13553034Sdougm } else { 1356*4327Sdougm /* need to do all protocols */ 1357*4327Sdougm ret = sa_proto_unshare("nfs", path); 13583034Sdougm } 13593034Sdougm if (ret == SA_OK) 13603034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 13613034Sdougm if (path != NULL) 1362*4327Sdougm sa_free_attr_string(path); 13633034Sdougm if (shared != NULL) 1364*4327Sdougm sa_free_attr_string(shared); 13653034Sdougm return (ret); 13663034Sdougm } 13673034Sdougm 13683034Sdougm /* 13693034Sdougm * sa_remove_share(share) 13703034Sdougm * 13713034Sdougm * remove the specified share from its containing group. 13723034Sdougm * Remove from the SMF or ZFS configuration space. 13733034Sdougm */ 13743034Sdougm 13753034Sdougm int 13763034Sdougm sa_remove_share(sa_share_t share) 13773034Sdougm { 13783034Sdougm sa_group_t group; 13793034Sdougm int ret = SA_OK; 13803034Sdougm char *type; 13813034Sdougm int transient = 0; 13823034Sdougm char *groupname; 13833034Sdougm char *zfs; 13843034Sdougm 13853034Sdougm type = sa_get_share_attr(share, "type"); 13863034Sdougm group = sa_get_parent_group(share); 13873034Sdougm zfs = sa_get_group_attr(group, "zfs"); 13883034Sdougm groupname = sa_get_group_attr(group, "name"); 13893034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 1390*4327Sdougm transient = 1; 13913034Sdougm if (type != NULL) 1392*4327Sdougm sa_free_attr_string(type); 13933034Sdougm 13943034Sdougm /* remove the node from its group then free the memory */ 13953034Sdougm 13963034Sdougm /* 13973034Sdougm * need to test if "busy" 13983034Sdougm */ 13993034Sdougm /* only do SMF action if permanent */ 14003034Sdougm if (!transient || zfs != NULL) { 1401*4327Sdougm /* remove from legacy dfstab as well as possible SMF */ 1402*4327Sdougm ret = sa_delete_legacy(share); 1403*4327Sdougm if (ret == SA_OK) { 1404*4327Sdougm if (!sa_group_is_zfs(group)) { 1405*4327Sdougm sa_handle_impl_t impl_handle; 1406*4327Sdougm impl_handle = (sa_handle_impl_t) 1407*4327Sdougm sa_find_group_handle(group); 1408*4327Sdougm if (impl_handle != NULL) { 1409*4327Sdougm ret = sa_delete_share( 1410*4327Sdougm impl_handle->scfhandle, group, 1411*4327Sdougm share); 1412*4327Sdougm } else { 1413*4327Sdougm ret = SA_SYSTEM_ERR; 1414*4327Sdougm } 1415*4327Sdougm } else { 1416*4327Sdougm char *sharepath = sa_get_share_attr(share, 1417*4327Sdougm "path"); 1418*4327Sdougm if (sharepath != NULL) { 1419*4327Sdougm ret = sa_zfs_set_sharenfs(group, 1420*4327Sdougm sharepath, 0); 1421*4327Sdougm sa_free_attr_string(sharepath); 1422*4327Sdougm } 1423*4327Sdougm } 14243034Sdougm } 14253034Sdougm } 14263034Sdougm if (groupname != NULL) 1427*4327Sdougm sa_free_attr_string(groupname); 14283034Sdougm if (zfs != NULL) 1429*4327Sdougm sa_free_attr_string(zfs); 14303034Sdougm 14313034Sdougm xmlUnlinkNode((xmlNodePtr)share); 14323034Sdougm xmlFreeNode((xmlNodePtr)share); 14333034Sdougm return (ret); 14343034Sdougm } 14353034Sdougm 14363034Sdougm /* 14373034Sdougm * sa_move_share(group, share) 14383034Sdougm * 14393034Sdougm * move the specified share to the specified group. Update SMF 14403034Sdougm * appropriately. 14413034Sdougm */ 14423034Sdougm 14433034Sdougm int 14443034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 14453034Sdougm { 14463034Sdougm sa_group_t oldgroup; 14473034Sdougm int ret = SA_OK; 14483034Sdougm 14493034Sdougm /* remove the node from its group then free the memory */ 14503034Sdougm 14513034Sdougm oldgroup = sa_get_parent_group(share); 14523034Sdougm if (oldgroup != group) { 1453*4327Sdougm sa_handle_impl_t impl_handle; 1454*4327Sdougm xmlUnlinkNode((xmlNodePtr)share); 14553034Sdougm /* 1456*4327Sdougm * now that the share isn't in its old group, add to 1457*4327Sdougm * the new one 14583034Sdougm */ 1459*4327Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 1460*4327Sdougm /* need to deal with SMF */ 1461*4327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1462*4327Sdougm if (impl_handle != NULL) { 1463*4327Sdougm /* 1464*4327Sdougm * need to remove from old group first and then add to 1465*4327Sdougm * new group. Ideally, we would do the other order but 1466*4327Sdougm * need to avoid having the share in two groups at the 1467*4327Sdougm * same time. 1468*4327Sdougm */ 1469*4327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 1470*4327Sdougm share); 1471*4327Sdougm if (ret == SA_OK) 1472*4327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 1473*4327Sdougm group, share); 1474*4327Sdougm } else { 1475*4327Sdougm ret = SA_SYSTEM_ERR; 1476*4327Sdougm } 14773034Sdougm } 14783034Sdougm return (ret); 14793034Sdougm } 14803034Sdougm 14813034Sdougm /* 14823034Sdougm * sa_get_parent_group(share) 14833034Sdougm * 14843034Sdougm * Return the containg group for the share. If a group was actually 14853034Sdougm * passed in, we don't want a parent so return NULL. 14863034Sdougm */ 14873034Sdougm 14883034Sdougm sa_group_t 14893034Sdougm sa_get_parent_group(sa_share_t share) 14903034Sdougm { 14913034Sdougm xmlNodePtr node = NULL; 14923034Sdougm if (share != NULL) { 1493*4327Sdougm node = ((xmlNodePtr)share)->parent; 14943034Sdougm /* 14953034Sdougm * make sure parent is a group and not sharecfg since 14963034Sdougm * we may be cheating and passing in a group. 14973034Sdougm * Eventually, groups of groups might come into being. 14983034Sdougm */ 1499*4327Sdougm if (node == NULL || 1500*4327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 1501*4327Sdougm node = NULL; 15023034Sdougm } 15033034Sdougm return ((sa_group_t)node); 15043034Sdougm } 15053034Sdougm 15063034Sdougm /* 15073910Sdougm * _sa_create_group(impl_handle, groupname) 15083034Sdougm * 15093034Sdougm * Create a group in the document. The caller will need to deal with 15103034Sdougm * configuration store and activation. 15113034Sdougm */ 15123034Sdougm 15133034Sdougm sa_group_t 15143910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 15153034Sdougm { 15163034Sdougm xmlNodePtr node = NULL; 15173034Sdougm 15183034Sdougm if (sa_valid_group_name(groupname)) { 1519*4327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 1520*4327Sdougm NULL); 1521*4327Sdougm if (node != NULL) { 1522*4327Sdougm xmlSetProp(node, (xmlChar *)"name", 1523*4327Sdougm (xmlChar *)groupname); 1524*4327Sdougm xmlSetProp(node, (xmlChar *)"state", 1525*4327Sdougm (xmlChar *)"enabled"); 1526*4327Sdougm } 15273034Sdougm } 15283034Sdougm return ((sa_group_t)node); 15293034Sdougm } 15303034Sdougm 15313034Sdougm /* 15323034Sdougm * _sa_create_zfs_group(group, groupname) 15333034Sdougm * 15343034Sdougm * Create a ZFS subgroup under the specified group. This may 15353034Sdougm * eventually form the basis of general sub-groups, but is currently 15363034Sdougm * restricted to ZFS. 15373034Sdougm */ 15383034Sdougm sa_group_t 15393034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 15403034Sdougm { 15413034Sdougm xmlNodePtr node = NULL; 15423034Sdougm 1543*4327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 15443034Sdougm if (node != NULL) { 15453034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 15463034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 15473034Sdougm } 15483034Sdougm 15493034Sdougm return ((sa_group_t)node); 15503034Sdougm } 15513034Sdougm 15523034Sdougm /* 15533034Sdougm * sa_create_group(groupname, *error) 15543034Sdougm * 15553034Sdougm * Create a new group with groupname. Need to validate that it is a 15563034Sdougm * legal name for SMF and the construct the SMF service instance of 15573034Sdougm * svc:/network/shares/group to implement the group. All necessary 15583034Sdougm * operational properties must be added to the group at this point 15593034Sdougm * (via the SMF transaction model). 15603034Sdougm */ 15613034Sdougm sa_group_t 15623910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 15633034Sdougm { 15643034Sdougm xmlNodePtr node = NULL; 15653034Sdougm sa_group_t group; 15663034Sdougm int ret; 1567*4327Sdougm char rbacstr[SA_STRSIZE]; 15683910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 15693034Sdougm 15703034Sdougm ret = SA_OK; 15713034Sdougm 15723910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 1573*4327Sdougm ret = SA_SYSTEM_ERR; 1574*4327Sdougm goto err; 15753034Sdougm } 15763034Sdougm 15773910Sdougm group = sa_get_group(handle, groupname); 15783034Sdougm if (group != NULL) { 1579*4327Sdougm ret = SA_DUPLICATE_NAME; 15803034Sdougm } else { 1581*4327Sdougm if (sa_valid_group_name(groupname)) { 1582*4327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 1583*4327Sdougm (xmlChar *)"group", NULL); 1584*4327Sdougm if (node != NULL) { 1585*4327Sdougm xmlSetProp(node, (xmlChar *)"name", 1586*4327Sdougm (xmlChar *)groupname); 1587*4327Sdougm /* default to the group being enabled */ 1588*4327Sdougm xmlSetProp(node, (xmlChar *)"state", 1589*4327Sdougm (xmlChar *)"enabled"); 1590*4327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 1591*4327Sdougm groupname); 1592*4327Sdougm if (ret == SA_OK) { 1593*4327Sdougm ret = sa_start_transaction( 1594*4327Sdougm impl_handle->scfhandle, 1595*4327Sdougm "operation"); 1596*4327Sdougm } 1597*4327Sdougm if (ret == SA_OK) { 1598*4327Sdougm ret = sa_set_property( 1599*4327Sdougm impl_handle->scfhandle, 1600*4327Sdougm "state", "enabled"); 1601*4327Sdougm if (ret == SA_OK) { 1602*4327Sdougm ret = sa_end_transaction( 1603*4327Sdougm impl_handle->scfhandle); 1604*4327Sdougm } else { 1605*4327Sdougm sa_abort_transaction( 1606*4327Sdougm impl_handle->scfhandle); 1607*4327Sdougm } 1608*4327Sdougm } 1609*4327Sdougm if (ret == SA_OK) { 1610*4327Sdougm /* initialize the RBAC strings */ 1611*4327Sdougm ret = sa_start_transaction( 1612*4327Sdougm impl_handle->scfhandle, 1613*4327Sdougm "general"); 1614*4327Sdougm if (ret == SA_OK) { 1615*4327Sdougm (void) snprintf(rbacstr, 1616*4327Sdougm sizeof (rbacstr), "%s.%s", 1617*4327Sdougm SA_RBAC_MANAGE, groupname); 1618*4327Sdougm ret = sa_set_property( 1619*4327Sdougm impl_handle->scfhandle, 16203034Sdougm "action_authorization", 16213034Sdougm rbacstr); 1622*4327Sdougm } 1623*4327Sdougm if (ret == SA_OK) { 1624*4327Sdougm (void) snprintf(rbacstr, 1625*4327Sdougm sizeof (rbacstr), "%s.%s", 1626*4327Sdougm SA_RBAC_VALUE, groupname); 1627*4327Sdougm ret = sa_set_property( 1628*4327Sdougm impl_handle->scfhandle, 16293034Sdougm "value_authorization", 16303034Sdougm rbacstr); 1631*4327Sdougm } 1632*4327Sdougm if (ret == SA_OK) { 1633*4327Sdougm ret = sa_end_transaction( 1634*4327Sdougm impl_handle->scfhandle); 1635*4327Sdougm } else { 1636*4327Sdougm sa_abort_transaction( 1637*4327Sdougm impl_handle->scfhandle); 1638*4327Sdougm } 1639*4327Sdougm } 1640*4327Sdougm if (ret != SA_OK) { 1641*4327Sdougm /* 1642*4327Sdougm * Couldn't commit the group 1643*4327Sdougm * so we need to undo 1644*4327Sdougm * internally. 1645*4327Sdougm */ 1646*4327Sdougm xmlUnlinkNode(node); 1647*4327Sdougm xmlFreeNode(node); 1648*4327Sdougm node = NULL; 1649*4327Sdougm } 16503034Sdougm } else { 1651*4327Sdougm ret = SA_NO_MEMORY; 16523034Sdougm } 16533034Sdougm } else { 1654*4327Sdougm ret = SA_INVALID_NAME; 16553034Sdougm } 16563034Sdougm } 16573034Sdougm err: 16583034Sdougm if (error != NULL) 1659*4327Sdougm *error = ret; 16603034Sdougm return ((sa_group_t)node); 16613034Sdougm } 16623034Sdougm 16633034Sdougm /* 16643034Sdougm * sa_remove_group(group) 16653034Sdougm * 16663034Sdougm * Remove the specified group. This deletes from the SMF repository. 16673034Sdougm * All property groups and properties are removed. 16683034Sdougm */ 16693034Sdougm 16703034Sdougm int 16713034Sdougm sa_remove_group(sa_group_t group) 16723034Sdougm { 16733034Sdougm char *name; 16743034Sdougm int ret = SA_OK; 16753910Sdougm sa_handle_impl_t impl_handle; 16763034Sdougm 16773910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 16783910Sdougm if (impl_handle != NULL) { 1679*4327Sdougm name = sa_get_group_attr(group, "name"); 1680*4327Sdougm if (name != NULL) { 1681*4327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 1682*4327Sdougm sa_free_attr_string(name); 1683*4327Sdougm } 1684*4327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 1685*4327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 16863910Sdougm } else { 1687*4327Sdougm ret = SA_SYSTEM_ERR; 16883034Sdougm } 16893034Sdougm return (ret); 16903034Sdougm } 16913034Sdougm 16923034Sdougm /* 16933034Sdougm * sa_update_config() 16943034Sdougm * 16953034Sdougm * Used to update legacy files that need to be updated in bulk 16963034Sdougm * Currently, this is a placeholder and will go away in a future 16973034Sdougm * release. 16983034Sdougm */ 16993034Sdougm 17003034Sdougm int 17013910Sdougm sa_update_config(sa_handle_t handle) 17023034Sdougm { 17033034Sdougm /* 17043034Sdougm * do legacy files first so we can tell when they change. 17053034Sdougm * This will go away when we start updating individual records 17063034Sdougm * rather than the whole file. 17073034Sdougm */ 17083910Sdougm update_legacy_config(handle); 17093034Sdougm return (SA_OK); 17103034Sdougm } 17113034Sdougm 17123034Sdougm /* 17133034Sdougm * get_node_attr(node, tag) 17143034Sdougm * 17153034Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 17163034Sdougm * used internally by a number of attribute oriented functions. 17173034Sdougm */ 17183034Sdougm 17193034Sdougm static char * 17203034Sdougm get_node_attr(void *nodehdl, char *tag) 17213034Sdougm { 17223034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 17233034Sdougm xmlChar *name = NULL; 17243034Sdougm 1725*4327Sdougm if (node != NULL) 17263034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 17273034Sdougm return ((char *)name); 17283034Sdougm } 17293034Sdougm 17303034Sdougm /* 17313034Sdougm * get_node_attr(node, tag) 17323034Sdougm * 17333034Sdougm * Set the speficied tag(attribute) to the specified value This is 17343034Sdougm * used internally by a number of attribute oriented functions. It 17353034Sdougm * doesn't update the repository, only the internal document state. 17363034Sdougm */ 17373034Sdougm 17383034Sdougm void 17393034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 17403034Sdougm { 17413034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 17423034Sdougm if (node != NULL && tag != NULL) { 1743*4327Sdougm if (value != NULL) 17443034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 1745*4327Sdougm else 17463034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 17473034Sdougm } 17483034Sdougm } 17493034Sdougm 17503034Sdougm /* 17513034Sdougm * sa_get_group_attr(group, tag) 17523034Sdougm * 17533034Sdougm * Get the specied attribute, if defined, for the group. 17543034Sdougm */ 17553034Sdougm 17563034Sdougm char * 17573034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 17583034Sdougm { 17593034Sdougm return (get_node_attr((void *)group, tag)); 17603034Sdougm } 17613034Sdougm 17623034Sdougm /* 17633034Sdougm * sa_set_group_attr(group, tag, value) 17643034Sdougm * 17653034Sdougm * set the specified tag/attribute on the group using value as its 17663034Sdougm * value. 17673034Sdougm * 17683034Sdougm * This will result in setting the property in the SMF repository as 17693034Sdougm * well as in the internal document. 17703034Sdougm */ 17713034Sdougm 17723034Sdougm int 17733034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 17743034Sdougm { 17753034Sdougm int ret; 17763034Sdougm char *groupname; 17773910Sdougm sa_handle_impl_t impl_handle; 17783034Sdougm 17793910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17803910Sdougm if (impl_handle != NULL) { 1781*4327Sdougm groupname = sa_get_group_attr(group, "name"); 1782*4327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 17833910Sdougm if (ret == SA_OK) { 1784*4327Sdougm set_node_attr((void *)group, tag, value); 1785*4327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 1786*4327Sdougm "operation"); 1787*4327Sdougm if (ret == SA_OK) { 1788*4327Sdougm ret = sa_set_property(impl_handle->scfhandle, 1789*4327Sdougm tag, value); 1790*4327Sdougm if (ret == SA_OK) 1791*4327Sdougm (void) sa_end_transaction( 1792*4327Sdougm impl_handle->scfhandle); 1793*4327Sdougm else 1794*4327Sdougm sa_abort_transaction( 1795*4327Sdougm impl_handle->scfhandle); 1796*4327Sdougm } 17973034Sdougm } 1798*4327Sdougm if (groupname != NULL) 1799*4327Sdougm sa_free_attr_string(groupname); 18003910Sdougm } else { 1801*4327Sdougm ret = SA_SYSTEM_ERR; 18023034Sdougm } 18033034Sdougm return (ret); 18043034Sdougm } 18053034Sdougm 18063034Sdougm /* 18073034Sdougm * sa_get_share_attr(share, tag) 18083034Sdougm * 18093034Sdougm * Return the value of the tag/attribute set on the specified 18103034Sdougm * share. Returns NULL if the tag doesn't exist. 18113034Sdougm */ 18123034Sdougm 18133034Sdougm char * 18143034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 18153034Sdougm { 18163034Sdougm return (get_node_attr((void *)share, tag)); 18173034Sdougm } 18183034Sdougm 18193034Sdougm /* 18203034Sdougm * sa_get_resource(group, resource) 18213034Sdougm * 18223034Sdougm * Search all the shares in the speified group for a share with a 18233034Sdougm * resource name matching the one specified. 18243034Sdougm * 18253034Sdougm * In the future, it may be advantageous to allow group to be NULL and 18263034Sdougm * search all groups but that isn't needed at present. 18273034Sdougm */ 18283034Sdougm 18293034Sdougm sa_share_t 18303034Sdougm sa_get_resource(sa_group_t group, char *resource) 18313034Sdougm { 18323034Sdougm sa_share_t share = NULL; 18333034Sdougm char *name = NULL; 18343034Sdougm 18353034Sdougm if (resource != NULL) { 1836*4327Sdougm for (share = sa_get_share(group, NULL); share != NULL; 1837*4327Sdougm share = sa_get_next_share(share)) { 1838*4327Sdougm name = sa_get_share_attr(share, "resource"); 1839*4327Sdougm if (name != NULL) { 1840*4327Sdougm if (strcmp(name, resource) == 0) 1841*4327Sdougm break; 1842*4327Sdougm sa_free_attr_string(name); 1843*4327Sdougm name = NULL; 1844*4327Sdougm } 18453034Sdougm } 1846*4327Sdougm if (name != NULL) 1847*4327Sdougm sa_free_attr_string(name); 18483034Sdougm } 18493034Sdougm return ((sa_share_t)share); 18503034Sdougm } 18513034Sdougm 18523034Sdougm /* 18533034Sdougm * _sa_set_share_description(share, description) 18543034Sdougm * 18553034Sdougm * Add a description tag with text contents to the specified share. 18563034Sdougm * A separate XML tag is used rather than a property. 18573034Sdougm */ 18583034Sdougm 18593034Sdougm xmlNodePtr 18603034Sdougm _sa_set_share_description(sa_share_t share, char *content) 18613034Sdougm { 18623034Sdougm xmlNodePtr node; 1863*4327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 1864*4327Sdougm NULL); 18653034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 18663034Sdougm return (node); 18673034Sdougm } 18683034Sdougm 18693034Sdougm /* 18703034Sdougm * sa_set_share_attr(share, tag, value) 18713034Sdougm * 18723034Sdougm * Set the share attribute specified by tag to the specified value. In 18733034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 18743034Sdougm * the share is not transient, commit the changes to the repository 18753034Sdougm * else just update the share internally. 18763034Sdougm */ 18773034Sdougm 18783034Sdougm int 18793034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 18803034Sdougm { 18813034Sdougm sa_group_t group; 18823034Sdougm sa_share_t resource; 18833034Sdougm int ret = SA_OK; 18843034Sdougm 18853034Sdougm group = sa_get_parent_group(share); 18863034Sdougm 18873034Sdougm /* 18883034Sdougm * There are some attributes that may have specific 18893034Sdougm * restrictions on them. Initially, only "resource" has 18903034Sdougm * special meaning that needs to be checked. Only one instance 18913034Sdougm * of a resource name may exist within a group. 18923034Sdougm */ 18933034Sdougm 18943034Sdougm if (strcmp(tag, "resource") == 0) { 1895*4327Sdougm resource = sa_get_resource(group, value); 1896*4327Sdougm if (resource != share && resource != NULL) 1897*4327Sdougm ret = SA_DUPLICATE_NAME; 18983034Sdougm } 18993034Sdougm if (ret == SA_OK) { 1900*4327Sdougm set_node_attr((void *)share, tag, value); 1901*4327Sdougm if (group != NULL) { 1902*4327Sdougm char *type; 1903*4327Sdougm /* we can probably optimize this some */ 1904*4327Sdougm type = sa_get_share_attr(share, "type"); 1905*4327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 1906*4327Sdougm sa_handle_impl_t impl_handle; 1907*4327Sdougm impl_handle = 1908*4327Sdougm (sa_handle_impl_t)sa_find_group_handle( 1909*4327Sdougm group); 1910*4327Sdougm if (impl_handle != NULL) { 1911*4327Sdougm ret = sa_commit_share( 1912*4327Sdougm impl_handle->scfhandle, group, 1913*4327Sdougm share); 1914*4327Sdougm } else { 1915*4327Sdougm ret = SA_SYSTEM_ERR; 1916*4327Sdougm } 1917*4327Sdougm } 1918*4327Sdougm if (type != NULL) 1919*4327Sdougm sa_free_attr_string(type); 19203910Sdougm } 19213034Sdougm } 19223034Sdougm return (ret); 19233034Sdougm } 19243034Sdougm 19253034Sdougm /* 19263034Sdougm * sa_get_property_attr(prop, tag) 19273034Sdougm * 19283034Sdougm * Get the value of the specified property attribute. Standard 19293034Sdougm * attributes are "type" and "value". 19303034Sdougm */ 19313034Sdougm 19323034Sdougm char * 19333034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 19343034Sdougm { 19353034Sdougm return (get_node_attr((void *)prop, tag)); 19363034Sdougm } 19373034Sdougm 19383034Sdougm /* 19393034Sdougm * sa_get_optionset_attr(prop, tag) 19403034Sdougm * 19413034Sdougm * Get the value of the specified property attribute. Standard 19423034Sdougm * attribute is "type". 19433034Sdougm */ 19443034Sdougm 19453034Sdougm char * 19463034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 19473034Sdougm { 19483034Sdougm return (get_node_attr((void *)optionset, tag)); 19493034Sdougm 19503034Sdougm } 19513034Sdougm 19523034Sdougm /* 19533034Sdougm * sa_set_optionset_attr(optionset, tag, value) 19543034Sdougm * 19553034Sdougm * Set the specified attribute(tag) to the specified value on the 19563034Sdougm * optionset. 19573034Sdougm */ 19583034Sdougm 19593034Sdougm void 19603034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 19613034Sdougm { 19623034Sdougm set_node_attr((void *)optionset, tag, value); 19633034Sdougm } 19643034Sdougm 19653034Sdougm /* 19663034Sdougm * sa_free_attr_string(string) 19673034Sdougm * 19683034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 19693034Sdougm * functions. 19703034Sdougm */ 19713034Sdougm 19723034Sdougm void 19733034Sdougm sa_free_attr_string(char *string) 19743034Sdougm { 19753034Sdougm xmlFree((xmlChar *)string); 19763034Sdougm } 19773034Sdougm 19783034Sdougm /* 19793034Sdougm * sa_get_optionset(group, proto) 19803034Sdougm * 19813034Sdougm * Return the optionset, if it exists, that is associated with the 19823034Sdougm * specified protocol. 19833034Sdougm */ 19843034Sdougm 19853034Sdougm sa_optionset_t 19863034Sdougm sa_get_optionset(void *group, char *proto) 19873034Sdougm { 19883034Sdougm xmlNodePtr node; 19893034Sdougm xmlChar *value = NULL; 19903034Sdougm 19913034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 1992*4327Sdougm node = node->next) { 19933034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 1994*4327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 1995*4327Sdougm if (proto != NULL) { 1996*4327Sdougm if (value != NULL && 1997*4327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 1998*4327Sdougm break; 1999*4327Sdougm } 2000*4327Sdougm if (value != NULL) { 2001*4327Sdougm xmlFree(value); 2002*4327Sdougm value = NULL; 2003*4327Sdougm } 2004*4327Sdougm } else { 2005*4327Sdougm break; 20063034Sdougm } 20073034Sdougm } 20083034Sdougm } 20093034Sdougm if (value != NULL) 2010*4327Sdougm xmlFree(value); 20113034Sdougm return ((sa_optionset_t)node); 20123034Sdougm } 20133034Sdougm 20143034Sdougm /* 20153034Sdougm * sa_get_next_optionset(optionset) 20163034Sdougm * 20173034Sdougm * Return the next optionset in the group. NULL if this was the last. 20183034Sdougm */ 20193034Sdougm 20203034Sdougm sa_optionset_t 20213034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 20223034Sdougm { 20233034Sdougm xmlNodePtr node; 20243034Sdougm 20253034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 2026*4327Sdougm node = node->next) { 20273034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 20283034Sdougm break; 20293034Sdougm } 20303034Sdougm } 20313034Sdougm return ((sa_optionset_t)node); 20323034Sdougm } 20333034Sdougm 20343034Sdougm /* 20353034Sdougm * sa_get_security(group, sectype, proto) 20363034Sdougm * 20373034Sdougm * Return the security optionset. The internal name is a hold over 20383034Sdougm * from the implementation and will be changed before the API is 20393034Sdougm * finalized. This is really a named optionset that can be negotiated 20403034Sdougm * as a group of properties (like NFS security options). 20413034Sdougm */ 20423034Sdougm 20433034Sdougm sa_security_t 20443034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 20453034Sdougm { 20463034Sdougm xmlNodePtr node; 20473034Sdougm xmlChar *value = NULL; 20483034Sdougm 20493034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 2050*4327Sdougm node = node->next) { 2051*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 2052*4327Sdougm if (proto != NULL) { 2053*4327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 2054*4327Sdougm if (value == NULL || 2055*4327Sdougm (value != NULL && 2056*4327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 2057*4327Sdougm /* it doesn't match so continue */ 2058*4327Sdougm xmlFree(value); 2059*4327Sdougm value = NULL; 2060*4327Sdougm continue; 2061*4327Sdougm } 2062*4327Sdougm } 2063*4327Sdougm if (value != NULL) { 2064*4327Sdougm xmlFree(value); 2065*4327Sdougm value = NULL; 2066*4327Sdougm } 2067*4327Sdougm /* potential match */ 2068*4327Sdougm if (sectype != NULL) { 2069*4327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 2070*4327Sdougm if (value != NULL && 2071*4327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 2072*4327Sdougm break; 2073*4327Sdougm } 2074*4327Sdougm } else { 2075*4327Sdougm break; 2076*4327Sdougm } 20773034Sdougm } 20783034Sdougm if (value != NULL) { 2079*4327Sdougm xmlFree(value); 2080*4327Sdougm value = NULL; 20813034Sdougm } 20823034Sdougm } 20833034Sdougm if (value != NULL) 2084*4327Sdougm xmlFree(value); 20853034Sdougm return ((sa_security_t)node); 20863034Sdougm } 20873034Sdougm 20883034Sdougm /* 20893034Sdougm * sa_get_next_security(security) 20903034Sdougm * 20913034Sdougm * Get the next security optionset if one exists. 20923034Sdougm */ 20933034Sdougm 20943034Sdougm sa_security_t 20953034Sdougm sa_get_next_security(sa_security_t security) 20963034Sdougm { 20973034Sdougm xmlNodePtr node; 20983034Sdougm 20993034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 2100*4327Sdougm node = node->next) { 21013034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 21023034Sdougm break; 21033034Sdougm } 21043034Sdougm } 21053034Sdougm return ((sa_security_t)node); 21063034Sdougm } 21073034Sdougm 21083034Sdougm /* 21093034Sdougm * sa_get_property(optionset, prop) 21103034Sdougm * 21113034Sdougm * Get the property object with the name specified in prop from the 21123034Sdougm * optionset. 21133034Sdougm */ 21143034Sdougm 21153034Sdougm sa_property_t 21163034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 21173034Sdougm { 21183034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 21193034Sdougm xmlChar *value = NULL; 21203034Sdougm 21213034Sdougm if (optionset == NULL) 2122*4327Sdougm return (NULL); 21233034Sdougm 21243034Sdougm for (node = node->children; node != NULL; 2125*4327Sdougm node = node->next) { 2126*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 2127*4327Sdougm if (prop == NULL) 2128*4327Sdougm break; 2129*4327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 2130*4327Sdougm if (value != NULL && 2131*4327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 2132*4327Sdougm break; 2133*4327Sdougm } 2134*4327Sdougm if (value != NULL) { 2135*4327Sdougm xmlFree(value); 2136*4327Sdougm value = NULL; 2137*4327Sdougm } 21383034Sdougm } 21393034Sdougm } 21403034Sdougm if (value != NULL) 21413034Sdougm xmlFree(value); 21423034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 2143*4327Sdougm /* 2144*4327Sdougm * avoid a non option node -- it is possible to be a 2145*4327Sdougm * text node 2146*4327Sdougm */ 2147*4327Sdougm node = NULL; 21483034Sdougm } 21493034Sdougm return ((sa_property_t)node); 21503034Sdougm } 21513034Sdougm 21523034Sdougm /* 21533034Sdougm * sa_get_next_property(property) 21543034Sdougm * 21553034Sdougm * Get the next property following the specified property. NULL if 21563034Sdougm * this was the last. 21573034Sdougm */ 21583034Sdougm 21593034Sdougm sa_property_t 21603034Sdougm sa_get_next_property(sa_property_t property) 21613034Sdougm { 21623034Sdougm xmlNodePtr node; 21633034Sdougm 21643034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 2165*4327Sdougm node = node->next) { 21663034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 21673034Sdougm break; 21683034Sdougm } 21693034Sdougm } 21703034Sdougm return ((sa_property_t)node); 21713034Sdougm } 21723034Sdougm 21733034Sdougm /* 21743034Sdougm * sa_set_share_description(share, content) 21753034Sdougm * 21763034Sdougm * Set the description of share to content. 21773034Sdougm */ 21783034Sdougm 21793034Sdougm int 21803034Sdougm sa_set_share_description(sa_share_t share, char *content) 21813034Sdougm { 21823034Sdougm xmlNodePtr node; 21833034Sdougm sa_group_t group; 21843034Sdougm int ret = SA_OK; 21853034Sdougm 21863034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 2187*4327Sdougm node = node->next) { 21883034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 21893034Sdougm break; 21903034Sdougm } 21913034Sdougm } 21923034Sdougm group = sa_get_parent_group(share); 21933034Sdougm /* no existing description but want to add */ 21943034Sdougm if (node == NULL && content != NULL) { 21953034Sdougm /* add a description */ 2196*4327Sdougm node = _sa_set_share_description(share, content); 21973034Sdougm } else if (node != NULL && content != NULL) { 21983034Sdougm /* update a description */ 21993034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 22003034Sdougm } else if (node != NULL && content == NULL) { 22013034Sdougm /* remove an existing description */ 22023034Sdougm xmlUnlinkNode(node); 22033034Sdougm xmlFreeNode(node); 22043034Sdougm } 22053910Sdougm if (group != NULL && is_persistent((sa_group_t)share)) { 2206*4327Sdougm sa_handle_impl_t impl_handle; 2207*4327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 2208*4327Sdougm if (impl_handle != NULL) { 2209*4327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 2210*4327Sdougm share); 2211*4327Sdougm } else { 2212*4327Sdougm ret = SA_SYSTEM_ERR; 2213*4327Sdougm } 22143910Sdougm } 22153034Sdougm return (ret); 22163034Sdougm } 22173034Sdougm 22183034Sdougm /* 22193034Sdougm * fixproblemchars(string) 22203034Sdougm * 22213034Sdougm * don't want any newline or tab characters in the text since these 22223034Sdougm * could break display of data and legacy file formats. 22233034Sdougm */ 22243034Sdougm static void 22253034Sdougm fixproblemchars(char *str) 22263034Sdougm { 22273034Sdougm int c; 22283034Sdougm for (c = *str; c != '\0'; c = *++str) { 2229*4327Sdougm if (c == '\t' || c == '\n') 2230*4327Sdougm *str = ' '; 2231*4327Sdougm else if (c == '"') 2232*4327Sdougm *str = '\''; 22333034Sdougm } 22343034Sdougm } 22353034Sdougm 22363034Sdougm /* 22373034Sdougm * sa_get_share_description(share) 22383034Sdougm * 22393034Sdougm * Return the description text for the specified share if it 22403034Sdougm * exists. NULL if no description exists. 22413034Sdougm */ 22423034Sdougm 22433034Sdougm char * 22443034Sdougm sa_get_share_description(sa_share_t share) 22453034Sdougm { 22463034Sdougm xmlChar *description = NULL; 22473034Sdougm xmlNodePtr node; 22483034Sdougm 22493034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 2250*4327Sdougm node = node->next) { 2251*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 2252*4327Sdougm break; 2253*4327Sdougm } 22543034Sdougm } 22553034Sdougm if (node != NULL) { 2256*4327Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 2257*4327Sdougm fixproblemchars((char *)description); 22583034Sdougm } 22593034Sdougm return ((char *)description); 22603034Sdougm } 22613034Sdougm 22623034Sdougm /* 22633034Sdougm * sa_free(share_description(description) 22643034Sdougm * 22653034Sdougm * Free the description string. 22663034Sdougm */ 22673034Sdougm 22683034Sdougm void 22693034Sdougm sa_free_share_description(char *description) 22703034Sdougm { 22713034Sdougm xmlFree((xmlChar *)description); 22723034Sdougm } 22733034Sdougm 22743034Sdougm /* 22753034Sdougm * sa_create_optionset(group, proto) 22763034Sdougm * 22773034Sdougm * Create an optionset for the specified protocol in the specied 22783034Sdougm * group. This is manifested as a property group within SMF. 22793034Sdougm */ 22803034Sdougm 22813034Sdougm sa_optionset_t 22823034Sdougm sa_create_optionset(sa_group_t group, char *proto) 22833034Sdougm { 22843034Sdougm sa_optionset_t optionset; 22853034Sdougm sa_group_t parent = group; 22863034Sdougm 22873034Sdougm optionset = sa_get_optionset(group, proto); 22883034Sdougm if (optionset != NULL) { 22893034Sdougm /* can't have a duplicate protocol */ 2290*4327Sdougm optionset = NULL; 22913034Sdougm } else { 2292*4327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 2293*4327Sdougm NULL, (xmlChar *)"optionset", NULL); 22943034Sdougm /* 22953034Sdougm * only put to repository if on a group and we were 22963034Sdougm * able to create an optionset. 22973034Sdougm */ 2298*4327Sdougm if (optionset != NULL) { 2299*4327Sdougm char oname[SA_STRSIZE]; 2300*4327Sdougm char *groupname; 2301*4327Sdougm char *id = NULL; 2302*4327Sdougm 2303*4327Sdougm if (sa_is_share(group)) 2304*4327Sdougm parent = sa_get_parent_group((sa_share_t)group); 2305*4327Sdougm 2306*4327Sdougm sa_set_optionset_attr(optionset, "type", proto); 23073034Sdougm 2308*4327Sdougm if (sa_is_share(group)) { 2309*4327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 2310*4327Sdougm } 2311*4327Sdougm (void) sa_optionset_name(optionset, oname, 2312*4327Sdougm sizeof (oname), id); 2313*4327Sdougm groupname = sa_get_group_attr(parent, "name"); 2314*4327Sdougm if (groupname != NULL && is_persistent(group)) { 2315*4327Sdougm sa_handle_impl_t impl_handle; 2316*4327Sdougm impl_handle = (sa_handle_impl_t) 2317*4327Sdougm sa_find_group_handle(group); 2318*4327Sdougm assert(impl_handle != NULL); 2319*4327Sdougm if (impl_handle != NULL) { 2320*4327Sdougm (void) sa_get_instance( 2321*4327Sdougm impl_handle->scfhandle, 2322*4327Sdougm groupname); 2323*4327Sdougm (void) sa_create_pgroup( 2324*4327Sdougm impl_handle->scfhandle, oname); 2325*4327Sdougm } 2326*4327Sdougm } 2327*4327Sdougm if (groupname != NULL) 2328*4327Sdougm sa_free_attr_string(groupname); 2329*4327Sdougm if (id != NULL) 2330*4327Sdougm sa_free_attr_string(id); 23313034Sdougm } 23323034Sdougm } 23333034Sdougm return (optionset); 23343034Sdougm } 23353034Sdougm 23363034Sdougm /* 23373034Sdougm * sa_get_property_parent(property) 23383034Sdougm * 23393034Sdougm * Given a property, return the object it is a property of. This will 23403034Sdougm * be an optionset of some type. 23413034Sdougm */ 23423034Sdougm 23433034Sdougm static sa_optionset_t 23443034Sdougm sa_get_property_parent(sa_property_t property) 23453034Sdougm { 23463034Sdougm xmlNodePtr node = NULL; 23473034Sdougm 2348*4327Sdougm if (property != NULL) 2349*4327Sdougm node = ((xmlNodePtr)property)->parent; 23503034Sdougm return ((sa_optionset_t)node); 23513034Sdougm } 23523034Sdougm 23533034Sdougm /* 23543034Sdougm * sa_get_optionset_parent(optionset) 23553034Sdougm * 23563034Sdougm * Return the parent of the specified optionset. This could be a group 23573034Sdougm * or a share. 23583034Sdougm */ 23593034Sdougm 23603034Sdougm static sa_group_t 23613034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 23623034Sdougm { 23633034Sdougm xmlNodePtr node = NULL; 23643034Sdougm 2365*4327Sdougm if (optionset != NULL) 2366*4327Sdougm node = ((xmlNodePtr)optionset)->parent; 23673034Sdougm return ((sa_group_t)node); 23683034Sdougm } 23693034Sdougm 23703034Sdougm /* 23713034Sdougm * zfs_needs_update(share) 23723034Sdougm * 23733034Sdougm * In order to avoid making multiple updates to a ZFS share when 23743034Sdougm * setting properties, the share attribute "changed" will be set to 23753034Sdougm * true when a property is added or modifed. When done adding 23763034Sdougm * properties, we can then detect that an update is needed. We then 23773034Sdougm * clear the state here to detect additional changes. 23783034Sdougm */ 23793034Sdougm 23803034Sdougm static int 23813034Sdougm zfs_needs_update(sa_share_t share) 23823034Sdougm { 23833034Sdougm char *attr; 23843034Sdougm int result = 0; 23853034Sdougm 23863034Sdougm attr = sa_get_share_attr(share, "changed"); 23873034Sdougm if (attr != NULL) { 2388*4327Sdougm sa_free_attr_string(attr); 23893034Sdougm result = 1; 23903034Sdougm } 23913034Sdougm set_node_attr((void *)share, "changed", NULL); 23923034Sdougm return (result); 23933034Sdougm } 23943034Sdougm 23953034Sdougm /* 23963034Sdougm * zfs_set_update(share) 23973034Sdougm * 23983034Sdougm * Set the changed attribute of the share to true. 23993034Sdougm */ 24003034Sdougm 24013034Sdougm static void 24023034Sdougm zfs_set_update(sa_share_t share) 24033034Sdougm { 24043034Sdougm set_node_attr((void *)share, "changed", "true"); 24053034Sdougm } 24063034Sdougm 24073034Sdougm /* 24083034Sdougm * sa_commit_properties(optionset, clear) 24093034Sdougm * 24103034Sdougm * Check if SMF or ZFS config and either update or abort the pending 24113034Sdougm * changes. 24123034Sdougm */ 24133034Sdougm 24143034Sdougm int 24153034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 24163034Sdougm { 24173034Sdougm sa_group_t group; 24183034Sdougm sa_group_t parent; 24193034Sdougm int zfs = 0; 24203034Sdougm int needsupdate = 0; 24213034Sdougm int ret = SA_OK; 24223910Sdougm sa_handle_impl_t impl_handle; 24233034Sdougm 24243034Sdougm group = sa_get_optionset_parent(optionset); 24253034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 2426*4327Sdougm /* only update ZFS if on a share */ 2427*4327Sdougm parent = sa_get_parent_group(group); 2428*4327Sdougm zfs++; 2429*4327Sdougm if (parent != NULL && is_zfs_group(parent)) 2430*4327Sdougm needsupdate = zfs_needs_update(group); 2431*4327Sdougm else 2432*4327Sdougm zfs = 0; 24333034Sdougm } 24343034Sdougm if (zfs) { 2435*4327Sdougm if (!clear && needsupdate) 2436*4327Sdougm ret = sa_zfs_update((sa_share_t)group); 24373034Sdougm } else { 2438*4327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 2439*4327Sdougm if (impl_handle != NULL) { 2440*4327Sdougm if (clear) { 2441*4327Sdougm (void) sa_abort_transaction( 2442*4327Sdougm impl_handle->scfhandle); 2443*4327Sdougm } else { 2444*4327Sdougm ret = sa_end_transaction( 2445*4327Sdougm impl_handle->scfhandle); 2446*4327Sdougm } 2447*4327Sdougm } else { 2448*4327Sdougm ret = SA_SYSTEM_ERR; 2449*4327Sdougm } 24503034Sdougm } 24513034Sdougm return (ret); 24523034Sdougm } 24533034Sdougm 24543034Sdougm /* 24553034Sdougm * sa_destroy_optionset(optionset) 24563034Sdougm * 24573034Sdougm * Remove the optionset from its group. Update the repostory to 24583034Sdougm * reflect this change. 24593034Sdougm */ 24603034Sdougm 24613034Sdougm int 24623034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 24633034Sdougm { 2464*4327Sdougm char name[SA_STRSIZE]; 24653034Sdougm int len; 24663034Sdougm int ret; 24673034Sdougm char *id = NULL; 24683034Sdougm sa_group_t group; 24693034Sdougm int ispersist = 1; 24703034Sdougm 24713034Sdougm /* now delete the prop group */ 24723034Sdougm group = sa_get_optionset_parent(optionset); 24733034Sdougm if (group != NULL && sa_is_share(group)) { 2474*4327Sdougm ispersist = is_persistent(group); 2475*4327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 24763034Sdougm } 24773034Sdougm if (ispersist) { 2478*4327Sdougm sa_handle_impl_t impl_handle; 2479*4327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 2480*4327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 2481*4327Sdougm if (impl_handle != NULL) { 2482*4327Sdougm if (len > 0) { 2483*4327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 2484*4327Sdougm name); 2485*4327Sdougm } 2486*4327Sdougm } else { 2487*4327Sdougm ret = SA_SYSTEM_ERR; 24883910Sdougm } 24893034Sdougm } 24903034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 24913034Sdougm xmlFreeNode((xmlNodePtr)optionset); 24923034Sdougm if (id != NULL) 2493*4327Sdougm sa_free_attr_string(id); 24943034Sdougm return (ret); 24953034Sdougm } 24963034Sdougm 24973034Sdougm /* private to the implementation */ 24983034Sdougm int 24993034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 25003034Sdougm { 25013034Sdougm int ret = SA_OK; 25023034Sdougm 25033034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 25043034Sdougm xmlFreeNode((xmlNodePtr)optionset); 25053034Sdougm return (ret); 25063034Sdougm } 25073034Sdougm 25083034Sdougm /* 25093034Sdougm * sa_create_security(group, sectype, proto) 25103034Sdougm * 25113034Sdougm * Create a security optionset (one that has a type name and a 25123034Sdougm * proto). Security is left over from a pure NFS implementation. The 25133034Sdougm * naming will change in the future when the API is released. 25143034Sdougm */ 25153034Sdougm sa_security_t 25163034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 25173034Sdougm { 25183034Sdougm sa_security_t security; 25193034Sdougm char *id = NULL; 25203034Sdougm sa_group_t parent; 25213034Sdougm char *groupname = NULL; 25223034Sdougm 25233034Sdougm if (group != NULL && sa_is_share(group)) { 2524*4327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 2525*4327Sdougm parent = sa_get_parent_group(group); 2526*4327Sdougm if (parent != NULL) 2527*4327Sdougm groupname = sa_get_group_attr(parent, "name"); 25283034Sdougm } else if (group != NULL) { 2529*4327Sdougm groupname = sa_get_group_attr(group, "name"); 25303034Sdougm } 25313034Sdougm 25323034Sdougm security = sa_get_security(group, sectype, proto); 25333034Sdougm if (security != NULL) { 25343034Sdougm /* can't have a duplicate security option */ 25353034Sdougm security = NULL; 25363034Sdougm } else { 25373034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 2538*4327Sdougm NULL, (xmlChar *)"security", NULL); 25393034Sdougm if (security != NULL) { 2540*4327Sdougm char oname[SA_STRSIZE]; 25413034Sdougm sa_set_security_attr(security, "type", proto); 25423034Sdougm 25433034Sdougm sa_set_security_attr(security, "sectype", sectype); 25443034Sdougm (void) sa_security_name(security, oname, 2545*4327Sdougm sizeof (oname), id); 25463034Sdougm if (groupname != NULL && is_persistent(group)) { 2547*4327Sdougm sa_handle_impl_t impl_handle; 2548*4327Sdougm impl_handle = 2549*4327Sdougm (sa_handle_impl_t)sa_find_group_handle( 2550*4327Sdougm group); 2551*4327Sdougm if (impl_handle != NULL) { 2552*4327Sdougm (void) sa_get_instance( 2553*4327Sdougm impl_handle->scfhandle, groupname); 2554*4327Sdougm (void) sa_create_pgroup( 2555*4327Sdougm impl_handle->scfhandle, oname); 2556*4327Sdougm } 25573034Sdougm } 25583034Sdougm } 25593034Sdougm } 25603034Sdougm if (groupname != NULL) 2561*4327Sdougm sa_free_attr_string(groupname); 25623034Sdougm return (security); 25633034Sdougm } 25643034Sdougm 25653034Sdougm /* 25663034Sdougm * sa_destroy_security(security) 25673034Sdougm * 25683034Sdougm * Remove the specified optionset from the document and the 25693034Sdougm * configuration. 25703034Sdougm */ 25713034Sdougm 25723034Sdougm int 25733034Sdougm sa_destroy_security(sa_security_t security) 25743034Sdougm { 2575*4327Sdougm char name[SA_STRSIZE]; 25763034Sdougm int len; 25773034Sdougm int ret = SA_OK; 25783034Sdougm char *id = NULL; 25793034Sdougm sa_group_t group; 25803034Sdougm int iszfs = 0; 25813034Sdougm int ispersist = 1; 25823034Sdougm 25833034Sdougm group = sa_get_optionset_parent(security); 25843034Sdougm 25853034Sdougm if (group != NULL) 2586*4327Sdougm iszfs = sa_group_is_zfs(group); 25873034Sdougm 25883034Sdougm if (group != NULL && !iszfs) { 2589*4327Sdougm if (sa_is_share(group)) 2590*4327Sdougm ispersist = is_persistent(group); 2591*4327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 25923034Sdougm } 25933034Sdougm if (ispersist) { 2594*4327Sdougm len = sa_security_name(security, name, sizeof (name), id); 2595*4327Sdougm if (!iszfs && len > 0) { 2596*4327Sdougm sa_handle_impl_t impl_handle; 2597*4327Sdougm impl_handle = 2598*4327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 2599*4327Sdougm if (impl_handle != NULL) { 2600*4327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 2601*4327Sdougm name); 2602*4327Sdougm } else { 2603*4327Sdougm ret = SA_SYSTEM_ERR; 2604*4327Sdougm } 26053910Sdougm } 26063034Sdougm } 26073034Sdougm xmlUnlinkNode((xmlNodePtr)security); 26083034Sdougm xmlFreeNode((xmlNodePtr)security); 2609*4327Sdougm if (iszfs) 2610*4327Sdougm ret = sa_zfs_update(group); 26113034Sdougm if (id != NULL) 2612*4327Sdougm sa_free_attr_string(id); 26133034Sdougm return (ret); 26143034Sdougm } 26153034Sdougm 26163034Sdougm /* 26173034Sdougm * sa_get_security_attr(optionset, tag) 26183034Sdougm * 26193034Sdougm * Return the specified attribute value from the optionset. 26203034Sdougm */ 26213034Sdougm 26223034Sdougm char * 26233034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 26243034Sdougm { 26253034Sdougm return (get_node_attr((void *)optionset, tag)); 26263034Sdougm 26273034Sdougm } 26283034Sdougm 26293034Sdougm /* 26303034Sdougm * sa_set_security_attr(optionset, tag, value) 26313034Sdougm * 26323034Sdougm * Set the optioset attribute specied by tag to the specified value. 26333034Sdougm */ 26343034Sdougm 26353034Sdougm void 26363034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 26373034Sdougm { 26383034Sdougm set_node_attr((void *)optionset, tag, value); 26393034Sdougm } 26403034Sdougm 26413034Sdougm /* 26423034Sdougm * is_nodetype(node, type) 26433034Sdougm * 26443034Sdougm * Check to see if node is of the type specified. 26453034Sdougm */ 26463034Sdougm 26473034Sdougm static int 26483034Sdougm is_nodetype(void *node, char *type) 26493034Sdougm { 26503034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 26513034Sdougm } 26523034Sdougm 2653*4327Sdougm 2654*4327Sdougm /* 2655*4327Sdougm * add_or_update() 2656*4327Sdougm * 2657*4327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 2658*4327Sdougm * readability. 2659*4327Sdougm */ 2660*4327Sdougm static int 2661*4327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 2662*4327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 2663*4327Sdougm { 2664*4327Sdougm int ret = SA_SYSTEM_ERR; 2665*4327Sdougm 2666*4327Sdougm if (value != NULL) { 2667*4327Sdougm if (type == SA_PROP_OP_ADD) 2668*4327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 2669*4327Sdougm entry, name, SCF_TYPE_ASTRING); 2670*4327Sdougm else 2671*4327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 2672*4327Sdougm entry, name, SCF_TYPE_ASTRING); 2673*4327Sdougm if (ret == 0) { 2674*4327Sdougm ret = scf_value_set_astring(value, valstr); 2675*4327Sdougm if (ret == 0) 2676*4327Sdougm ret = scf_entry_add_value(entry, value); 2677*4327Sdougm if (ret == 0) 2678*4327Sdougm return (ret); 2679*4327Sdougm scf_value_destroy(value); 2680*4327Sdougm } else { 2681*4327Sdougm scf_entry_destroy(entry); 2682*4327Sdougm } 2683*4327Sdougm } 2684*4327Sdougm return (SA_SYSTEM_ERR); 2685*4327Sdougm } 2686*4327Sdougm 26873034Sdougm /* 26883034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 26893034Sdougm * 26903034Sdougm * Add/remove/update the specified property prop into the optionset or 26913034Sdougm * share. If a share, sort out which property group based on GUID. In 26923034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 26933034Sdougm * marked as needing an update) 26943034Sdougm */ 26953034Sdougm 26963034Sdougm static int 26973034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 26983034Sdougm sa_property_t prop, int type) 26993034Sdougm { 27003034Sdougm char *name; 27013034Sdougm char *valstr; 27023034Sdougm int ret = SA_OK; 27033034Sdougm scf_transaction_entry_t *entry; 27043034Sdougm scf_value_t *value; 27053034Sdougm int opttype; /* 1 == optionset, 0 == security */ 27063034Sdougm char *id = NULL; 27073034Sdougm int iszfs = 0; 27083034Sdougm int isshare = 0; 27093034Sdougm sa_group_t parent = NULL; 27103910Sdougm sa_handle_impl_t impl_handle; 27113910Sdougm scfutilhandle_t *scf_handle; 27123034Sdougm 27133034Sdougm if (!is_persistent(group)) { 27143034Sdougm /* 27153034Sdougm * if the group/share is not persistent we don't need 27163034Sdougm * to do anything here 27173034Sdougm */ 2718*4327Sdougm return (SA_OK); 27193034Sdougm } 27203910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 2721*4327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 2722*4327Sdougm return (SA_SYSTEM_ERR); 27233910Sdougm scf_handle = impl_handle->scfhandle; 27243034Sdougm name = sa_get_property_attr(prop, "type"); 27253034Sdougm valstr = sa_get_property_attr(prop, "value"); 27263034Sdougm entry = scf_entry_create(scf_handle->handle); 27273034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 27283034Sdougm 27293034Sdougm if (valstr != NULL && entry != NULL) { 2730*4327Sdougm if (sa_is_share(group)) { 2731*4327Sdougm isshare = 1; 2732*4327Sdougm parent = sa_get_parent_group(group); 2733*4327Sdougm if (parent != NULL) 2734*4327Sdougm iszfs = is_zfs_group(parent); 2735*4327Sdougm } else { 2736*4327Sdougm iszfs = is_zfs_group(group); 27373034Sdougm } 2738*4327Sdougm if (!iszfs) { 2739*4327Sdougm if (scf_handle->trans == NULL) { 2740*4327Sdougm char oname[SA_STRSIZE]; 2741*4327Sdougm char *groupname = NULL; 2742*4327Sdougm if (isshare) { 2743*4327Sdougm if (parent != NULL) { 2744*4327Sdougm groupname = 2745*4327Sdougm sa_get_group_attr(parent, 2746*4327Sdougm "name"); 2747*4327Sdougm } 2748*4327Sdougm id = 2749*4327Sdougm sa_get_share_attr((sa_share_t)group, 2750*4327Sdougm "id"); 2751*4327Sdougm } else { 2752*4327Sdougm groupname = sa_get_group_attr(group, 2753*4327Sdougm "name"); 2754*4327Sdougm } 2755*4327Sdougm if (groupname != NULL) { 2756*4327Sdougm ret = sa_get_instance(scf_handle, 2757*4327Sdougm groupname); 2758*4327Sdougm sa_free_attr_string(groupname); 2759*4327Sdougm } 2760*4327Sdougm if (opttype) 2761*4327Sdougm (void) sa_optionset_name(optionset, 2762*4327Sdougm oname, sizeof (oname), id); 2763*4327Sdougm else 2764*4327Sdougm (void) sa_security_name(optionset, 2765*4327Sdougm oname, sizeof (oname), id); 2766*4327Sdougm ret = sa_start_transaction(scf_handle, oname); 27673910Sdougm } 2768*4327Sdougm if (ret == SA_OK) { 2769*4327Sdougm switch (type) { 2770*4327Sdougm case SA_PROP_OP_REMOVE: 2771*4327Sdougm ret = scf_transaction_property_delete( 2772*4327Sdougm scf_handle->trans, entry, name); 2773*4327Sdougm break; 2774*4327Sdougm case SA_PROP_OP_ADD: 2775*4327Sdougm case SA_PROP_OP_UPDATE: 2776*4327Sdougm value = scf_value_create( 2777*4327Sdougm scf_handle->handle); 2778*4327Sdougm ret = add_or_update(scf_handle, type, 2779*4327Sdougm value, entry, name, valstr); 2780*4327Sdougm break; 27813034Sdougm } 27823034Sdougm } 2783*4327Sdougm } else { 2784*4327Sdougm /* 2785*4327Sdougm * ZFS update. The calling function would have updated 2786*4327Sdougm * the internal XML structure. Just need to flag it as 2787*4327Sdougm * changed for ZFS. 2788*4327Sdougm */ 2789*4327Sdougm zfs_set_update((sa_share_t)group); 2790*4327Sdougm } 27913034Sdougm } 27923034Sdougm 27933034Sdougm if (name != NULL) 2794*4327Sdougm sa_free_attr_string(name); 27953034Sdougm if (valstr != NULL) 2796*4327Sdougm sa_free_attr_string(valstr); 27973034Sdougm else if (entry != NULL) 2798*4327Sdougm scf_entry_destroy(entry); 27993034Sdougm 28003034Sdougm if (ret == -1) 2801*4327Sdougm ret = SA_SYSTEM_ERR; 28023034Sdougm 28033034Sdougm return (ret); 28043034Sdougm } 28053034Sdougm 28063034Sdougm /* 28073034Sdougm * sa_create_property(name, value) 28083034Sdougm * 28093034Sdougm * Create a new property with the specified name and value. 28103034Sdougm */ 28113034Sdougm 28123034Sdougm sa_property_t 28133034Sdougm sa_create_property(char *name, char *value) 28143034Sdougm { 28153034Sdougm xmlNodePtr node; 28163034Sdougm 28173034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 28183034Sdougm if (node != NULL) { 28193034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 28203034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 28213034Sdougm } 28223034Sdougm return ((sa_property_t)node); 28233034Sdougm } 28243034Sdougm 28253034Sdougm /* 28263034Sdougm * sa_add_property(object, property) 28273034Sdougm * 28283034Sdougm * Add the specified property to the object. Issue the appropriate 28293034Sdougm * transaction or mark a ZFS object as needing an update. 28303034Sdougm */ 28313034Sdougm 28323034Sdougm int 28333034Sdougm sa_add_property(void *object, sa_property_t property) 28343034Sdougm { 28353034Sdougm int ret = SA_OK; 28363034Sdougm sa_group_t parent; 28373034Sdougm sa_group_t group; 28383034Sdougm char *proto; 28393034Sdougm 28403034Sdougm proto = sa_get_optionset_attr(object, "type"); 28413034Sdougm if (property != NULL) { 2842*4327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 2843*4327Sdougm SA_OK) { 2844*4327Sdougm property = (sa_property_t)xmlAddChild( 2845*4327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 2846*4327Sdougm } else { 2847*4327Sdougm if (proto != NULL) 2848*4327Sdougm sa_free_attr_string(proto); 2849*4327Sdougm return (ret); 2850*4327Sdougm } 28513034Sdougm } 28523034Sdougm 28533034Sdougm if (proto != NULL) 2854*4327Sdougm sa_free_attr_string(proto); 28553034Sdougm 28563034Sdougm parent = sa_get_parent_group(object); 28573034Sdougm if (!is_persistent(parent)) { 2858*4327Sdougm return (ret); 28593034Sdougm } 28603034Sdougm 28613034Sdougm if (sa_is_share(parent)) 2862*4327Sdougm group = sa_get_parent_group(parent); 28633034Sdougm else 2864*4327Sdougm group = parent; 28653034Sdougm 2866*4327Sdougm if (property == NULL) { 2867*4327Sdougm ret = SA_NO_MEMORY; 2868*4327Sdougm } else { 2869*4327Sdougm char oname[SA_STRSIZE]; 28703034Sdougm 2871*4327Sdougm if (!is_zfs_group(group)) { 2872*4327Sdougm char *id = NULL; 2873*4327Sdougm sa_handle_impl_t impl_handle; 2874*4327Sdougm scfutilhandle_t *scf_handle; 28753910Sdougm 2876*4327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 2877*4327Sdougm group); 2878*4327Sdougm if (impl_handle == NULL || 2879*4327Sdougm impl_handle->scfhandle == NULL) 2880*4327Sdougm ret = SA_SYSTEM_ERR; 2881*4327Sdougm if (ret == SA_OK) { 2882*4327Sdougm scf_handle = impl_handle->scfhandle; 2883*4327Sdougm if (sa_is_share((sa_group_t)parent)) { 2884*4327Sdougm id = sa_get_share_attr( 2885*4327Sdougm (sa_share_t)parent, "id"); 2886*4327Sdougm } 2887*4327Sdougm if (scf_handle->trans == NULL) { 2888*4327Sdougm if (is_nodetype(object, "optionset")) { 2889*4327Sdougm (void) sa_optionset_name( 2890*4327Sdougm (sa_optionset_t)object, 2891*4327Sdougm oname, sizeof (oname), id); 2892*4327Sdougm } else { 2893*4327Sdougm (void) sa_security_name( 2894*4327Sdougm (sa_optionset_t)object, 2895*4327Sdougm oname, sizeof (oname), id); 2896*4327Sdougm } 2897*4327Sdougm ret = sa_start_transaction(scf_handle, 2898*4327Sdougm oname); 2899*4327Sdougm } 2900*4327Sdougm if (ret == SA_OK) { 2901*4327Sdougm char *name; 2902*4327Sdougm char *value; 2903*4327Sdougm name = sa_get_property_attr(property, 2904*4327Sdougm "type"); 2905*4327Sdougm value = sa_get_property_attr(property, 2906*4327Sdougm "value"); 2907*4327Sdougm if (name != NULL && value != NULL) { 2908*4327Sdougm if (scf_handle->scf_state == 2909*4327Sdougm SCH_STATE_INIT) { 2910*4327Sdougm ret = sa_set_property( 2911*4327Sdougm scf_handle, name, 2912*4327Sdougm value); 2913*4327Sdougm } 2914*4327Sdougm } else { 2915*4327Sdougm ret = SA_CONFIG_ERR; 2916*4327Sdougm } 2917*4327Sdougm if (name != NULL) 2918*4327Sdougm sa_free_attr_string( 2919*4327Sdougm name); 2920*4327Sdougm if (value != NULL) 2921*4327Sdougm sa_free_attr_string(value); 2922*4327Sdougm } 2923*4327Sdougm if (id != NULL) 2924*4327Sdougm sa_free_attr_string(id); 2925*4327Sdougm } 2926*4327Sdougm } else { 2927*4327Sdougm /* 2928*4327Sdougm * ZFS is a special case. We do want 2929*4327Sdougm * to allow editing property/security 2930*4327Sdougm * lists since we can have a better 2931*4327Sdougm * syntax and we also want to keep 2932*4327Sdougm * things consistent when possible. 2933*4327Sdougm * 2934*4327Sdougm * Right now, we defer until the 2935*4327Sdougm * sa_commit_properties so we can get 2936*4327Sdougm * them all at once. We do need to 2937*4327Sdougm * mark the share as "changed" 2938*4327Sdougm */ 2939*4327Sdougm zfs_set_update((sa_share_t)parent); 29403034Sdougm } 29413034Sdougm } 29423034Sdougm return (ret); 29433034Sdougm } 29443034Sdougm 29453034Sdougm /* 29463034Sdougm * sa_remove_property(property) 29473034Sdougm * 29483034Sdougm * Remove the specied property from its containing object. Update the 29493034Sdougm * repository as appropriate. 29503034Sdougm */ 29513034Sdougm 29523034Sdougm int 29533034Sdougm sa_remove_property(sa_property_t property) 29543034Sdougm { 29553034Sdougm int ret = SA_OK; 29563034Sdougm 29573034Sdougm if (property != NULL) { 29583034Sdougm sa_optionset_t optionset; 29593034Sdougm sa_group_t group; 29603034Sdougm optionset = sa_get_property_parent(property); 29613034Sdougm if (optionset != NULL) { 2962*4327Sdougm group = sa_get_optionset_parent(optionset); 2963*4327Sdougm if (group != NULL) { 2964*4327Sdougm ret = sa_set_prop_by_prop(optionset, group, 2965*4327Sdougm property, SA_PROP_OP_REMOVE); 2966*4327Sdougm } 29673034Sdougm } 29683034Sdougm xmlUnlinkNode((xmlNodePtr)property); 29693034Sdougm xmlFreeNode((xmlNodePtr)property); 29703034Sdougm } else { 2971*4327Sdougm ret = SA_NO_SUCH_PROP; 29723034Sdougm } 29733034Sdougm return (ret); 29743034Sdougm } 29753034Sdougm 29763034Sdougm /* 29773034Sdougm * sa_update_property(property, value) 29783034Sdougm * 29793034Sdougm * Update the specified property to the new value. If value is NULL, 29803034Sdougm * we currently treat this as a remove. 29813034Sdougm */ 29823034Sdougm 29833034Sdougm int 29843034Sdougm sa_update_property(sa_property_t property, char *value) 29853034Sdougm { 29863034Sdougm int ret = SA_OK; 29873034Sdougm if (value == NULL) { 29883034Sdougm return (sa_remove_property(property)); 29893034Sdougm } else { 29903034Sdougm sa_optionset_t optionset; 29913034Sdougm sa_group_t group; 29923034Sdougm set_node_attr((void *)property, "value", value); 29933034Sdougm optionset = sa_get_property_parent(property); 29943034Sdougm if (optionset != NULL) { 2995*4327Sdougm group = sa_get_optionset_parent(optionset); 2996*4327Sdougm if (group != NULL) { 2997*4327Sdougm ret = sa_set_prop_by_prop(optionset, group, 2998*4327Sdougm property, SA_PROP_OP_UPDATE); 2999*4327Sdougm } 30003034Sdougm } else { 3001*4327Sdougm ret = SA_NO_SUCH_PROP; 30023034Sdougm } 30033034Sdougm } 30043034Sdougm return (ret); 30053034Sdougm } 30063034Sdougm 30073034Sdougm /* 30083034Sdougm * sa_get_protocol_property(propset, prop) 30093034Sdougm * 30103034Sdougm * Get the specified protocol specific property. These are global to 30113034Sdougm * the protocol and not specific to a group or share. 30123034Sdougm */ 30133034Sdougm 30143034Sdougm sa_property_t 30153034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 30163034Sdougm { 30173034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 30183034Sdougm xmlChar *value = NULL; 30193034Sdougm 30203034Sdougm for (node = node->children; node != NULL; 3021*4327Sdougm node = node->next) { 3022*4327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 3023*4327Sdougm if (prop == NULL) 3024*4327Sdougm break; 3025*4327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 3026*4327Sdougm if (value != NULL && 3027*4327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 3028*4327Sdougm break; 3029*4327Sdougm } 3030*4327Sdougm if (value != NULL) { 3031*4327Sdougm xmlFree(value); 3032*4327Sdougm value = NULL; 3033*4327Sdougm } 30343034Sdougm } 30353034Sdougm } 30363034Sdougm if (value != NULL) 30373034Sdougm xmlFree(value); 30383034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 3039*4327Sdougm /* 3040*4327Sdougm * avoid a non option node -- it is possible to be a 3041*4327Sdougm * text node 3042*4327Sdougm */ 3043*4327Sdougm node = NULL; 30443034Sdougm } 30453034Sdougm return ((sa_property_t)node); 30463034Sdougm } 30473034Sdougm 30483034Sdougm /* 30493034Sdougm * sa_get_next_protocol_property(prop) 30503034Sdougm * 30513034Sdougm * Get the next protocol specific property in the list. 30523034Sdougm */ 30533034Sdougm 30543034Sdougm sa_property_t 30553034Sdougm sa_get_next_protocol_property(sa_property_t prop) 30563034Sdougm { 30573034Sdougm xmlNodePtr node; 30583034Sdougm 30593034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 3060*4327Sdougm node = node->next) { 30613034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 30623034Sdougm break; 30633034Sdougm } 30643034Sdougm } 30653034Sdougm return ((sa_property_t)node); 30663034Sdougm } 30673034Sdougm 30683034Sdougm /* 30693034Sdougm * sa_set_protocol_property(prop, value) 30703034Sdougm * 30713034Sdougm * Set the specified property to have the new value. The protocol 30723034Sdougm * specific plugin will then be called to update the property. 30733034Sdougm */ 30743034Sdougm 30753034Sdougm int 30763034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 30773034Sdougm { 30783034Sdougm sa_protocol_properties_t propset; 30793034Sdougm char *proto; 30803034Sdougm int ret = SA_INVALID_PROTOCOL; 30813034Sdougm 30823034Sdougm propset = ((xmlNodePtr)prop)->parent; 30833034Sdougm if (propset != NULL) { 3084*4327Sdougm proto = sa_get_optionset_attr(propset, "type"); 3085*4327Sdougm if (proto != NULL) { 3086*4327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 3087*4327Sdougm ret = sa_proto_set_property(proto, prop); 3088*4327Sdougm sa_free_attr_string(proto); 3089*4327Sdougm } 30903034Sdougm } 30913034Sdougm return (ret); 30923034Sdougm } 30933034Sdougm 30943034Sdougm /* 30953034Sdougm * sa_add_protocol_property(propset, prop) 30963034Sdougm * 30973034Sdougm * Add a new property to the protocol sepcific property set. 30983034Sdougm */ 30993034Sdougm 31003034Sdougm int 31013034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 31023034Sdougm { 31033034Sdougm xmlNodePtr node; 31043034Sdougm 31053034Sdougm /* should check for legitimacy */ 31063034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 31073034Sdougm if (node != NULL) 3108*4327Sdougm return (SA_OK); 31093034Sdougm return (SA_NO_MEMORY); 31103034Sdougm } 31113034Sdougm 31123034Sdougm /* 31133034Sdougm * sa_create_protocol_properties(proto) 31143034Sdougm * 31153034Sdougm * Create a protocol specifity property set. 31163034Sdougm */ 31173034Sdougm 31183034Sdougm sa_protocol_properties_t 31193034Sdougm sa_create_protocol_properties(char *proto) 31203034Sdougm { 31213034Sdougm xmlNodePtr node; 3122*4327Sdougm 31233034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 3124*4327Sdougm if (node != NULL) 3125*4327Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 31263034Sdougm return (node); 31273034Sdougm } 3128