smb_kshare.c revision 4846df9b53c813b173160a71c267f6678e9bf59b
/*
* 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
* 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 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_door.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_ktypes.h>
typedef struct smb_unshare {
char us_sharename[MAXNAMELEN];
static smb_export_t smb_export;
static int smb_kshare_cmp(const void *, const void *);
static void smb_kshare_hold(const void *);
static boolean_t smb_kshare_rele(const void *);
static void smb_kshare_destroy(void *);
static char *smb_kshare_oemname(const char *);
static int smb_kshare_is_special(const char *);
static boolean_t smb_kshare_is_admin(const char *);
static void smb_kshare_unexport_thread(smb_thread_t *, void *);
static int smb_kshare_export(smb_kshare_t *);
static int smb_kshare_unexport(const char *);
static int smb_kshare_export_trans(char *, char *, char *);
static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
static boolean_t smb_export_isready(void);
static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
static smb_avl_nops_t smb_kshare_avlops = {
};
extern int smb_server_lookup(smb_server_t **);
extern void smb_server_release(smb_server_t *);
/*
* This function is not MultiThread safe. The caller has to make sure only one
* thread calls this function.
*/
{
return (door_ki_lookup(door_id));
}
/*
* This function is not MultiThread safe. The caller has to make sure only one
* thread calls this function.
*/
void
{
if (dhdl)
}
/*
* This is a special interface that will be utilized by ZFS to cause
*
* arg is either a smb_share_t or share_name from userspace.
* It will need to be copied into the kernel. It is smb_share_t
* for add operations and share_name for delete operations.
*/
int
{
door_arg_t doorarg = { 0 };
int error;
int rc;
unsigned int used;
int opcode;
switch (opcode) {
case SMB_SHROP_ADD:
return (error);
}
break;
case SMB_SHROP_DELETE:
return (error);
}
break;
}
if (lmshare)
return (NERR_InternalError);
}
if (error) {
if (lmshare)
return (error);
}
if (lmshare)
return (NERR_InternalError);
}
if (opcode == SMB_SHROP_ADD)
if (smb_dr_decode_finish(dec_ctx))
if (lmshare)
}
/*
* Executes map and unmap command for shares.
*/
int
{
int exec_rc = 0;
(void) smb_kdoor_upcall(SMB_DR_SHR_EXEC,
return (exec_rc);
}
/*
* Obtains any host access restriction on the specified
* share for the given host (ipaddr) by calling smbd
*/
{
if (smb_inet_iszero(ipaddr))
return (ACE_ALL_PERMS);
return (ACE_ALL_PERMS);
flag |= SMB_SHRF_ACC_RO;
flag |= SMB_SHRF_ACC_RW;
switch (host_access) {
case SMB_SHRF_ACC_RO:
break;
case SMB_SHRF_ACC_OPEN:
case SMB_SHRF_ACC_RW:
break;
case SMB_SHRF_ACC_NONE:
default:
access = 0;
}
return (access);
}
/*
* This function is called when smb_server_t is
* exporting SMB shares
*/
void
smb_export_start(void)
{
if (smb_export.e_ready) {
return;
}
}
/*
* This function is called when smb_server_t goes
* away which means SMB shares should not be made
* available to clients
*/
void
smb_export_stop(void)
{
if (!smb_export.e_ready) {
return;
}
}
int
smb_kshare_init(void)
{
int rc;
return (rc);
return (0);
}
void
smb_kshare_fini(void)
{
}
}
/*
* A list of shares in nvlist format can be sent down
* from userspace thourgh the IOCTL interface. The nvlist
* is unpacked here and all the shares in the list will
* be exported.
*/
int
{
char *shrname;
int rc = 0;
if (!smb_export_isready())
return (ENOTACTIVE);
return (rc);
!= 0)
goto out;
/*
* Since this loop can run for a while we want to exit
* as soon as the server state is anything but RUNNING
* to allow shutdown to proceed.
*/
goto out;
continue;
shrname);
continue;
}
shrname);
continue;
}
/* smb_kshare_export consumes shr so it's not leaked */
continue;
}
}
rc = 0;
out:
return (rc);
}
/*
* This function is invoked when a share is disabled to disconnect trees
* file system. Queueing the request for asynchronous processing allows the
* call to return immediately so that, if the unshare is being done in the
* context of a forced unmount, the forced unmount will always be able to
* proceed (unblocking stuck I/O and eventually allowing all blocked unshare
* processes to complete).
*
* The path lookup to find the root vnode of the VFS in question and the
* release of this vnode are done synchronously prior to any associated
* unmount. Doing these asynchronous to an associated unmount could run
* the risk of a spurious EBUSY for a standard unmount or an EIO during
* the path lookup due to a forced unmount finishing first.
*/
int
{
char *shrname;
int rc;
return (rc);
continue;
continue;
}
if (unexport)
return (0);
}
/*
* Get properties (currently only shortname enablement)
* of specified share.
*/
int
{
return (0);
}
/*
* This function builds a response for a NetShareEnum RAP request.
* List of shares is scanned twice. In the first round the total number
* of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
* and also the number of shares that fit in the given buffer are calculated.
* In the second round the shares data are encoded in the buffer.
*
* The data associated with each share has two parts, a fixed size part and
* a variable size part which is share's comment. The outline of the response
* buffer is so that fixed part for all the shares will appear first and follows
* with the comments for all those shares and that's why the data cannot be
* encoded in one round without unnecessarily complicating the code.
*/
void
{
int remained;
if (!smb_export_isready()) {
esi->es_datasize = 0;
return;
}
/* Do the necessary calculations in the first round */
continue;
}
} else {
continue;
}
}
if (remained <= 0) {
continue;
}
}
}
/* Encode the data in the second round */
continue;
}
} else {
continue;
}
}
break;
}
break;
}
}
}
/*
* Looks up the given share and returns a pointer
* to its definition if it's found. A hold on the
* object is taken before the pointer is returned
* in which case the caller MUST always call
* smb_kshare_release().
*/
smb_kshare_lookup(const char *shrname)
{
if (!smb_export_isready())
return (NULL);
return (shr);
}
/*
* Releases the hold taken on the specified share object
*/
void
{
}
/*
* Add the given share in the specified server.
* If the share is a disk share, smb_vfs_hold() is
* invoked to ensure that there is a hold on the
* corresponding file system before the share is
* added to shares AVL.
*
* If the share is an Autohome share and it is
* already in the AVL only a reference count for
* that share is incremented.
*/
static int
{
int rc = 0;
}
return (rc);
}
return (EEXIST);
}
auto_shr->shr_autocnt++;
return (0);
}
return (rc);
}
}
} else {
}
return (rc);
}
/*
* Removes the share specified by 'shrname' from the AVL
* tree of the given server if it's there.
*
* If the share is an Autohome share, the autohome count
* is decremented and the share is only removed if the
* count goes to zero.
*
* If the share is a disk share, the hold on the corresponding
* file system is released before removing the share from
* the AVL tree.
*/
static int
smb_kshare_unexport(const char *shrname)
{
int rc;
return (ENOENT);
shr->shr_autocnt--;
if (!auto_unexport) {
return (0);
}
}
return (rc);
}
}
return (0);
}
/*
* Exports IPC$ or Admin shares
*/
static int
{
else
if (path)
if (cmnt)
return (smb_kshare_export(shr));
}
/*
* Decodes share information in an nvlist format into a smb_kshare_t
* structure.
*
* This is a temporary function and will be replaced by functions
* provided by libsharev2 code after it's available.
*/
static smb_kshare_t *
{
int rc;
if (rc != 0) {
" (%d)", rc);
return (NULL);
}
if (rc != 0) {
return (NULL);
}
&tmp.shr_container);
if (rc != 0) {
" (%d)", rc);
return (NULL);
}
}
if (tmp.shr_container)
if (tmp.shr_access_none)
if (tmp.shr_access_ro)
if (tmp.shr_access_rw)
return (shr);
}
#if 0
static void
{
}
#endif
/*
* Compare function used by shares AVL
*/
static int
{
int rc;
if (rc < 0)
return (-1);
if (rc > 0)
return (1);
return (0);
}
/*
* This function is called by smb_avl routines whenever
* there is a need to take a hold on a share structure
* inside AVL
*/
static void
smb_kshare_hold(const void *p)
{
shr->shr_refcnt++;
}
/*
* This function must be called by smb_avl routines whenever
* smb_kshare_hold is called and the hold needs to be released.
*/
static boolean_t
smb_kshare_rele(const void *p)
{
shr->shr_refcnt--;
return (destroy);
}
/*
* Frees all the memory allocated for the given
* share structure. It also removes the structure
* from the share cache.
*/
static void
smb_kshare_destroy(void *p)
{
}
/*
* Generate an OEM name for the given share name. If the name is
* shorter than 13 bytes the oemname will be returned; otherwise NULL
* is returned.
*/
static char *
smb_kshare_oemname(const char *shrname)
{
char *oem_name;
int length;
return (NULL);
}
return (oem_name);
}
/*
* Special share reserved for interprocess communication (IPC$) or
* remote administration of the server (ADMIN$). Can also refer to
* administrative shares such as C$, D$, E$, and so forth.
*/
static int
smb_kshare_is_special(const char *sharename)
{
int len;
return (0);
return (0);
return (STYPE_SPECIAL);
return (0);
}
/*
* Check whether or not this is a default admin share: C$, D$ etc.
*/
static boolean_t
smb_kshare_is_admin(const char *sharename)
{
return (B_FALSE);
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Decodes the given boolean share option.
* If the option is present in the nvlist and it's value is true
* returns the corresponding flag value, otherwise returns 0.
*/
static uint32_t
{
char *boolp;
return (flag);
return (0);
}
/*
* Map a client-side caching (CSC) option to the appropriate share
* flag. Only one option is allowed; an error will be logged if
* multiple options have been specified. We don't need to do anything
* about multiple values here because the SRVSVC will not recognize
* a value containing multiple flags and will return the default value.
*
* If the option value is not recognized, it will be ignored: invalid
* values will typically be caught and rejected by sharemgr.
*/
static void
{
int i;
static struct {
char *value;
} cscopt[] = {
{ "disabled", SMB_SHRF_CSC_DISABLED },
{ "manual", SMB_SHRF_CSC_MANUAL },
{ "auto", SMB_SHRF_CSC_AUTO },
{ "vdo", SMB_SHRF_CSC_VDO }
};
return;
break;
}
}
case 0:
case SMB_SHRF_CSC_DISABLED:
case SMB_SHRF_CSC_MANUAL:
case SMB_SHRF_CSC_AUTO:
case SMB_SHRF_CSC_VDO:
break;
default:
break;
}
}
/*
* This function processes the unexport event list and disconnects shares
* asynchronously. The function executes as a zone-specific thread.
*
* The server arg passed in is safe to use without a reference count, because
* the server cannot be deleted until smb_thread_stop()/destroy() return,
* which is also when the thread exits.
*/
/*ARGSUSED*/
static void
{
while (smb_thread_continue(thread)) {
!= NULL) {
}
}
}
static boolean_t
smb_export_isready(void)
{
return (ready);
}
/*
* Return 0 upon success. Otherwise > 0
*/
static int
{
int err;
switch (status) {
case SMB_SHARE_DSUCCESS:
return (0);
case SMB_SHARE_DERROR:
(void) smb_dr_decode_finish(dec_ctx);
return (err);
}
ASSERT(0);
return (EINVAL);
}