1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21da6c28aaSamw /*
2296a62adaSjoyce mcintosh * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23da6c28aaSamw * Use is subject to license terms.
24*12b65585SGordon Ross *
25*12b65585SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26da6c28aaSamw */
27da6c28aaSamw
289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <syslog.h>
29da6c28aaSamw #include <stdlib.h>
30da6c28aaSamw #include <unistd.h>
31da6c28aaSamw #include <limits.h>
32da6c28aaSamw #include <strings.h>
33da6c28aaSamw #include <synch.h>
34da6c28aaSamw #include <errno.h>
35da6c28aaSamw #include <sys/types.h>
36da6c28aaSamw #include <sys/stat.h>
373db3f65cSamw #include <sys/avl.h>
38da6c28aaSamw #include <fcntl.h>
39da6c28aaSamw #include <thread.h>
40da6c28aaSamw #include <pwd.h>
417b59d02dSjb150015 #include <dlfcn.h>
427b59d02dSjb150015 #include <link.h>
433db3f65cSamw #include <assert.h>
44da6c28aaSamw #include <smbsrv/libsmb.h>
45da6c28aaSamw
46da6c28aaSamw #define SMB_PASSWD "/var/smb/smbpasswd"
47da6c28aaSamw #define SMB_OPASSWD "/var/smb/osmbpasswd"
48da6c28aaSamw #define SMB_PASSTEMP "/var/smb/ptmp"
49da6c28aaSamw #define SMB_PASSLCK "/var/smb/.pwd.lock"
503db3f65cSamw
51da6c28aaSamw #define SMB_PWD_DISABLE "*DIS*"
52da6c28aaSamw #define SMB_PWD_BUFSIZE 256
53da6c28aaSamw
54da6c28aaSamw #define S_WAITTIME 15
55da6c28aaSamw
56da6c28aaSamw typedef enum {
57da6c28aaSamw SMB_PWD_NAME = 0,
58da6c28aaSamw SMB_PWD_UID,
59da6c28aaSamw SMB_PWD_LMHASH,
60da6c28aaSamw SMB_PWD_NTHASH,
61da6c28aaSamw SMB_PWD_NARG
62da6c28aaSamw } smb_pwdarg_t;
63da6c28aaSamw
643db3f65cSamw static struct flock flock = { 0, 0, 0, 0, 0, 0 };
65da6c28aaSamw static pid_t lck_pid = 0; /* process's pid at last lock */
66da6c28aaSamw static thread_t lck_tid = 0; /* thread that holds the lock */
67da6c28aaSamw static int fildes = -1;
68da6c28aaSamw static mutex_t lck_lock = DEFAULTMUTEX;
697b59d02dSjb150015 static void *smb_pwd_hdl = NULL;
70da6c28aaSamw
717b59d02dSjb150015 static struct {
7289dc44ceSjose borrego smb_passwd_t *(*pwop_getpwnam)(const char *, smb_passwd_t *);
7389dc44ceSjose borrego smb_passwd_t *(*pwop_getpwuid)(uid_t, smb_passwd_t *);
743db3f65cSamw int (*pwop_setcntl)(const char *, int);
753db3f65cSamw int (*pwop_setpasswd)(const char *, const char *);
763db3f65cSamw int (*pwop_num)(void);
773db3f65cSamw int (*pwop_iteropen)(smb_pwditer_t *);
783db3f65cSamw smb_luser_t *(*pwop_iterate)(smb_pwditer_t *);
793db3f65cSamw void (*pwop_iterclose)(smb_pwditer_t *);
807b59d02dSjb150015 } smb_pwd_ops;
817b59d02dSjb150015
82da6c28aaSamw static int smb_pwd_lock(void);
83da6c28aaSamw static int smb_pwd_unlock(void);
84da6c28aaSamw static int smb_pwd_flck(void);
85da6c28aaSamw static int smb_pwd_fulck(void);
86da6c28aaSamw
873db3f65cSamw /*
883db3f65cSamw * buffer structure used by smb_pwd_fgetent/smb_pwd_fputent
893db3f65cSamw */
903db3f65cSamw typedef struct smb_pwbuf {
913db3f65cSamw char pw_buf[SMB_PWD_BUFSIZE];
923db3f65cSamw smb_passwd_t *pw_pwd;
933db3f65cSamw } smb_pwbuf_t;
943db3f65cSamw
953db3f65cSamw /*
963db3f65cSamw * flag values used with smb_pwd_fgetent
973db3f65cSamw */
983db3f65cSamw #define SMB_PWD_GETF_ALL 1 /* get all the account info */
993db3f65cSamw #define SMB_PWD_GETF_NOPWD 2 /* password is not needed */
1003db3f65cSamw
1013db3f65cSamw static smb_pwbuf_t *smb_pwd_fgetent(FILE *, smb_pwbuf_t *, uint32_t);
10229bd2886SAlan Wright static int smb_pwd_fputent(FILE *, const smb_pwbuf_t *);
103da6c28aaSamw static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int);
104da6c28aaSamw static int smb_pwd_update(const char *, const char *, int);
105da6c28aaSamw
1063db3f65cSamw /*
1073db3f65cSamw * Local Users Cache
1083db3f65cSamw *
1093db3f65cSamw * Simplifying assumptions
1103db3f65cSamw *
1113db3f65cSamw * o smbpasswd is a service private file and shouldn't be edited manually
1123db3f65cSamw * o accounts are only added/modified via passwd and/or smbadm CLIs
1133db3f65cSamw * o accounts are not removed but disabled using smbadm CLI
1143db3f65cSamw * o editing smbpasswd manually might result in cache inconsistency
1153db3f65cSamw *
1163db3f65cSamw * Cache is created and populated upon service startup.
1173db3f65cSamw * Cache is updated each time users list is requested if there's been
1183db3f65cSamw * any change in smbpasswd file. The change criteria is smbpasswd's
1193db3f65cSamw * modification timestamp.
1203db3f65cSamw */
1217b59d02dSjb150015
1223db3f65cSamw /*
1233db3f65cSamw * User cache handle
1243db3f65cSamw */
1253db3f65cSamw typedef struct smb_uchandle {
1263db3f65cSamw avl_tree_t uc_cache;
1273db3f65cSamw rwlock_t uc_cache_lck;
1283db3f65cSamw timestruc_t uc_timestamp;
1293db3f65cSamw uint32_t uc_refcnt;
1303db3f65cSamw uint32_t uc_state;
1313db3f65cSamw mutex_t uc_mtx;
1323db3f65cSamw cond_t uc_cv;
1333db3f65cSamw } smb_uchandle_t;
1343db3f65cSamw
1353db3f65cSamw #define SMB_UCHS_NOCACHE 0
1363db3f65cSamw #define SMB_UCHS_CREATED 1
1373db3f65cSamw #define SMB_UCHS_UPDATING 2
1383db3f65cSamw #define SMB_UCHS_UPDATED 3
1393db3f65cSamw #define SMB_UCHS_DESTROYING 4
1403db3f65cSamw
1413db3f65cSamw /*
1423db3f65cSamw * User cache node
1433db3f65cSamw */
1443db3f65cSamw typedef struct smb_ucnode {
1453db3f65cSamw smb_luser_t cn_user;
1463db3f65cSamw avl_node_t cn_link;
1473db3f65cSamw } smb_ucnode_t;
1483db3f65cSamw
1493db3f65cSamw static void smb_lucache_create(void);
1503db3f65cSamw static void smb_lucache_destroy(void);
1513db3f65cSamw static void smb_lucache_update(void);
1523db3f65cSamw static int smb_lucache_num(void);
1533db3f65cSamw static int smb_lucache_lock(void);
1543db3f65cSamw static void smb_lucache_unlock(void);
1553db3f65cSamw static int smb_lucache_do_update(void);
1563db3f65cSamw static void smb_lucache_flush(void);
1573db3f65cSamw
1583db3f65cSamw static smb_uchandle_t smb_uch;
1593db3f65cSamw
1603db3f65cSamw /*
1613db3f65cSamw * smb_pwd_init
1623db3f65cSamw *
1633db3f65cSamw * Initializes the cache if requested.
1643db3f65cSamw * Checks to see if a password management utility library
1653db3f65cSamw * is interposed. If yes then it'll initializes smb_pwd_ops
1663db3f65cSamw * structure with function pointers from this library.
1673db3f65cSamw */
1683db3f65cSamw void
smb_pwd_init(boolean_t create_cache)1693db3f65cSamw smb_pwd_init(boolean_t create_cache)
1703db3f65cSamw {
1713db3f65cSamw if (create_cache) {
1723db3f65cSamw smb_lucache_create();
173fe1c642dSBill Krier #if 0
174fe1c642dSBill Krier /*
175fe1c642dSBill Krier * This pre-loading of the cache results in idmapd requests.
176fe1c642dSBill Krier * With the change to allow idmapd to call into libsmb to
177fe1c642dSBill Krier * map names and SIDs, this creates a circular startup
178fe1c642dSBill Krier * dependency. This call has been temporarily disabled to
179fe1c642dSBill Krier * avoid this issue. It can be enabled when the name/SID
180fe1c642dSBill Krier * lookup can be done directly on the LSA service.
181fe1c642dSBill Krier */
1823db3f65cSamw smb_lucache_update();
183fe1c642dSBill Krier #endif
1843db3f65cSamw }
1853db3f65cSamw
1861fcced4cSJordan Brown smb_pwd_hdl = smb_dlopen();
1871fcced4cSJordan Brown if (smb_pwd_hdl == NULL)
1883db3f65cSamw return;
1897b59d02dSjb150015
1907b59d02dSjb150015 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
1917b59d02dSjb150015
19289dc44ceSjose borrego smb_pwd_ops.pwop_getpwnam =
19389dc44ceSjose borrego (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpwnam");
19489dc44ceSjose borrego
19589dc44ceSjose borrego smb_pwd_ops.pwop_getpwuid =
19689dc44ceSjose borrego (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpwuid");
1977b59d02dSjb150015
1983db3f65cSamw smb_pwd_ops.pwop_setcntl =
1997b59d02dSjb150015 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setcntl");
2007b59d02dSjb150015
2013db3f65cSamw smb_pwd_ops.pwop_setpasswd =
2027b59d02dSjb150015 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setpasswd");
2037b59d02dSjb150015
2043db3f65cSamw smb_pwd_ops.pwop_num =
2053db3f65cSamw (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_num");
2063db3f65cSamw
2073db3f65cSamw smb_pwd_ops.pwop_iteropen =
2083db3f65cSamw (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_iteropen");
2093db3f65cSamw
2103db3f65cSamw smb_pwd_ops.pwop_iterclose =
2113db3f65cSamw (void (*)())dlsym(smb_pwd_hdl, "smb_pwd_iterclose");
2123db3f65cSamw
2133db3f65cSamw smb_pwd_ops.pwop_iterate =
2143db3f65cSamw (smb_luser_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_iterate");
2153db3f65cSamw
21689dc44ceSjose borrego if (smb_pwd_ops.pwop_getpwnam == NULL ||
21789dc44ceSjose borrego smb_pwd_ops.pwop_getpwuid == NULL ||
2183db3f65cSamw smb_pwd_ops.pwop_setcntl == NULL ||
2193db3f65cSamw smb_pwd_ops.pwop_setpasswd == NULL ||
2203db3f65cSamw smb_pwd_ops.pwop_num == NULL ||
2213db3f65cSamw smb_pwd_ops.pwop_iteropen == NULL ||
2223db3f65cSamw smb_pwd_ops.pwop_iterclose == NULL ||
2233db3f65cSamw smb_pwd_ops.pwop_iterate == NULL) {
2241fcced4cSJordan Brown smb_dlclose(smb_pwd_hdl);
2257b59d02dSjb150015 smb_pwd_hdl = NULL;
2267b59d02dSjb150015
2277b59d02dSjb150015 /* If error or function(s) are missing, use original lib */
2287b59d02dSjb150015 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
2297b59d02dSjb150015 }
2307b59d02dSjb150015 }
2317b59d02dSjb150015
2323db3f65cSamw /*
2333db3f65cSamw * smb_pwd_fini
2343db3f65cSamw *
2353db3f65cSamw * Destroys the cache.
2363db3f65cSamw * Closes interposed library.
2373db3f65cSamw */
2387b59d02dSjb150015 void
smb_pwd_fini(void)2397b59d02dSjb150015 smb_pwd_fini(void)
2407b59d02dSjb150015 {
2413db3f65cSamw smb_lucache_destroy();
2421fcced4cSJordan Brown smb_dlclose(smb_pwd_hdl);
2437b59d02dSjb150015 smb_pwd_hdl = NULL;
2441fcced4cSJordan Brown bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
2457b59d02dSjb150015 }
2467b59d02dSjb150015
247da6c28aaSamw /*
24889dc44ceSjose borrego * smb_pwd_getpwnam
249da6c28aaSamw *
250da6c28aaSamw * Returns a smb password structure for the given user name.
251da6c28aaSamw * smbpw is a pointer to a buffer allocated by the caller.
252da6c28aaSamw *
253da6c28aaSamw * Returns NULL upon failure.
254da6c28aaSamw */
255da6c28aaSamw smb_passwd_t *
smb_pwd_getpwnam(const char * name,smb_passwd_t * smbpw)25689dc44ceSjose borrego smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw)
257da6c28aaSamw {
258da6c28aaSamw boolean_t found = B_FALSE;
259da6c28aaSamw smb_pwbuf_t pwbuf;
260da6c28aaSamw FILE *fp;
2613db3f65cSamw int err;
262da6c28aaSamw
26389dc44ceSjose borrego if (smb_pwd_ops.pwop_getpwnam != NULL)
26489dc44ceSjose borrego return (smb_pwd_ops.pwop_getpwnam(name, smbpw));
2657b59d02dSjb150015
266da6c28aaSamw err = smb_pwd_lock();
267*12b65585SGordon Ross if (err != SMB_PWE_SUCCESS) {
268*12b65585SGordon Ross syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", err);
269da6c28aaSamw return (NULL);
270*12b65585SGordon Ross }
271da6c28aaSamw
272da6c28aaSamw if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
273*12b65585SGordon Ross syslog(LOG_WARNING, "smb_pwdutil: open failed, %m");
274da6c28aaSamw (void) smb_pwd_unlock();
275da6c28aaSamw return (NULL);
276da6c28aaSamw }
277da6c28aaSamw
278da6c28aaSamw pwbuf.pw_pwd = smbpw;
279da6c28aaSamw
2803db3f65cSamw while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
28189dc44ceSjose borrego if (strcmp(name, smbpw->pw_name) == 0) {
28289dc44ceSjose borrego found = B_TRUE;
28389dc44ceSjose borrego break;
28489dc44ceSjose borrego }
28589dc44ceSjose borrego }
28689dc44ceSjose borrego
28789dc44ceSjose borrego (void) fclose(fp);
28889dc44ceSjose borrego (void) smb_pwd_unlock();
28989dc44ceSjose borrego
29089dc44ceSjose borrego if (!found) {
29189dc44ceSjose borrego bzero(smbpw, sizeof (smb_passwd_t));
29289dc44ceSjose borrego return (NULL);
29389dc44ceSjose borrego }
29489dc44ceSjose borrego
29589dc44ceSjose borrego return (smbpw);
29689dc44ceSjose borrego }
29789dc44ceSjose borrego
29889dc44ceSjose borrego /*
29989dc44ceSjose borrego * smb_pwd_getpwuid
30089dc44ceSjose borrego *
30189dc44ceSjose borrego * Returns a smb password structure for the given UID
30289dc44ceSjose borrego * smbpw is a pointer to a buffer allocated by the caller.
30389dc44ceSjose borrego *
30489dc44ceSjose borrego * Returns NULL upon failure.
30589dc44ceSjose borrego */
30689dc44ceSjose borrego smb_passwd_t *
smb_pwd_getpwuid(uid_t uid,smb_passwd_t * smbpw)30789dc44ceSjose borrego smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw)
30889dc44ceSjose borrego {
30989dc44ceSjose borrego boolean_t found = B_FALSE;
31089dc44ceSjose borrego smb_pwbuf_t pwbuf;
31189dc44ceSjose borrego FILE *fp;
31289dc44ceSjose borrego int err;
31389dc44ceSjose borrego
31489dc44ceSjose borrego if (smb_pwd_ops.pwop_getpwuid != NULL)
31589dc44ceSjose borrego return (smb_pwd_ops.pwop_getpwuid(uid, smbpw));
31689dc44ceSjose borrego
31789dc44ceSjose borrego err = smb_pwd_lock();
318*12b65585SGordon Ross if (err != SMB_PWE_SUCCESS) {
319*12b65585SGordon Ross syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", err);
32089dc44ceSjose borrego return (NULL);
321*12b65585SGordon Ross }
32289dc44ceSjose borrego
32389dc44ceSjose borrego if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
324*12b65585SGordon Ross syslog(LOG_WARNING, "smb_pwdutil: open failed, %m");
32589dc44ceSjose borrego (void) smb_pwd_unlock();
32689dc44ceSjose borrego return (NULL);
32789dc44ceSjose borrego }
32889dc44ceSjose borrego
32989dc44ceSjose borrego pwbuf.pw_pwd = smbpw;
33089dc44ceSjose borrego
33189dc44ceSjose borrego while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
33289dc44ceSjose borrego if (uid == smbpw->pw_uid) {
333da6c28aaSamw found = B_TRUE;
334da6c28aaSamw break;
335da6c28aaSamw }
336da6c28aaSamw }
337da6c28aaSamw
338da6c28aaSamw (void) fclose(fp);
339da6c28aaSamw (void) smb_pwd_unlock();
340da6c28aaSamw
341da6c28aaSamw if (!found) {
342da6c28aaSamw bzero(smbpw, sizeof (smb_passwd_t));
343da6c28aaSamw return (NULL);
344da6c28aaSamw }
345da6c28aaSamw
346da6c28aaSamw return (smbpw);
347da6c28aaSamw }
348da6c28aaSamw
349da6c28aaSamw /*
3503db3f65cSamw * smb_pwd_setpasswd
351da6c28aaSamw *
352da6c28aaSamw * Update/add the given user to the smbpasswd file.
353da6c28aaSamw */
354da6c28aaSamw int
smb_pwd_setpasswd(const char * name,const char * password)355da6c28aaSamw smb_pwd_setpasswd(const char *name, const char *password)
356da6c28aaSamw {
3573db3f65cSamw if (smb_pwd_ops.pwop_setpasswd != NULL)
3583db3f65cSamw return (smb_pwd_ops.pwop_setpasswd(name, password));
3597b59d02dSjb150015
360da6c28aaSamw return (smb_pwd_update(name, password, 0));
361da6c28aaSamw }
362da6c28aaSamw
363da6c28aaSamw /*
364da6c28aaSamw * smb_pwd_setcntl
365da6c28aaSamw *
366da6c28aaSamw * Change the account state. This can be making the account
367da6c28aaSamw * disable/enable or removing its LM hash.
368da6c28aaSamw */
369da6c28aaSamw int
smb_pwd_setcntl(const char * name,int control)370da6c28aaSamw smb_pwd_setcntl(const char *name, int control)
371da6c28aaSamw {
3723db3f65cSamw if (smb_pwd_ops.pwop_setcntl != NULL)
3733db3f65cSamw return (smb_pwd_ops.pwop_setcntl(name, control));
3747b59d02dSjb150015
375da6c28aaSamw if (control == 0)
376da6c28aaSamw return (SMB_PWE_SUCCESS);
377da6c28aaSamw
378da6c28aaSamw return (smb_pwd_update(name, NULL, control));
379da6c28aaSamw }
380da6c28aaSamw
3813db3f65cSamw /*
3823db3f65cSamw * smb_pwd_num
3833db3f65cSamw *
3843db3f65cSamw * Returns the number of cached local users
3853db3f65cSamw */
3863db3f65cSamw int
smb_pwd_num(void)3873db3f65cSamw smb_pwd_num(void)
3883db3f65cSamw {
3893db3f65cSamw if (smb_pwd_ops.pwop_num != NULL)
3903db3f65cSamw return (smb_pwd_ops.pwop_num());
3913db3f65cSamw
39296a62adaSjoyce mcintosh smb_lucache_update();
39396a62adaSjoyce mcintosh
3943db3f65cSamw return (smb_lucache_num());
3953db3f65cSamw }
3963db3f65cSamw
3973db3f65cSamw /*
3983db3f65cSamw * smb_pwd_iteropen
3993db3f65cSamw *
4003db3f65cSamw * Initalizes the given iterator handle.
4013db3f65cSamw * This handle will be used to iterate the users cache
4023db3f65cSamw * by the caller. The cache will be locked for read and it
4033db3f65cSamw * will remain locked until smb_pwd_iterclose() is called.
4043db3f65cSamw */
4053db3f65cSamw int
smb_pwd_iteropen(smb_pwditer_t * iter)4063db3f65cSamw smb_pwd_iteropen(smb_pwditer_t *iter)
4073db3f65cSamw {
4083db3f65cSamw if (iter == NULL)
4093db3f65cSamw return (SMB_PWE_INVALID_PARAM);
4103db3f65cSamw
4113db3f65cSamw if (smb_pwd_ops.pwop_iteropen != NULL)
4123db3f65cSamw return (smb_pwd_ops.pwop_iteropen(iter));
4133db3f65cSamw
4143db3f65cSamw iter->spi_next = NULL;
4153db3f65cSamw
4163db3f65cSamw smb_lucache_update();
4173db3f65cSamw
4183db3f65cSamw return (smb_lucache_lock());
4193db3f65cSamw }
4203db3f65cSamw
4213db3f65cSamw /*
4223db3f65cSamw * smb_pwd_iterate
4233db3f65cSamw *
4243db3f65cSamw * Scans through users cache using the given iterator
4253db3f65cSamw */
4263db3f65cSamw smb_luser_t *
smb_pwd_iterate(smb_pwditer_t * iter)4273db3f65cSamw smb_pwd_iterate(smb_pwditer_t *iter)
4283db3f65cSamw {
4293db3f65cSamw smb_ucnode_t *ucnode;
4303db3f65cSamw
4313db3f65cSamw if (iter == NULL)
4323db3f65cSamw return (NULL);
4333db3f65cSamw
4343db3f65cSamw if (smb_pwd_ops.pwop_iterate != NULL)
4353db3f65cSamw return (smb_pwd_ops.pwop_iterate(iter));
4363db3f65cSamw
4373db3f65cSamw if (iter->spi_next == NULL)
4383db3f65cSamw ucnode = avl_first(&smb_uch.uc_cache);
4393db3f65cSamw else
4403db3f65cSamw ucnode = AVL_NEXT(&smb_uch.uc_cache, iter->spi_next);
4413db3f65cSamw
4423db3f65cSamw if ((iter->spi_next = ucnode) != NULL)
4433db3f65cSamw return (&ucnode->cn_user);
4443db3f65cSamw
4453db3f65cSamw return (NULL);
4463db3f65cSamw }
4473db3f65cSamw
4483db3f65cSamw /*
4493db3f65cSamw * smb_pwd_iterclose
4503db3f65cSamw *
4513db3f65cSamw * Closes the given iterator. Effectively it only unlocks the cache
4523db3f65cSamw */
4533db3f65cSamw void
smb_pwd_iterclose(smb_pwditer_t * iter)4543db3f65cSamw smb_pwd_iterclose(smb_pwditer_t *iter)
4553db3f65cSamw {
4563db3f65cSamw if (smb_pwd_ops.pwop_iterclose != NULL) {
4573db3f65cSamw smb_pwd_ops.pwop_iterclose(iter);
4583db3f65cSamw return;
4593db3f65cSamw }
4603db3f65cSamw
4613db3f65cSamw if (iter != NULL)
4623db3f65cSamw smb_lucache_unlock();
4633db3f65cSamw }
4643db3f65cSamw
4653db3f65cSamw /*
4663db3f65cSamw * smb_pwd_update
4673db3f65cSamw *
4683db3f65cSamw * Updates the password entry of the given user if the user already
4693db3f65cSamw * has an entry, otherwise it'll add an entry for the user with
4703db3f65cSamw * given password and control information.
4713db3f65cSamw */
472da6c28aaSamw static int
smb_pwd_update(const char * name,const char * password,int control)473da6c28aaSamw smb_pwd_update(const char *name, const char *password, int control)
474da6c28aaSamw {
475da6c28aaSamw struct stat64 stbuf;
476da6c28aaSamw FILE *src, *dst;
477da6c28aaSamw int tempfd;
478da6c28aaSamw int err = SMB_PWE_SUCCESS;
479da6c28aaSamw smb_pwbuf_t pwbuf;
480da6c28aaSamw smb_passwd_t smbpw;
481da6c28aaSamw boolean_t newent = B_TRUE;
482da6c28aaSamw boolean_t user_disable = B_FALSE;
483da6c28aaSamw char uxbuf[1024];
484da6c28aaSamw struct passwd uxpw;
485dc20a302Sas200622 int64_t lm_level;
486da6c28aaSamw
487da6c28aaSamw err = smb_pwd_lock();
488da6c28aaSamw if (err != SMB_PWE_SUCCESS)
489da6c28aaSamw return (err);
490da6c28aaSamw
491da6c28aaSamw if (stat64(SMB_PASSWD, &stbuf) < 0) {
492da6c28aaSamw err = SMB_PWE_STAT_FAILED;
493da6c28aaSamw goto passwd_exit;
494da6c28aaSamw }
495da6c28aaSamw
496da6c28aaSamw if ((tempfd = open(SMB_PASSTEMP, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
497da6c28aaSamw err = SMB_PWE_OPEN_FAILED;
498da6c28aaSamw goto passwd_exit;
499da6c28aaSamw }
500da6c28aaSamw
501da6c28aaSamw if ((dst = fdopen(tempfd, "wF")) == NULL) {
502da6c28aaSamw err = SMB_PWE_OPEN_FAILED;
503da6c28aaSamw goto passwd_exit;
504da6c28aaSamw }
505da6c28aaSamw
506da6c28aaSamw if ((src = fopen(SMB_PASSWD, "rF")) == NULL) {
507da6c28aaSamw err = SMB_PWE_OPEN_FAILED;
508da6c28aaSamw (void) fclose(dst);
509da6c28aaSamw (void) unlink(SMB_PASSTEMP);
510da6c28aaSamw goto passwd_exit;
511da6c28aaSamw }
512da6c28aaSamw
513dc20a302Sas200622 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lm_level) != SMBD_SMF_OK)
514da6c28aaSamw lm_level = 4;
515da6c28aaSamw
516da6c28aaSamw if (lm_level >= 4)
517da6c28aaSamw control |= SMB_PWC_NOLM;
518da6c28aaSamw
5193db3f65cSamw pwbuf.pw_pwd = &smbpw;
5203db3f65cSamw
521da6c28aaSamw /*
522da6c28aaSamw * copy old password entries to temporary file while replacing
523da6c28aaSamw * the entry that matches "name"
524da6c28aaSamw */
5253db3f65cSamw while (smb_pwd_fgetent(src, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
52689dc44ceSjose borrego if (strcmp(smbpw.pw_name, name) == 0) {
527da6c28aaSamw err = smb_pwd_chgpwent(&smbpw, password, control);
528da6c28aaSamw if (err == SMB_PWE_USER_DISABLE)
529da6c28aaSamw user_disable = B_TRUE;
530da6c28aaSamw err = smb_pwd_fputent(dst, &pwbuf);
531da6c28aaSamw newent = B_FALSE;
532da6c28aaSamw } else {
533da6c28aaSamw err = smb_pwd_fputent(dst, &pwbuf);
534da6c28aaSamw }
535da6c28aaSamw
536da6c28aaSamw if (err != SMB_PWE_SUCCESS) {
537da6c28aaSamw (void) fclose(src);
538da6c28aaSamw (void) fclose(dst);
539da6c28aaSamw goto passwd_exit;
540da6c28aaSamw }
541da6c28aaSamw }
542da6c28aaSamw
543da6c28aaSamw if (newent) {
544da6c28aaSamw if (getpwnam_r(name, &uxpw, uxbuf, sizeof (uxbuf))) {
5453db3f65cSamw bzero(&smbpw, sizeof (smb_passwd_t));
54689dc44ceSjose borrego (void) strlcpy(smbpw.pw_name, uxpw.pw_name,
54789dc44ceSjose borrego sizeof (smbpw.pw_name));
548da6c28aaSamw smbpw.pw_uid = uxpw.pw_uid;
549da6c28aaSamw (void) smb_pwd_chgpwent(&smbpw, password, control);
550da6c28aaSamw err = smb_pwd_fputent(dst, &pwbuf);
551da6c28aaSamw } else {
552da6c28aaSamw err = SMB_PWE_USER_UNKNOWN;
553da6c28aaSamw }
554da6c28aaSamw
555da6c28aaSamw if (err != SMB_PWE_SUCCESS) {
556da6c28aaSamw (void) fclose(src);
557da6c28aaSamw (void) fclose(dst);
558da6c28aaSamw goto passwd_exit;
559da6c28aaSamw }
560da6c28aaSamw }
561da6c28aaSamw
562da6c28aaSamw (void) fclose(src);
563da6c28aaSamw if (fclose(dst) != 0) {
564da6c28aaSamw err = SMB_PWE_CLOSE_FAILED;
565da6c28aaSamw goto passwd_exit; /* Don't trust the temporary file */
566da6c28aaSamw }
567da6c28aaSamw
568da6c28aaSamw /* Rename temp to passwd */
569da6c28aaSamw if (unlink(SMB_OPASSWD) && access(SMB_OPASSWD, 0) == 0) {
570da6c28aaSamw err = SMB_PWE_UPDATE_FAILED;
571da6c28aaSamw (void) unlink(SMB_PASSTEMP);
572da6c28aaSamw goto passwd_exit;
573da6c28aaSamw }
574da6c28aaSamw
575da6c28aaSamw if (link(SMB_PASSWD, SMB_OPASSWD) == -1) {
576da6c28aaSamw err = SMB_PWE_UPDATE_FAILED;
577da6c28aaSamw (void) unlink(SMB_PASSTEMP);
578da6c28aaSamw goto passwd_exit;
579da6c28aaSamw }
580da6c28aaSamw
581da6c28aaSamw if (rename(SMB_PASSTEMP, SMB_PASSWD) == -1) {
582da6c28aaSamw err = SMB_PWE_UPDATE_FAILED;
583da6c28aaSamw (void) unlink(SMB_PASSTEMP);
584da6c28aaSamw goto passwd_exit;
585da6c28aaSamw }
586da6c28aaSamw
587da6c28aaSamw (void) chmod(SMB_PASSWD, 0400);
588da6c28aaSamw
589da6c28aaSamw passwd_exit:
590da6c28aaSamw (void) smb_pwd_unlock();
591da6c28aaSamw if ((err == SMB_PWE_SUCCESS) && user_disable)
592da6c28aaSamw err = SMB_PWE_USER_DISABLE;
593da6c28aaSamw
594da6c28aaSamw return (err);
595da6c28aaSamw }
596da6c28aaSamw
597da6c28aaSamw /*
5983db3f65cSamw * smb_pwd_fgetent
599da6c28aaSamw *
600da6c28aaSamw * Parse the buffer in the passed pwbuf and fill in the
601da6c28aaSamw * smb password structure to point to the parsed information.
602da6c28aaSamw * The entry format is:
603da6c28aaSamw *
604da6c28aaSamw * <user-name>:<user-id>:<LM hash>:<NTLM hash>
605da6c28aaSamw *
6063db3f65cSamw * Returns a pointer to the passed pwbuf structure on success,
607da6c28aaSamw * otherwise returns NULL.
608da6c28aaSamw */
609da6c28aaSamw static smb_pwbuf_t *
smb_pwd_fgetent(FILE * fp,smb_pwbuf_t * pwbuf,uint32_t flags)6103db3f65cSamw smb_pwd_fgetent(FILE *fp, smb_pwbuf_t *pwbuf, uint32_t flags)
611da6c28aaSamw {
612da6c28aaSamw char *argv[SMB_PWD_NARG];
6133db3f65cSamw char *pwentry;
614da6c28aaSamw smb_passwd_t *pw;
615da6c28aaSamw smb_pwdarg_t i;
616da6c28aaSamw int lm_len, nt_len;
617da6c28aaSamw
6183db3f65cSamw pwentry = pwbuf->pw_buf;
6193db3f65cSamw if (fgets(pwentry, SMB_PWD_BUFSIZE, fp) == NULL)
620da6c28aaSamw return (NULL);
6213db3f65cSamw (void) trim_whitespace(pwentry);
622da6c28aaSamw
623da6c28aaSamw for (i = 0; i < SMB_PWD_NARG; ++i) {
6243db3f65cSamw if ((argv[i] = strsep((char **)&pwentry, ":")) == NULL)
625da6c28aaSamw return (NULL);
626da6c28aaSamw }
627da6c28aaSamw
628da6c28aaSamw if ((*argv[SMB_PWD_NAME] == '\0') || (*argv[SMB_PWD_UID] == '\0'))
629da6c28aaSamw return (NULL);
630da6c28aaSamw
631da6c28aaSamw pw = pwbuf->pw_pwd;
632da6c28aaSamw bzero(pw, sizeof (smb_passwd_t));
633da6c28aaSamw pw->pw_uid = strtoul(argv[SMB_PWD_UID], 0, 10);
63489dc44ceSjose borrego (void) strlcpy(pw->pw_name, argv[SMB_PWD_NAME], sizeof (pw->pw_name));
635da6c28aaSamw
636da6c28aaSamw if (strcmp(argv[SMB_PWD_LMHASH], SMB_PWD_DISABLE) == 0) {
637da6c28aaSamw pw->pw_flags |= SMB_PWF_DISABLE;
6383db3f65cSamw if (flags != SMB_PWD_GETF_NOPWD) {
639da6c28aaSamw (void) strcpy((char *)pw->pw_lmhash, SMB_PWD_DISABLE);
640da6c28aaSamw (void) strcpy((char *)pw->pw_nthash, SMB_PWD_DISABLE);
6413db3f65cSamw }
642da6c28aaSamw return (pwbuf);
643da6c28aaSamw }
644da6c28aaSamw
6453db3f65cSamw if (flags == SMB_PWD_GETF_NOPWD)
6463db3f65cSamw return (pwbuf);
6473db3f65cSamw
648da6c28aaSamw lm_len = strlen(argv[SMB_PWD_LMHASH]);
649da6c28aaSamw if (lm_len == SMBAUTH_HEXHASH_SZ) {
650da6c28aaSamw (void) hextobin(argv[SMB_PWD_LMHASH], SMBAUTH_HEXHASH_SZ,
651da6c28aaSamw (char *)pw->pw_lmhash, SMBAUTH_HASH_SZ);
652da6c28aaSamw
653da6c28aaSamw pw->pw_flags |= SMB_PWF_LM;
654da6c28aaSamw } else if (lm_len != 0) {
655da6c28aaSamw return (NULL);
656da6c28aaSamw }
657da6c28aaSamw
658da6c28aaSamw nt_len = strlen(argv[SMB_PWD_NTHASH]);
659da6c28aaSamw if (nt_len == SMBAUTH_HEXHASH_SZ) {
660da6c28aaSamw (void) hextobin(argv[SMB_PWD_NTHASH], SMBAUTH_HEXHASH_SZ,
661da6c28aaSamw (char *)pw->pw_nthash, SMBAUTH_HASH_SZ);
662da6c28aaSamw
663da6c28aaSamw pw->pw_flags |= SMB_PWF_NT;
664da6c28aaSamw } else if (nt_len != 0) {
665da6c28aaSamw return (NULL);
666da6c28aaSamw }
667da6c28aaSamw
668da6c28aaSamw return (pwbuf);
669da6c28aaSamw }
670da6c28aaSamw
6713db3f65cSamw /*
6723db3f65cSamw * smb_pwd_chgpwent
6733db3f65cSamw *
6743db3f65cSamw * Updates the given smb_passwd_t structure with given password and
6753db3f65cSamw * control information.
6763db3f65cSamw */
677da6c28aaSamw static int
smb_pwd_chgpwent(smb_passwd_t * smbpw,const char * password,int control)678da6c28aaSamw smb_pwd_chgpwent(smb_passwd_t *smbpw, const char *password, int control)
679da6c28aaSamw {
680da6c28aaSamw if (control & SMB_PWC_DISABLE) {
6813db3f65cSamw /* disable the user */
682da6c28aaSamw smbpw->pw_flags |= SMB_PWF_DISABLE;
683da6c28aaSamw (void) strcpy((char *)smbpw->pw_lmhash, SMB_PWD_DISABLE);
684da6c28aaSamw (void) strcpy((char *)smbpw->pw_nthash, SMB_PWD_DISABLE);
685da6c28aaSamw smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
686da6c28aaSamw return (SMB_PWE_SUCCESS);
6873db3f65cSamw }
6883db3f65cSamw
6893db3f65cSamw if ((control & SMB_PWC_ENABLE) && (smbpw->pw_flags & SMB_PWF_DISABLE)) {
6903db3f65cSamw /* enable the user if it's been disabled */
691da6c28aaSamw *smbpw->pw_lmhash = '\0';
692da6c28aaSamw *smbpw->pw_nthash = '\0';
693da6c28aaSamw smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
694da6c28aaSamw return (SMB_PWE_SUCCESS);
695da6c28aaSamw }
696da6c28aaSamw
697da6c28aaSamw /* No password update if account is disabled */
698da6c28aaSamw if (smbpw->pw_flags & SMB_PWF_DISABLE)
699da6c28aaSamw return (SMB_PWE_USER_DISABLE);
700da6c28aaSamw
7013db3f65cSamw /* This call was just to update the control flags */
7023db3f65cSamw if (password == NULL)
7033db3f65cSamw return (SMB_PWE_SUCCESS);
7043db3f65cSamw
705da6c28aaSamw if (control & SMB_PWC_NOLM) {
7063db3f65cSamw /* LM hash should not be present */
707da6c28aaSamw smbpw->pw_flags &= ~SMB_PWF_LM;
708da6c28aaSamw *smbpw->pw_lmhash = '\0';
709da6c28aaSamw } else {
710da6c28aaSamw smbpw->pw_flags |= SMB_PWF_LM;
71129bd2886SAlan Wright (void) smb_auth_lm_hash(password, smbpw->pw_lmhash);
712da6c28aaSamw }
713da6c28aaSamw
714da6c28aaSamw smbpw->pw_flags |= SMB_PWF_NT;
71529bd2886SAlan Wright (void) smb_auth_ntlm_hash(password, smbpw->pw_nthash);
716da6c28aaSamw return (SMB_PWE_SUCCESS);
717da6c28aaSamw }
718da6c28aaSamw
719da6c28aaSamw /*
7203db3f65cSamw * smb_pwd_fputent
721da6c28aaSamw *
7223db3f65cSamw * If LM/NTLM hash are present, converts them to hex string
723da6c28aaSamw * and write them along with user's name and Id to the smbpasswd
724da6c28aaSamw * file.
725da6c28aaSamw */
726da6c28aaSamw static int
smb_pwd_fputent(FILE * fp,const smb_pwbuf_t * pwbuf)72729bd2886SAlan Wright smb_pwd_fputent(FILE *fp, const smb_pwbuf_t *pwbuf)
728da6c28aaSamw {
729da6c28aaSamw smb_passwd_t *pw = pwbuf->pw_pwd;
730da6c28aaSamw char hex_nthash[SMBAUTH_HEXHASH_SZ+1];
731da6c28aaSamw char hex_lmhash[SMBAUTH_HEXHASH_SZ+1];
732da6c28aaSamw int rc;
733da6c28aaSamw
734da6c28aaSamw if ((pw->pw_flags & SMB_PWF_LM) == SMB_PWF_LM) {
735da6c28aaSamw (void) bintohex((char *)pw->pw_lmhash, SMBAUTH_HASH_SZ,
736da6c28aaSamw hex_lmhash, SMBAUTH_HEXHASH_SZ);
737da6c28aaSamw hex_lmhash[SMBAUTH_HEXHASH_SZ] = '\0';
738da6c28aaSamw } else {
739da6c28aaSamw (void) strcpy(hex_lmhash, (char *)pw->pw_lmhash);
740da6c28aaSamw }
741da6c28aaSamw
742da6c28aaSamw if ((pw->pw_flags & SMB_PWF_NT) == SMB_PWF_NT) {
743da6c28aaSamw (void) bintohex((char *)pw->pw_nthash, SMBAUTH_HASH_SZ,
744da6c28aaSamw hex_nthash, SMBAUTH_HEXHASH_SZ);
745da6c28aaSamw hex_nthash[SMBAUTH_HEXHASH_SZ] = '\0';
746da6c28aaSamw } else {
747da6c28aaSamw (void) strcpy(hex_nthash, (char *)pw->pw_nthash);
748da6c28aaSamw }
749da6c28aaSamw
75089dc44ceSjose borrego rc = fprintf(fp, "%s:%u:%s:%s\n", pw->pw_name, pw->pw_uid,
751da6c28aaSamw hex_lmhash, hex_nthash);
752da6c28aaSamw
753da6c28aaSamw if (rc <= 0)
754da6c28aaSamw return (SMB_PWE_WRITE_FAILED);
755da6c28aaSamw
756da6c28aaSamw return (SMB_PWE_SUCCESS);
757da6c28aaSamw }
758da6c28aaSamw
7593db3f65cSamw /*
7603db3f65cSamw * smb_pwd_lock
7613db3f65cSamw *
7623db3f65cSamw * A wrapper around smb_pwd_flck() which locks smb password
7633db3f65cSamw * file so that only one thread at a time is operational.
7643db3f65cSamw */
765da6c28aaSamw static int
smb_pwd_lock(void)766da6c28aaSamw smb_pwd_lock(void)
767da6c28aaSamw {
768da6c28aaSamw int res;
769da6c28aaSamw
770da6c28aaSamw if (smb_pwd_flck()) {
771da6c28aaSamw switch (errno) {
772da6c28aaSamw case EINTR:
773da6c28aaSamw res = SMB_PWE_BUSY;
774da6c28aaSamw break;
775da6c28aaSamw case EACCES:
776da6c28aaSamw res = SMB_PWE_DENIED;
777da6c28aaSamw break;
778da6c28aaSamw case 0:
779da6c28aaSamw res = SMB_PWE_SUCCESS;
780da6c28aaSamw break;
781da6c28aaSamw }
782da6c28aaSamw } else
783da6c28aaSamw res = SMB_PWE_SUCCESS;
784da6c28aaSamw
785da6c28aaSamw return (res);
786da6c28aaSamw }
787da6c28aaSamw
7883db3f65cSamw /*
78996a62adaSjoyce mcintosh * smb_pwd_unlock
7903db3f65cSamw *
7913db3f65cSamw * A wrapper around smb_pwd_fulck() which unlocks
7923db3f65cSamw * smb password file.
7933db3f65cSamw */
794da6c28aaSamw static int
smb_pwd_unlock(void)795da6c28aaSamw smb_pwd_unlock(void)
796da6c28aaSamw {
797da6c28aaSamw if (smb_pwd_fulck())
798da6c28aaSamw return (SMB_PWE_SYSTEM_ERROR);
799da6c28aaSamw
800da6c28aaSamw return (SMB_PWE_SUCCESS);
801da6c28aaSamw }
802da6c28aaSamw
8033db3f65cSamw /*
8043db3f65cSamw * smb_pwd_flck
8053db3f65cSamw *
8063db3f65cSamw * Creates a lock file and grabs an exclusive (write) lock on it.
8073db3f65cSamw */
808da6c28aaSamw static int
smb_pwd_flck(void)809da6c28aaSamw smb_pwd_flck(void)
810da6c28aaSamw {
811da6c28aaSamw int seconds = 0;
812da6c28aaSamw
813da6c28aaSamw (void) mutex_lock(&lck_lock);
814da6c28aaSamw for (;;) {
815da6c28aaSamw if (lck_pid != 0 && lck_pid != getpid()) {
816da6c28aaSamw /* somebody forked */
817da6c28aaSamw lck_pid = 0;
818da6c28aaSamw lck_tid = 0;
819da6c28aaSamw }
820da6c28aaSamw
821da6c28aaSamw if (lck_tid == 0) {
822da6c28aaSamw if ((fildes = creat(SMB_PASSLCK, 0600)) == -1)
823da6c28aaSamw break;
824da6c28aaSamw flock.l_type = F_WRLCK;
825da6c28aaSamw if (fcntl(fildes, F_SETLK, &flock) != -1) {
826da6c28aaSamw lck_pid = getpid();
827da6c28aaSamw lck_tid = thr_self();
828da6c28aaSamw (void) mutex_unlock(&lck_lock);
829da6c28aaSamw return (0);
830da6c28aaSamw }
831da6c28aaSamw (void) close(fildes);
832da6c28aaSamw fildes = -1;
833da6c28aaSamw }
834da6c28aaSamw
835da6c28aaSamw if (seconds++ >= S_WAITTIME) {
836da6c28aaSamw /*
837da6c28aaSamw * For compatibility with the past, pretend
838da6c28aaSamw * that we were interrupted by SIGALRM.
839da6c28aaSamw */
840da6c28aaSamw errno = EINTR;
841da6c28aaSamw break;
842da6c28aaSamw }
843da6c28aaSamw
844da6c28aaSamw (void) mutex_unlock(&lck_lock);
845da6c28aaSamw (void) sleep(1);
846da6c28aaSamw (void) mutex_lock(&lck_lock);
847da6c28aaSamw }
848da6c28aaSamw (void) mutex_unlock(&lck_lock);
849da6c28aaSamw
850da6c28aaSamw return (-1);
851da6c28aaSamw }
852da6c28aaSamw
8533db3f65cSamw /*
8543db3f65cSamw * smb_pwd_fulck
8553db3f65cSamw *
8563db3f65cSamw * Unlocks smb password file for operations done via
8573db3f65cSamw * this library APIs.
8583db3f65cSamw */
859da6c28aaSamw static int
smb_pwd_fulck(void)860da6c28aaSamw smb_pwd_fulck(void)
861da6c28aaSamw {
862da6c28aaSamw (void) mutex_lock(&lck_lock);
863da6c28aaSamw if (lck_tid == thr_self() && fildes >= 0) {
864da6c28aaSamw flock.l_type = F_UNLCK;
865da6c28aaSamw (void) fcntl(fildes, F_SETLK, &flock);
866da6c28aaSamw (void) close(fildes);
867da6c28aaSamw fildes = -1;
868da6c28aaSamw lck_pid = 0;
869da6c28aaSamw lck_tid = 0;
870da6c28aaSamw (void) mutex_unlock(&lck_lock);
871da6c28aaSamw return (0);
872da6c28aaSamw }
873da6c28aaSamw (void) mutex_unlock(&lck_lock);
874da6c28aaSamw return (-1);
875da6c28aaSamw }
8763db3f65cSamw
8773db3f65cSamw /*
8783db3f65cSamw * Local User Cache Functions
8793db3f65cSamw *
8803db3f65cSamw * Local user cache is implemented using AVL tree
8813db3f65cSamw */
8823db3f65cSamw
8833db3f65cSamw /*
8843db3f65cSamw * smb_lucache_cmp
8853db3f65cSamw *
8863db3f65cSamw * AVL compare function, the key is username.
8873db3f65cSamw */
8883db3f65cSamw static int
smb_lucache_cmp(const void * p1,const void * p2)8893db3f65cSamw smb_lucache_cmp(const void *p1, const void *p2)
8903db3f65cSamw {
8913db3f65cSamw smb_ucnode_t *u1 = (smb_ucnode_t *)p1;
8923db3f65cSamw smb_ucnode_t *u2 = (smb_ucnode_t *)p2;
8933db3f65cSamw int rc;
8943db3f65cSamw
8953db3f65cSamw rc = strcmp(u1->cn_user.su_name, u2->cn_user.su_name);
8963db3f65cSamw
8973db3f65cSamw if (rc < 0)
8983db3f65cSamw return (-1);
8993db3f65cSamw
9003db3f65cSamw if (rc > 0)
9013db3f65cSamw return (1);
9023db3f65cSamw
9033db3f65cSamw return (0);
9043db3f65cSamw }
9053db3f65cSamw
9063db3f65cSamw /*
9073db3f65cSamw * smb_lucache_update
9083db3f65cSamw *
9093db3f65cSamw * Updates the cache if needed. Whether an update is needed
9103db3f65cSamw * is determined based on smbpasswd file modification timestamp
9113db3f65cSamw */
9123db3f65cSamw static void
smb_lucache_update(void)9133db3f65cSamw smb_lucache_update(void)
9143db3f65cSamw {
9153db3f65cSamw struct stat64 stbuf;
9163db3f65cSamw int rc;
9173db3f65cSamw
9183db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
9193db3f65cSamw switch (smb_uch.uc_state) {
9203db3f65cSamw default:
9213db3f65cSamw case SMB_UCHS_NOCACHE:
9223db3f65cSamw assert(0);
9233db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9243db3f65cSamw return;
9253db3f65cSamw
9263db3f65cSamw case SMB_UCHS_CREATED:
9273db3f65cSamw case SMB_UCHS_UPDATED:
9283db3f65cSamw break;
9293db3f65cSamw
9303db3f65cSamw case SMB_UCHS_UPDATING:
9313db3f65cSamw /* Want only one thread executing this function at a time */
9323db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9333db3f65cSamw return;
9343db3f65cSamw
9353db3f65cSamw case SMB_UCHS_DESTROYING:
9363db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9373db3f65cSamw return;
9383db3f65cSamw }
9393db3f65cSamw
9403db3f65cSamw /*
9413db3f65cSamw * smb_pwd_lock() is not called here so it can
9423db3f65cSamw * be checked quickly whether an updated is needed
9433db3f65cSamw */
9443db3f65cSamw if (stat64(SMB_PASSWD, &stbuf) < 0) {
9453db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9463db3f65cSamw if (errno != ENOENT)
9473db3f65cSamw return;
9483db3f65cSamw
9493db3f65cSamw /* no smbpasswd file; empty the cache */
9503db3f65cSamw smb_lucache_flush();
9513db3f65cSamw return;
9523db3f65cSamw }
9533db3f65cSamw
9543db3f65cSamw if (stbuf.st_size == 0) {
9553db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9563db3f65cSamw
9573db3f65cSamw /* empty smbpasswd file; empty the cache */
9583db3f65cSamw smb_lucache_flush();
9593db3f65cSamw return;
9603db3f65cSamw }
9613db3f65cSamw
9623db3f65cSamw if ((smb_uch.uc_timestamp.tv_sec == stbuf.st_mtim.tv_sec) &&
9633db3f65cSamw (smb_uch.uc_timestamp.tv_nsec == stbuf.st_mtim.tv_nsec)) {
9643db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9653db3f65cSamw /* No changes since the last cache update */
9663db3f65cSamw return;
9673db3f65cSamw }
9683db3f65cSamw
9693db3f65cSamw smb_uch.uc_state = SMB_UCHS_UPDATING;
9703db3f65cSamw smb_uch.uc_refcnt++;
9713db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9723db3f65cSamw
9733db3f65cSamw rc = smb_lucache_do_update();
9743db3f65cSamw
9753db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
9763db3f65cSamw if ((rc == SMB_PWE_SUCCESS) && (stat64(SMB_PASSWD, &stbuf) == 0))
9773db3f65cSamw smb_uch.uc_timestamp = stbuf.st_mtim;
9783db3f65cSamw smb_uch.uc_state = SMB_UCHS_UPDATED;
9793db3f65cSamw smb_uch.uc_refcnt--;
9803db3f65cSamw (void) cond_broadcast(&smb_uch.uc_cv);
9813db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
9823db3f65cSamw }
9833db3f65cSamw
9843db3f65cSamw /*
9853db3f65cSamw * smb_lucache_do_update
9863db3f65cSamw *
9873db3f65cSamw * This function takes care of updating the AVL tree.
9883db3f65cSamw * If an entry has been updated, it'll be modified in place.
9893db3f65cSamw *
9903db3f65cSamw * New entries will be added to a temporary AVL tree then
9913db3f65cSamw * passwod file is unlocked and all the new entries will
9923db3f65cSamw * be transferred to the main cache from the temporary tree.
9933db3f65cSamw *
9943db3f65cSamw * This function MUST NOT be called directly
9953db3f65cSamw */
9963db3f65cSamw static int
smb_lucache_do_update(void)9973db3f65cSamw smb_lucache_do_update(void)
9983db3f65cSamw {
9993db3f65cSamw avl_tree_t tmp_cache;
10003db3f65cSamw smb_pwbuf_t pwbuf;
10013db3f65cSamw smb_passwd_t smbpw;
10023db3f65cSamw smb_ucnode_t uc_node;
10033db3f65cSamw smb_ucnode_t *uc_newnode;
10043db3f65cSamw smb_luser_t *user;
10053db3f65cSamw smb_sid_t *sid;
10063db3f65cSamw idmap_stat idm_stat;
10073db3f65cSamw int rc = SMB_PWE_SUCCESS;
10083db3f65cSamw void *cookie = NULL;
10093db3f65cSamw FILE *fp;
10103db3f65cSamw
1011*12b65585SGordon Ross if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) {
1012*12b65585SGordon Ross syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", rc);
10133db3f65cSamw return (rc);
1014*12b65585SGordon Ross }
10153db3f65cSamw
10163db3f65cSamw if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
1017*12b65585SGordon Ross syslog(LOG_WARNING, "smb_pwdutil: open failed, %m");
10183db3f65cSamw (void) smb_pwd_unlock();
10193db3f65cSamw return (SMB_PWE_OPEN_FAILED);
10203db3f65cSamw }
10213db3f65cSamw
10223db3f65cSamw avl_create(&tmp_cache, smb_lucache_cmp,
10233db3f65cSamw sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link));
10243db3f65cSamw
10253db3f65cSamw bzero(&pwbuf, sizeof (smb_pwbuf_t));
10263db3f65cSamw pwbuf.pw_pwd = &smbpw;
10273db3f65cSamw
10283db3f65cSamw (void) rw_rdlock(&smb_uch.uc_cache_lck);
10293db3f65cSamw
10303db3f65cSamw while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_NOPWD) != NULL) {
103189dc44ceSjose borrego uc_node.cn_user.su_name = smbpw.pw_name;
10323db3f65cSamw uc_newnode = avl_find(&smb_uch.uc_cache, &uc_node, NULL);
10333db3f65cSamw if (uc_newnode) {
10343db3f65cSamw /* update the node info */
10353db3f65cSamw uc_newnode->cn_user.su_ctrl = smbpw.pw_flags;
10363db3f65cSamw continue;
10373db3f65cSamw }
10383db3f65cSamw
10393db3f65cSamw /* create a new node */
10403db3f65cSamw if ((uc_newnode = malloc(sizeof (smb_ucnode_t))) == NULL) {
10413db3f65cSamw rc = SMB_PWE_NO_MEMORY;
10423db3f65cSamw break;
10433db3f65cSamw }
10443db3f65cSamw
10453db3f65cSamw bzero(uc_newnode, sizeof (smb_ucnode_t));
10463db3f65cSamw user = &uc_newnode->cn_user;
10473db3f65cSamw user->su_ctrl = smbpw.pw_flags;
10483db3f65cSamw
10493db3f65cSamw idm_stat = smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, &sid);
10503db3f65cSamw if (idm_stat != IDMAP_SUCCESS) {
10513db3f65cSamw syslog(LOG_WARNING, "smb_pwdutil: couldn't obtain SID "
10523db3f65cSamw "for uid=%u (%d)", smbpw.pw_uid, idm_stat);
10533db3f65cSamw free(uc_newnode);
10543db3f65cSamw continue;
10553db3f65cSamw }
10563db3f65cSamw (void) smb_sid_getrid(sid, &user->su_rid);
10573db3f65cSamw smb_sid_free(sid);
10583db3f65cSamw
105989dc44ceSjose borrego user->su_name = strdup(smbpw.pw_name);
10603db3f65cSamw if (user->su_name == NULL) {
10613db3f65cSamw rc = SMB_PWE_NO_MEMORY;
10623db3f65cSamw free(uc_newnode);
10633db3f65cSamw break;
10643db3f65cSamw }
10653db3f65cSamw
10663db3f65cSamw avl_add(&tmp_cache, uc_newnode);
10673db3f65cSamw }
10683db3f65cSamw
10693db3f65cSamw (void) rw_unlock(&smb_uch.uc_cache_lck);
10703db3f65cSamw (void) fclose(fp);
10713db3f65cSamw (void) smb_pwd_unlock();
10723db3f65cSamw
10733db3f65cSamw /* Destroy the temporary list */
10743db3f65cSamw (void) rw_wrlock(&smb_uch.uc_cache_lck);
10753db3f65cSamw while ((uc_newnode = avl_destroy_nodes(&tmp_cache, &cookie)) != NULL) {
10763db3f65cSamw avl_add(&smb_uch.uc_cache, uc_newnode);
10773db3f65cSamw }
10783db3f65cSamw (void) rw_unlock(&smb_uch.uc_cache_lck);
10793db3f65cSamw
10803db3f65cSamw avl_destroy(&tmp_cache);
10813db3f65cSamw
10823db3f65cSamw return (rc);
10833db3f65cSamw }
10843db3f65cSamw
10853db3f65cSamw /*
10863db3f65cSamw * smb_lucache_create
10873db3f65cSamw *
10883db3f65cSamw * Creates the AVL tree and initializes the global user cache handle.
10893db3f65cSamw * This function doesn't populate the cache.
10903db3f65cSamw * User cache is only created by smbd at startup
10913db3f65cSamw */
10923db3f65cSamw static void
smb_lucache_create(void)10933db3f65cSamw smb_lucache_create(void)
10943db3f65cSamw {
10953db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
10963db3f65cSamw if (smb_uch.uc_state != SMB_UCHS_NOCACHE) {
10973db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
10983db3f65cSamw return;
10993db3f65cSamw }
11003db3f65cSamw
11013db3f65cSamw avl_create(&smb_uch.uc_cache, smb_lucache_cmp,
11023db3f65cSamw sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link));
11033db3f65cSamw
11043db3f65cSamw smb_uch.uc_state = SMB_UCHS_CREATED;
11053db3f65cSamw bzero(&smb_uch.uc_timestamp, sizeof (timestruc_t));
11063db3f65cSamw smb_uch.uc_refcnt = 0;
11073db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
11083db3f65cSamw }
11093db3f65cSamw
11103db3f65cSamw /*
11113db3f65cSamw * smb_lucache_flush
11123db3f65cSamw *
11133db3f65cSamw * Removes and frees all the cache entries
11143db3f65cSamw */
11153db3f65cSamw static void
smb_lucache_flush(void)11163db3f65cSamw smb_lucache_flush(void)
11173db3f65cSamw {
11183db3f65cSamw void *cookie = NULL;
11193db3f65cSamw smb_ucnode_t *ucnode;
11203db3f65cSamw
11213db3f65cSamw (void) rw_wrlock(&smb_uch.uc_cache_lck);
11223db3f65cSamw while ((ucnode = avl_destroy_nodes(&smb_uch.uc_cache, &cookie))
11233db3f65cSamw != NULL) {
11243db3f65cSamw free(ucnode->cn_user.su_name);
11253db3f65cSamw free(ucnode->cn_user.su_fullname);
11263db3f65cSamw free(ucnode->cn_user.su_desc);
11273db3f65cSamw free(ucnode);
11283db3f65cSamw }
11293db3f65cSamw (void) rw_unlock(&smb_uch.uc_cache_lck);
11303db3f65cSamw }
11313db3f65cSamw
11323db3f65cSamw /*
11333db3f65cSamw * smb_lucache_destroy
11343db3f65cSamw *
11353db3f65cSamw * Destroys the cache.
11363db3f65cSamw * This function is only called in smb_pwd_fini()
11373db3f65cSamw * User cache is only destroyed by smbd upon shutdown
11383db3f65cSamw */
11393db3f65cSamw static void
smb_lucache_destroy(void)11403db3f65cSamw smb_lucache_destroy(void)
11413db3f65cSamw {
11423db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
11433db3f65cSamw switch (smb_uch.uc_state) {
11443db3f65cSamw case SMB_UCHS_NOCACHE:
11453db3f65cSamw case SMB_UCHS_DESTROYING:
11463db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
11473db3f65cSamw return;
11483db3f65cSamw
11493db3f65cSamw default:
11503db3f65cSamw break;
11513db3f65cSamw }
11523db3f65cSamw
11533db3f65cSamw smb_uch.uc_state = SMB_UCHS_DESTROYING;
11543db3f65cSamw
11553db3f65cSamw while (smb_uch.uc_refcnt > 0)
11563db3f65cSamw (void) cond_wait(&smb_uch.uc_cv, &smb_uch.uc_mtx);
11573db3f65cSamw
11583db3f65cSamw smb_lucache_flush();
11593db3f65cSamw
11603db3f65cSamw avl_destroy(&smb_uch.uc_cache);
11613db3f65cSamw smb_uch.uc_state = SMB_UCHS_NOCACHE;
11623db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
11633db3f65cSamw }
11643db3f65cSamw
11653db3f65cSamw /*
11663db3f65cSamw * smb_lucache_lock
11673db3f65cSamw *
11683db3f65cSamw * Locks the user cache for reading and also
11693db3f65cSamw * increment the handle reference count.
11703db3f65cSamw */
11713db3f65cSamw static int
smb_lucache_lock(void)11723db3f65cSamw smb_lucache_lock(void)
11733db3f65cSamw {
11743db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
11753db3f65cSamw switch (smb_uch.uc_state) {
11763db3f65cSamw case SMB_UCHS_NOCACHE:
11773db3f65cSamw assert(0);
11783db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
11793db3f65cSamw return (SMB_PWE_DENIED);
11803db3f65cSamw
11813db3f65cSamw case SMB_UCHS_DESTROYING:
11823db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
11833db3f65cSamw return (SMB_PWE_DENIED);
11843db3f65cSamw }
11853db3f65cSamw smb_uch.uc_refcnt++;
11863db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
11873db3f65cSamw
11883db3f65cSamw (void) rw_rdlock(&smb_uch.uc_cache_lck);
11893db3f65cSamw return (SMB_PWE_SUCCESS);
11903db3f65cSamw }
11913db3f65cSamw
11923db3f65cSamw /*
11933db3f65cSamw * smb_lucache_unlock
11943db3f65cSamw *
11953db3f65cSamw * Unlock the cache
11963db3f65cSamw */
11973db3f65cSamw static void
smb_lucache_unlock(void)11983db3f65cSamw smb_lucache_unlock(void)
11993db3f65cSamw {
12003db3f65cSamw (void) rw_unlock(&smb_uch.uc_cache_lck);
12013db3f65cSamw
12023db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
12033db3f65cSamw smb_uch.uc_refcnt--;
12043db3f65cSamw (void) cond_broadcast(&smb_uch.uc_cv);
12053db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
12063db3f65cSamw }
12073db3f65cSamw
12083db3f65cSamw /*
12093db3f65cSamw * smb_lucache_num
12103db3f65cSamw *
12113db3f65cSamw * Returns the number of cache entries
12123db3f65cSamw */
12133db3f65cSamw static int
smb_lucache_num(void)12143db3f65cSamw smb_lucache_num(void)
12153db3f65cSamw {
12163db3f65cSamw int num;
12173db3f65cSamw
12183db3f65cSamw (void) mutex_lock(&smb_uch.uc_mtx);
12193db3f65cSamw switch (smb_uch.uc_state) {
12203db3f65cSamw case SMB_UCHS_NOCACHE:
12213db3f65cSamw assert(0);
12223db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
12233db3f65cSamw return (0);
12243db3f65cSamw
12253db3f65cSamw case SMB_UCHS_DESTROYING:
12263db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
12273db3f65cSamw return (0);
12283db3f65cSamw }
12293db3f65cSamw (void) mutex_unlock(&smb_uch.uc_mtx);
12303db3f65cSamw
12313db3f65cSamw (void) rw_rdlock(&smb_uch.uc_cache_lck);
12323db3f65cSamw num = (int)avl_numnodes(&smb_uch.uc_cache);
12333db3f65cSamw (void) rw_unlock(&smb_uch.uc_cache_lck);
12343db3f65cSamw
12353db3f65cSamw return (num);
12363db3f65cSamw }
1237