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