/*
* 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
*/
/*
*/
#include <syslog.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <strings.h>
#include <synch.h>
#include <errno.h>
#include <pwd.h>
#include <dlfcn.h>
#include <link.h>
#include <assert.h>
typedef enum {
SMB_PWD_NAME = 0,
} smb_pwdarg_t;
static struct {
int (*pwop_setcntl)(const char *, int);
int (*pwop_setpasswd)(const char *, const char *);
int (*pwop_num)(void);
} smb_pwd_ops;
static int smb_pwd_lock(void);
static int smb_pwd_unlock(void);
/*
* buffer structure used by smb_pwd_fgetent/smb_pwd_fputent
*/
typedef struct smb_pwbuf {
} smb_pwbuf_t;
/*
* flag values used with smb_pwd_fgetent
*/
static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int);
static int smb_pwd_update(const char *, const char *, int);
/*
* Local Users Cache
*
* Simplifying assumptions
*
* o smbpasswd is a service private file and shouldn't be edited manually
* o accounts are not removed but disabled using smbadm CLI
* o editing smbpasswd manually might result in cache inconsistency
*
* Cache is created and populated upon service startup.
* Cache is updated each time users list is requested if there's been
* any change in smbpasswd file. The change criteria is smbpasswd's
* modification timestamp.
*/
/*
* User cache handle
*/
typedef struct smb_uchandle {
#define SMB_UCHS_NOCACHE 0
/*
* User cache node
*/
typedef struct smb_ucnode {
} smb_ucnode_t;
static void smb_lucache_create(void);
static void smb_lucache_destroy(void);
static void smb_lucache_update(void);
static int smb_lucache_num(void);
static int smb_lucache_lock(void);
static void smb_lucache_unlock(void);
static int smb_lucache_do_update(void);
static void smb_lucache_flush(void);
/*
* smb_pwd_init
*
* Initializes the cache if requested.
* Checks to see if a password management utility library
* is interposed. If yes then it'll initializes smb_pwd_ops
* structure with function pointers from this library.
*/
void
{
if (create_cache) {
#if 0
/*
* This pre-loading of the cache results in idmapd requests.
* With the change to allow idmapd to call into libsmb to
* map names and SIDs, this creates a circular startup
* dependency. This call has been temporarily disabled to
* lookup can be done directly on the LSA service.
*/
#endif
}
smb_pwd_hdl = smb_dlopen();
if (smb_pwd_hdl == NULL)
return;
smb_pwd_hdl = NULL;
/* If error or function(s) are missing, use original lib */
}
}
/*
* smb_pwd_fini
*
* Destroys the cache.
* Closes interposed library.
*/
void
smb_pwd_fini(void)
{
smb_pwd_hdl = NULL;
}
/*
* smb_pwd_getpwnam
*
* Perform case-sensitve lookup of the given user name. If exact match
* cannot be found, perform case-insensitive lookup.
*/
{
return (pw);
}
/*
* smb_pwd_getpwuid
*
* Returns a smb password structure for the given UID
* smbpw is a pointer to a buffer allocated by the caller.
*
* Returns NULL upon failure.
*/
{
int err;
err = smb_pwd_lock();
if (err != SMB_PWE_SUCCESS)
return (NULL);
(void) smb_pwd_unlock();
return (NULL);
}
break;
}
}
(void) smb_pwd_unlock();
if (!found) {
return (NULL);
}
return (smbpw);
}
/*
* smb_pwd_setpasswd
*
*/
int
{
}
/*
* smb_pwd_setcntl
*
* Change the account state. This can be making the account
*/
int
{
if (control == 0)
return (SMB_PWE_SUCCESS);
}
/*
* smb_pwd_num
*
* Returns the number of cached local users
*/
int
smb_pwd_num(void)
{
return (smb_pwd_ops.pwop_num());
return (smb_lucache_num());
}
/*
* smb_pwd_iteropen
*
* Initalizes the given iterator handle.
* This handle will be used to iterate the users cache
* by the caller. The cache will be locked for read and it
* will remain locked until smb_pwd_iterclose() is called.
*/
int
{
return (SMB_PWE_INVALID_PARAM);
return (smb_lucache_lock());
}
/*
* smb_pwd_iterate
*
* Scans through users cache using the given iterator
*/
{
return (NULL);
else
return (NULL);
}
/*
* smb_pwd_iterclose
*
* Closes the given iterator. Effectively it only unlocks the cache
*/
void
{
return;
}
}
/*
* smb_pwd_update
*
* Updates the password entry of the given user if the user already
* has an entry, otherwise it'll add an entry for the user with
* given password and control information.
*/
static int
{
int tempfd;
err = smb_pwd_lock();
if (err != SMB_PWE_SUCCESS)
return (err);
goto passwd_exit;
}
goto passwd_exit;
}
goto passwd_exit;
}
(void) unlink(SMB_PASSTEMP);
goto passwd_exit;
}
lm_level = 4;
if (lm_level >= 4)
control |= SMB_PWC_NOLM;
/*
* copy old password entries to temporary file while replacing
* the entry that matches "name"
*/
if (err == SMB_PWE_USER_DISABLE)
} else {
}
if (err != SMB_PWE_SUCCESS) {
goto passwd_exit;
}
}
if (newent) {
} else {
}
if (err != SMB_PWE_SUCCESS) {
goto passwd_exit;
}
}
goto passwd_exit; /* Don't trust the temporary file */
}
/* Rename temp to passwd */
(void) unlink(SMB_PASSTEMP);
goto passwd_exit;
}
(void) unlink(SMB_PASSTEMP);
goto passwd_exit;
}
(void) unlink(SMB_PASSTEMP);
goto passwd_exit;
}
(void) smb_pwd_unlock();
return (err);
}
/*
* smb_pwd_fgetent
*
* Parse the buffer in the passed pwbuf and fill in the
* smb password structure to point to the parsed information.
* The entry format is:
*
* <user-name>:<user-id>:<LM hash>:<NTLM hash>
*
* Returns a pointer to the passed pwbuf structure on success,
* otherwise returns NULL.
*/
static smb_pwbuf_t *
{
char *pwentry;
smb_pwdarg_t i;
return (NULL);
(void) trim_whitespace(pwentry);
for (i = 0; i < SMB_PWD_NARG; ++i) {
return (NULL);
}
return (NULL);
if (flags != SMB_PWD_GETF_NOPWD) {
}
return (pwbuf);
}
if (flags == SMB_PWD_GETF_NOPWD)
return (pwbuf);
if (lm_len == SMBAUTH_HEXHASH_SZ) {
} else if (lm_len != 0) {
return (NULL);
}
if (nt_len == SMBAUTH_HEXHASH_SZ) {
} else if (nt_len != 0) {
return (NULL);
}
return (pwbuf);
}
/*
* smb_pwd_chgpwent
*
* Updates the given smb_passwd_t structure with given password and
* control information.
*/
static int
{
if (control & SMB_PWC_DISABLE) {
/* disable the user */
return (SMB_PWE_SUCCESS);
}
/* enable the user if it's been disabled */
return (SMB_PWE_SUCCESS);
}
/* No password update if account is disabled */
return (SMB_PWE_USER_DISABLE);
/* This call was just to update the control flags */
return (SMB_PWE_SUCCESS);
if (control & SMB_PWC_NOLM) {
/* LM hash should not be present */
} else {
}
return (SMB_PWE_SUCCESS);
}
/*
* smb_pwd_fputent
*
* and write them along with user's name and Id to the smbpasswd
* file.
*/
static int
{
int rc;
} else {
}
} else {
}
if (rc <= 0)
return (SMB_PWE_WRITE_FAILED);
return (SMB_PWE_SUCCESS);
}
/*
* smb_pwd_getpwnam_core
*
* Performs either case-sensitive (cs == TRUE) or case-insensitive (cs == FALSE)
* lookups of the given user name.
*
* Returns a smb password structure if a match is found.
*
* smbpw is a pointer to a buffer allocated by the caller.
*
* Returns NULL upon failure.
*
* Limitation on case-insensitive lookup
* ======================================
* If there are multiple database entries with the same username, differing only
* in case, this function will return the first match it finds.
*/
static smb_passwd_t *
{
int err;
err = smb_pwd_lock();
if (err != SMB_PWE_SUCCESS)
return (NULL);
(void) smb_pwd_unlock();
return (NULL);
}
if (cs)
else
if (err == 0) {
break;
}
}
(void) smb_pwd_unlock();
if (!found) {
return (NULL);
}
return (smbpw);
}
/*
* smb_pwd_lock
*
* A wrapper around smb_file_lock() which locks smb password
* file so that only one thread at a time is operational.
*/
static int
smb_pwd_lock(void)
{
int res;
switch (errno) {
case EINTR:
res = SMB_PWE_BUSY;
break;
case EACCES:
break;
case 0:
break;
}
} else
return (res);
}
/*
* smb_pwd_unlock
*
* A wrapper around smb_file_unlock() which unlocks
* smb password file.
*/
static int
smb_pwd_unlock(void)
{
if (smb_file_unlock(&lockinfo))
return (SMB_PWE_SYSTEM_ERROR);
return (SMB_PWE_SUCCESS);
}
/*
* Local User Cache Functions
*
* Local user cache is implemented using AVL tree
*/
/*
* smb_lucache_cmp
*
* AVL compare function, the key is username.
*/
static int
{
int rc;
if (rc < 0)
return (-1);
if (rc > 0)
return (1);
return (0);
}
/*
* smb_lucache_update
*
* Updates the cache if needed. Whether an update is needed
* is determined based on smbpasswd file modification timestamp
*/
static void
smb_lucache_update(void)
{
int rc;
default:
case SMB_UCHS_NOCACHE:
assert(0);
return;
case SMB_UCHS_CREATED:
case SMB_UCHS_UPDATED:
break;
case SMB_UCHS_UPDATING:
/* Want only one thread executing this function at a time */
return;
case SMB_UCHS_DESTROYING:
return;
}
/*
* smb_pwd_lock() is not called here so it can
* be checked quickly whether an updated is needed
*/
return;
/* no smbpasswd file; empty the cache */
return;
}
/* empty smbpasswd file; empty the cache */
return;
}
/* No changes since the last cache update */
return;
}
rc = smb_lucache_do_update();
}
/*
* smb_lucache_do_update
*
* This function takes care of updating the AVL tree.
* If an entry has been updated, it'll be modified in place.
*
* New entries will be added to a temporary AVL tree then
* passwod file is unlocked and all the new entries will
* be transferred to the main cache from the temporary tree.
*
* This function MUST NOT be called directly
*/
static int
smb_lucache_do_update(void)
{
return (rc);
(void) smb_pwd_unlock();
return (SMB_PWE_OPEN_FAILED);
}
if (uc_newnode) {
/* update the node info */
continue;
}
/* create a new node */
break;
}
if (idm_stat != IDMAP_SUCCESS) {
continue;
}
break;
}
}
(void) smb_pwd_unlock();
/* Destroy the temporary list */
}
return (rc);
}
/*
* smb_lucache_create
*
* Creates the AVL tree and initializes the global user cache handle.
* This function doesn't populate the cache.
* User cache is only created by smbd at startup
*/
static void
smb_lucache_create(void)
{
return;
}
}
/*
* smb_lucache_flush
*
* Removes and frees all the cache entries
*/
static void
smb_lucache_flush(void)
{
!= NULL) {
}
}
/*
* smb_lucache_destroy
*
* Destroys the cache.
* This function is only called in smb_pwd_fini()
* User cache is only destroyed by smbd upon shutdown
*/
static void
smb_lucache_destroy(void)
{
case SMB_UCHS_NOCACHE:
case SMB_UCHS_DESTROYING:
return;
default:
break;
}
}
/*
* smb_lucache_lock
*
* Locks the user cache for reading and also
* increment the handle reference count.
*/
static int
smb_lucache_lock(void)
{
case SMB_UCHS_NOCACHE:
assert(0);
return (SMB_PWE_DENIED);
case SMB_UCHS_DESTROYING:
return (SMB_PWE_DENIED);
}
return (SMB_PWE_SUCCESS);
}
/*
* smb_lucache_unlock
*
* Unlock the cache
*/
static void
smb_lucache_unlock(void)
{
}
/*
* smb_lucache_num
*
* Returns the number of cache entries
*/
static int
smb_lucache_num(void)
{
int num;
case SMB_UCHS_NOCACHE:
assert(0);
return (0);
case SMB_UCHS_DESTROYING:
return (0);
}
return (num);
}