summaryrefslogtreecommitdiff
path: root/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c
diff options
context:
space:
mode:
authoramw <none@none>2007-10-25 16:34:29 -0700
committeramw <none@none>2007-10-25 16:34:29 -0700
commitda6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch)
tree65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c
parente845e33dd0d1aea22db7edaa8c7d43955d24609b (diff)
downloadillumos-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.c1035
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);
+ }
+}