diff options
author | amw <none@none> | 2007-10-25 16:34:29 -0700 |
---|---|---|
committer | amw <none@none> | 2007-10-25 16:34:29 -0700 |
commit | da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch) | |
tree | 65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c | |
parent | e845e33dd0d1aea22db7edaa8c7d43955d24609b (diff) | |
download | illumos-gate-da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0.tar.gz |
PSARC/2007/218 caller_context_t in all VOPs
PSARC/2007/227 VFS Feature Registration and ACL on Create
PSARC/2007/244 ZFS Case-insensitive support
PSARC/2007/315 Extensible Attribute Interfaces
PSARC/2007/394 ls(1) new command line options '-/' and '-%': CIFS system attributes support
PSARC/2007/403 Modified Access Checks for CIFS
PSARC/2007/410 Add system attribute support to chmod(1)
PSARC/2007/432 CIFS system attributes support for cp(1), pack(1), unpack(1), compress(1) and uncompress(1)
PSARC/2007/444 Rescind SETTABLE Attribute
PSARC/2007/459 CIFS system attributes support for cpio(1), pax(1), tar(1)
PSARC/2007/546 Update utilities to match CIFS system attributes changes.
PSARC/2007/560 ZFS sharesmb property
4890717 want append-only files
6417428 Case-insensitive file system name lookup to support CIFS
6417435 DOS attributes and additional timestamps to support for CIFS
6417442 File system quarantined and modified attributes to support an integrated Anti-Virus service
6417453 FS boolean property for rejecting/allowing invalid UTF-8 sequences in file names
6473733 RFE: Need support for open-deny modes
6473755 RFE: Need ability to reconcile oplock and delegation conflicts
6494624 sharemgr needs to support CIFS shares better
6546705 All vnode operations need to pass caller_context_t
6546706 Need VOP_SETATTR/VOP_GETATTR to support new, optional attributes
6546893 Solaris system attribute support
6550962 ZFS ACL inheritance needs to be enhanced to support Automatic Inheritance
6553589 RFE: VFS Feature Registration facility
6553770 RFE: ZFS support for ACL-on-CREATE (PSARC 2007/227)
6565581 ls(1) should support file system attributes proposed in PSARC/2007/315
6566784 NTFS streams are not copied along with the files.
6576205 cp(1), pack(1) and compress(1) should support file system attributes proposed in PSARC/2007/315
6578875 RFE: kernel interfaces for nbmand need improvement
6578883 RFE: VOP_SHRLOCK needs additional access types
6578885 chmod(1) should support file system attributes proposed in PSARC/2007/315
6578886 RFE: disallow nbmand state to change on remount
6583349 ACL parser needs to support audit/alarm ACE types
6590347 tar(1) should support filesystem attributes proposed in PSARC/2007/315
6597357 *tar* xv@ doesn't show the hidden directory even though it is restored
6597360 *tar* should re-init xattr info if openat() fails during extraction of and extended attribute
6597368 *tar* cannot restore hard linked extended attributes
6597374 *tar* doesn't display "x " when hard linked attributes are restored
6597375 *tar* extended attribute header off by one
6614861 *cpio* incorrectly archives extended system attributes with -@
6614896 *pax* incorrectly archives extended system attributes with -@
6615225 *tar* incorrectly archives extended system attributes with -@
6617183 CIFS Service - PSARC 2006/715
Diffstat (limited to 'usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c')
-rw-r--r-- | usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c b/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c new file mode 100644 index 0000000000..1f5083f448 --- /dev/null +++ b/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c @@ -0,0 +1,1035 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* helper functions for using libscf with CIFS */ + +#include <libscf.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <errno.h> +#include <libintl.h> +#include <assert.h> +#include <strings.h> + +#include <uuid/uuid.h> +#include <sys/param.h> + +#include <smbsrv/alloc.h> + +#include <smbsrv/libsmb.h> + +/* + * smb_smf_scf_log_error(msg) + * Logs error messages from scf API's + */ +static void +smb_smf_scf_log_error(char *msg) +{ + if (!msg) { + syslog(LOG_ERR, " SMBD SMF problem: %s\n", + scf_strerror(scf_error())); + } else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/ + syslog(LOG_ERR, msg, scf_strerror(scf_error())); + } +} + +/* + * Check if instance with given name exists for a service. + * Returns 0 is instance exist + */ +int +smb_smf_instance_exists(smb_scfhandle_t *handle, char *inst_name) +{ + int ret = SMBD_SMF_OK; + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + handle->scf_instance = scf_instance_create(handle->scf_handle); + if (scf_service_get_instance(handle->scf_service, inst_name, + handle->scf_instance) != SCF_SUCCESS) + ret = SMBD_SMF_SYSTEM_ERR; + + scf_instance_destroy(handle->scf_instance); + handle->scf_instance = NULL; + return (ret); +} + +/* + * Create a service instance. returns 0 if successful. + * If instance already exists enable it. + */ +int +smb_smf_instance_create(smb_scfhandle_t *handle, char *serv_prefix, + char *inst_name) +{ + char *instance; + int ret = SMBD_SMF_OK; + int sz; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + if (!serv_prefix || !inst_name) + return (SMBD_SMF_SYSTEM_ERR); + + sz = strlen(serv_prefix) + strlen(inst_name) + 2; + instance = malloc(sz); + if (!instance) + return (SMBD_SMF_NO_MEMORY); + + (void) snprintf(instance, sz, "%s:%s", serv_prefix, inst_name); + handle->scf_instance = scf_instance_create(handle->scf_handle); + if (scf_service_get_instance(handle->scf_service, inst_name, + handle->scf_instance) != SCF_SUCCESS) { + if (scf_service_add_instance(handle->scf_service, + inst_name, handle->scf_instance) == SCF_SUCCESS) { + if (smf_enable_instance(instance, 0)) + ret = SMBD_SMF_SYSTEM_ERR; + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + if (smf_enable_instance(instance, 0)) + ret = SMBD_SMF_SYSTEM_ERR; + } + free(instance); + return (ret); +} + +/* + * Delete a specified instance. Return SMBD_SMF_OK for success. + */ +int +smb_smf_instance_delete(smb_scfhandle_t *handle, char *inst_name) +{ + int ret = SMBD_SMF_OK; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + handle->scf_instance = scf_instance_create(handle->scf_handle); + if (scf_service_get_instance(handle->scf_service, inst_name, + handle->scf_instance) == SCF_SUCCESS) { + if (scf_instance_delete(handle->scf_instance) == SCF_SUCCESS) { + return (ret); + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + smb_smf_scf_log_error(NULL); + ret = SMBD_SMF_SYSTEM_ERR; + } + return (ret); +} + +/* + * smb_smf_create_service_pgroup(handle, pgroup) + * + * create a new property group at service level. + */ +int +smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBD_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBD_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) + handle->scf_pg = scf_pg_create(handle->scf_handle); + + /* + * if the pgroup exists, we are done. If it doesn't, then we + * need to actually add one to the service instance. + */ + if (scf_service_get_pg(handle->scf_service, + pgroup, handle->scf_pg) != 0) { + /* doesn't exist so create one */ + if (scf_service_add_pg(handle->scf_service, pgroup, + SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error(NULL); + switch (err) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + default: + ret = SMBD_SMF_SYSTEM_ERR; + break; + } + } + } + return (ret); +} + +/* + * smb_smf_create_instance_pgroup(handle, pgroup) + * + * create a new property group at instance level. + */ +int +smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBD_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBD_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) + handle->scf_pg = scf_pg_create(handle->scf_handle); + + /* + * if the pgroup exists, we are done. If it doesn't, then we + * need to actually add one to the service instance. + */ + if (scf_instance_get_pg(handle->scf_instance, + pgroup, handle->scf_pg) != 0) { + /* doesn't exist so create one */ + if (scf_instance_add_pg(handle->scf_instance, pgroup, + SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error(NULL); + switch (err) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + default: + ret = SMBD_SMF_SYSTEM_ERR; + break; + } + } + } + return (ret); +} + +/* + * smb_smf_delete_service_pgroup(handle, pgroup) + * + * remove the property group from the current service. + * but only if it actually exists. + */ +int +smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBD_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBD_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) + handle->scf_pg = scf_pg_create(handle->scf_handle); + + /* + * only delete if it does exist. + */ + if (scf_service_get_pg(handle->scf_service, + pgroup, handle->scf_pg) == 0) { + /* does exist so delete it */ + if (scf_pg_delete(handle->scf_pg) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + err = scf_error(); + if (err != SCF_ERROR_NONE) { + smb_smf_scf_log_error("SMF delpg " + "problem: %s\n"); + } + } + } else { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error("SMF getpg problem: %s\n"); + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR && + scf_error() == SCF_ERROR_PERMISSION_DENIED) { + ret = SMBD_SMF_NO_PERMISSION; + } + return (ret); +} + +/* + * smb_smf_delete_instance_pgroup(handle, pgroup) + * + * remove the property group from the current instance. + * but only if it actually exists. + */ +int +smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBD_SMF_OK; + int err; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) + handle->scf_pg = scf_pg_create(handle->scf_handle); + + /* + * only delete if it does exist. + */ + if (scf_instance_get_pg(handle->scf_instance, + pgroup, handle->scf_pg) == 0) { + /* does exist so delete it */ + if (scf_pg_delete(handle->scf_pg) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + err = scf_error(); + if (err != SCF_ERROR_NONE) { + smb_smf_scf_log_error("SMF delpg " + "problem: %s\n"); + } + } + } else { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error("SMF getpg problem: %s\n"); + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR && + scf_error() == SCF_ERROR_PERMISSION_DENIED) + ret = SMBD_SMF_NO_PERMISSION; + + return (ret); +} + +/* + * Start transaction on current pg in handle. + * The pg could be service or instance level. + * Must be called after pg handle is obtained + * from create or get. + */ +int +smb_smf_start_transaction(smb_scfhandle_t *handle) +{ + int ret = SMBD_SMF_OK; + + if (!handle || (!handle->scf_pg)) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * lookup the property group and create it if it doesn't already + * exist. + */ + if (handle->scf_state == SCH_STATE_INIT) { + if (ret == SMBD_SMF_OK) { + handle->scf_trans = + scf_transaction_create(handle->scf_handle); + if (handle->scf_trans != NULL) { + if (scf_transaction_start(handle->scf_trans, + handle->scf_pg) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + scf_transaction_destroy( + handle->scf_trans); + handle->scf_trans = NULL; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } + } + if (ret == SMBD_SMF_SYSTEM_ERR && + scf_error() == SCF_ERROR_PERMISSION_DENIED) + ret = SMBD_SMF_NO_PERMISSION; + + return (ret); +} + +/* + * smb_smf_end_transaction(handle) + * + * Commit the changes that were added to the transaction in the + * handle. Do all necessary cleanup. + */ +int +smb_smf_end_transaction(smb_scfhandle_t *handle) +{ + int ret = SMBD_SMF_OK; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + if (handle->scf_trans == NULL) { + ret = SMBD_SMF_SYSTEM_ERR; + } else { + if (scf_transaction_commit(handle->scf_trans) < 0) { + ret = SMBD_SMF_SYSTEM_ERR; + smb_smf_scf_log_error("Failed to commit " + "transaction: %s"); + } + scf_transaction_destroy_children(handle->scf_trans); + scf_transaction_destroy(handle->scf_trans); + handle->scf_trans = NULL; + } + return (ret); +} + +/* + * Deletes property in current pg + */ +int +smb_smf_delete_property(smb_scfhandle_t *handle, char *propname) +{ + int ret = SMBD_SMF_OK; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + entry = scf_entry_create(handle->scf_handle); + if (entry != NULL) { + if (scf_transaction_property_delete(handle->scf_trans, entry, + propname) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + } + } + + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if ((ret != SMBD_SMF_OK) && (entry != NULL)) + scf_entry_destroy(entry); + + return (ret); +} + +/* + * Sets string property in current pg + */ +int +smb_smf_set_string_property(smb_scfhandle_t *handle, + char *propname, char *valstr) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value = NULL; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_ASTRING) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_ASTRING) == 0) { + if (scf_value_set_astring(value, valstr) == 0) { + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } else { + /* value couldn't be constructed */ + ret = SMBD_SMF_SYSTEM_ERR; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + } + } + + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Gets string property value.upto sz size. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname, + char *valstr, size_t sz) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value; + scf_property_t *prop; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if (value && prop && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_astring(value, valstr, sz) < 0) { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Set integer value of property. + * The value is returned as int64_t value + * Caller ensures appropriate translation. + */ +int +smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname, + int64_t valint) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value = NULL; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_INTEGER) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_INTEGER) == 0) { + scf_value_set_integer(value, valint); + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + } + } + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Gets integer property value. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname, + int64_t *valint) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value = NULL; + scf_property_t *prop = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if ((prop) && (value) && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_integer(value, + valint) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Set boolean value of property. + * The value is returned as int64_t value + * Caller ensures appropriate translation. + */ +int +smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname, + uint8_t valbool) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value = NULL; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_BOOLEAN) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_BOOLEAN) == 0) { + scf_value_set_boolean(value, valbool); + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + } + } + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Gets boolean property value. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname, + uint8_t *valbool) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value = NULL; + scf_property_t *prop = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if ((prop) && (value) && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_boolean(value, + valbool) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Sets a blob property value. + */ +int +smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname, + void *voidval, size_t sz) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value; + scf_transaction_entry_t *entry; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_OPAQUE) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_OPAQUE) == 0) { + if (scf_value_set_opaque(value, voidval, sz) == 0) { + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBD_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } else { + /* value couldn't be constructed */ + ret = SMBD_SMF_SYSTEM_ERR; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (ret == SMBD_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBD_SMF_NO_PERMISSION; + break; + } + } + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Gets a blob property value. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname, + void *v, size_t sz) +{ + int ret = SMBD_SMF_OK; + scf_value_t *value = NULL; + scf_property_t *prop = NULL; + + if (handle == NULL) + return (SMBD_SMF_SYSTEM_ERR); + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if ((prop) && (value) && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_opaque(value, (char *)v, sz) != sz) { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + } else { + ret = SMBD_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Get property based on property type. Returns string value of that + * property. Only SCF_TYPE_ASTRING, SCF_TYPE_INTEGER, SCF_TYPE_BOOLEAN + * supported. + */ +int +smb_smf_get_property(smb_scfhandle_t *handle, int proptype, char *propname, + char *valstr, size_t sz) +{ + int64_t valint = 0; + uint8_t valbool = 0; + int ret = SMBD_SMF_OK; + + switch (proptype) { + case SCF_TYPE_ASTRING: + ret = smb_smf_get_string_property(handle, propname, + valstr, sz); + break; + case SCF_TYPE_INTEGER: + if ((ret = smb_smf_get_integer_property(handle, propname, + &valint)) != 0) + return (ret); + (void) snprintf(valstr, sz, "%lld", valint); + break; + case SCF_TYPE_BOOLEAN: + if ((ret = smb_smf_get_boolean_property(handle, propname, + &valbool)) != 0) + return (ret); + (void) strlcpy(valstr, (valbool ? "true" : "false"), sz); + break; + default: + return (SMBD_SMF_SYSTEM_ERR); + } + return (ret); +} + +/* + * Set property based on property type. + * Only SCF_TYPE_ASTRING, SCF_TYPE_INTEGER, SCF_TYPE_BOOLEAN supported. + */ +int +smb_smf_set_property(smb_scfhandle_t *handle, int proptype, + char *propname, char *valstr) +{ + int64_t valint = 0; + uint8_t valbool = 0; + int ret = SMBD_SMF_OK; + + switch (proptype) { + case SCF_TYPE_ASTRING: + ret = smb_smf_set_string_property(handle, propname, + valstr); + break; + case SCF_TYPE_INTEGER: + valint = strtol(valstr, 0, 10); + ret = smb_smf_set_integer_property(handle, propname, + valint); + break; + case SCF_TYPE_BOOLEAN: + if (strcasecmp(valstr, "true") == 0) + valbool = 1; + ret = smb_smf_set_boolean_property(handle, propname, valbool); + break; + default: + return (SMBD_SMF_SYSTEM_ERR); + } + return (ret); +} + +/* + * Gets an instance iterator for the service specified. + */ +smb_scfhandle_t * +smb_smf_get_iterator(char *svc_name) +{ + smb_scfhandle_t *handle = NULL; + + handle = smb_smf_scf_init(svc_name); + if (!handle) + return (NULL); + + handle->scf_inst_iter = scf_iter_create(handle->scf_handle); + if (handle->scf_inst_iter) { + if (scf_iter_service_instances(handle->scf_inst_iter, + handle->scf_service) != 0) { + smb_smf_scf_fini(handle); + handle = NULL; + } else { + handle->scf_instance = NULL; + } + } else { + smb_smf_scf_fini(handle); + handle = NULL; + } + return (handle); +} + +/* + * smb_smf_scf_init() + * + * must be called before using any of the SCF functions. + * Returns smb_scfhandle_t pointer if success. + */ +smb_scfhandle_t * +smb_smf_scf_init(char *svc_name) +{ + smb_scfhandle_t *handle; + + handle = malloc(sizeof (smb_scfhandle_t)); + if (handle != NULL) { + bzero((char *)handle, sizeof (smb_scfhandle_t)); + handle->scf_state = SCH_STATE_INITIALIZING; + handle->scf_handle = scf_handle_create(SCF_VERSION); + if (handle->scf_handle != NULL) { + if (scf_handle_bind(handle->scf_handle) == 0) { + handle->scf_scope = + scf_scope_create(handle->scf_handle); + if (scf_handle_get_local_scope( + handle->scf_handle, handle->scf_scope) != 0) + goto err; + + handle->scf_service = + scf_service_create(handle->scf_handle); + + if (scf_scope_get_service(handle->scf_scope, + svc_name, handle->scf_service) + != SCF_SUCCESS) { + goto err; + } + handle->scf_pg = + scf_pg_create(handle->scf_handle); + handle->scf_state = SCH_STATE_INIT; + } else { + goto err; + } + } else { + free(handle); + handle = NULL; + smb_smf_scf_log_error("Could not access SMF " + "repository: %s\n"); + } + } + return (handle); + + /* error handling/unwinding */ +err: + (void) smb_smf_scf_fini(handle); + (void) smb_smf_scf_log_error("SMF initialization problem: %s\n"); + return (NULL); +} + +/* + * smb_smf_scf_fini(handle) + * + * must be called when done. Called with the handle allocated in + * smb_smf_scf_init(), it cleans up the state and frees any SCF resources + * still in use. + */ +void +smb_smf_scf_fini(smb_scfhandle_t *handle) +{ + if (handle != NULL) { + int unbind = 0; + scf_iter_destroy(handle->scf_pg_iter); + handle->scf_pg_iter = NULL; + + scf_iter_destroy(handle->scf_inst_iter); + handle->scf_inst_iter = NULL; + + unbind = 1; + scf_scope_destroy(handle->scf_scope); + handle->scf_scope = NULL; + + scf_instance_destroy(handle->scf_instance); + handle->scf_instance = NULL; + + scf_service_destroy(handle->scf_service); + handle->scf_service = NULL; + + scf_pg_destroy(handle->scf_pg); + handle->scf_pg = NULL; + + handle->scf_state = SCH_STATE_UNINIT; + if (unbind) + (void) scf_handle_unbind(handle->scf_handle); + scf_handle_destroy(handle->scf_handle); + handle->scf_handle = NULL; + + free(handle); + } +} |