lmshare.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* 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 2007 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();
static int lmshare_delete_shmgr(struct lmshare_info *);
static int lmshare_setinfo_shmgr(struct lmshare_info *);
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
{
}
/*
* Load shares from sharemanager.
*/
/*ARGSUSED*/
static void *
lmshare_load(void *args)
{
if (lmshare_create_table() != NERR_Success) {
return (NULL);
}
"information: no libshare handle");
return (NULL);
}
/* Skip disabled or unknown state group */
continue;
}
/* Check and see if smb protocol is available */
continue;
continue;
}
"resource for path: %s", path);
continue;
}
SMB_PROTOCOL_NAME, 1);
}
}
/* We are done with all shares for same path */
}
}
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_open_iterator
*
* Create and initialize an iterator for traversing hash table.
* It gets a mode that can be LMSHR_IM_ALL to iterate through all
* the shares stored in table or LMSHR_IM_PRES to iterate through
* only presentable shares.
*
* It also accepts a local IP address. This is used in dual head
* systems to only return the shares that belong to the head which
* is specified by the 'ipaddr'. If ipaddr is 0 it'll return shares
* of both heads.
*
* On success return pointer to the new iterator.
* On failure return (NULL).
*/
{
/*LINTED E_BAD_PTR_CAST_ALIGN*/
((char *)shi + sizeof (lmshare_iterator_t));
} else {
}
return (shi);
}
/*
* lmshare_close_iterator
*
* Free memory allocated by the given iterator.
*/
void
{
}
/*
* lmshare_iterate
*
* Iterate on the shares in the hash table. The iterator must be opened
* 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);
}
sizeof (lmshare_info_t));
}
}
}
}
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);
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);
}
/*
* lmshare_decode_type
*
* Gets a SMB share type as an integer value and return
* a string name for it.
*/
static char *
{
switch (stype) {
case STYPE_DISKTREE:
return ("Disk");
case STYPE_PRINTQ:
return ("Print Queue");
case STYPE_DEVICE:
return ("Device");
case STYPE_IPC:
return ("IPC");
case STYPE_DFS:
return ("DFS");
case STYPE_SPECIAL:
return ("Special");
default:
return ("Unknown");
/* NOTREACHED */
};
}
/*
* lmshare_loginfo
*
* Decodes and writes the information of the given
* share to the specified file.
*/
void
{
}
{
int list_idx = 0;
int i = 0;
return (NERR_InternalError);
/*
* Don't return restricted shares.
*/
continue;
}
if (i++ < offset)
continue;
sizeof (lmshare_info_t));
if (++list_idx == LMSHARES_PER_REQUEST)
break;
}
return (NERR_Success);
}
/*
* 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);
}