xref: /onnv-gate/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c (revision 11963:061945695ce1)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
2211633SJoyce.McIntosh@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
26*11963SAfshin.Ardakani@Sun.COM #include <syslog.h>
275331Samw #include <stdlib.h>
285331Samw #include <unistd.h>
295331Samw #include <limits.h>
305331Samw #include <strings.h>
315331Samw #include <synch.h>
325331Samw #include <errno.h>
335331Samw #include <sys/types.h>
345331Samw #include <sys/stat.h>
357052Samw #include <sys/avl.h>
365331Samw #include <fcntl.h>
375331Samw #include <thread.h>
385331Samw #include <pwd.h>
396030Sjb150015 #include <dlfcn.h>
406030Sjb150015 #include <link.h>
417052Samw #include <assert.h>
425331Samw #include <smbsrv/libsmb.h>
435331Samw 
445331Samw #define	SMB_PASSWD	"/var/smb/smbpasswd"
455331Samw #define	SMB_OPASSWD	"/var/smb/osmbpasswd"
465331Samw #define	SMB_PASSTEMP	"/var/smb/ptmp"
475331Samw #define	SMB_PASSLCK	"/var/smb/.pwd.lock"
487052Samw 
495331Samw #define	SMB_PWD_DISABLE	"*DIS*"
505331Samw #define	SMB_PWD_BUFSIZE 256
515331Samw 
525331Samw #define	S_WAITTIME	15
535331Samw 
545331Samw typedef enum {
555331Samw 	SMB_PWD_NAME = 0,
565331Samw 	SMB_PWD_UID,
575331Samw 	SMB_PWD_LMHASH,
585331Samw 	SMB_PWD_NTHASH,
595331Samw 	SMB_PWD_NARG
605331Samw } smb_pwdarg_t;
615331Samw 
627052Samw static struct flock flock = { 0, 0, 0, 0, 0, 0 };
635331Samw static pid_t lck_pid = 0;	/* process's pid at last lock */
645331Samw static thread_t lck_tid = 0;	/* thread that holds the lock */
655331Samw static int fildes = -1;
665331Samw static mutex_t lck_lock = DEFAULTMUTEX;
676030Sjb150015 static void *smb_pwd_hdl = NULL;
685331Samw 
696030Sjb150015 static struct {
708474SJose.Borrego@Sun.COM 	smb_passwd_t *(*pwop_getpwnam)(const char *, smb_passwd_t *);
718474SJose.Borrego@Sun.COM 	smb_passwd_t *(*pwop_getpwuid)(uid_t, smb_passwd_t *);
727052Samw 	int (*pwop_setcntl)(const char *, int);
737052Samw 	int (*pwop_setpasswd)(const char *, const char *);
747052Samw 	int (*pwop_num)(void);
757052Samw 	int (*pwop_iteropen)(smb_pwditer_t *);
767052Samw 	smb_luser_t *(*pwop_iterate)(smb_pwditer_t *);
777052Samw 	void (*pwop_iterclose)(smb_pwditer_t *);
786030Sjb150015 } smb_pwd_ops;
796030Sjb150015 
805331Samw static int smb_pwd_lock(void);
815331Samw static int smb_pwd_unlock(void);
825331Samw static int smb_pwd_flck(void);
835331Samw static int smb_pwd_fulck(void);
845331Samw 
857052Samw /*
867052Samw  * buffer structure used by smb_pwd_fgetent/smb_pwd_fputent
877052Samw  */
887052Samw typedef struct smb_pwbuf {
897052Samw 	char		pw_buf[SMB_PWD_BUFSIZE];
907052Samw 	smb_passwd_t	*pw_pwd;
917052Samw } smb_pwbuf_t;
927052Samw 
937052Samw /*
947052Samw  * flag values used with smb_pwd_fgetent
957052Samw  */
967052Samw #define	SMB_PWD_GETF_ALL	1	/* get all the account info */
977052Samw #define	SMB_PWD_GETF_NOPWD	2	/* password is not needed */
987052Samw 
997052Samw static smb_pwbuf_t *smb_pwd_fgetent(FILE *, smb_pwbuf_t *, uint32_t);
1009832Samw@Sun.COM static int smb_pwd_fputent(FILE *, const smb_pwbuf_t *);
1015331Samw static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int);
1025331Samw static int smb_pwd_update(const char *, const char *, int);
1035331Samw 
1047052Samw /*
1057052Samw  * Local Users Cache
1067052Samw  *
1077052Samw  * Simplifying assumptions
1087052Samw  *
1097052Samw  * 	o smbpasswd is a service private file and shouldn't be edited manually
1107052Samw  * 	o accounts are only added/modified via passwd and/or smbadm CLIs
1117052Samw  * 	o accounts are not removed but disabled using smbadm CLI
1127052Samw  * 	o editing smbpasswd manually might result in cache inconsistency
1137052Samw  *
1147052Samw  * Cache is created and populated upon service startup.
1157052Samw  * Cache is updated each time users list is requested if there's been
1167052Samw  * any change in smbpasswd file. The change criteria is smbpasswd's
1177052Samw  * modification timestamp.
1187052Samw  */
1197052Samw 
1207052Samw /*
1217052Samw  * User cache handle
1227052Samw  */
1237052Samw typedef struct smb_uchandle {
1247052Samw 	avl_tree_t	uc_cache;
1257052Samw 	rwlock_t	uc_cache_lck;
1267052Samw 	timestruc_t	uc_timestamp;
1277052Samw 	uint32_t	uc_refcnt;
1287052Samw 	uint32_t	uc_state;
1297052Samw 	mutex_t		uc_mtx;
1307052Samw 	cond_t		uc_cv;
1317052Samw } smb_uchandle_t;
1327052Samw 
1337052Samw #define	SMB_UCHS_NOCACHE	0
1347052Samw #define	SMB_UCHS_CREATED	1
1357052Samw #define	SMB_UCHS_UPDATING	2
1367052Samw #define	SMB_UCHS_UPDATED	3
1377052Samw #define	SMB_UCHS_DESTROYING	4
1387052Samw 
1397052Samw /*
1407052Samw  * User cache node
1417052Samw  */
1427052Samw typedef struct smb_ucnode {
1437052Samw 	smb_luser_t	cn_user;
1447052Samw 	avl_node_t	cn_link;
1457052Samw } smb_ucnode_t;
1467052Samw 
1477052Samw static void smb_lucache_create(void);
1487052Samw static void smb_lucache_destroy(void);
1497052Samw static void smb_lucache_update(void);
1507052Samw static int smb_lucache_num(void);
1517052Samw static int smb_lucache_lock(void);
1527052Samw static void smb_lucache_unlock(void);
1537052Samw static int smb_lucache_do_update(void);
1547052Samw static void smb_lucache_flush(void);
1557052Samw 
1567052Samw static smb_uchandle_t smb_uch;
1577052Samw 
1587052Samw /*
1597052Samw  * smb_pwd_init
1607052Samw  *
1617052Samw  * Initializes the cache if requested.
1627052Samw  * Checks to see if a password management utility library
1637052Samw  * is interposed. If yes then it'll initializes smb_pwd_ops
1647052Samw  * structure with function pointers from this library.
1657052Samw  */
1666030Sjb150015 void
smb_pwd_init(boolean_t create_cache)1677052Samw smb_pwd_init(boolean_t create_cache)
1686030Sjb150015 {
1697052Samw 	if (create_cache) {
1707052Samw 		smb_lucache_create();
17111337SWilliam.Krier@Sun.COM #if 0
17211337SWilliam.Krier@Sun.COM 		/*
17311337SWilliam.Krier@Sun.COM 		 * This pre-loading of the cache results in idmapd requests.
17411337SWilliam.Krier@Sun.COM 		 * With the change to allow idmapd to call into libsmb to
17511337SWilliam.Krier@Sun.COM 		 * map names and SIDs, this creates a circular startup
17611337SWilliam.Krier@Sun.COM 		 * dependency.  This call has been temporarily disabled to
17711337SWilliam.Krier@Sun.COM 		 * avoid this issue.  It can be enabled when the name/SID
17811337SWilliam.Krier@Sun.COM 		 * lookup can be done directly on the LSA service.
17911337SWilliam.Krier@Sun.COM 		 */
1807052Samw 		smb_lucache_update();
18111337SWilliam.Krier@Sun.COM #endif
1827052Samw 	}
1837052Samw 
18410122SJordan.Brown@Sun.COM 	smb_pwd_hdl = smb_dlopen();
18510122SJordan.Brown@Sun.COM 	if (smb_pwd_hdl == NULL)
1867052Samw 		return;
1876030Sjb150015 
1886030Sjb150015 	bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
1896030Sjb150015 
1908474SJose.Borrego@Sun.COM 	smb_pwd_ops.pwop_getpwnam =
1918474SJose.Borrego@Sun.COM 	    (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpwnam");
1928474SJose.Borrego@Sun.COM 
1938474SJose.Borrego@Sun.COM 	smb_pwd_ops.pwop_getpwuid =
1948474SJose.Borrego@Sun.COM 	    (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpwuid");
1956030Sjb150015 
1967052Samw 	smb_pwd_ops.pwop_setcntl =
1976030Sjb150015 	    (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setcntl");
1986030Sjb150015 
1997052Samw 	smb_pwd_ops.pwop_setpasswd =
2006030Sjb150015 	    (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setpasswd");
2016030Sjb150015 
2027052Samw 	smb_pwd_ops.pwop_num =
2037052Samw 	    (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_num");
2047052Samw 
2057052Samw 	smb_pwd_ops.pwop_iteropen =
2067052Samw 	    (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_iteropen");
2077052Samw 
2087052Samw 	smb_pwd_ops.pwop_iterclose =
2097052Samw 	    (void (*)())dlsym(smb_pwd_hdl, "smb_pwd_iterclose");
2107052Samw 
2117052Samw 	smb_pwd_ops.pwop_iterate =
2127052Samw 	    (smb_luser_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_iterate");
2137052Samw 
2148474SJose.Borrego@Sun.COM 	if (smb_pwd_ops.pwop_getpwnam == NULL ||
2158474SJose.Borrego@Sun.COM 	    smb_pwd_ops.pwop_getpwuid == NULL ||
2167052Samw 	    smb_pwd_ops.pwop_setcntl == NULL ||
2177052Samw 	    smb_pwd_ops.pwop_setpasswd == NULL ||
2187052Samw 	    smb_pwd_ops.pwop_num == NULL ||
2197052Samw 	    smb_pwd_ops.pwop_iteropen == NULL ||
2207052Samw 	    smb_pwd_ops.pwop_iterclose == NULL ||
2217052Samw 	    smb_pwd_ops.pwop_iterate == NULL) {
22210122SJordan.Brown@Sun.COM 		smb_dlclose(smb_pwd_hdl);
2236030Sjb150015 		smb_pwd_hdl = NULL;
2246030Sjb150015 
2256030Sjb150015 		/* If error or function(s) are missing, use original lib */
2266030Sjb150015 		bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
2276030Sjb150015 	}
2286030Sjb150015 }
2296030Sjb150015 
2307052Samw /*
2317052Samw  * smb_pwd_fini
2327052Samw  *
2337052Samw  * Destroys the cache.
2347052Samw  * Closes interposed library.
2357052Samw  */
2366030Sjb150015 void
smb_pwd_fini(void)2376030Sjb150015 smb_pwd_fini(void)
2386030Sjb150015 {
2397052Samw 	smb_lucache_destroy();
24010122SJordan.Brown@Sun.COM 	smb_dlclose(smb_pwd_hdl);
24110122SJordan.Brown@Sun.COM 	smb_pwd_hdl = NULL;
24210122SJordan.Brown@Sun.COM 	bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
2436030Sjb150015 }
2446030Sjb150015 
2455331Samw /*
2468474SJose.Borrego@Sun.COM  * smb_pwd_getpwnam
2475331Samw  *
2485331Samw  * Returns a smb password structure for the given user name.
2495331Samw  * smbpw is a pointer to a buffer allocated by the caller.
2505331Samw  *
2515331Samw  * Returns NULL upon failure.
2525331Samw  */
2535331Samw smb_passwd_t *
smb_pwd_getpwnam(const char * name,smb_passwd_t * smbpw)2548474SJose.Borrego@Sun.COM smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw)
2555331Samw {
2565331Samw 	boolean_t found = B_FALSE;
2575331Samw 	smb_pwbuf_t pwbuf;
2587052Samw 	FILE *fp;
2595331Samw 	int err;
2605331Samw 
2618474SJose.Borrego@Sun.COM 	if (smb_pwd_ops.pwop_getpwnam != NULL)
2628474SJose.Borrego@Sun.COM 		return (smb_pwd_ops.pwop_getpwnam(name, smbpw));
2636030Sjb150015 
2645331Samw 	err = smb_pwd_lock();
2655331Samw 	if (err != SMB_PWE_SUCCESS)
2665331Samw 		return (NULL);
2675331Samw 
2685331Samw 	if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
2695331Samw 		(void) smb_pwd_unlock();
2705331Samw 		return (NULL);
2715331Samw 	}
2725331Samw 
2735331Samw 	pwbuf.pw_pwd = smbpw;
2745331Samw 
2757052Samw 	while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
2768474SJose.Borrego@Sun.COM 		if (strcmp(name, smbpw->pw_name) == 0) {
2778474SJose.Borrego@Sun.COM 			if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
2788474SJose.Borrego@Sun.COM 				found = B_TRUE;
2798474SJose.Borrego@Sun.COM 			break;
2808474SJose.Borrego@Sun.COM 		}
2818474SJose.Borrego@Sun.COM 	}
2828474SJose.Borrego@Sun.COM 
2838474SJose.Borrego@Sun.COM 	(void) fclose(fp);
2848474SJose.Borrego@Sun.COM 	(void) smb_pwd_unlock();
2858474SJose.Borrego@Sun.COM 
2868474SJose.Borrego@Sun.COM 	if (!found) {
2878474SJose.Borrego@Sun.COM 		bzero(smbpw, sizeof (smb_passwd_t));
2888474SJose.Borrego@Sun.COM 		return (NULL);
2898474SJose.Borrego@Sun.COM 	}
2908474SJose.Borrego@Sun.COM 
2918474SJose.Borrego@Sun.COM 	return (smbpw);
2928474SJose.Borrego@Sun.COM }
2938474SJose.Borrego@Sun.COM 
2948474SJose.Borrego@Sun.COM /*
2958474SJose.Borrego@Sun.COM  * smb_pwd_getpwuid
2968474SJose.Borrego@Sun.COM  *
2978474SJose.Borrego@Sun.COM  * Returns a smb password structure for the given UID
2988474SJose.Borrego@Sun.COM  * smbpw is a pointer to a buffer allocated by the caller.
2998474SJose.Borrego@Sun.COM  *
3008474SJose.Borrego@Sun.COM  * Returns NULL upon failure.
3018474SJose.Borrego@Sun.COM  */
3028474SJose.Borrego@Sun.COM smb_passwd_t *
smb_pwd_getpwuid(uid_t uid,smb_passwd_t * smbpw)3038474SJose.Borrego@Sun.COM smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw)
3048474SJose.Borrego@Sun.COM {
3058474SJose.Borrego@Sun.COM 	boolean_t found = B_FALSE;
3068474SJose.Borrego@Sun.COM 	smb_pwbuf_t pwbuf;
3078474SJose.Borrego@Sun.COM 	FILE *fp;
3088474SJose.Borrego@Sun.COM 	int err;
3098474SJose.Borrego@Sun.COM 
3108474SJose.Borrego@Sun.COM 	if (smb_pwd_ops.pwop_getpwuid != NULL)
3118474SJose.Borrego@Sun.COM 		return (smb_pwd_ops.pwop_getpwuid(uid, smbpw));
3128474SJose.Borrego@Sun.COM 
3138474SJose.Borrego@Sun.COM 	err = smb_pwd_lock();
3148474SJose.Borrego@Sun.COM 	if (err != SMB_PWE_SUCCESS)
3158474SJose.Borrego@Sun.COM 		return (NULL);
3168474SJose.Borrego@Sun.COM 
3178474SJose.Borrego@Sun.COM 	if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
3188474SJose.Borrego@Sun.COM 		(void) smb_pwd_unlock();
3198474SJose.Borrego@Sun.COM 		return (NULL);
3208474SJose.Borrego@Sun.COM 	}
3218474SJose.Borrego@Sun.COM 
3228474SJose.Borrego@Sun.COM 	pwbuf.pw_pwd = smbpw;
3238474SJose.Borrego@Sun.COM 
3248474SJose.Borrego@Sun.COM 	while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
3258474SJose.Borrego@Sun.COM 		if (uid == smbpw->pw_uid) {
3265331Samw 			if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
3275331Samw 				found = B_TRUE;
3285331Samw 			break;
3295331Samw 		}
3305331Samw 	}
3315331Samw 
3325331Samw 	(void) fclose(fp);
3335331Samw 	(void) smb_pwd_unlock();
3345331Samw 
3355331Samw 	if (!found) {
3365331Samw 		bzero(smbpw, sizeof (smb_passwd_t));
3375331Samw 		return (NULL);
3385331Samw 	}
3395331Samw 
3405331Samw 	return (smbpw);
3415331Samw }
3425331Samw 
3435331Samw /*
3447052Samw  * smb_pwd_setpasswd
3455331Samw  *
3465331Samw  * Update/add the given user to the smbpasswd file.
3475331Samw  */
3485331Samw int
smb_pwd_setpasswd(const char * name,const char * password)3495331Samw smb_pwd_setpasswd(const char *name, const char *password)
3505331Samw {
3517052Samw 	if (smb_pwd_ops.pwop_setpasswd != NULL)
3527052Samw 		return (smb_pwd_ops.pwop_setpasswd(name, password));
3536030Sjb150015 
3545331Samw 	return (smb_pwd_update(name, password, 0));
3555331Samw }
3565331Samw 
3575331Samw /*
3585331Samw  * smb_pwd_setcntl
3595331Samw  *
3605331Samw  * Change the account state. This can be making the account
3615331Samw  * disable/enable or removing its LM hash.
3625331Samw  */
3635331Samw int
smb_pwd_setcntl(const char * name,int control)3645331Samw smb_pwd_setcntl(const char *name, int control)
3655331Samw {
3667052Samw 	if (smb_pwd_ops.pwop_setcntl != NULL)
3677052Samw 		return (smb_pwd_ops.pwop_setcntl(name, control));
3686030Sjb150015 
3695331Samw 	if (control == 0)
3705331Samw 		return (SMB_PWE_SUCCESS);
3715331Samw 
3725331Samw 	return (smb_pwd_update(name, NULL, control));
3735331Samw }
3745331Samw 
3757052Samw /*
3767052Samw  * smb_pwd_num
3777052Samw  *
3787052Samw  * Returns the number of cached local users
3797052Samw  */
3807052Samw int
smb_pwd_num(void)3817052Samw smb_pwd_num(void)
3827052Samw {
3837052Samw 	if (smb_pwd_ops.pwop_num != NULL)
3847052Samw 		return (smb_pwd_ops.pwop_num());
3857052Samw 
38611633SJoyce.McIntosh@Sun.COM 	smb_lucache_update();
38711633SJoyce.McIntosh@Sun.COM 
3887052Samw 	return (smb_lucache_num());
3897052Samw }
3907052Samw 
3917052Samw /*
3927052Samw  * smb_pwd_iteropen
3937052Samw  *
3947052Samw  * Initalizes the given iterator handle.
3957052Samw  * This handle will be used to iterate the users cache
3967052Samw  * by the caller. The cache will be locked for read and it
3977052Samw  * will remain locked until smb_pwd_iterclose() is called.
3987052Samw  */
3997052Samw int
smb_pwd_iteropen(smb_pwditer_t * iter)4007052Samw smb_pwd_iteropen(smb_pwditer_t *iter)
4017052Samw {
4027052Samw 	if (iter == NULL)
4037052Samw 		return (SMB_PWE_INVALID_PARAM);
4047052Samw 
4057052Samw 	if (smb_pwd_ops.pwop_iteropen != NULL)
4067052Samw 		return (smb_pwd_ops.pwop_iteropen(iter));
4077052Samw 
4087052Samw 	iter->spi_next = NULL;
4097052Samw 
4107052Samw 	smb_lucache_update();
4117052Samw 
4127052Samw 	return (smb_lucache_lock());
4137052Samw }
4147052Samw 
4157052Samw /*
4167052Samw  * smb_pwd_iterate
4177052Samw  *
4187052Samw  * Scans through users cache using the given iterator
4197052Samw  */
4207052Samw smb_luser_t *
smb_pwd_iterate(smb_pwditer_t * iter)4217052Samw smb_pwd_iterate(smb_pwditer_t *iter)
4227052Samw {
4237052Samw 	smb_ucnode_t *ucnode;
4247052Samw 
4257052Samw 	if (iter == NULL)
4267052Samw 		return (NULL);
4277052Samw 
4287052Samw 	if (smb_pwd_ops.pwop_iterate != NULL)
4297052Samw 		return (smb_pwd_ops.pwop_iterate(iter));
4307052Samw 
4317052Samw 	if (iter->spi_next == NULL)
4327052Samw 		ucnode = avl_first(&smb_uch.uc_cache);
4337052Samw 	else
4347052Samw 		ucnode = AVL_NEXT(&smb_uch.uc_cache, iter->spi_next);
4357052Samw 
4367052Samw 	if ((iter->spi_next = ucnode) != NULL)
4377052Samw 		return (&ucnode->cn_user);
4387052Samw 
4397052Samw 	return (NULL);
4407052Samw }
4417052Samw 
4427052Samw /*
4437052Samw  * smb_pwd_iterclose
4447052Samw  *
4457052Samw  * Closes the given iterator. Effectively it only unlocks the cache
4467052Samw  */
4477052Samw void
smb_pwd_iterclose(smb_pwditer_t * iter)4487052Samw smb_pwd_iterclose(smb_pwditer_t *iter)
4497052Samw {
4507052Samw 	if (smb_pwd_ops.pwop_iterclose != NULL) {
4517052Samw 		smb_pwd_ops.pwop_iterclose(iter);
4527052Samw 		return;
4537052Samw 	}
4547052Samw 
4557052Samw 	if (iter != NULL)
4567052Samw 		smb_lucache_unlock();
4577052Samw }
4587052Samw 
4597052Samw /*
4607052Samw  * smb_pwd_update
4617052Samw  *
4627052Samw  * Updates the password entry of the given user if the user already
4637052Samw  * has an entry, otherwise it'll add an entry for the user with
4647052Samw  * given password and control information.
4657052Samw  */
4665331Samw static int
smb_pwd_update(const char * name,const char * password,int control)4675331Samw smb_pwd_update(const char *name, const char *password, int control)
4685331Samw {
4695331Samw 	struct stat64 stbuf;
4705331Samw 	FILE *src, *dst;
4715331Samw 	int tempfd;
4725331Samw 	int err = SMB_PWE_SUCCESS;
4735331Samw 	smb_pwbuf_t pwbuf;
4745331Samw 	smb_passwd_t smbpw;
4755331Samw 	boolean_t newent = B_TRUE;
4765331Samw 	boolean_t user_disable = B_FALSE;
4775331Samw 	char uxbuf[1024];
4785331Samw 	struct passwd uxpw;
4795772Sas200622 	int64_t lm_level;
4805331Samw 
4815331Samw 	err = smb_pwd_lock();
4825331Samw 	if (err != SMB_PWE_SUCCESS)
4835331Samw 		return (err);
4845331Samw 
4855331Samw 	if (stat64(SMB_PASSWD, &stbuf) < 0) {
4865331Samw 		err = SMB_PWE_STAT_FAILED;
4875331Samw 		goto passwd_exit;
4885331Samw 	}
4895331Samw 
4905331Samw 	if ((tempfd = open(SMB_PASSTEMP, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
4915331Samw 		err = SMB_PWE_OPEN_FAILED;
4925331Samw 		goto passwd_exit;
4935331Samw 	}
4945331Samw 
4955331Samw 	if ((dst = fdopen(tempfd, "wF")) == NULL) {
4965331Samw 		err = SMB_PWE_OPEN_FAILED;
4975331Samw 		goto passwd_exit;
4985331Samw 	}
4995331Samw 
5005331Samw 	if ((src = fopen(SMB_PASSWD, "rF")) == NULL) {
5015331Samw 		err = SMB_PWE_OPEN_FAILED;
5025331Samw 		(void) fclose(dst);
5035331Samw 		(void) unlink(SMB_PASSTEMP);
5045331Samw 		goto passwd_exit;
5055331Samw 	}
5065331Samw 
5075772Sas200622 	if (smb_config_getnum(SMB_CI_LM_LEVEL, &lm_level) != SMBD_SMF_OK)
5085331Samw 		lm_level = 4;
5095331Samw 
5105331Samw 	if (lm_level >= 4)
5115331Samw 		control |= SMB_PWC_NOLM;
5125331Samw 
5137052Samw 	pwbuf.pw_pwd = &smbpw;
5147052Samw 
5155331Samw 	/*
5165331Samw 	 * copy old password entries to temporary file while replacing
5175331Samw 	 * the entry that matches "name"
5185331Samw 	 */
5197052Samw 	while (smb_pwd_fgetent(src, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
5208474SJose.Borrego@Sun.COM 		if (strcmp(smbpw.pw_name, name) == 0) {
5215331Samw 			err = smb_pwd_chgpwent(&smbpw, password, control);
5225331Samw 			if (err == SMB_PWE_USER_DISABLE)
5235331Samw 				user_disable = B_TRUE;
5245331Samw 			err = smb_pwd_fputent(dst, &pwbuf);
5255331Samw 			newent = B_FALSE;
5265331Samw 		} else {
5275331Samw 			err = smb_pwd_fputent(dst, &pwbuf);
5285331Samw 		}
5295331Samw 
5305331Samw 		if (err != SMB_PWE_SUCCESS) {
5315331Samw 			(void) fclose(src);
5325331Samw 			(void) fclose(dst);
5335331Samw 			goto passwd_exit;
5345331Samw 		}
5355331Samw 	}
5365331Samw 
5375331Samw 	if (newent) {
5385331Samw 		if (getpwnam_r(name, &uxpw, uxbuf, sizeof (uxbuf))) {
5397052Samw 			bzero(&smbpw, sizeof (smb_passwd_t));
5408474SJose.Borrego@Sun.COM 			(void) strlcpy(smbpw.pw_name, uxpw.pw_name,
5418474SJose.Borrego@Sun.COM 			    sizeof (smbpw.pw_name));
5425331Samw 			smbpw.pw_uid = uxpw.pw_uid;
5435331Samw 			(void) smb_pwd_chgpwent(&smbpw, password, control);
5445331Samw 			err = smb_pwd_fputent(dst, &pwbuf);
5455331Samw 		} else {
5465331Samw 			err = SMB_PWE_USER_UNKNOWN;
5475331Samw 		}
5485331Samw 
5495331Samw 		if (err != SMB_PWE_SUCCESS) {
5505331Samw 			(void) fclose(src);
5515331Samw 			(void) fclose(dst);
5525331Samw 			goto passwd_exit;
5535331Samw 		}
5545331Samw 	}
5555331Samw 
5565331Samw 	(void) fclose(src);
5575331Samw 	if (fclose(dst) != 0) {
5585331Samw 		err = SMB_PWE_CLOSE_FAILED;
5595331Samw 		goto passwd_exit; /* Don't trust the temporary file */
5605331Samw 	}
5615331Samw 
5625331Samw 	/* Rename temp to passwd */
5635331Samw 	if (unlink(SMB_OPASSWD) && access(SMB_OPASSWD, 0) == 0) {
5645331Samw 		err = SMB_PWE_UPDATE_FAILED;
5655331Samw 		(void) unlink(SMB_PASSTEMP);
5665331Samw 		goto passwd_exit;
5675331Samw 	}
5685331Samw 
5695331Samw 	if (link(SMB_PASSWD, SMB_OPASSWD) == -1) {
5705331Samw 		err = SMB_PWE_UPDATE_FAILED;
5715331Samw 		(void) unlink(SMB_PASSTEMP);
5725331Samw 		goto passwd_exit;
5735331Samw 	}
5745331Samw 
5755331Samw 	if (rename(SMB_PASSTEMP, SMB_PASSWD) == -1) {
5765331Samw 		err = SMB_PWE_UPDATE_FAILED;
5775331Samw 		(void) unlink(SMB_PASSTEMP);
5785331Samw 		goto passwd_exit;
5795331Samw 	}
5805331Samw 
5815331Samw 	(void) chmod(SMB_PASSWD, 0400);
5825331Samw 
5835331Samw passwd_exit:
5845331Samw 	(void) smb_pwd_unlock();
5855331Samw 	if ((err == SMB_PWE_SUCCESS) && user_disable)
5865331Samw 		err = SMB_PWE_USER_DISABLE;
5875331Samw 
5885331Samw 	return (err);
5895331Samw }
5905331Samw 
5915331Samw /*
5927052Samw  * smb_pwd_fgetent
5935331Samw  *
5945331Samw  * Parse the buffer in the passed pwbuf and fill in the
5955331Samw  * smb password structure to point to the parsed information.
5965331Samw  * The entry format is:
5975331Samw  *
5985331Samw  *	<user-name>:<user-id>:<LM hash>:<NTLM hash>
5995331Samw  *
6007052Samw  * Returns a pointer to the passed pwbuf structure on success,
6015331Samw  * otherwise returns NULL.
6025331Samw  */
6035331Samw static smb_pwbuf_t *
smb_pwd_fgetent(FILE * fp,smb_pwbuf_t * pwbuf,uint32_t flags)6047052Samw smb_pwd_fgetent(FILE *fp, smb_pwbuf_t *pwbuf, uint32_t flags)
6055331Samw {
6065331Samw 	char *argv[SMB_PWD_NARG];
6077052Samw 	char *pwentry;
6085331Samw 	smb_passwd_t *pw;
6095331Samw 	smb_pwdarg_t i;
6105331Samw 	int lm_len, nt_len;
6115331Samw 
6127052Samw 	pwentry = pwbuf->pw_buf;
6137052Samw 	if (fgets(pwentry, SMB_PWD_BUFSIZE, fp) == NULL)
6145331Samw 		return (NULL);
6157052Samw 	(void) trim_whitespace(pwentry);
6165331Samw 
6175331Samw 	for (i = 0; i < SMB_PWD_NARG; ++i) {
6187052Samw 		if ((argv[i] = strsep((char **)&pwentry, ":")) == NULL)
6195331Samw 			return (NULL);
6205331Samw 	}
6215331Samw 
6225331Samw 	if ((*argv[SMB_PWD_NAME] == '\0') || (*argv[SMB_PWD_UID] == '\0'))
6235331Samw 		return (NULL);
6245331Samw 
6255331Samw 	pw = pwbuf->pw_pwd;
6265331Samw 	bzero(pw, sizeof (smb_passwd_t));
6275331Samw 	pw->pw_uid = strtoul(argv[SMB_PWD_UID], 0, 10);
6288474SJose.Borrego@Sun.COM 	(void) strlcpy(pw->pw_name, argv[SMB_PWD_NAME], sizeof (pw->pw_name));
6295331Samw 
6305331Samw 	if (strcmp(argv[SMB_PWD_LMHASH], SMB_PWD_DISABLE) == 0) {
6315331Samw 		pw->pw_flags |= SMB_PWF_DISABLE;
6327052Samw 		if (flags != SMB_PWD_GETF_NOPWD) {
6337052Samw 			(void) strcpy((char *)pw->pw_lmhash, SMB_PWD_DISABLE);
6347052Samw 			(void) strcpy((char *)pw->pw_nthash, SMB_PWD_DISABLE);
6357052Samw 		}
6365331Samw 		return (pwbuf);
6375331Samw 	}
6385331Samw 
6397052Samw 	if (flags == SMB_PWD_GETF_NOPWD)
6407052Samw 		return (pwbuf);
6417052Samw 
6425331Samw 	lm_len = strlen(argv[SMB_PWD_LMHASH]);
6435331Samw 	if (lm_len == SMBAUTH_HEXHASH_SZ) {
6445331Samw 		(void) hextobin(argv[SMB_PWD_LMHASH], SMBAUTH_HEXHASH_SZ,
6455331Samw 		    (char *)pw->pw_lmhash, SMBAUTH_HASH_SZ);
6465331Samw 
6475331Samw 		pw->pw_flags |= SMB_PWF_LM;
6485331Samw 	} else if (lm_len != 0) {
6495331Samw 		return (NULL);
6505331Samw 	}
6515331Samw 
6525331Samw 	nt_len = strlen(argv[SMB_PWD_NTHASH]);
6535331Samw 	if (nt_len == SMBAUTH_HEXHASH_SZ) {
6545331Samw 		(void) hextobin(argv[SMB_PWD_NTHASH], SMBAUTH_HEXHASH_SZ,
6555331Samw 		    (char *)pw->pw_nthash, SMBAUTH_HASH_SZ);
6565331Samw 
6575331Samw 		pw->pw_flags |= SMB_PWF_NT;
6585331Samw 	} else if (nt_len != 0) {
6595331Samw 		return (NULL);
6605331Samw 	}
6615331Samw 
6625331Samw 	return (pwbuf);
6635331Samw }
6645331Samw 
6657052Samw /*
6667052Samw  * smb_pwd_chgpwent
6677052Samw  *
6687052Samw  * Updates the given smb_passwd_t structure with given password and
6697052Samw  * control information.
6707052Samw  */
6715331Samw static int
smb_pwd_chgpwent(smb_passwd_t * smbpw,const char * password,int control)6725331Samw smb_pwd_chgpwent(smb_passwd_t *smbpw, const char *password, int control)
6735331Samw {
6745331Samw 	if (control & SMB_PWC_DISABLE) {
6757052Samw 		/* disable the user */
6765331Samw 		smbpw->pw_flags |= SMB_PWF_DISABLE;
6775331Samw 		(void) strcpy((char *)smbpw->pw_lmhash, SMB_PWD_DISABLE);
6785331Samw 		(void) strcpy((char *)smbpw->pw_nthash, SMB_PWD_DISABLE);
6795331Samw 		smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
6805331Samw 		return (SMB_PWE_SUCCESS);
6817052Samw 	}
6827052Samw 
6837052Samw 	if ((control & SMB_PWC_ENABLE) && (smbpw->pw_flags & SMB_PWF_DISABLE)) {
6847052Samw 		/* enable the user if it's been disabled */
6855331Samw 		*smbpw->pw_lmhash = '\0';
6865331Samw 		*smbpw->pw_nthash = '\0';
6875331Samw 		smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
6885331Samw 		return (SMB_PWE_SUCCESS);
6895331Samw 	}
6905331Samw 
6915331Samw 	/* No password update if account is disabled */
6925331Samw 	if (smbpw->pw_flags & SMB_PWF_DISABLE)
6935331Samw 		return (SMB_PWE_USER_DISABLE);
6945331Samw 
6957052Samw 	/* This call was just to update the control flags */
6967052Samw 	if (password == NULL)
6977052Samw 		return (SMB_PWE_SUCCESS);
6987052Samw 
6995331Samw 	if (control & SMB_PWC_NOLM) {
7007052Samw 		/* LM hash should not be present */
7015331Samw 		smbpw->pw_flags &= ~SMB_PWF_LM;
7025331Samw 		*smbpw->pw_lmhash = '\0';
7035331Samw 	} else {
7045331Samw 		smbpw->pw_flags |= SMB_PWF_LM;
7059832Samw@Sun.COM 		(void) smb_auth_lm_hash(password, smbpw->pw_lmhash);
7065331Samw 	}
7075331Samw 
7085331Samw 	smbpw->pw_flags |= SMB_PWF_NT;
7099832Samw@Sun.COM 	(void) smb_auth_ntlm_hash(password, smbpw->pw_nthash);
7105331Samw 	return (SMB_PWE_SUCCESS);
7115331Samw }
7125331Samw 
7135331Samw /*
7147052Samw  * smb_pwd_fputent
7155331Samw  *
7167052Samw  * If LM/NTLM hash are present, converts them to hex string
7175331Samw  * and write them along with user's name and Id to the smbpasswd
7185331Samw  * file.
7195331Samw  */
7205331Samw static int
smb_pwd_fputent(FILE * fp,const smb_pwbuf_t * pwbuf)7219832Samw@Sun.COM smb_pwd_fputent(FILE *fp, const smb_pwbuf_t *pwbuf)
7225331Samw {
7235331Samw 	smb_passwd_t *pw = pwbuf->pw_pwd;
7245331Samw 	char hex_nthash[SMBAUTH_HEXHASH_SZ+1];
7255331Samw 	char hex_lmhash[SMBAUTH_HEXHASH_SZ+1];
7265331Samw 	int rc;
7275331Samw 
7285331Samw 	if ((pw->pw_flags & SMB_PWF_LM) == SMB_PWF_LM) {
7295331Samw 		(void) bintohex((char *)pw->pw_lmhash, SMBAUTH_HASH_SZ,
7305331Samw 		    hex_lmhash, SMBAUTH_HEXHASH_SZ);
7315331Samw 		hex_lmhash[SMBAUTH_HEXHASH_SZ] = '\0';
7325331Samw 	} else {
7335331Samw 		(void) strcpy(hex_lmhash, (char *)pw->pw_lmhash);
7345331Samw 	}
7355331Samw 
7365331Samw 	if ((pw->pw_flags & SMB_PWF_NT) == SMB_PWF_NT) {
7375331Samw 		(void) bintohex((char *)pw->pw_nthash, SMBAUTH_HASH_SZ,
7385331Samw 		    hex_nthash, SMBAUTH_HEXHASH_SZ);
7395331Samw 		hex_nthash[SMBAUTH_HEXHASH_SZ] = '\0';
7405331Samw 	} else {
7415331Samw 		(void) strcpy(hex_nthash, (char *)pw->pw_nthash);
7425331Samw 	}
7435331Samw 
7448474SJose.Borrego@Sun.COM 	rc = fprintf(fp, "%s:%u:%s:%s\n", pw->pw_name, pw->pw_uid,
7455331Samw 	    hex_lmhash, hex_nthash);
7465331Samw 
7475331Samw 	if (rc <= 0)
7485331Samw 		return (SMB_PWE_WRITE_FAILED);
7495331Samw 
7505331Samw 	return (SMB_PWE_SUCCESS);
7515331Samw }
7525331Samw 
7537052Samw /*
7547052Samw  * smb_pwd_lock
7557052Samw  *
7567052Samw  * A wrapper around smb_pwd_flck() which locks smb password
7577052Samw  * file so that only one thread at a time is operational.
7587052Samw  */
7595331Samw static int
smb_pwd_lock(void)7605331Samw smb_pwd_lock(void)
7615331Samw {
7625331Samw 	int res;
7635331Samw 
7645331Samw 	if (smb_pwd_flck()) {
7655331Samw 		switch (errno) {
7665331Samw 		case EINTR:
7675331Samw 			res = SMB_PWE_BUSY;
7685331Samw 			break;
7695331Samw 		case EACCES:
7705331Samw 			res = SMB_PWE_DENIED;
7715331Samw 			break;
7725331Samw 		case 0:
7735331Samw 			res = SMB_PWE_SUCCESS;
7745331Samw 			break;
7755331Samw 		}
7765331Samw 	} else
7775331Samw 		res = SMB_PWE_SUCCESS;
7785331Samw 
7795331Samw 	return (res);
7805331Samw }
7815331Samw 
7827052Samw /*
78311633SJoyce.McIntosh@Sun.COM  * smb_pwd_unlock
7847052Samw  *
7857052Samw  * A wrapper around smb_pwd_fulck() which unlocks
7867052Samw  * smb password file.
7877052Samw  */
7885331Samw static int
smb_pwd_unlock(void)7895331Samw smb_pwd_unlock(void)
7905331Samw {
7915331Samw 	if (smb_pwd_fulck())
7925331Samw 		return (SMB_PWE_SYSTEM_ERROR);
7935331Samw 
7945331Samw 	return (SMB_PWE_SUCCESS);
7955331Samw }
7965331Samw 
7977052Samw /*
7987052Samw  * smb_pwd_flck
7997052Samw  *
8007052Samw  * Creates a lock file and grabs an exclusive (write) lock on it.
8017052Samw  */
8025331Samw static int
smb_pwd_flck(void)8035331Samw smb_pwd_flck(void)
8045331Samw {
8055331Samw 	int seconds = 0;
8065331Samw 
8075331Samw 	(void) mutex_lock(&lck_lock);
8085331Samw 	for (;;) {
8095331Samw 		if (lck_pid != 0 && lck_pid != getpid()) {
8105331Samw 			/* somebody forked */
8115331Samw 			lck_pid = 0;
8125331Samw 			lck_tid = 0;
8135331Samw 		}
8145331Samw 
8155331Samw 		if (lck_tid == 0) {
8165331Samw 			if ((fildes = creat(SMB_PASSLCK, 0600)) == -1)
8175331Samw 				break;
8185331Samw 			flock.l_type = F_WRLCK;
8195331Samw 			if (fcntl(fildes, F_SETLK, &flock) != -1) {
8205331Samw 				lck_pid = getpid();
8215331Samw 				lck_tid = thr_self();
8225331Samw 				(void) mutex_unlock(&lck_lock);
8235331Samw 				return (0);
8245331Samw 			}
8255331Samw 			(void) close(fildes);
8265331Samw 			fildes = -1;
8275331Samw 		}
8285331Samw 
8295331Samw 		if (seconds++ >= S_WAITTIME) {
8305331Samw 			/*
8315331Samw 			 * For compatibility with the past, pretend
8325331Samw 			 * that we were interrupted by SIGALRM.
8335331Samw 			 */
8345331Samw 			errno = EINTR;
8355331Samw 			break;
8365331Samw 		}
8375331Samw 
8385331Samw 		(void) mutex_unlock(&lck_lock);
8395331Samw 		(void) sleep(1);
8405331Samw 		(void) mutex_lock(&lck_lock);
8415331Samw 	}
8425331Samw 	(void) mutex_unlock(&lck_lock);
8435331Samw 
8445331Samw 	return (-1);
8455331Samw }
8465331Samw 
8477052Samw /*
8487052Samw  * smb_pwd_fulck
8497052Samw  *
8507052Samw  * Unlocks smb password file for operations done via
8517052Samw  * this library APIs.
8527052Samw  */
8535331Samw static int
smb_pwd_fulck(void)8545331Samw smb_pwd_fulck(void)
8555331Samw {
8565331Samw 	(void) mutex_lock(&lck_lock);
8575331Samw 	if (lck_tid == thr_self() && fildes >= 0) {
8585331Samw 		flock.l_type = F_UNLCK;
8595331Samw 		(void) fcntl(fildes, F_SETLK, &flock);
8605331Samw 		(void) close(fildes);
8615331Samw 		fildes = -1;
8625331Samw 		lck_pid = 0;
8635331Samw 		lck_tid = 0;
8645331Samw 		(void) mutex_unlock(&lck_lock);
8655331Samw 		return (0);
8665331Samw 	}
8675331Samw 	(void) mutex_unlock(&lck_lock);
8685331Samw 	return (-1);
8695331Samw }
8707052Samw 
8717052Samw /*
8727052Samw  * Local User Cache Functions
8737052Samw  *
8747052Samw  * Local user cache is implemented using AVL tree
8757052Samw  */
8767052Samw 
8777052Samw /*
8787052Samw  * smb_lucache_cmp
8797052Samw  *
8807052Samw  * AVL compare function, the key is username.
8817052Samw  */
8827052Samw static int
smb_lucache_cmp(const void * p1,const void * p2)8837052Samw smb_lucache_cmp(const void *p1, const void *p2)
8847052Samw {
8857052Samw 	smb_ucnode_t *u1 = (smb_ucnode_t *)p1;
8867052Samw 	smb_ucnode_t *u2 = (smb_ucnode_t *)p2;
8877052Samw 	int rc;
8887052Samw 
8897052Samw 	rc = strcmp(u1->cn_user.su_name, u2->cn_user.su_name);
8907052Samw 
8917052Samw 	if (rc < 0)
8927052Samw 		return (-1);
8937052Samw 
8947052Samw 	if (rc > 0)
8957052Samw 		return (1);
8967052Samw 
8977052Samw 	return (0);
8987052Samw }
8997052Samw 
9007052Samw /*
9017052Samw  * smb_lucache_update
9027052Samw  *
9037052Samw  * Updates the cache if needed. Whether an update is needed
9047052Samw  * is determined based on smbpasswd file modification timestamp
9057052Samw  */
9067052Samw static void
smb_lucache_update(void)9077052Samw smb_lucache_update(void)
9087052Samw {
9097052Samw 	struct stat64 stbuf;
9107052Samw 	int rc;
9117052Samw 
9127052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
9137052Samw 	switch (smb_uch.uc_state) {
9147052Samw 	default:
9157052Samw 	case SMB_UCHS_NOCACHE:
9167052Samw 		assert(0);
9177052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
9187052Samw 		return;
9197052Samw 
9207052Samw 	case SMB_UCHS_CREATED:
9217052Samw 	case SMB_UCHS_UPDATED:
9227052Samw 		break;
9237052Samw 
9247052Samw 	case SMB_UCHS_UPDATING:
9257052Samw 		/* Want only one thread executing this function at a time */
9267052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
9277052Samw 		return;
9287052Samw 
9297052Samw 	case SMB_UCHS_DESTROYING:
9307052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
9317052Samw 		return;
9327052Samw 	}
9337052Samw 
9347052Samw 	/*
9357052Samw 	 * smb_pwd_lock() is not called here so it can
9367052Samw 	 * be checked quickly whether an updated is needed
9377052Samw 	 */
9387052Samw 	if (stat64(SMB_PASSWD, &stbuf) < 0) {
9397052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
9407052Samw 		if (errno != ENOENT)
9417052Samw 			return;
9427052Samw 
9437052Samw 		/* no smbpasswd file; empty the cache */
9447052Samw 		smb_lucache_flush();
9457052Samw 		return;
9467052Samw 	}
9477052Samw 
9487052Samw 	if (stbuf.st_size == 0) {
9497052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
9507052Samw 
9517052Samw 		/* empty smbpasswd file; empty the cache */
9527052Samw 		smb_lucache_flush();
9537052Samw 		return;
9547052Samw 	}
9557052Samw 
9567052Samw 	if ((smb_uch.uc_timestamp.tv_sec == stbuf.st_mtim.tv_sec) &&
9577052Samw 	    (smb_uch.uc_timestamp.tv_nsec == stbuf.st_mtim.tv_nsec)) {
9587052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
9597052Samw 		/* No changes since the last cache update */
9607052Samw 		return;
9617052Samw 	}
9627052Samw 
9637052Samw 	smb_uch.uc_state = SMB_UCHS_UPDATING;
9647052Samw 	smb_uch.uc_refcnt++;
9657052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
9667052Samw 
9677052Samw 	rc = smb_lucache_do_update();
9687052Samw 
9697052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
9707052Samw 	if ((rc == SMB_PWE_SUCCESS) && (stat64(SMB_PASSWD, &stbuf) == 0))
9717052Samw 		smb_uch.uc_timestamp = stbuf.st_mtim;
9727052Samw 	smb_uch.uc_state = SMB_UCHS_UPDATED;
9737052Samw 	smb_uch.uc_refcnt--;
9747052Samw 	(void) cond_broadcast(&smb_uch.uc_cv);
9757052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
9767052Samw }
9777052Samw 
9787052Samw /*
9797052Samw  * smb_lucache_do_update
9807052Samw  *
9817052Samw  * This function takes care of updating the AVL tree.
9827052Samw  * If an entry has been updated, it'll be modified in place.
9837052Samw  *
9847052Samw  * New entries will be added to a temporary AVL tree then
9857052Samw  * passwod file is unlocked and all the new entries will
9867052Samw  * be transferred to the main cache from the temporary tree.
9877052Samw  *
9887052Samw  * This function MUST NOT be called directly
9897052Samw  */
9907052Samw static int
smb_lucache_do_update(void)9917052Samw smb_lucache_do_update(void)
9927052Samw {
9937052Samw 	avl_tree_t tmp_cache;
9947052Samw 	smb_pwbuf_t pwbuf;
9957052Samw 	smb_passwd_t smbpw;
9967052Samw 	smb_ucnode_t uc_node;
9977052Samw 	smb_ucnode_t *uc_newnode;
9987052Samw 	smb_luser_t *user;
9997052Samw 	smb_sid_t *sid;
10007052Samw 	idmap_stat idm_stat;
10017052Samw 	int rc = SMB_PWE_SUCCESS;
10027052Samw 	void *cookie = NULL;
10037052Samw 	FILE *fp;
10047052Samw 
10057052Samw 	if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS)
10067052Samw 		return (rc);
10077052Samw 
10087052Samw 	if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
10097052Samw 		(void) smb_pwd_unlock();
10107052Samw 		return (SMB_PWE_OPEN_FAILED);
10117052Samw 	}
10127052Samw 
10137052Samw 	avl_create(&tmp_cache, smb_lucache_cmp,
10147052Samw 	    sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link));
10157052Samw 
10167052Samw 	bzero(&pwbuf, sizeof (smb_pwbuf_t));
10177052Samw 	pwbuf.pw_pwd = &smbpw;
10187052Samw 
10197052Samw 	(void) rw_rdlock(&smb_uch.uc_cache_lck);
10207052Samw 
10217052Samw 	while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_NOPWD) != NULL) {
10228474SJose.Borrego@Sun.COM 		uc_node.cn_user.su_name = smbpw.pw_name;
10237052Samw 		uc_newnode = avl_find(&smb_uch.uc_cache, &uc_node, NULL);
10247052Samw 		if (uc_newnode) {
10257052Samw 			/* update the node info */
10267052Samw 			uc_newnode->cn_user.su_ctrl = smbpw.pw_flags;
10277052Samw 			continue;
10287052Samw 		}
10297052Samw 
10307052Samw 		/* create a new node */
10317052Samw 		if ((uc_newnode = malloc(sizeof (smb_ucnode_t))) == NULL) {
10327052Samw 			rc = SMB_PWE_NO_MEMORY;
10337052Samw 			break;
10347052Samw 		}
10357052Samw 
10367052Samw 		bzero(uc_newnode, sizeof (smb_ucnode_t));
10377052Samw 		user = &uc_newnode->cn_user;
10387052Samw 		user->su_ctrl = smbpw.pw_flags;
10397052Samw 
10407052Samw 		idm_stat = smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, &sid);
10417052Samw 		if (idm_stat != IDMAP_SUCCESS) {
10427052Samw 			syslog(LOG_WARNING, "smb_pwdutil: couldn't obtain SID "
10437052Samw 			    "for uid=%u (%d)", smbpw.pw_uid, idm_stat);
10447052Samw 			free(uc_newnode);
10457052Samw 			continue;
10467052Samw 		}
10477052Samw 		(void) smb_sid_getrid(sid, &user->su_rid);
10487052Samw 		smb_sid_free(sid);
10497052Samw 
10508474SJose.Borrego@Sun.COM 		user->su_name = strdup(smbpw.pw_name);
10517052Samw 		if (user->su_name == NULL) {
10527052Samw 			rc = SMB_PWE_NO_MEMORY;
10537052Samw 			free(uc_newnode);
10547052Samw 			break;
10557052Samw 		}
10567052Samw 
10577052Samw 		avl_add(&tmp_cache, uc_newnode);
10587052Samw 	}
10597052Samw 
10607052Samw 	(void) rw_unlock(&smb_uch.uc_cache_lck);
10617052Samw 	(void) fclose(fp);
10627052Samw 	(void) smb_pwd_unlock();
10637052Samw 
10647052Samw 	/* Destroy the temporary list */
10657052Samw 	(void) rw_wrlock(&smb_uch.uc_cache_lck);
10667052Samw 	while ((uc_newnode = avl_destroy_nodes(&tmp_cache, &cookie)) != NULL) {
10677052Samw 		avl_add(&smb_uch.uc_cache, uc_newnode);
10687052Samw 	}
10697052Samw 	(void) rw_unlock(&smb_uch.uc_cache_lck);
10707052Samw 
10717052Samw 	avl_destroy(&tmp_cache);
10727052Samw 
10737052Samw 	return (rc);
10747052Samw }
10757052Samw 
10767052Samw /*
10777052Samw  * smb_lucache_create
10787052Samw  *
10797052Samw  * Creates the AVL tree and initializes the global user cache handle.
10807052Samw  * This function doesn't populate the cache.
10817052Samw  * User cache is only created by smbd at startup
10827052Samw  */
10837052Samw static void
smb_lucache_create(void)10847052Samw smb_lucache_create(void)
10857052Samw {
10867052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
10877052Samw 	if (smb_uch.uc_state != SMB_UCHS_NOCACHE) {
10887052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
10897052Samw 		return;
10907052Samw 	}
10917052Samw 
10927052Samw 	avl_create(&smb_uch.uc_cache, smb_lucache_cmp,
10937052Samw 	    sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link));
10947052Samw 
10957052Samw 	smb_uch.uc_state = SMB_UCHS_CREATED;
10967052Samw 	bzero(&smb_uch.uc_timestamp, sizeof (timestruc_t));
10977052Samw 	smb_uch.uc_refcnt = 0;
10987052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
10997052Samw }
11007052Samw 
11017052Samw /*
11027052Samw  * smb_lucache_flush
11037052Samw  *
11047052Samw  * Removes and frees all the cache entries
11057052Samw  */
11067052Samw static void
smb_lucache_flush(void)11077052Samw smb_lucache_flush(void)
11087052Samw {
11097052Samw 	void *cookie = NULL;
11107052Samw 	smb_ucnode_t *ucnode;
11117052Samw 
11127052Samw 	(void) rw_wrlock(&smb_uch.uc_cache_lck);
11137052Samw 	while ((ucnode = avl_destroy_nodes(&smb_uch.uc_cache, &cookie))
11147052Samw 	    != NULL) {
11157052Samw 		free(ucnode->cn_user.su_name);
11167052Samw 		free(ucnode->cn_user.su_fullname);
11177052Samw 		free(ucnode->cn_user.su_desc);
11187052Samw 		free(ucnode);
11197052Samw 	}
11207052Samw 	(void) rw_unlock(&smb_uch.uc_cache_lck);
11217052Samw }
11227052Samw 
11237052Samw /*
11247052Samw  * smb_lucache_destroy
11257052Samw  *
11267052Samw  * Destroys the cache.
11277052Samw  * This function is only called in smb_pwd_fini()
11287052Samw  * User cache is only destroyed by smbd upon shutdown
11297052Samw  */
11307052Samw static void
smb_lucache_destroy(void)11317052Samw smb_lucache_destroy(void)
11327052Samw {
11337052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
11347052Samw 	switch (smb_uch.uc_state) {
11357052Samw 	case SMB_UCHS_NOCACHE:
11367052Samw 	case SMB_UCHS_DESTROYING:
11377052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
11387052Samw 		return;
11397052Samw 
11407052Samw 	default:
11417052Samw 		break;
11427052Samw 	}
11437052Samw 
11447052Samw 	smb_uch.uc_state = SMB_UCHS_DESTROYING;
11457052Samw 
11467052Samw 	while (smb_uch.uc_refcnt > 0)
11477052Samw 		(void) cond_wait(&smb_uch.uc_cv, &smb_uch.uc_mtx);
11487052Samw 
11497052Samw 	smb_lucache_flush();
11507052Samw 
11517052Samw 	avl_destroy(&smb_uch.uc_cache);
11527052Samw 	smb_uch.uc_state = SMB_UCHS_NOCACHE;
11537052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
11547052Samw }
11557052Samw 
11567052Samw /*
11577052Samw  * smb_lucache_lock
11587052Samw  *
11597052Samw  * Locks the user cache for reading and also
11607052Samw  * increment the handle reference count.
11617052Samw  */
11627052Samw static int
smb_lucache_lock(void)11637052Samw smb_lucache_lock(void)
11647052Samw {
11657052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
11667052Samw 	switch (smb_uch.uc_state) {
11677052Samw 	case SMB_UCHS_NOCACHE:
11687052Samw 		assert(0);
11697052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
11707052Samw 		return (SMB_PWE_DENIED);
11717052Samw 
11727052Samw 	case SMB_UCHS_DESTROYING:
11737052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
11747052Samw 		return (SMB_PWE_DENIED);
11757052Samw 	}
11767052Samw 	smb_uch.uc_refcnt++;
11777052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
11787052Samw 
11797052Samw 	(void) rw_rdlock(&smb_uch.uc_cache_lck);
11807052Samw 	return (SMB_PWE_SUCCESS);
11817052Samw }
11827052Samw 
11837052Samw /*
11847052Samw  * smb_lucache_unlock
11857052Samw  *
11867052Samw  * Unlock the cache
11877052Samw  */
11887052Samw static void
smb_lucache_unlock(void)11897052Samw smb_lucache_unlock(void)
11907052Samw {
11917052Samw 	(void) rw_unlock(&smb_uch.uc_cache_lck);
11927052Samw 
11937052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
11947052Samw 	smb_uch.uc_refcnt--;
11957052Samw 	(void) cond_broadcast(&smb_uch.uc_cv);
11967052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
11977052Samw }
11987052Samw 
11997052Samw /*
12007052Samw  * smb_lucache_num
12017052Samw  *
12027052Samw  * Returns the number of cache entries
12037052Samw  */
12047052Samw static int
smb_lucache_num(void)12057052Samw smb_lucache_num(void)
12067052Samw {
12077052Samw 	int num;
12087052Samw 
12097052Samw 	(void) mutex_lock(&smb_uch.uc_mtx);
12107052Samw 	switch (smb_uch.uc_state) {
12117052Samw 	case SMB_UCHS_NOCACHE:
12127052Samw 		assert(0);
12137052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
12147052Samw 		return (0);
12157052Samw 
12167052Samw 	case SMB_UCHS_DESTROYING:
12177052Samw 		(void) mutex_unlock(&smb_uch.uc_mtx);
12187052Samw 		return (0);
12197052Samw 	}
12207052Samw 	(void) mutex_unlock(&smb_uch.uc_mtx);
12217052Samw 
12227052Samw 	(void) rw_rdlock(&smb_uch.uc_cache_lck);
12237052Samw 	num = (int)avl_numnodes(&smb_uch.uc_cache);
12247052Samw 	(void) rw_unlock(&smb_uch.uc_cache_lck);
12257052Samw 
12267052Samw 	return (num);
12277052Samw }
1228