2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <syslog.h>
2N/A#include <errno.h>
2N/A#include <libshare.h>
2N/A#include <sharefs/share.h>
2N/A
2N/A#include <smbsrv/smb_share.h>
2N/A#include <smbsrv/libsmb.h>
2N/A
2N/Astatic struct {
2N/A char *value;
2N/A uint32_t flag;
2N/A} cscopt[] = {
2N/A { "disabled", SMB_SHRF_CSC_DISABLED },
2N/A { "manual", SMB_SHRF_CSC_MANUAL },
2N/A { "auto", SMB_SHRF_CSC_AUTO },
2N/A { "vdo", SMB_SHRF_CSC_VDO }
2N/A};
2N/A
2N/Astatic uint32_t smb_share_mklist(libshare_handle_t *, const smb_share_t *,
2N/A nvlist_t **);
2N/A
2N/A/*
2N/A * Sends the given share definition to libshare
2N/A * to be exported.
2N/A */
2N/Auint32_t
2N/Asmb_share_add(const smb_share_t *si)
2N/A{
2N/A libshare_handle_t *shdl;
2N/A nvlist_t *share;
2N/A int status;
2N/A int rc;
2N/A
2N/A if ((status = smb_name_validate_share(si->shr_name)) != ERROR_SUCCESS)
2N/A return (status);
2N/A
2N/A if ((shdl = sa_open()) == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if ((status = smb_share_mklist(shdl, si, &share)) != ERROR_SUCCESS) {
2N/A sa_close(shdl);
2N/A return (status);
2N/A }
2N/A
2N/A rc = sa_share_publish(shdl, share, SA_PROT_SMB, 0, B_FALSE);
2N/A
2N/A sa_share_free(share);
2N/A sa_close(shdl);
2N/A
2N/A return (smb_share_lmerr(rc));
2N/A}
2N/A
2N/A/*
2N/A * Asks smbsrv to remove the specified share
2N/A */
2N/Auint32_t
2N/Asmb_share_remove(const char *share_name)
2N/A{
2N/A smb_share_t si;
2N/A libshare_handle_t *shdl;
2N/A nvlist_t *share;
2N/A uint32_t status;
2N/A int rc;
2N/A
2N/A if (share_name == NULL)
2N/A return (NERR_NetNameNotFound);
2N/A
2N/A bzero(&si, sizeof (si));
2N/A if ((si.shr_name = strdup(share_name)) == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if ((shdl = sa_open()) == NULL) {
2N/A free(si.shr_name);
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A }
2N/A
2N/A if ((status = smb_share_mklist(shdl, &si, &share)) != ERROR_SUCCESS) {
2N/A free(si.shr_name);
2N/A sa_close(shdl);
2N/A return (status);
2N/A }
2N/A
2N/A rc = sa_share_unpublish(shdl, share, SA_PROT_SMB, 0);
2N/A
2N/A sa_share_free(share);
2N/A free(si.shr_name);
2N/A sa_close(shdl);
2N/A
2N/A return (smb_share_lmerr(rc));
2N/A}
2N/A
2N/Auint32_t
2N/Asmb_share_count(void)
2N/A{
2N/A return (smb_kmod_share_count(SMB_SHARENUM_FLAG_ALL));
2N/A}
2N/A
2N/A/*
2N/A * Return B_TRUE if the share exists. Otherwise return B_FALSE.
2N/A */
2N/Aboolean_t
2N/Asmb_share_exists(const char *sharename)
2N/A{
2N/A return ((smb_share_lookup(sharename, NULL) == NERR_Success));
2N/A}
2N/A
2N/A/*
2N/A * Lookup a share by path. The path can be the empty string.
2N/A *
2N/A * If the share-info pointer is non-null, the share data is returned in si.
2N/A *
2N/A * If the share-info is null, the share is still looked up and the result
2N/A * indicates whether or not the path is shared.
2N/A */
2N/Auint32_t
2N/Asmb_share_check(const char *path, smb_share_t *si)
2N/A{
2N/A if (path == NULL)
2N/A return (NERR_NetNameNotFound);
2N/A
2N/A return (smb_kmod_share_lookup(path, SMB_SHRKEY_WINPATH, si));
2N/A}
2N/A
2N/A/*
2N/A * Lookup a share by name.
2N/A *
2N/A * If the share-info pointer is non-null, the share data is returned in si.
2N/A *
2N/A * If the share-info is null, the share is still looked up and the result
2N/A * indicates whether or not a share with the specified name exists.
2N/A */
2N/Auint32_t
2N/Asmb_share_lookup(const char *sharename, smb_share_t *si)
2N/A{
2N/A if (sharename == NULL || *sharename == '\0')
2N/A return (NERR_NetNameNotFound);
2N/A
2N/A if (smb_name_validate_share(sharename) != NERR_Success)
2N/A return (NERR_NetNameNotFound);
2N/A
2N/A return (smb_kmod_share_lookup(sharename, SMB_SHRKEY_NAME, si));
2N/A}
2N/A
2N/Avoid
2N/Asmb_share_free(smb_share_t *si)
2N/A{
2N/A if (si == NULL)
2N/A return;
2N/A
2N/A free(si->shr_name);
2N/A free(si->shr_path);
2N/A free(si->shr_cmnt);
2N/A free(si->shr_container);
2N/A free(si->shr_winpath);
2N/A free(si->shr_access_none);
2N/A free(si->shr_access_ro);
2N/A free(si->shr_access_rw);
2N/A}
2N/A
2N/A/*
2N/A * Return the option name for the first CSC flag (there should be only
2N/A * one) encountered in the share flags.
2N/A */
2N/Achar *
2N/Asmb_share_csc_name(const smb_share_t *si)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
2N/A if (si->shr_flags & cscopt[i].flag)
2N/A return (cscopt[i].value);
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * Map a client-side caching (CSC) option to the appropriate share
2N/A * flag. Only one option is allowed; an error will be logged if
2N/A * multiple options have been specified. We don't need to do anything
2N/A * about multiple values here because the SRVSVC will not recognize
2N/A * a value containing multiple flags and will return the default value.
2N/A *
2N/A * If the option value is not recognized, it will be ignored: invalid
2N/A * values will typically be caught and rejected by sharemgr.
2N/A */
2N/Avoid
2N/Asmb_share_csc_option(const char *value, smb_share_t *si)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
2N/A if (strcasecmp(value, cscopt[i].value) == 0) {
2N/A si->shr_flags |= cscopt[i].flag;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
2N/A case 0:
2N/A case SMB_SHRF_CSC_DISABLED:
2N/A case SMB_SHRF_CSC_MANUAL:
2N/A case SMB_SHRF_CSC_AUTO:
2N/A case SMB_SHRF_CSC_VDO:
2N/A break;
2N/A
2N/A default:
2N/A syslog(LOG_INFO, "csc option conflict: 0x%08x",
2N/A si->shr_flags & SMB_SHRF_CSC_MASK);
2N/A break;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Check that the client-side caching (CSC) option value is valid.
2N/A */
2N/Aboolean_t
2N/Asmb_share_csc_valid(const char *value)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
2N/A if (strcasecmp(value, cscopt[i].value) == 0)
2N/A return (B_TRUE);
2N/A }
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * Converts libshare error codes to Win32 error codes.
2N/A */
2N/Auint32_t
2N/Asmb_share_lmerr(int sa_err)
2N/A{
2N/A switch (sa_err) {
2N/A case SA_OK:
2N/A return (NERR_Success);
2N/A case SA_SHARE_NOT_FOUND:
2N/A return (NERR_NetNameNotFound);
2N/A case SA_NO_MEMORY:
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A case SA_DUPLICATE_NAME:
2N/A return (NERR_DuplicateShare);
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A return (NERR_InternalError);
2N/A}
2N/A
2N/A/*
2N/A * This function converts the given smb_share_t
2N/A * structure to the nvlist share format.
2N/A */
2N/Astatic uint32_t
2N/Asmb_share_mklist(libshare_handle_t *shdl, const smb_share_t *si,
2N/A nvlist_t **ret_share)
2N/A{
2N/A nvlist_t *share;
2N/A nvlist_t *props;
2N/A char *csc;
2N/A int rc = 0;
2N/A char *mntpnt;
2N/A
2N/A *ret_share = NULL;
2N/A
2N/A if ((share = sa_share_alloc(si->shr_name, si->shr_path)) == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (si->shr_path != NULL) {
2N/A /*
2N/A * add global share properties to share nvlist
2N/A * start with share description
2N/A */
2N/A if (si->shr_cmnt) {
2N/A if ((rc = sa_share_set_desc(share, si->shr_cmnt))
2N/A != SA_OK) {
2N/A sa_share_free(share);
2N/A return (smb_share_lmerr(rc));
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Now add the mount point, derived from path
2N/A */
2N/A if ((mntpnt = malloc(MAXPATHLEN)) == NULL) {
2N/A sa_share_free(share);
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A }
2N/A
2N/A if ((rc = sa_get_mntpnt_for_path(shdl, si->shr_path, mntpnt,
2N/A MAXPATHLEN, NULL, NULL, 0, NULL, 0)) != SA_OK) {
2N/A /* could not resolve mntpnt use "" */
2N/A free(mntpnt);
2N/A if ((mntpnt = strdup("")) == NULL) {
2N/A sa_share_free(share);
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A }
2N/A }
2N/A
2N/A rc = sa_share_set_mntpnt(share, mntpnt);
2N/A free(mntpnt);
2N/A if (rc != SA_OK) {
2N/A sa_share_free(share);
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A }
2N/A
2N/A /*
2N/A * Now add protocol specific properties
2N/A * These are stored in an embedded nvlist
2N/A */
2N/A if ((rc = sa_share_set_def_proto(share, SA_PROT_SMB))
2N/A != SA_OK) {
2N/A sa_share_free(share);
2N/A return (smb_share_lmerr(rc));
2N/A }
2N/A
2N/A if ((props = sa_share_get_proto(share, SA_PROT_SMB)) == NULL) {
2N/A sa_share_free(share);
2N/A return (NERR_InternalError);
2N/A }
2N/A
2N/A if (si->shr_container)
2N/A rc |= sa_share_set_prop(props, SHOPT_AD_CONTAINER,
2N/A si->shr_container);
2N/A if (si->shr_access_none)
2N/A rc |= sa_share_set_prop(props, SHOPT_NONE,
2N/A si->shr_access_none);
2N/A if (si->shr_access_ro)
2N/A rc |= sa_share_set_prop(props, SHOPT_RO,
2N/A si->shr_access_ro);
2N/A if (si->shr_access_rw)
2N/A rc |= sa_share_set_prop(props, SHOPT_RW,
2N/A si->shr_access_rw);
2N/A
2N/A if ((si->shr_flags & SMB_SHRF_TRANS) != 0)
2N/A rc |= sa_share_set_transient(share);
2N/A if ((si->shr_flags & SMB_SHRF_ABE) != 0)
2N/A rc |= sa_share_set_prop(props, SHOPT_ABE, "true");
2N/A if ((si->shr_flags & SMB_SHRF_CATIA) != 0)
2N/A rc |= sa_share_set_prop(props, SHOPT_CATIA, "true");
2N/A if ((si->shr_flags & SMB_SHRF_GUEST_OK) != 0)
2N/A rc |= sa_share_set_prop(props, SHOPT_GUEST, "true");
2N/A if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
2N/A rc |= sa_share_set_prop(props, SHOPT_DFSROOT, "true");
2N/A
2N/A if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
2N/A rc |= sa_share_set_prop(props, "Autohome", "true");
2N/A rc |= nvlist_add_uint32(props, "uid", si->shr_uid);
2N/A rc |= nvlist_add_uint32(props, "gid", si->shr_gid);
2N/A }
2N/A
2N/A rc |= nvlist_add_byte(props, "drive", si->shr_drive);
2N/A
2N/A if ((csc = smb_share_csc_name(si)) != NULL)
2N/A rc |= sa_share_set_prop(props, SHOPT_CSC, csc);
2N/A
2N/A rc |= nvlist_add_uint32(props, "type", si->shr_type);
2N/A
2N/A if (rc != 0) {
2N/A sa_share_free(share);
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A }
2N/A }
2N/A
2N/A *ret_share = share;
2N/A return (ERROR_SUCCESS);
2N/A}