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
) {
545 getpwnam_r(name
, &uxpw
, uxbuf
, sizeof (uxbuf
), &pwdp
);
547 bzero(&smbpw
, sizeof (smb_passwd_t
));
548 (void) strlcpy(smbpw
.pw_name
, uxpw
.pw_name
,
549 sizeof (smbpw
.pw_name
));
550 smbpw
.pw_uid
= uxpw
.pw_uid
;
551 (void) smb_pwd_chgpwent(&smbpw
, password
, control
);
552 err
= smb_pwd_fputent(dst
, &pwbuf
);
554 err
= SMB_PWE_USER_UNKNOWN
;
557 if (err
!= SMB_PWE_SUCCESS
) {
565 if (fclose(dst
) != 0) {
566 err
= SMB_PWE_CLOSE_FAILED
;
567 goto passwd_exit
; /* Don't trust the temporary file */
570 /* Rename temp to passwd */
571 if (unlink(SMB_OPASSWD
) && access(SMB_OPASSWD
, 0) == 0) {
572 err
= SMB_PWE_UPDATE_FAILED
;
573 (void) unlink(SMB_PASSTEMP
);
577 if (link(SMB_PASSWD
, SMB_OPASSWD
) == -1) {
578 err
= SMB_PWE_UPDATE_FAILED
;
579 (void) unlink(SMB_PASSTEMP
);
583 if (rename(SMB_PASSTEMP
, SMB_PASSWD
) == -1) {
584 err
= SMB_PWE_UPDATE_FAILED
;
585 (void) unlink(SMB_PASSTEMP
);
589 (void) chmod(SMB_PASSWD
, 0400);
592 (void) smb_pwd_unlock();
593 if ((err
== SMB_PWE_SUCCESS
) && user_disable
)
594 err
= SMB_PWE_USER_DISABLE
;
602 * Parse the buffer in the passed pwbuf and fill in the
603 * smb password structure to point to the parsed information.
604 * The entry format is:
606 * <user-name>:<user-id>:<LM hash>:<NTLM hash>
608 * Returns a pointer to the passed pwbuf structure on success,
609 * otherwise returns NULL.
612 smb_pwd_fgetent(FILE *fp
, smb_pwbuf_t
*pwbuf
, uint32_t flags
)
614 char *argv
[SMB_PWD_NARG
];
620 pwentry
= pwbuf
->pw_buf
;
621 if (fgets(pwentry
, SMB_PWD_BUFSIZE
, fp
) == NULL
)
623 (void) trim_whitespace(pwentry
);
625 for (i
= 0; i
< SMB_PWD_NARG
; ++i
) {
626 if ((argv
[i
] = strsep((char **)&pwentry
, ":")) == NULL
)
630 if ((*argv
[SMB_PWD_NAME
] == '\0') || (*argv
[SMB_PWD_UID
] == '\0'))
634 bzero(pw
, sizeof (smb_passwd_t
));
635 pw
->pw_uid
= strtoul(argv
[SMB_PWD_UID
], 0, 10);
636 (void) strlcpy(pw
->pw_name
, argv
[SMB_PWD_NAME
], sizeof (pw
->pw_name
));
638 if (strcmp(argv
[SMB_PWD_LMHASH
], SMB_PWD_DISABLE
) == 0) {
639 pw
->pw_flags
|= SMB_PWF_DISABLE
;
640 if (flags
!= SMB_PWD_GETF_NOPWD
) {
641 (void) strcpy((char *)pw
->pw_lmhash
, SMB_PWD_DISABLE
);
642 (void) strcpy((char *)pw
->pw_nthash
, SMB_PWD_DISABLE
);
647 if (flags
== SMB_PWD_GETF_NOPWD
)
650 lm_len
= strlen(argv
[SMB_PWD_LMHASH
]);
651 if (lm_len
== SMBAUTH_HEXHASH_SZ
) {
652 (void) hextobin(argv
[SMB_PWD_LMHASH
], SMBAUTH_HEXHASH_SZ
,
653 (char *)pw
->pw_lmhash
, SMBAUTH_HASH_SZ
);
655 pw
->pw_flags
|= SMB_PWF_LM
;
656 } else if (lm_len
!= 0) {
660 nt_len
= strlen(argv
[SMB_PWD_NTHASH
]);
661 if (nt_len
== SMBAUTH_HEXHASH_SZ
) {
662 (void) hextobin(argv
[SMB_PWD_NTHASH
], SMBAUTH_HEXHASH_SZ
,
663 (char *)pw
->pw_nthash
, SMBAUTH_HASH_SZ
);
665 pw
->pw_flags
|= SMB_PWF_NT
;
666 } else if (nt_len
!= 0) {
676 * Updates the given smb_passwd_t structure with given password and
677 * control information.
680 smb_pwd_chgpwent(smb_passwd_t
*smbpw
, const char *password
, int control
)
682 if (control
& SMB_PWC_DISABLE
) {
683 /* disable the user */
684 smbpw
->pw_flags
|= SMB_PWF_DISABLE
;
685 (void) strcpy((char *)smbpw
->pw_lmhash
, SMB_PWD_DISABLE
);
686 (void) strcpy((char *)smbpw
->pw_nthash
, SMB_PWD_DISABLE
);
687 smbpw
->pw_flags
&= ~(SMB_PWF_LM
| SMB_PWF_NT
);
688 return (SMB_PWE_SUCCESS
);
691 if ((control
& SMB_PWC_ENABLE
) && (smbpw
->pw_flags
& SMB_PWF_DISABLE
)) {
692 /* enable the user if it's been disabled */
693 *smbpw
->pw_lmhash
= '\0';
694 *smbpw
->pw_nthash
= '\0';
695 smbpw
->pw_flags
&= ~(SMB_PWF_LM
| SMB_PWF_NT
);
696 return (SMB_PWE_SUCCESS
);
699 /* No password update if account is disabled */
700 if (smbpw
->pw_flags
& SMB_PWF_DISABLE
)
701 return (SMB_PWE_USER_DISABLE
);
703 /* This call was just to update the control flags */
704 if (password
== NULL
)
705 return (SMB_PWE_SUCCESS
);
707 if (control
& SMB_PWC_NOLM
) {
708 /* LM hash should not be present */
709 smbpw
->pw_flags
&= ~SMB_PWF_LM
;
710 *smbpw
->pw_lmhash
= '\0';
712 smbpw
->pw_flags
|= SMB_PWF_LM
;
713 (void) smb_auth_lm_hash(password
, smbpw
->pw_lmhash
);
716 smbpw
->pw_flags
|= SMB_PWF_NT
;
717 (void) smb_auth_ntlm_hash(password
, smbpw
->pw_nthash
);
718 return (SMB_PWE_SUCCESS
);
724 * If LM/NTLM hash are present, converts them to hex string
725 * and write them along with user's name and Id to the smbpasswd
729 smb_pwd_fputent(FILE *fp
, const smb_pwbuf_t
*pwbuf
)
731 smb_passwd_t
*pw
= pwbuf
->pw_pwd
;
732 char hex_nthash
[SMBAUTH_HEXHASH_SZ
+1];
733 char hex_lmhash
[SMBAUTH_HEXHASH_SZ
+1];
736 if ((pw
->pw_flags
& SMB_PWF_LM
) == SMB_PWF_LM
) {
737 (void) bintohex((char *)pw
->pw_lmhash
, SMBAUTH_HASH_SZ
,
738 hex_lmhash
, SMBAUTH_HEXHASH_SZ
);
739 hex_lmhash
[SMBAUTH_HEXHASH_SZ
] = '\0';
741 (void) strcpy(hex_lmhash
, (char *)pw
->pw_lmhash
);
744 if ((pw
->pw_flags
& SMB_PWF_NT
) == SMB_PWF_NT
) {
745 (void) bintohex((char *)pw
->pw_nthash
, SMBAUTH_HASH_SZ
,
746 hex_nthash
, SMBAUTH_HEXHASH_SZ
);
747 hex_nthash
[SMBAUTH_HEXHASH_SZ
] = '\0';
749 (void) strcpy(hex_nthash
, (char *)pw
->pw_nthash
);
752 rc
= fprintf(fp
, "%s:%u:%s:%s\n", pw
->pw_name
, pw
->pw_uid
,
753 hex_lmhash
, hex_nthash
);
756 return (SMB_PWE_WRITE_FAILED
);
758 return (SMB_PWE_SUCCESS
);
764 * A wrapper around smb_pwd_flck() which locks smb password
765 * file so that only one thread at a time is operational.
772 if (smb_pwd_flck()) {
778 res
= SMB_PWE_DENIED
;
781 res
= SMB_PWE_SUCCESS
;
785 res
= SMB_PWE_SUCCESS
;
793 * A wrapper around smb_pwd_fulck() which unlocks
800 return (SMB_PWE_SYSTEM_ERROR
);
802 return (SMB_PWE_SUCCESS
);
808 * Creates a lock file and grabs an exclusive (write) lock on it.
815 (void) mutex_lock(&lck_lock
);
817 if (lck_pid
!= 0 && lck_pid
!= getpid()) {
818 /* somebody forked */
824 if ((fildes
= creat(SMB_PASSLCK
, 0600)) == -1)
826 flock
.l_type
= F_WRLCK
;
827 if (fcntl(fildes
, F_SETLK
, &flock
) != -1) {
829 lck_tid
= thr_self();
830 (void) mutex_unlock(&lck_lock
);
833 (void) close(fildes
);
837 if (seconds
++ >= S_WAITTIME
) {
839 * For compatibility with the past, pretend
840 * that we were interrupted by SIGALRM.
846 (void) mutex_unlock(&lck_lock
);
848 (void) mutex_lock(&lck_lock
);
850 (void) mutex_unlock(&lck_lock
);
858 * Unlocks smb password file for operations done via
864 (void) mutex_lock(&lck_lock
);
865 if (lck_tid
== thr_self() && fildes
>= 0) {
866 flock
.l_type
= F_UNLCK
;
867 (void) fcntl(fildes
, F_SETLK
, &flock
);
868 (void) close(fildes
);
872 (void) mutex_unlock(&lck_lock
);
875 (void) mutex_unlock(&lck_lock
);
880 * Local User Cache Functions
882 * Local user cache is implemented using AVL tree
888 * AVL compare function, the key is username.
891 smb_lucache_cmp(const void *p1
, const void *p2
)
893 smb_ucnode_t
*u1
= (smb_ucnode_t
*)p1
;
894 smb_ucnode_t
*u2
= (smb_ucnode_t
*)p2
;
897 rc
= strcmp(u1
->cn_user
.su_name
, u2
->cn_user
.su_name
);
911 * Updates the cache if needed. Whether an update is needed
912 * is determined based on smbpasswd file modification timestamp
915 smb_lucache_update(void)
920 (void) mutex_lock(&smb_uch
.uc_mtx
);
921 switch (smb_uch
.uc_state
) {
923 case SMB_UCHS_NOCACHE
:
925 (void) mutex_unlock(&smb_uch
.uc_mtx
);
928 case SMB_UCHS_CREATED
:
929 case SMB_UCHS_UPDATED
:
932 case SMB_UCHS_UPDATING
:
933 /* Want only one thread executing this function at a time */
934 (void) mutex_unlock(&smb_uch
.uc_mtx
);
937 case SMB_UCHS_DESTROYING
:
938 (void) mutex_unlock(&smb_uch
.uc_mtx
);
943 * smb_pwd_lock() is not called here so it can
944 * be checked quickly whether an updated is needed
946 if (stat64(SMB_PASSWD
, &stbuf
) < 0) {
947 (void) mutex_unlock(&smb_uch
.uc_mtx
);
951 /* no smbpasswd file; empty the cache */
956 if (stbuf
.st_size
== 0) {
957 (void) mutex_unlock(&smb_uch
.uc_mtx
);
959 /* empty smbpasswd file; empty the cache */
964 if ((smb_uch
.uc_timestamp
.tv_sec
== stbuf
.st_mtim
.tv_sec
) &&
965 (smb_uch
.uc_timestamp
.tv_nsec
== stbuf
.st_mtim
.tv_nsec
)) {
966 (void) mutex_unlock(&smb_uch
.uc_mtx
);
967 /* No changes since the last cache update */
971 smb_uch
.uc_state
= SMB_UCHS_UPDATING
;
973 (void) mutex_unlock(&smb_uch
.uc_mtx
);
975 rc
= smb_lucache_do_update();
977 (void) mutex_lock(&smb_uch
.uc_mtx
);
978 if ((rc
== SMB_PWE_SUCCESS
) && (stat64(SMB_PASSWD
, &stbuf
) == 0))
979 smb_uch
.uc_timestamp
= stbuf
.st_mtim
;
980 smb_uch
.uc_state
= SMB_UCHS_UPDATED
;
982 (void) cond_broadcast(&smb_uch
.uc_cv
);
983 (void) mutex_unlock(&smb_uch
.uc_mtx
);
987 * smb_lucache_do_update
989 * This function takes care of updating the AVL tree.
990 * If an entry has been updated, it'll be modified in place.
992 * New entries will be added to a temporary AVL tree then
993 * passwod file is unlocked and all the new entries will
994 * be transferred to the main cache from the temporary tree.
996 * This function MUST NOT be called directly
999 smb_lucache_do_update(void)
1001 avl_tree_t tmp_cache
;
1004 smb_ucnode_t uc_node
;
1005 smb_ucnode_t
*uc_newnode
;
1008 idmap_stat idm_stat
;
1009 int rc
= SMB_PWE_SUCCESS
;
1010 void *cookie
= NULL
;
1013 if ((rc
= smb_pwd_lock()) != SMB_PWE_SUCCESS
) {
1014 syslog(LOG_WARNING
, "smb_pwdutil: lock failed, err=%d", rc
);
1018 if ((fp
= fopen(SMB_PASSWD
, "rF")) == NULL
) {
1019 syslog(LOG_WARNING
, "smb_pwdutil: open failed, %m");
1020 (void) smb_pwd_unlock();
1021 return (SMB_PWE_OPEN_FAILED
);
1024 avl_create(&tmp_cache
, smb_lucache_cmp
,
1025 sizeof (smb_ucnode_t
), offsetof(smb_ucnode_t
, cn_link
));
1027 bzero(&pwbuf
, sizeof (smb_pwbuf_t
));
1028 pwbuf
.pw_pwd
= &smbpw
;
1030 (void) rw_rdlock(&smb_uch
.uc_cache_lck
);
1032 while (smb_pwd_fgetent(fp
, &pwbuf
, SMB_PWD_GETF_NOPWD
) != NULL
) {
1033 uc_node
.cn_user
.su_name
= smbpw
.pw_name
;
1034 uc_newnode
= avl_find(&smb_uch
.uc_cache
, &uc_node
, NULL
);
1036 /* update the node info */
1037 uc_newnode
->cn_user
.su_ctrl
= smbpw
.pw_flags
;
1041 /* create a new node */
1042 if ((uc_newnode
= malloc(sizeof (smb_ucnode_t
))) == NULL
) {
1043 rc
= SMB_PWE_NO_MEMORY
;
1047 bzero(uc_newnode
, sizeof (smb_ucnode_t
));
1048 user
= &uc_newnode
->cn_user
;
1049 user
->su_ctrl
= smbpw
.pw_flags
;
1051 idm_stat
= smb_idmap_getsid(smbpw
.pw_uid
, SMB_IDMAP_USER
, &sid
);
1052 if (idm_stat
!= IDMAP_SUCCESS
) {
1053 syslog(LOG_WARNING
, "smb_pwdutil: couldn't obtain SID "
1054 "for uid=%u (%d)", smbpw
.pw_uid
, idm_stat
);
1058 (void) smb_sid_getrid(sid
, &user
->su_rid
);
1061 user
->su_name
= strdup(smbpw
.pw_name
);
1062 if (user
->su_name
== NULL
) {
1063 rc
= SMB_PWE_NO_MEMORY
;
1068 avl_add(&tmp_cache
, uc_newnode
);
1071 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1073 (void) smb_pwd_unlock();
1075 /* Destroy the temporary list */
1076 (void) rw_wrlock(&smb_uch
.uc_cache_lck
);
1077 while ((uc_newnode
= avl_destroy_nodes(&tmp_cache
, &cookie
)) != NULL
) {
1078 avl_add(&smb_uch
.uc_cache
, uc_newnode
);
1080 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1082 avl_destroy(&tmp_cache
);
1088 * smb_lucache_create
1090 * Creates the AVL tree and initializes the global user cache handle.
1091 * This function doesn't populate the cache.
1092 * User cache is only created by smbd at startup
1095 smb_lucache_create(void)
1097 (void) mutex_lock(&smb_uch
.uc_mtx
);
1098 if (smb_uch
.uc_state
!= SMB_UCHS_NOCACHE
) {
1099 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1103 avl_create(&smb_uch
.uc_cache
, smb_lucache_cmp
,
1104 sizeof (smb_ucnode_t
), offsetof(smb_ucnode_t
, cn_link
));
1106 smb_uch
.uc_state
= SMB_UCHS_CREATED
;
1107 bzero(&smb_uch
.uc_timestamp
, sizeof (timestruc_t
));
1108 smb_uch
.uc_refcnt
= 0;
1109 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1115 * Removes and frees all the cache entries
1118 smb_lucache_flush(void)
1120 void *cookie
= NULL
;
1121 smb_ucnode_t
*ucnode
;
1123 (void) rw_wrlock(&smb_uch
.uc_cache_lck
);
1124 while ((ucnode
= avl_destroy_nodes(&smb_uch
.uc_cache
, &cookie
))
1126 free(ucnode
->cn_user
.su_name
);
1127 free(ucnode
->cn_user
.su_fullname
);
1128 free(ucnode
->cn_user
.su_desc
);
1131 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1135 * smb_lucache_destroy
1137 * Destroys the cache.
1138 * This function is only called in smb_pwd_fini()
1139 * User cache is only destroyed by smbd upon shutdown
1142 smb_lucache_destroy(void)
1144 (void) mutex_lock(&smb_uch
.uc_mtx
);
1145 switch (smb_uch
.uc_state
) {
1146 case SMB_UCHS_NOCACHE
:
1147 case SMB_UCHS_DESTROYING
:
1148 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1155 smb_uch
.uc_state
= SMB_UCHS_DESTROYING
;
1157 while (smb_uch
.uc_refcnt
> 0)
1158 (void) cond_wait(&smb_uch
.uc_cv
, &smb_uch
.uc_mtx
);
1160 smb_lucache_flush();
1162 avl_destroy(&smb_uch
.uc_cache
);
1163 smb_uch
.uc_state
= SMB_UCHS_NOCACHE
;
1164 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1170 * Locks the user cache for reading and also
1171 * increment the handle reference count.
1174 smb_lucache_lock(void)
1176 (void) mutex_lock(&smb_uch
.uc_mtx
);
1177 switch (smb_uch
.uc_state
) {
1178 case SMB_UCHS_NOCACHE
:
1180 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1181 return (SMB_PWE_DENIED
);
1183 case SMB_UCHS_DESTROYING
:
1184 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1185 return (SMB_PWE_DENIED
);
1187 smb_uch
.uc_refcnt
++;
1188 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1190 (void) rw_rdlock(&smb_uch
.uc_cache_lck
);
1191 return (SMB_PWE_SUCCESS
);
1195 * smb_lucache_unlock
1200 smb_lucache_unlock(void)
1202 (void) rw_unlock(&smb_uch
.uc_cache_lck
);
1204 (void) mutex_lock(&smb_uch
.uc_mtx
);
1205 smb_uch
.uc_refcnt
--;
1206 (void) cond_broadcast(&smb_uch
.uc_cv
);
1207 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1213 * Returns the number of cache entries
1216 smb_lucache_num(void)
1220 (void) mutex_lock(&smb_uch
.uc_mtx
);
1221 switch (smb_uch
.uc_state
) {
1222 case SMB_UCHS_NOCACHE
:
1224 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1227 case SMB_UCHS_DESTROYING
:
1228 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1231 (void) mutex_unlock(&smb_uch
.uc_mtx
);
1233 (void) rw_rdlock(&smb_uch
.uc_cache_lck
);
1234 num
= (int)avl_numnodes(&smb_uch
.uc_cache
);
1235 (void) rw_unlock(&smb_uch
.uc_cache_lck
);