4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
35 #include <sys/types.h>
44 #include <smbsrv/libsmb.h>
46 #define SMB_PASSWD "/var/smb/smbpasswd"
47 #define SMB_OPASSWD "/var/smb/osmbpasswd"
48 #define SMB_PASSTEMP "/var/smb/ptmp"
49 #define SMB_PASSLCK "/var/smb/.pwd.lock"
51 #define SMB_PWD_DISABLE "*DIS*"
52 #define SMB_PWD_BUFSIZE 256
64 static struct flock flock
= { 0, 0, 0, 0, 0, 0 };
65 static pid_t lck_pid
= 0; /* process's pid at last lock */
66 static thread_t lck_tid
= 0; /* thread that holds the lock */
67 static int fildes
= -1;
68 static mutex_t lck_lock
= DEFAULTMUTEX
;
69 static void *smb_pwd_hdl
= NULL
;
72 smb_passwd_t
*(*pwop_getpwnam
)(const char *, smb_passwd_t
*);
73 smb_passwd_t
*(*pwop_getpwuid
)(uid_t
, smb_passwd_t
*);
74 int (*pwop_setcntl
)(const char *, int);
75 int (*pwop_setpasswd
)(const char *, const char *);
76 int (*pwop_num
)(void);
77 int (*pwop_iteropen
)(smb_pwditer_t
*);
78 smb_luser_t
*(*pwop_iterate
)(smb_pwditer_t
*);
79 void (*pwop_iterclose
)(smb_pwditer_t
*);
82 static int smb_pwd_lock(void);
83 static int smb_pwd_unlock(void);
84 static int smb_pwd_flck(void);
85 static int smb_pwd_fulck(void);
88 * buffer structure used by smb_pwd_fgetent/smb_pwd_fputent
90 typedef struct smb_pwbuf
{
91 char pw_buf
[SMB_PWD_BUFSIZE
];
96 * flag values used with smb_pwd_fgetent
98 #define SMB_PWD_GETF_ALL 1 /* get all the account info */
99 #define SMB_PWD_GETF_NOPWD 2 /* password is not needed */
101 static smb_pwbuf_t
*smb_pwd_fgetent(FILE *, smb_pwbuf_t
*, uint32_t);
102 static int smb_pwd_fputent(FILE *, const smb_pwbuf_t
*);
103 static int smb_pwd_chgpwent(smb_passwd_t
*, const char *, int);
104 static int smb_pwd_update(const char *, const char *, int);
109 * Simplifying assumptions
111 * o smbpasswd is a service private file and shouldn't be edited manually
112 * o accounts are only added/modified via passwd and/or smbadm CLIs
113 * o accounts are not removed but disabled using smbadm CLI
114 * o editing smbpasswd manually might result in cache inconsistency
116 * Cache is created and populated upon service startup.
117 * Cache is updated each time users list is requested if there's been
118 * any change in smbpasswd file. The change criteria is smbpasswd's
119 * modification timestamp.
125 typedef struct smb_uchandle
{
127 rwlock_t uc_cache_lck
;
128 timestruc_t uc_timestamp
;
135 #define SMB_UCHS_NOCACHE 0
136 #define SMB_UCHS_CREATED 1
137 #define SMB_UCHS_UPDATING 2
138 #define SMB_UCHS_UPDATED 3
139 #define SMB_UCHS_DESTROYING 4
144 typedef struct smb_ucnode
{
149 static void smb_lucache_create(void);
150 static void smb_lucache_destroy(void);
151 static void smb_lucache_update(void);
152 static int smb_lucache_num(void);
153 static int smb_lucache_lock(void);
154 static void smb_lucache_unlock(void);
155 static int smb_lucache_do_update(void);
156 static void smb_lucache_flush(void);
158 static smb_uchandle_t smb_uch
;
163 * Initializes the cache if requested.
164 * Checks to see if a password management utility library
165 * is interposed. If yes then it'll initializes smb_pwd_ops
166 * structure with function pointers from this library.
169 smb_pwd_init(boolean_t create_cache
)
172 smb_lucache_create();
175 * This pre-loading of the cache results in idmapd requests.
176 * With the change to allow idmapd to call into libsmb to
177 * map names and SIDs, this creates a circular startup
178 * dependency. This call has been temporarily disabled to
179 * avoid this issue. It can be enabled when the name/SID
180 * lookup can be done directly on the LSA service.
182 smb_lucache_update();
186 smb_pwd_hdl
= smb_dlopen();
187 if (smb_pwd_hdl
== NULL
)
190 bzero((void *)&smb_pwd_ops
, sizeof (smb_pwd_ops
));
192 smb_pwd_ops
.pwop_getpwnam
=
193 (smb_passwd_t
*(*)())dlsym(smb_pwd_hdl
, "smb_pwd_getpwnam");
195 smb_pwd_ops
.pwop_getpwuid
=
196 (smb_passwd_t
*(*)())dlsym(smb_pwd_hdl
, "smb_pwd_getpwuid");
198 smb_pwd_ops
.pwop_setcntl
=
199 (int (*)())dlsym(smb_pwd_hdl
, "smb_pwd_setcntl");
201 smb_pwd_ops
.pwop_setpasswd
=
202 (int (*)())dlsym(smb_pwd_hdl
, "smb_pwd_setpasswd");
204 smb_pwd_ops
.pwop_num
=
205 (int (*)())dlsym(smb_pwd_hdl
, "smb_pwd_num");
207 smb_pwd_ops
.pwop_iteropen
=
208 (int (*)())dlsym(smb_pwd_hdl
, "smb_pwd_iteropen");
210 smb_pwd_ops
.pwop_iterclose
=
211 (void (*)())dlsym(smb_pwd_hdl
, "smb_pwd_iterclose");
213 smb_pwd_ops
.pwop_iterate
=
214 (smb_luser_t
*(*)())dlsym(smb_pwd_hdl
, "smb_pwd_iterate");
216 if (smb_pwd_ops
.pwop_getpwnam
== NULL
||
217 smb_pwd_ops
.pwop_getpwuid
== NULL
||
218 smb_pwd_ops
.pwop_setcntl
== NULL
||
219 smb_pwd_ops
.pwop_setpasswd
== NULL
||
220 smb_pwd_ops
.pwop_num
== NULL
||
221 smb_pwd_ops
.pwop_iteropen
== NULL
||
222 smb_pwd_ops
.pwop_iterclose
== NULL
||
223 smb_pwd_ops
.pwop_iterate
== NULL
) {
224 smb_dlclose(smb_pwd_hdl
);
227 /* If error or function(s) are missing, use original lib */
228 bzero((void *)&smb_pwd_ops
, sizeof (smb_pwd_ops
));
235 * Destroys the cache.
236 * Closes interposed library.
241 smb_lucache_destroy();
242 smb_dlclose(smb_pwd_hdl
);
244 bzero((void *)&smb_pwd_ops
, sizeof (smb_pwd_ops
));
250 * Returns a smb password structure for the given user name.
251 * smbpw is a pointer to a buffer allocated by the caller.
253 * Returns NULL upon failure.
256 smb_pwd_getpwnam(const char *name
, smb_passwd_t
*smbpw
)
258 boolean_t found
= B_FALSE
;
263 if (smb_pwd_ops
.pwop_getpwnam
!= NULL
)
264 return (smb_pwd_ops
.pwop_getpwnam(name
, smbpw
));
266 err
= smb_pwd_lock();
267 if (err
!= SMB_PWE_SUCCESS
) {
268 syslog(LOG_WARNING
, "smb_pwdutil: lock failed, err=%d", err
);
272 if ((fp
= fopen(SMB_PASSWD
, "rF")) == NULL
) {
273 syslog(LOG_WARNING
, "smb_pwdutil: open failed, %m");
274 (void) smb_pwd_unlock();
278 pwbuf
.pw_pwd
= smbpw
;
280 while (smb_pwd_fgetent(fp
, &pwbuf
, SMB_PWD_GETF_ALL
) != NULL
) {
281 if (strcmp(name
, smbpw
->pw_name
) == 0) {
288 (void) smb_pwd_unlock();
291 bzero(smbpw
, sizeof (smb_passwd_t
));
301 * Returns a smb password structure for the given UID
302 * smbpw is a pointer to a buffer allocated by the caller.
304 * Returns NULL upon failure.
307 smb_pwd_getpwuid(uid_t uid
, smb_passwd_t
*smbpw
)
309 boolean_t found
= B_FALSE
;
314 if (smb_pwd_ops
.pwop_getpwuid
!= NULL
)
315 return (smb_pwd_ops
.pwop_getpwuid(uid
, smbpw
));
317 err
= smb_pwd_lock();
318 if (err
!= SMB_PWE_SUCCESS
) {
319 syslog(LOG_WARNING
, "smb_pwdutil: lock failed, err=%d", err
);
323 if ((fp
= fopen(SMB_PASSWD
, "rF")) == NULL
) {
324 syslog(LOG_WARNING
, "smb_pwdutil: open failed, %m");
325 (void) smb_pwd_unlock();
329 pwbuf
.pw_pwd
= smbpw
;
331 while (smb_pwd_fgetent(fp
, &pwbuf
, SMB_PWD_GETF_ALL
) != NULL
) {
332 if (uid
== smbpw
->pw_uid
) {
339 (void) smb_pwd_unlock();
342 bzero(smbpw
, sizeof (smb_passwd_t
));
352 * Update/add the given user to the smbpasswd file.
355 smb_pwd_setpasswd(const char *name
, const char *password
)
357 if (smb_pwd_ops
.pwop_setpasswd
!= NULL
)
358 return (smb_pwd_ops
.pwop_setpasswd(name
, password
));
360 return (smb_pwd_update(name
, password
, 0));
366 * Change the account state. This can be making the account
367 * disable/enable or removing its LM hash.
370 smb_pwd_setcntl(const char *name
, int control
)
372 if (smb_pwd_ops
.pwop_setcntl
!= NULL
)
373 return (smb_pwd_ops
.pwop_setcntl(name
, control
));
376 return (SMB_PWE_SUCCESS
);
378 return (smb_pwd_update(name
, NULL
, control
));
384 * Returns the number of cached local users
389 if (smb_pwd_ops
.pwop_num
!= NULL
)
390 return (smb_pwd_ops
.pwop_num());
392 smb_lucache_update();
394 return (smb_lucache_num());
400 * Initalizes the given iterator handle.
401 * This handle will be used to iterate the users cache
402 * by the caller. The cache will be locked for read and it
403 * will remain locked until smb_pwd_iterclose() is called.
406 smb_pwd_iteropen(smb_pwditer_t
*iter
)
409 return (SMB_PWE_INVALID_PARAM
);
411 if (smb_pwd_ops
.pwop_iteropen
!= NULL
)
412 return (smb_pwd_ops
.pwop_iteropen(iter
));
414 iter
->spi_next
= NULL
;
416 smb_lucache_update();
418 return (smb_lucache_lock());
424 * Scans through users cache using the given iterator
427 smb_pwd_iterate(smb_pwditer_t
*iter
)
429 smb_ucnode_t
*ucnode
;
434 if (smb_pwd_ops
.pwop_iterate
!= NULL
)
435 return (smb_pwd_ops
.pwop_iterate(iter
));
437 if (iter
->spi_next
== NULL
)
438 ucnode
= avl_first(&smb_uch
.uc_cache
);
440 ucnode
= AVL_NEXT(&smb_uch
.uc_cache
, iter
->spi_next
);
442 if ((iter
->spi_next
= ucnode
) != NULL
)
443 return (&ucnode
->cn_user
);
451 * Closes the given iterator. Effectively it only unlocks the cache
454 smb_pwd_iterclose(smb_pwditer_t
*iter
)
456 if (smb_pwd_ops
.pwop_iterclose
!= NULL
) {
457 smb_pwd_ops
.pwop_iterclose(iter
);
462 smb_lucache_unlock();
468 * Updates the password entry of the given user if the user already
469 * has an entry, otherwise it'll add an entry for the user with
470 * given password and control information.
473 smb_pwd_update(const char *name
, const char *password
, int control
)
478 int err
= SMB_PWE_SUCCESS
;
481 boolean_t newent
= B_TRUE
;
482 boolean_t user_disable
= B_FALSE
;
487 err
= smb_pwd_lock();
488 if (err
!= SMB_PWE_SUCCESS
)
491 if (stat64(SMB_PASSWD
, &stbuf
) < 0) {
492 err
= SMB_PWE_STAT_FAILED
;
496 if ((tempfd
= open(SMB_PASSTEMP
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) < 0) {
497 err
= SMB_PWE_OPEN_FAILED
;
501 if ((dst
= fdopen(tempfd
, "wF")) == NULL
) {
502 err
= SMB_PWE_OPEN_FAILED
;
506 if ((src
= fopen(SMB_PASSWD
, "rF")) == NULL
) {
507 err
= SMB_PWE_OPEN_FAILED
;
509 (void) unlink(SMB_PASSTEMP
);
513 if (smb_config_getnum(SMB_CI_LM_LEVEL
, &lm_level
) != SMBD_SMF_OK
)
517 control
|= SMB_PWC_NOLM
;
519 pwbuf
.pw_pwd
= &smbpw
;
522 * copy old password entries to temporary file while replacing
523 * the entry that matches "name"
525 while (smb_pwd_fgetent(src
, &pwbuf
, SMB_PWD_GETF_ALL
) != NULL
) {
526 if (strcmp(smbpw
.pw_name
, name
) == 0) {
527 err
= smb_pwd_chgpwent(&smbpw
, password
, control
);
528 if (err
== SMB_PWE_USER_DISABLE
)
529 user_disable
= B_TRUE
;
530 err
= smb_pwd_fputent(dst
, &pwbuf
);
533 err
= smb_pwd_fputent(dst
, &pwbuf
);
536 if (err
!= SMB_PWE_SUCCESS
) {
544 if (getpwnam_r(name
, &uxpw
, uxbuf
, sizeof (uxbuf
))) {
545 bzero(&smbpw
, sizeof (smb_passwd_t
));
546 (void) strlcpy(smbpw
.pw_name
, uxpw
.pw_name
,
547 sizeof (smbpw
.pw_name
));
548 smbpw
.pw_uid
= uxpw
.pw_uid
;
549 (void) smb_pwd_chgpwent(&smbpw
, password
, control
);
550 err
= smb_pwd_fputent(dst
, &pwbuf
);
552 err
= SMB_PWE_USER_UNKNOWN
;
555 if (err
!= SMB_PWE_SUCCESS
) {
563 if (fclose(dst
) != 0) {
564 err
= SMB_PWE_CLOSE_FAILED
;
565 goto passwd_exit
; /* Don't trust the temporary file */
568 /* Rename temp to passwd */
569 if (unlink(SMB_OPASSWD
) && access(SMB_OPASSWD
, 0) == 0) {
570 err
= SMB_PWE_UPDATE_FAILED
;
571 (void) unlink(SMB_PASSTEMP
);
575 if (link(SMB_PASSWD
, SMB_OPASSWD
) == -1) {
576 err
= SMB_PWE_UPDATE_FAILED
;
577 (void) unlink(SMB_PASSTEMP
);
581 if (rename(SMB_PASSTEMP
, SMB_PASSWD
) == -1) {
582 err
= SMB_PWE_UPDATE_FAILED
;
583 (void) unlink(SMB_PASSTEMP
);
587 (void) chmod(SMB_PASSWD
, 0400);
590 (void) smb_pwd_unlock();
591 if ((err
== SMB_PWE_SUCCESS
) && user_disable
)
592 err
= SMB_PWE_USER_DISABLE
;
600 * Parse the buffer in the passed pwbuf and fill in the
601 * smb password structure to point to the parsed information.
602 * The entry format is:
604 * <user-name>:<user-id>:<LM hash>:<NTLM hash>
606 * Returns a pointer to the passed pwbuf structure on success,
607 * otherwise returns NULL.
610 smb_pwd_fgetent(FILE *fp
, smb_pwbuf_t
*pwbuf
, uint32_t flags
)
612 char *argv
[SMB_PWD_NARG
];
618 pwentry
= pwbuf
->pw_buf
;
619 if (fgets(pwentry
, SMB_PWD_BUFSIZE
, fp
) == NULL
)
621 (void) trim_whitespace(pwentry
);
623 for (i
= 0; i
< SMB_PWD_NARG
; ++i
) {
624 if ((argv
[i
] = strsep((char **)&pwentry
, ":")) == NULL
)
628 if ((*argv
[SMB_PWD_NAME
] == '\0') || (*argv
[SMB_PWD_UID
] == '\0'))
632 bzero(pw
, sizeof (smb_passwd_t
));
633 pw
->pw_uid
= strtoul(argv
[SMB_PWD_UID
], 0, 10);
634 (void) strlcpy(pw
->pw_name
, argv
[SMB_PWD_NAME
], sizeof (pw
->pw_name
));
636 if (strcmp(argv
[SMB_PWD_LMHASH
], SMB_PWD_DISABLE
) == 0) {
637 pw
->pw_flags
|= SMB_PWF_DISABLE
;
638 if (flags
!= SMB_PWD_GETF_NOPWD
) {
639 (void) strcpy((char *)pw
->pw_lmhash
, SMB_PWD_DISABLE
);
640 (void) strcpy((char *)pw
->pw_nthash
, SMB_PWD_DISABLE
);
645 if (flags
== SMB_PWD_GETF_NOPWD
)
648 lm_len
= strlen(argv
[SMB_PWD_LMHASH
]);
649 if (lm_len
== SMBAUTH_HEXHASH_SZ
) {
650 (void) hextobin(argv
[SMB_PWD_LMHASH
], SMBAUTH_HEXHASH_SZ
,
651 (char *)pw
->pw_lmhash
, SMBAUTH_HASH_SZ
);
653 pw
->pw_flags
|= SMB_PWF_LM
;
654 } else if (lm_len
!= 0) {
658 nt_len
= strlen(argv
[SMB_PWD_NTHASH
]);
659 if (nt_len
== SMBAUTH_HEXHASH_SZ
) {
660 (void) hextobin(argv
[SMB_PWD_NTHASH
], SMBAUTH_HEXHASH_SZ
,
661 (char *)pw
->pw_nthash
, SMBAUTH_HASH_SZ
);
663 pw
->pw_flags
|= SMB_PWF_NT
;
664 } else if (nt_len
!= 0) {
674 * Updates the given smb_passwd_t structure with given password and
675 * control information.
678 smb_pwd_chgpwent(smb_passwd_t
*smbpw
, const char *password
, int control
)
680 if (control
& SMB_PWC_DISABLE
) {
681 /* disable the user */
682 smbpw
->pw_flags
|= SMB_PWF_DISABLE
;
683 (void) strcpy((char *)smbpw
->pw_lmhash
, SMB_PWD_DISABLE
);
684 (void) strcpy((char *)smbpw
->pw_nthash
, SMB_PWD_DISABLE
);
685 smbpw
->pw_flags
&= ~(SMB_PWF_LM
| SMB_PWF_NT
);
686 return (SMB_PWE_SUCCESS
);
689 if ((control
& SMB_PWC_ENABLE
) && (smbpw
->pw_flags
& SMB_PWF_DISABLE
)) {
690 /* enable the user if it's been disabled */
691 *smbpw
->pw_lmhash
= '\0';
692 *smbpw
->pw_nthash
= '\0';
693 smbpw
->pw_flags
&= ~(SMB_PWF_LM
| SMB_PWF_NT
);
694 return (SMB_PWE_SUCCESS
);
697 /* No password update if account is disabled */
698 if (smbpw
->pw_flags
& SMB_PWF_DISABLE
)
699 return (SMB_PWE_USER_DISABLE
);
701 /* This call was just to update the control flags */
702 if (password
== NULL
)
703 return (SMB_PWE_SUCCESS
);
705 if (control
& SMB_PWC_NOLM
) {
706 /* LM hash should not be present */
707 smbpw
->pw_flags
&= ~SMB_PWF_LM
;
708 *smbpw
->pw_lmhash
= '\0';
710 smbpw
->pw_flags
|= SMB_PWF_LM
;
711 (void) smb_auth_lm_hash(password
, smbpw
->pw_lmhash
);
714 smbpw
->pw_flags
|= SMB_PWF_NT
;
715 (void) smb_auth_ntlm_hash(password
, smbpw
->pw_nthash
);
716 return (SMB_PWE_SUCCESS
);
722 * If LM/NTLM hash are present, converts them to hex string
723 * and write them along with user's name and Id to the smbpasswd
727 smb_pwd_fputent(FILE *fp
, const smb_pwbuf_t
*pwbuf
)
729 smb_passwd_t
*pw
= pwbuf
->pw_pwd
;
730 char hex_nthash
[SMBAUTH_HEXHASH_SZ
+1];
731 char hex_lmhash
[SMBAUTH_HEXHASH_SZ
+1];
734 if ((pw
->pw_flags
& SMB_PWF_LM
) == SMB_PWF_LM
) {
735 (void) bintohex((char *)pw
->pw_lmhash
, SMBAUTH_HASH_SZ
,
736 hex_lmhash
, SMBAUTH_HEXHASH_SZ
);
737 hex_lmhash
[SMBAUTH_HEXHASH_SZ
] = '\0';
739 (void) strcpy(hex_lmhash
, (char *)pw
->pw_lmhash
);
742 if ((pw
->pw_flags
& SMB_PWF_NT
) == SMB_PWF_NT
) {
743 (void) bintohex((char *)pw
->pw_nthash
, SMBAUTH_HASH_SZ
,
744 hex_nthash
, SMBAUTH_HEXHASH_SZ
);
745 hex_nthash
[SMBAUTH_HEXHASH_SZ
] = '\0';
747 (void) strcpy(hex_nthash
, (char *)pw
->pw_nthash
);
750 rc
= fprintf(fp
, "%s:%u:%s:%s\n", pw
->pw_name
, pw
->pw_uid
,
751 hex_lmhash
, hex_nthash
);
754 return (SMB_PWE_WRITE_FAILED
);
756 return (SMB_PWE_SUCCESS
);
762 * A wrapper around smb_pwd_flck() which locks smb password
763 * file so that only one thread at a time is operational.
770 if (smb_pwd_flck()) {
776 res
= SMB_PWE_DENIED
;
779 res
= SMB_PWE_SUCCESS
;
783 res
= SMB_PWE_SUCCESS
;
791 * A wrapper around smb_pwd_fulck() which unlocks
798 return (SMB_PWE_SYSTEM_ERROR
);
800 return (SMB_PWE_SUCCESS
);
806 * Creates a lock file and grabs an exclusive (write) lock on it.
813 (void) mutex_lock(&lck_lock
);
815 if (lck_pid
!= 0 && lck_pid
!= getpid()) {
816 /* somebody forked */
822 if ((fildes
= creat(SMB_PASSLCK
, 0600)) == -1)
824 flock
.l_type
= F_WRLCK
;
825 if (fcntl(fildes
, F_SETLK
, &flock
) != -1) {
827 lck_tid
= thr_self();
828 (void) mutex_unlock(&lck_lock
);
831 (void) close(fildes
);
835 if (seconds
++ >= S_WAITTIME
) {
837 * For compatibility with the past, pretend
838 * that we were interrupted by SIGALRM.
844 (void) mutex_unlock(&lck_lock
);
846 (void) mutex_lock(&lck_lock
);
848 (void) mutex_unlock(&lck_lock
);
856 * Unlocks smb password file for operations done via
862 (void) mutex_lock(&lck_lock
);
863 if (lck_tid
== thr_self() && fildes
>= 0) {
864 flock
.l_type
= F_UNLCK
;
865 (void) fcntl(fildes
, F_SETLK
, &flock
);
866 (void) close(fildes
);
870 (void) mutex_unlock(&lck_lock
);
873 (void) mutex_unlock(&lck_lock
);
878 * Local User Cache Functions
880 * Local user cache is implemented using AVL tree
886 * AVL compare function, the key is username.
889 smb_lucache_cmp(const void *p1
, const void *p2
)
891 smb_ucnode_t
*u1
= (smb_ucnode_t
*)p1
;
892 smb_ucnode_t
*u2
= (smb_ucnode_t
*)p2
;
895 rc
= strcmp(u1
->cn_user
.su_name
, u2
->cn_user
.su_name
);
909 * Updates the cache if needed. Whether an update is needed
910 * is determined based on smbpasswd file modification timestamp
913 smb_lucache_update(void)
918 (void) mutex_lock(&smb_uch
.uc_mtx
);
919 switch (smb_uch
.uc_state
) {
921 case SMB_UCHS_NOCACHE
:
923 (void) mutex_unlock(&smb_uch
.uc_mtx
);
926 case SMB_UCHS_CREATED
:
927 case SMB_UCHS_UPDATED
:
930 case SMB_UCHS_UPDATING
:
931 /* Want only one thread executing this function at a time */
932 (void) mutex_unlock(&smb_uch
.uc_mtx
);
935 case SMB_UCHS_DESTROYING
:
936 (void) mutex_unlock(&smb_uch
.uc_mtx
);
941 * smb_pwd_lock() is not called here so it can
942 * be checked quickly whether an updated is needed
944 if (stat64(SMB_PASSWD
, &stbuf
) < 0) {
945 (void) mutex_unlock(&smb_uch
.uc_mtx
);
949 /* no smbpasswd file; empty the cache */
954 if (stbuf
.st_size
== 0) {
955 (void) mutex_unlock(&smb_uch
.uc_mtx
);
957 /* empty smbpasswd file; empty the cache */
962 if ((smb_uch
.uc_timestamp
.tv_sec
== stbuf
.st_mtim
.tv_sec
) &&
963 (smb_uch
.uc_timestamp
.tv_nsec
== stbuf
.st_mtim
.tv_nsec
)) {
964 (void) mutex_unlock(&smb_uch
.uc_mtx
);
965 /* No changes since the last cache update */
969 smb_uch
.uc_state
= SMB_UCHS_UPDATING
;
971 (void) mutex_unlock(&smb_uch
.uc_mtx
);
973 rc
= smb_lucache_do_update();
975 (void) mutex_lock(&smb_uch
.uc_mtx
);
976 if ((rc
== SMB_PWE_SUCCESS
) && (stat64(SMB_PASSWD
, &stbuf
) == 0))
977 smb_uch
.uc_timestamp
= stbuf
.st_mtim
;
978 smb_uch
.uc_state
= SMB_UCHS_UPDATED
;
980 (void) cond_broadcast(&smb_uch
.uc_cv
);
981 (void) mutex_unlock(&smb_uch
.uc_mtx
);
985 * smb_lucache_do_update
987 * This function takes care of updating the AVL tree.
988 * If an entry has been updated, it'll be modified in place.
990 * New entries will be added to a temporary AVL tree then
991 * passwod file is unlocked and all the new entries will
992 * be transferred to the main cache from the temporary tree.
994 * This function MUST NOT be called directly
997 smb_lucache_do_update(void)
999 avl_tree_t tmp_cache
;
1002 smb_ucnode_t uc_node
;
1003 smb_ucnode_t
*uc_newnode
;
1006 idmap_stat idm_stat
;
1007 int rc
= SMB_PWE_SUCCESS
;
1008 void *cookie
= NULL
;
1011 if ((rc
= smb_pwd_lock()) != SMB_PWE_SUCCESS
) {
1012 syslog(LOG_WARNING
, "smb_pwdutil: lock failed, err=%d", rc
);
1016 if ((fp
= fopen(SMB_PASSWD
, "rF")) == NULL
) {
1017 syslog(LOG_WARNING
, "smb_pwdutil: open failed, %m");
1018 (void) smb_pwd_unlock();
1019 return (SMB_PWE_OPEN_FAILED
);
1022 avl_create(&tmp_cache
, smb_lucache_cmp
,
1023 sizeof (smb_ucnode_t
), offsetof(smb_ucnode_t
, cn_link
));
1025 bzero(&pwbuf
, sizeof (smb_pwbuf_t
));
1026 pwbuf
.pw_pwd
= &smbpw
;
1028 (void) rw_rdlock(&smb_uch
.uc_cache_lck
);
1030 while (smb_pwd_fgetent(fp
, &pwbuf
, SMB_PWD_GETF_NOPWD
) != NULL
) {
1031 uc_node
.cn_user
.su_name
= smbpw
.pw_name
;
1032 uc_newnode
= avl_find(&smb_uch
.uc_cache
, &uc_node
, NULL
);
1034 /* update the node info */
1035 uc_newnode
->cn_user
.su_ctrl
= smbpw
.pw_flags
;
1039 /* create a new node */
1040 if ((uc_newnode
= malloc(sizeof (smb_ucnode_t
))) == NULL
) {
1041 rc
= SMB_PWE_NO_MEMORY
;
1045 bzero(uc_newnode
, sizeof (smb_ucnode_t
));
1046 user
= &uc_newnode
->cn_user
;
1047 user
->su_ctrl
= smbpw
.pw_flags
;
1049 idm_stat
= smb_idmap_getsid(smbpw
.pw_uid
, SMB_IDMAP_USER
, &sid
);
1050 if (idm_stat
!= IDMAP_SUCCESS
) {
1051 syslog(LOG_WARNING
, "smb_pwdutil: couldn't obtain SID "
1052 "for uid=%u (%d)", smbpw
.pw_uid
, idm_stat
);
1056 (void) smb_sid_getrid(sid
, &user
->su_rid
);
1059 user
->su_name
= strdup(smbpw
.pw_name
);
1060 if (user
->su_name
== NULL
) {
1061 rc
= SMB_PWE_NO_MEMORY
;
1066 avl_add(&tmp_cache
, uc_newnode
);
1069 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1071 (void) smb_pwd_unlock();
1073 /* Destroy the temporary list */
1074 (void) rw_wrlock(&smb_uch
.uc_cache_lck
);
1075 while ((uc_newnode
= avl_destroy_nodes(&tmp_cache
, &cookie
)) != NULL
) {
1076 avl_add(&smb_uch
.uc_cache
, uc_newnode
);
1078 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1080 avl_destroy(&tmp_cache
);
1086 * smb_lucache_create
1088 * Creates the AVL tree and initializes the global user cache handle.
1089 * This function doesn't populate the cache.
1090 * User cache is only created by smbd at startup
1093 smb_lucache_create(void)
1095 (void) mutex_lock(&smb_uch
.uc_mtx
);
1096 if (smb_uch
.uc_state
!= SMB_UCHS_NOCACHE
) {
1097 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1101 avl_create(&smb_uch
.uc_cache
, smb_lucache_cmp
,
1102 sizeof (smb_ucnode_t
), offsetof(smb_ucnode_t
, cn_link
));
1104 smb_uch
.uc_state
= SMB_UCHS_CREATED
;
1105 bzero(&smb_uch
.uc_timestamp
, sizeof (timestruc_t
));
1106 smb_uch
.uc_refcnt
= 0;
1107 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1113 * Removes and frees all the cache entries
1116 smb_lucache_flush(void)
1118 void *cookie
= NULL
;
1119 smb_ucnode_t
*ucnode
;
1121 (void) rw_wrlock(&smb_uch
.uc_cache_lck
);
1122 while ((ucnode
= avl_destroy_nodes(&smb_uch
.uc_cache
, &cookie
))
1124 free(ucnode
->cn_user
.su_name
);
1125 free(ucnode
->cn_user
.su_fullname
);
1126 free(ucnode
->cn_user
.su_desc
);
1129 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1133 * smb_lucache_destroy
1135 * Destroys the cache.
1136 * This function is only called in smb_pwd_fini()
1137 * User cache is only destroyed by smbd upon shutdown
1140 smb_lucache_destroy(void)
1142 (void) mutex_lock(&smb_uch
.uc_mtx
);
1143 switch (smb_uch
.uc_state
) {
1144 case SMB_UCHS_NOCACHE
:
1145 case SMB_UCHS_DESTROYING
:
1146 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1153 smb_uch
.uc_state
= SMB_UCHS_DESTROYING
;
1155 while (smb_uch
.uc_refcnt
> 0)
1156 (void) cond_wait(&smb_uch
.uc_cv
, &smb_uch
.uc_mtx
);
1158 smb_lucache_flush();
1160 avl_destroy(&smb_uch
.uc_cache
);
1161 smb_uch
.uc_state
= SMB_UCHS_NOCACHE
;
1162 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1168 * Locks the user cache for reading and also
1169 * increment the handle reference count.
1172 smb_lucache_lock(void)
1174 (void) mutex_lock(&smb_uch
.uc_mtx
);
1175 switch (smb_uch
.uc_state
) {
1176 case SMB_UCHS_NOCACHE
:
1178 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1179 return (SMB_PWE_DENIED
);
1181 case SMB_UCHS_DESTROYING
:
1182 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1183 return (SMB_PWE_DENIED
);
1185 smb_uch
.uc_refcnt
++;
1186 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1188 (void) rw_rdlock(&smb_uch
.uc_cache_lck
);
1189 return (SMB_PWE_SUCCESS
);
1193 * smb_lucache_unlock
1198 smb_lucache_unlock(void)
1200 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1202 (void) mutex_lock(&smb_uch
.uc_mtx
);
1203 smb_uch
.uc_refcnt
--;
1204 (void) cond_broadcast(&smb_uch
.uc_cv
);
1205 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1211 * Returns the number of cache entries
1214 smb_lucache_num(void)
1218 (void) mutex_lock(&smb_uch
.uc_mtx
);
1219 switch (smb_uch
.uc_state
) {
1220 case SMB_UCHS_NOCACHE
:
1222 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1225 case SMB_UCHS_DESTROYING
:
1226 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1229 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1231 (void) rw_rdlock(&smb_uch
.uc_cache_lck
);
1232 num
= (int)avl_numnodes(&smb_uch
.uc_cache
);
1233 (void) rw_unlock(&smb_uch
.uc_cache_lck
);