lmshare.c revision 3ad684d66b78e06edd37e2c4fd3b3949f095194b
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* returns Win32 error codes, usually network error values (lmerr.h).
*/
#include <errno.h>
#include <synch.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <syslog.h>
#include <thread.h>
#include <fcntl.h>
#include <unistd.h>
#include <netdb.h>
#include <synch.h>
#include <pthread.h>
#include <ctype.h>
#include <smbsrv/libsmbns.h>
#include <libshare.h>
#include <smbsrv/smb_vops.h>
#define LMSHR_HASHTAB_SZ 1024
static rwlock_t lmshare_lock;
static pthread_t lmshare_load_thread;
static void *lmshare_load(void *);
static DWORD lmshare_create_table(void);
static int lmshare_delete_shmgr(struct lmshare_info *);
static int lmshare_setinfo_shmgr(struct lmshare_info *);
static DWORD lmshare_set_refcnt(char *, int);
static void lmshare_set_oemname(lmshare_info_t *);
typedef struct lmshare_ad_item {
char name[MAXNAMELEN];
char container[MAXPATHLEN];
char flag;
typedef struct lmshare_ad_queue {
int nentries;
static lmshare_ad_queue_t ad_queue;
static int publish_on = 0;
static pthread_t lmshare_publish_thread;
static void *lmshare_publisher(void *);
static void lmshare_stop_publish();
/*
* Start loading lmshare information from sharemanager
* and create the cache.
*/
int
{
int rc;
lmshare_publisher, 0);
if (rc != 0) {
"share publishing is disabled");
}
lmshare_load, 0);
if (rc != 0) {
"existing shares will not be available");
}
return (rc);
}
void
{
}
/*
* lmshare_load_shares
*
* Helper function for lmshare_load. It attempts to load the shares
* contained in the group.
*/
static void
{
/* Don't bother if "smb" isn't set on the group */
return;
continue;
}
"resource for path: %s", path);
continue;
}
}
}
/* We are done with all shares for same path */
}
}
/*
* lmshare_load
*
* Load shares from sharemanager. The args argument is currently not
* used. The function walks through all the groups in libshare and
* calls lmshare_load_shares for each group found. It also looks for
* sub-groups and calls lmshare_load_shares for each sub-group found.
*/
/*ARGSUSED*/
static void *
lmshare_load(void *args)
{
char *gstate;
if (lmshare_create_table() != NERR_Success) {
return (NULL);
}
"information: no libshare handle");
return (NULL);
}
continue;
/* Skip disabled or unknown state group */
continue;
}
/*
* Attempt to load the shares. lmshare_load_shares
* will check to see if the protocol is enabled or
* not. We then want to check for any sub-groups on
* this group. This is needed in the ZFS case where
* the top level ZFS group won't have "smb" protocol
* enabled but the sub-groups will.
*/
}
}
return (NULL);
}
/*
* lmshare_callback
*
* Call back to free share structures stored
* in shares' hash table.
*/
static void
{
}
/*
* lmshare_create_table
*
* Create the share hash table.
*/
static DWORD
lmshare_create_table(void)
{
if (lmshare_handle == NULL) {
(void) rw_wrlock(&lmshare_lock);
MAXNAMELEN, 0);
if (lmshare_handle == NULL) {
" unable to create share table");
(void) rw_unlock(&lmshare_lock);
return (NERR_InternalError);
}
(void) rw_unlock(&lmshare_lock);
}
return (NERR_Success);
}
/*
* lmshare_add_adminshare
*
* add the admin share for the volume when the share database
* for that volume is going to be loaded.
*/
{
struct lmshare_info si;
if (drive == 0)
return (NERR_InvalidDevice);
return (rc);
}
/*
* lmshare_num_shares
*
* Return the total number of shares, which should be the same value
* that would be returned from a share enum request.
*/
int
lmshare_num_shares(void)
{
int n_shares;
/* If we don't store IPC$ in hash table we should do this */
n_shares++;
return (n_shares);
}
/*
* lmshare_init_iterator
*
* Initialize an iterator for traversing hash table.
* 'mode' is used for filtering shares when iterating.
*/
void
{
}
/*
* lmshare_iterate
*
* Iterate on the shares in the hash table. The iterator must be initialized
* before the first iteration. On subsequent calls, the iterator must be
* passed unchanged.
*
* Returns NULL on failure or when all shares are visited, otherwise
* returns information of visited share.
*
* Note that there are some special shares, i.e. IPC$, that must also
* be processed.
*/
{
return (NULL);
/*
* IPC$ is always first.
*/
}
if ((item = ht_findfirst(
return (NULL);
}
}
}
}
}
return (NULL);
}
/*
* lmshare_add
*
* Add a share. This is a wrapper round lmshare_setinfo that checks
* whether or not the share already exists. If the share exists, an
* error is returned.
*
* Don't check lmshare_is_dir here: it causes rootfs to recurse.
*/
{
return (NERR_InvalidDevice);
/*
* Only autohome shares can be added multiple times
*/
return (NERR_DuplicateShare);
}
}
}
if (status)
return (status);
}
/*
* lmshare_delete
*
* Remove a share. Ensure that all SMB trees associated with this share
* are disconnected. If the share does not exist, an error is returned.
*/
{
char path[MAXPATHLEN];
if (share_name)
(void) utf8_strlwr(share_name);
if (lmshare_is_valid(share_name) == 0 ||
lmshare_exists(share_name) == 0) {
return (NERR_NetNameNotFound);
}
(void) rw_wrlock(&lmshare_lock);
(void) rw_unlock(&lmshare_lock);
return (NERR_ItemNotFound);
}
(void) rw_unlock(&lmshare_lock);
return (NERR_InternalError);
}
(void) rw_unlock(&lmshare_lock);
return (status);
}
}
(void) rw_unlock(&lmshare_lock);
return (NERR_InternalError);
}
/*
* Copy the path before the entry is removed from the hash table
*/
/* Delete from hash table */
(void) rw_unlock(&lmshare_lock);
}
/*
* lmshare_set_refcnt
*
* sets the autohome refcnt for a share
*/
static DWORD
{
if (share_name) {
(void) utf8_strlwr(share_name);
}
(void) rw_wrlock(&lmshare_lock);
(void) rw_unlock(&lmshare_lock);
return (NERR_ItemNotFound);
}
(void) rw_unlock(&lmshare_lock);
return (NERR_InternalError);
}
(void) rw_unlock(&lmshare_lock);
return (NERR_Success);
}
/*
* lmshare_rename
*
* Rename a share. Check that the current name exists and the new name
* doesn't exist. The rename is performed by deleting the current share
* definition and creating a new share with the new name.
*/
{
struct lmshare_info si;
if (lmshare_is_valid(from_name) == 0 ||
lmshare_is_valid(to_name) == 0)
return (NERR_InvalidDevice);
(void) utf8_strlwr(from_name);
(void) utf8_strlwr(to_name);
if (lmshare_exists(from_name) == 0)
return (NERR_NetNameNotFound);
if (lmshare_exists(to_name))
return (NERR_DuplicateShare);
return (nerr);
return (nerr);
}
/*
* lmshare_exists
*
* Returns 1 if the share exists. Otherwise returns 0.
*/
int
lmshare_exists(char *share_name)
{
if (share_name == 0 || *share_name == 0)
return (0);
return (0);
else
return (1);
}
/*
* lmshare_is_special
*
* Simple check to determine if share name represents a special share,
* i.e. the last character of the name is a '$'. Returns STYPE_SPECIAL
* if the name is special. Otherwise returns 0.
*/
int
lmshare_is_special(char *share_name)
{
int len;
if (share_name == 0)
return (0);
return (0);
return (STYPE_SPECIAL);
else
return (0);
}
/*
* lmshare_is_restricted
*
* Check whether or not there is a restriction on a share. Restricted
* shares are generally STYPE_SPECIAL, for example, IPC$. All the
* administration share names are restricted: C$, D$ etc. Returns 1
* if the share is restricted. Otherwise 0 is returned to indicate
* that there are no restrictions.
*/
int
lmshare_is_restricted(char *share_name)
{
static char *restricted[] = {
"IPC$"
};
int i;
for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
return (1);
}
if (lmshare_is_admin(share_name))
return (1);
return (0);
}
/*
* lmshare_is_admin
*
* Check whether or not access to the share should be restricted to
* administrators. This is a bit of a hack because what we're doing
* is checking for the default admin shares: C$, D$ etc.. There are
* other shares that have restrictions: see lmshare_is_restricted().
*
* Returns 1 if the shares is an admin share. Otherwise 0 is returned
* to indicate that there are no restrictions.
*/
int
lmshare_is_admin(char *share_name)
{
if (share_name == 0)
return (0);
return (1);
}
return (0);
}
/*
* lmshare_is_valid
*
* Check if any invalid char is present in share name. According to
* MSDN article #236388: "Err Msg: The Share Name Contains Invalid
* Characters", the list of invalid character is:
*
* " / \ [ ] : | < > + ; , ? * =
*
* Also rejects if control characters are embedded.
*
* If the sharename is valid, return (1). Otherwise return (0).
*/
int
lmshare_is_valid(char *share_name)
{
char *invalid = "\"/\\[]:|<>+;,?*=";
char *cp;
if (share_name == 0)
return (0);
return (0);
return (0);
return (1);
}
/*
* lmshare_is_dir
*
* Check to determine if a share object represents a directory.
*
* Returns 1 if the path leads to a directory. Otherwise returns 0.
*/
int
lmshare_is_dir(char *path)
{
return (1);
return (0);
}
/*
* lmshare_getinfo
*
* Load the information for the specified share into the supplied share
* info structure. If the shared directory does not begin with a /, one
* will be inserted as a prefix.
*/
{
int i, endidx;
int dirlen;
(void) rw_rdlock(&lmshare_lock);
(void) utf8_strlwr(share_name);
(void) rw_unlock(&lmshare_lock);
return (NERR_NetNameNotFound);
}
(void) rw_unlock(&lmshare_lock);
return (NERR_NetNameNotFound);
for (i = endidx; i >= 0; i--)
}
return (NERR_Success);
}
/*
* Remove share from sharemanager repository.
*/
static int
{
"share lib");
return (1);
}
return (1);
}
return (1);
}
return (1);
}
return (0);
}
static int
{
int share_created = 0;
int err;
/* Add share to sharemanager */
return (1);
}
return (1);
}
return (1);
}
share_created = 1;
}
goto failure;
}
}
"description in sharemgr");
goto failure;
}
goto failure;
}
return (0);
}
}
}
}
return (1);
}
/*
* del_fromhash
*
* Delete the given share only from hash table
*/
static DWORD
del_fromhash(char *share_name)
{
if (share_name == 0)
return (NERR_NetNameNotFound);
(void) utf8_strlwr(share_name);
if (lmshare_is_valid(share_name) == 0 ||
lmshare_exists(share_name) == 0) {
return (NERR_NetNameNotFound);
}
(void) rw_wrlock(&lmshare_lock);
(void) rw_unlock(&lmshare_lock);
return (NERR_Success);
}
/*
* lmshare_setinfo
*
* Adds the specified share into the system hash table
* and also store its info in the corresponding disk
* structure if it is not a temporary (LMSHRM_TRANS) share.
* when the first share is going to be added, create shares
* hash table if it is not already created.
* If the share already exists, it will be replaced. If the
* new share directory name does not begin with a /, one will be
* inserted as a prefix.
*/
{
int i, endidx;
int dirlen;
int res = NERR_Success;
for (i = endidx; i >= 0; i--)
}
/* XXX Do we need to translate the directory here? to real path */
return (NERR_UnknownDevDir);
/*
* We should allocate memory for new entry because we
* don't know anything about the passed pointer i.e.
* it maybe destroyed by caller of this function while
* we only store a pointer to the data in hash table.
* Hash table doesn't do any allocation for the data that
* is being added.
*/
return (NERR_NoRoom);
}
/*
* If we can't find it, use the new one to get things in sync,
* but if there is an existing one, that is the one to
* unpublish.
*/
if (doshm) {
if (res != NERR_Success) {
return (res);
}
} else {
/* Unpublish old share from AD */
}
/* if it's not transient it should be permanent */
(void) rw_wrlock(&lmshare_lock);
add_si->share_name);
(void) rw_unlock(&lmshare_lock);
return (NERR_InternalError);
}
(void) rw_unlock(&lmshare_lock);
add_si->share_name);
return (NERR_InternalError);
}
}
return (res);
}
void
{
int list_idx = 0;
int i = 0;
/*
* Don't return restricted shares.
*/
continue;
}
if (i++ < offset)
continue;
sizeof (lmshare_info_t));
if (++list_idx == LMSHARES_PER_REQUEST)
break;
}
}
/*
* Put the share on publish queue.
*/
void
{
if (publish_on == 0)
return;
return;
(void) mutex_lock(&lmshare_publish_mutex);
(void) mutex_unlock(&lmshare_publish_mutex);
return;
}
/*LINTED - E_CONSTANT_CONDITION*/
if (poke)
(void) cond_signal(&lmshare_publish_cv);
(void) mutex_unlock(&lmshare_publish_mutex);
}
void
{
(void) mutex_lock(&lmshare_publish_mutex);
publish_on = 0;
(void) cond_signal(&lmshare_publish_cv);
(void) mutex_unlock(&lmshare_publish_mutex);
}
/*
* This functions waits to be signaled and once running
* lmshare_stop_publish when called will exit this thread.
*/
/*ARGSUSED*/
static void *
lmshare_publisher(void *arg)
{
ADS_HANDLE *ah;
char hostname[MAXHOSTNAMELEN];
char name[MAXNAMELEN];
char container[MAXPATHLEN];
char flag;
/*LINTED - E_CONSTANT_CONDITION*/
publish_on = 1;
hostname[0] = '\0';
for (;;) {
(void) cond_wait(&lmshare_publish_cv,
if (hostname[0] == '\0') {
continue;
}
if (publish_on == 0) {
(void) mutex_unlock(&lmshare_publish_mutex);
break;
}
/*LINTED - E_CONSTANT_CONDITION*/
}
(void) mutex_unlock(&lmshare_publish_mutex);
break;
}
continue;
/* We mostly have no AD config so just clear the list */
/*LINTED - E_CONSTANT_CONDITION*/
}
continue;
}
sizeof (container));
if (flag == LMSHR_UNPUBLISH)
else
}
/*LINTED - E_CONSTANT_CONDITION*/
}
}
}
return (NULL);
}
/*
* lmshare_get_realpath
*
* Derive the real path of a share from the path provided by a
* Windows client application during the share addition.
*
* For instance, the real path of C:\ is /cvol and the
*
* clipath - path provided by the Windows client is in the
* format of <drive letter>:\<dir>
* realpath - path that will be stored as the directory field of
* the lmshare_info_t structure of the share.
* maxlen - maximum length fo the realpath buffer
*
* Return LAN Manager network error code.
*/
/*ARGSUSED*/
{
/* XXX do this translation */
return (NERR_Success);
}
/*
* lmshare_set_oemname
*
* Generates the OEM name of the given share. If it's
* shorter than 13 chars it'll be saved in si->oem_name.
* Otherwise si->oem_name will be empty and LMSHRM_LONGNAME
* will be set in si->mode.
*/
static void
{
unsigned int cpid = oem_get_smb_cpid();
char *oem_name;
int length;
return;
}
} else {
}
}