1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <syslog.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <limits.h>
30 #include <strings.h>
31 #include <synch.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/avl.h>
36 #include <fcntl.h>
37 #include <thread.h>
38 #include <pwd.h>
39 #include <dlfcn.h>
40 #include <link.h>
41 #include <assert.h>
42 #include <smbsrv/libsmb.h>
43
44 #define SMB_PASSWD "/var/smb/smbpasswd"
45 #define SMB_OPASSWD "/var/smb/osmbpasswd"
46 #define SMB_PASSTEMP "/var/smb/ptmp"
47 #define SMB_PASSLCK "/var/smb/.pwd.lock"
48
49 #define SMB_PWD_DISABLE "*DIS*"
50 #define SMB_PWD_BUFSIZE 256
51
52 #define S_WAITTIME 15
53
54 typedef enum {
55 SMB_PWD_NAME = 0,
56 SMB_PWD_UID,
57 SMB_PWD_LMHASH,
58 SMB_PWD_NTHASH,
59 SMB_PWD_NARG
60 } smb_pwdarg_t;
61
62 static struct flock flock = { 0, 0, 0, 0, 0, 0 };
63 static pid_t lck_pid = 0; /* process's pid at last lock */
64 static thread_t lck_tid = 0; /* thread that holds the lock */
65 static int fildes = -1;
66 static mutex_t lck_lock = DEFAULTMUTEX;
67 static void *smb_pwd_hdl = NULL;
68
69 static struct {
70 smb_passwd_t *(*pwop_getpwnam)(const char *, smb_passwd_t *);
71 smb_passwd_t *(*pwop_getpwuid)(uid_t, smb_passwd_t *);
72 int (*pwop_setcntl)(const char *, int);
73 int (*pwop_setpasswd)(const char *, const char *);
74 int (*pwop_num)(void);
75 int (*pwop_iteropen)(smb_pwditer_t *);
76 smb_luser_t *(*pwop_iterate)(smb_pwditer_t *);
77 void (*pwop_iterclose)(smb_pwditer_t *);
78 } smb_pwd_ops;
79
80 static int smb_pwd_lock(void);
81 static int smb_pwd_unlock(void);
82 static int smb_pwd_flck(void);
83 static int smb_pwd_fulck(void);
84
85 /*
86 * buffer structure used by smb_pwd_fgetent/smb_pwd_fputent
87 */
88 typedef struct smb_pwbuf {
89 char pw_buf[SMB_PWD_BUFSIZE];
90 smb_passwd_t *pw_pwd;
91 } smb_pwbuf_t;
92
93 /*
94 * flag values used with smb_pwd_fgetent
95 */
96 #define SMB_PWD_GETF_ALL 1 /* get all the account info */
97 #define SMB_PWD_GETF_NOPWD 2 /* password is not needed */
98
99 static smb_pwbuf_t *smb_pwd_fgetent(FILE *, smb_pwbuf_t *, uint32_t);
100 static int smb_pwd_fputent(FILE *, const smb_pwbuf_t *);
101 static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int);
102 static int smb_pwd_update(const char *, const char *, int);
103
104 /*
105 * Local Users Cache
106 *
107 * Simplifying assumptions
108 *
109 * o smbpasswd is a service private file and shouldn't be edited manually
110 * o accounts are only added/modified via passwd and/or smbadm CLIs
111 * o accounts are not removed but disabled using smbadm CLI
112 * o editing smbpasswd manually might result in cache inconsistency
113 *
114 * Cache is created and populated upon service startup.
115 * Cache is updated each time users list is requested if there's been
116 * any change in smbpasswd file. The change criteria is smbpasswd's
117 * modification timestamp.
118 */
119
120 /*
121 * User cache handle
122 */
123 typedef struct smb_uchandle {
124 avl_tree_t uc_cache;
125 rwlock_t uc_cache_lck;
126 timestruc_t uc_timestamp;
127 uint32_t uc_refcnt;
128 uint32_t uc_state;
129 mutex_t uc_mtx;
130 cond_t uc_cv;
131 } smb_uchandle_t;
132
133 #define SMB_UCHS_NOCACHE 0
134 #define SMB_UCHS_CREATED 1
135 #define SMB_UCHS_UPDATING 2
136 #define SMB_UCHS_UPDATED 3
137 #define SMB_UCHS_DESTROYING 4
138
139 /*
140 * User cache node
141 */
142 typedef struct smb_ucnode {
143 smb_luser_t cn_user;
144 avl_node_t cn_link;
145 } smb_ucnode_t;
146
147 static void smb_lucache_create(void);
148 static void smb_lucache_destroy(void);
149 static void smb_lucache_update(void);
150 static int smb_lucache_num(void);
151 static int smb_lucache_lock(void);
152 static void smb_lucache_unlock(void);
153 static int smb_lucache_do_update(void);
154 static void smb_lucache_flush(void);
155
156 static smb_uchandle_t smb_uch;
157
158 /*
159 * smb_pwd_init
160 *
161 * Initializes the cache if requested.
162 * Checks to see if a password management utility library
163 * is interposed. If yes then it'll initializes smb_pwd_ops
164 * structure with function pointers from this library.
165 */
166 void
smb_pwd_init(boolean_t create_cache)167 smb_pwd_init(boolean_t create_cache)
168 {
169 if (create_cache) {
170 smb_lucache_create();
171 #if 0
172 /*
173 * This pre-loading of the cache results in idmapd requests.
174 * With the change to allow idmapd to call into libsmb to
175 * map names and SIDs, this creates a circular startup
176 * dependency. This call has been temporarily disabled to
177 * avoid this issue. It can be enabled when the name/SID
178 * lookup can be done directly on the LSA service.
179 */
180 smb_lucache_update();
181 #endif
182 }
183
184 smb_pwd_hdl = smb_dlopen();
185 if (smb_pwd_hdl == NULL)
186 return;
187
188 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
189
190 smb_pwd_ops.pwop_getpwnam =
191 (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpwnam");
192
193 smb_pwd_ops.pwop_getpwuid =
194 (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpwuid");
195
196 smb_pwd_ops.pwop_setcntl =
197 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setcntl");
198
199 smb_pwd_ops.pwop_setpasswd =
200 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setpasswd");
201
202 smb_pwd_ops.pwop_num =
203 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_num");
204
205 smb_pwd_ops.pwop_iteropen =
206 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_iteropen");
207
208 smb_pwd_ops.pwop_iterclose =
209 (void (*)())dlsym(smb_pwd_hdl, "smb_pwd_iterclose");
210
211 smb_pwd_ops.pwop_iterate =
212 (smb_luser_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_iterate");
213
214 if (smb_pwd_ops.pwop_getpwnam == NULL ||
215 smb_pwd_ops.pwop_getpwuid == NULL ||
216 smb_pwd_ops.pwop_setcntl == NULL ||
217 smb_pwd_ops.pwop_setpasswd == NULL ||
218 smb_pwd_ops.pwop_num == NULL ||
219 smb_pwd_ops.pwop_iteropen == NULL ||
220 smb_pwd_ops.pwop_iterclose == NULL ||
221 smb_pwd_ops.pwop_iterate == NULL) {
222 smb_dlclose(smb_pwd_hdl);
223 smb_pwd_hdl = NULL;
224
225 /* If error or function(s) are missing, use original lib */
226 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
227 }
228 }
229
230 /*
231 * smb_pwd_fini
232 *
233 * Destroys the cache.
234 * Closes interposed library.
235 */
236 void
smb_pwd_fini(void)237 smb_pwd_fini(void)
238 {
239 smb_lucache_destroy();
240 smb_dlclose(smb_pwd_hdl);
241 smb_pwd_hdl = NULL;
242 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
243 }
244
245 /*
246 * smb_pwd_getpwnam
247 *
248 * Returns a smb password structure for the given user name.
249 * smbpw is a pointer to a buffer allocated by the caller.
250 *
251 * Returns NULL upon failure.
252 */
253 smb_passwd_t *
smb_pwd_getpwnam(const char * name,smb_passwd_t * smbpw)254 smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw)
255 {
256 boolean_t found = B_FALSE;
257 smb_pwbuf_t pwbuf;
258 FILE *fp;
259 int err;
260
261 if (smb_pwd_ops.pwop_getpwnam != NULL)
262 return (smb_pwd_ops.pwop_getpwnam(name, smbpw));
263
264 err = smb_pwd_lock();
265 if (err != SMB_PWE_SUCCESS)
266 return (NULL);
267
268 if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
269 (void) smb_pwd_unlock();
270 return (NULL);
271 }
272
273 pwbuf.pw_pwd = smbpw;
274
275 while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
276 if (strcmp(name, smbpw->pw_name) == 0) {
277 if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
278 found = B_TRUE;
279 break;
280 }
281 }
282
283 (void) fclose(fp);
284 (void) smb_pwd_unlock();
285
286 if (!found) {
287 bzero(smbpw, sizeof (smb_passwd_t));
288 return (NULL);
289 }
290
291 return (smbpw);
292 }
293
294 /*
295 * smb_pwd_getpwuid
296 *
297 * Returns a smb password structure for the given UID
298 * smbpw is a pointer to a buffer allocated by the caller.
299 *
300 * Returns NULL upon failure.
301 */
302 smb_passwd_t *
smb_pwd_getpwuid(uid_t uid,smb_passwd_t * smbpw)303 smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw)
304 {
305 boolean_t found = B_FALSE;
306 smb_pwbuf_t pwbuf;
307 FILE *fp;
308 int err;
309
310 if (smb_pwd_ops.pwop_getpwuid != NULL)
311 return (smb_pwd_ops.pwop_getpwuid(uid, smbpw));
312
313 err = smb_pwd_lock();
314 if (err != SMB_PWE_SUCCESS)
315 return (NULL);
316
317 if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
318 (void) smb_pwd_unlock();
319 return (NULL);
320 }
321
322 pwbuf.pw_pwd = smbpw;
323
324 while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
325 if (uid == smbpw->pw_uid) {
326 if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
327 found = B_TRUE;
328 break;
329 }
330 }
331
332 (void) fclose(fp);
333 (void) smb_pwd_unlock();
334
335 if (!found) {
336 bzero(smbpw, sizeof (smb_passwd_t));
337 return (NULL);
338 }
339
340 return (smbpw);
341 }
342
343 /*
344 * smb_pwd_setpasswd
345 *
346 * Update/add the given user to the smbpasswd file.
347 */
348 int
smb_pwd_setpasswd(const char * name,const char * password)349 smb_pwd_setpasswd(const char *name, const char *password)
350 {
351 if (smb_pwd_ops.pwop_setpasswd != NULL)
352 return (smb_pwd_ops.pwop_setpasswd(name, password));
353
354 return (smb_pwd_update(name, password, 0));
355 }
356
357 /*
358 * smb_pwd_setcntl
359 *
360 * Change the account state. This can be making the account
361 * disable/enable or removing its LM hash.
362 */
363 int
smb_pwd_setcntl(const char * name,int control)364 smb_pwd_setcntl(const char *name, int control)
365 {
366 if (smb_pwd_ops.pwop_setcntl != NULL)
367 return (smb_pwd_ops.pwop_setcntl(name, control));
368
369 if (control == 0)
370 return (SMB_PWE_SUCCESS);
371
372 return (smb_pwd_update(name, NULL, control));
373 }
374
375 /*
376 * smb_pwd_num
377 *
378 * Returns the number of cached local users
379 */
380 int
smb_pwd_num(void)381 smb_pwd_num(void)
382 {
383 if (smb_pwd_ops.pwop_num != NULL)
384 return (smb_pwd_ops.pwop_num());
385
386 smb_lucache_update();
387
388 return (smb_lucache_num());
389 }
390
391 /*
392 * smb_pwd_iteropen
393 *
394 * Initalizes the given iterator handle.
395 * This handle will be used to iterate the users cache
396 * by the caller. The cache will be locked for read and it
397 * will remain locked until smb_pwd_iterclose() is called.
398 */
399 int
smb_pwd_iteropen(smb_pwditer_t * iter)400 smb_pwd_iteropen(smb_pwditer_t *iter)
401 {
402 if (iter == NULL)
403 return (SMB_PWE_INVALID_PARAM);
404
405 if (smb_pwd_ops.pwop_iteropen != NULL)
406 return (smb_pwd_ops.pwop_iteropen(iter));
407
408 iter->spi_next = NULL;
409
410 smb_lucache_update();
411
412 return (smb_lucache_lock());
413 }
414
415 /*
416 * smb_pwd_iterate
417 *
418 * Scans through users cache using the given iterator
419 */
420 smb_luser_t *
smb_pwd_iterate(smb_pwditer_t * iter)421 smb_pwd_iterate(smb_pwditer_t *iter)
422 {
423 smb_ucnode_t *ucnode;
424
425 if (iter == NULL)
426 return (NULL);
427
428 if (smb_pwd_ops.pwop_iterate != NULL)
429 return (smb_pwd_ops.pwop_iterate(iter));
430
431 if (iter->spi_next == NULL)
432 ucnode = avl_first(&smb_uch.uc_cache);
433 else
434 ucnode = AVL_NEXT(&smb_uch.uc_cache, iter->spi_next);
435
436 if ((iter->spi_next = ucnode) != NULL)
437 return (&ucnode->cn_user);
438
439 return (NULL);
440 }
441
442 /*
443 * smb_pwd_iterclose
444 *
445 * Closes the given iterator. Effectively it only unlocks the cache
446 */
447 void
smb_pwd_iterclose(smb_pwditer_t * iter)448 smb_pwd_iterclose(smb_pwditer_t *iter)
449 {
450 if (smb_pwd_ops.pwop_iterclose != NULL) {
451 smb_pwd_ops.pwop_iterclose(iter);
452 return;
453 }
454
455 if (iter != NULL)
456 smb_lucache_unlock();
457 }
458
459 /*
460 * smb_pwd_update
461 *
462 * Updates the password entry of the given user if the user already
463 * has an entry, otherwise it'll add an entry for the user with
464 * given password and control information.
465 */
466 static int
smb_pwd_update(const char * name,const char * password,int control)467 smb_pwd_update(const char *name, const char *password, int control)
468 {
469 struct stat64 stbuf;
470 FILE *src, *dst;
471 int tempfd;
472 int err = SMB_PWE_SUCCESS;
473 smb_pwbuf_t pwbuf;
474 smb_passwd_t smbpw;
475 boolean_t newent = B_TRUE;
476 boolean_t user_disable = B_FALSE;
477 char uxbuf[1024];
478 struct passwd uxpw;
479 int64_t lm_level;
480
481 err = smb_pwd_lock();
482 if (err != SMB_PWE_SUCCESS)
483 return (err);
484
485 if (stat64(SMB_PASSWD, &stbuf) < 0) {
486 err = SMB_PWE_STAT_FAILED;
487 goto passwd_exit;
488 }
489
490 if ((tempfd = open(SMB_PASSTEMP, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
491 err = SMB_PWE_OPEN_FAILED;
492 goto passwd_exit;
493 }
494
495 if ((dst = fdopen(tempfd, "wF")) == NULL) {
496 err = SMB_PWE_OPEN_FAILED;
497 goto passwd_exit;
498 }
499
500 if ((src = fopen(SMB_PASSWD, "rF")) == NULL) {
501 err = SMB_PWE_OPEN_FAILED;
502 (void) fclose(dst);
503 (void) unlink(SMB_PASSTEMP);
504 goto passwd_exit;
505 }
506
507 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lm_level) != SMBD_SMF_OK)
508 lm_level = 4;
509
510 if (lm_level >= 4)
511 control |= SMB_PWC_NOLM;
512
513 pwbuf.pw_pwd = &smbpw;
514
515 /*
516 * copy old password entries to temporary file while replacing
517 * the entry that matches "name"
518 */
519 while (smb_pwd_fgetent(src, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
520 if (strcmp(smbpw.pw_name, name) == 0) {
521 err = smb_pwd_chgpwent(&smbpw, password, control);
522 if (err == SMB_PWE_USER_DISABLE)
523 user_disable = B_TRUE;
524 err = smb_pwd_fputent(dst, &pwbuf);
525 newent = B_FALSE;
526 } else {
527 err = smb_pwd_fputent(dst, &pwbuf);
528 }
529
530 if (err != SMB_PWE_SUCCESS) {
531 (void) fclose(src);
532 (void) fclose(dst);
533 goto passwd_exit;
534 }
535 }
536
537 if (newent) {
538 if (getpwnam_r(name, &uxpw, uxbuf, sizeof (uxbuf))) {
539 bzero(&smbpw, sizeof (smb_passwd_t));
540 (void) strlcpy(smbpw.pw_name, uxpw.pw_name,
541 sizeof (smbpw.pw_name));
542 smbpw.pw_uid = uxpw.pw_uid;
543 (void) smb_pwd_chgpwent(&smbpw, password, control);
544 err = smb_pwd_fputent(dst, &pwbuf);
545 } else {
546 err = SMB_PWE_USER_UNKNOWN;
547 }
548
549 if (err != SMB_PWE_SUCCESS) {
550 (void) fclose(src);
551 (void) fclose(dst);
552 goto passwd_exit;
553 }
554 }
555
556 (void) fclose(src);
557 if (fclose(dst) != 0) {
558 err = SMB_PWE_CLOSE_FAILED;
559 goto passwd_exit; /* Don't trust the temporary file */
560 }
561
562 /* Rename temp to passwd */
563 if (unlink(SMB_OPASSWD) && access(SMB_OPASSWD, 0) == 0) {
564 err = SMB_PWE_UPDATE_FAILED;
565 (void) unlink(SMB_PASSTEMP);
566 goto passwd_exit;
567 }
568
569 if (link(SMB_PASSWD, SMB_OPASSWD) == -1) {
570 err = SMB_PWE_UPDATE_FAILED;
571 (void) unlink(SMB_PASSTEMP);
572 goto passwd_exit;
573 }
574
575 if (rename(SMB_PASSTEMP, SMB_PASSWD) == -1) {
576 err = SMB_PWE_UPDATE_FAILED;
577 (void) unlink(SMB_PASSTEMP);
578 goto passwd_exit;
579 }
580
581 (void) chmod(SMB_PASSWD, 0400);
582
583 passwd_exit:
584 (void) smb_pwd_unlock();
585 if ((err == SMB_PWE_SUCCESS) && user_disable)
586 err = SMB_PWE_USER_DISABLE;
587
588 return (err);
589 }
590
591 /*
592 * smb_pwd_fgetent
593 *
594 * Parse the buffer in the passed pwbuf and fill in the
595 * smb password structure to point to the parsed information.
596 * The entry format is:
597 *
598 * <user-name>:<user-id>:<LM hash>:<NTLM hash>
599 *
600 * Returns a pointer to the passed pwbuf structure on success,
601 * otherwise returns NULL.
602 */
603 static smb_pwbuf_t *
smb_pwd_fgetent(FILE * fp,smb_pwbuf_t * pwbuf,uint32_t flags)604 smb_pwd_fgetent(FILE *fp, smb_pwbuf_t *pwbuf, uint32_t flags)
605 {
606 char *argv[SMB_PWD_NARG];
607 char *pwentry;
608 smb_passwd_t *pw;
609 smb_pwdarg_t i;
610 int lm_len, nt_len;
611
612 pwentry = pwbuf->pw_buf;
613 if (fgets(pwentry, SMB_PWD_BUFSIZE, fp) == NULL)
614 return (NULL);
615 (void) trim_whitespace(pwentry);
616
617 for (i = 0; i < SMB_PWD_NARG; ++i) {
618 if ((argv[i] = strsep((char **)&pwentry, ":")) == NULL)
619 return (NULL);
620 }
621
622 if ((*argv[SMB_PWD_NAME] == '\0') || (*argv[SMB_PWD_UID] == '\0'))
623 return (NULL);
624
625 pw = pwbuf->pw_pwd;
626 bzero(pw, sizeof (smb_passwd_t));
627 pw->pw_uid = strtoul(argv[SMB_PWD_UID], 0, 10);
628 (void) strlcpy(pw->pw_name, argv[SMB_PWD_NAME], sizeof (pw->pw_name));
629
630 if (strcmp(argv[SMB_PWD_LMHASH], SMB_PWD_DISABLE) == 0) {
631 pw->pw_flags |= SMB_PWF_DISABLE;
632 if (flags != SMB_PWD_GETF_NOPWD) {
633 (void) strcpy((char *)pw->pw_lmhash, SMB_PWD_DISABLE);
634 (void) strcpy((char *)pw->pw_nthash, SMB_PWD_DISABLE);
635 }
636 return (pwbuf);
637 }
638
639 if (flags == SMB_PWD_GETF_NOPWD)
640 return (pwbuf);
641
642 lm_len = strlen(argv[SMB_PWD_LMHASH]);
643 if (lm_len == SMBAUTH_HEXHASH_SZ) {
644 (void) hextobin(argv[SMB_PWD_LMHASH], SMBAUTH_HEXHASH_SZ,
645 (char *)pw->pw_lmhash, SMBAUTH_HASH_SZ);
646
647 pw->pw_flags |= SMB_PWF_LM;
648 } else if (lm_len != 0) {
649 return (NULL);
650 }
651
652 nt_len = strlen(argv[SMB_PWD_NTHASH]);
653 if (nt_len == SMBAUTH_HEXHASH_SZ) {
654 (void) hextobin(argv[SMB_PWD_NTHASH], SMBAUTH_HEXHASH_SZ,
655 (char *)pw->pw_nthash, SMBAUTH_HASH_SZ);
656
657 pw->pw_flags |= SMB_PWF_NT;
658 } else if (nt_len != 0) {
659 return (NULL);
660 }
661
662 return (pwbuf);
663 }
664
665 /*
666 * smb_pwd_chgpwent
667 *
668 * Updates the given smb_passwd_t structure with given password and
669 * control information.
670 */
671 static int
smb_pwd_chgpwent(smb_passwd_t * smbpw,const char * password,int control)672 smb_pwd_chgpwent(smb_passwd_t *smbpw, const char *password, int control)
673 {
674 if (control & SMB_PWC_DISABLE) {
675 /* disable the user */
676 smbpw->pw_flags |= SMB_PWF_DISABLE;
677 (void) strcpy((char *)smbpw->pw_lmhash, SMB_PWD_DISABLE);
678 (void) strcpy((char *)smbpw->pw_nthash, SMB_PWD_DISABLE);
679 smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
680 return (SMB_PWE_SUCCESS);
681 }
682
683 if ((control & SMB_PWC_ENABLE) && (smbpw->pw_flags & SMB_PWF_DISABLE)) {
684 /* enable the user if it's been disabled */
685 *smbpw->pw_lmhash = '\0';
686 *smbpw->pw_nthash = '\0';
687 smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT);
688 return (SMB_PWE_SUCCESS);
689 }
690
691 /* No password update if account is disabled */
692 if (smbpw->pw_flags & SMB_PWF_DISABLE)
693 return (SMB_PWE_USER_DISABLE);
694
695 /* This call was just to update the control flags */
696 if (password == NULL)
697 return (SMB_PWE_SUCCESS);
698
699 if (control & SMB_PWC_NOLM) {
700 /* LM hash should not be present */
701 smbpw->pw_flags &= ~SMB_PWF_LM;
702 *smbpw->pw_lmhash = '\0';
703 } else {
704 smbpw->pw_flags |= SMB_PWF_LM;
705 (void) smb_auth_lm_hash(password, smbpw->pw_lmhash);
706 }
707
708 smbpw->pw_flags |= SMB_PWF_NT;
709 (void) smb_auth_ntlm_hash(password, smbpw->pw_nthash);
710 return (SMB_PWE_SUCCESS);
711 }
712
713 /*
714 * smb_pwd_fputent
715 *
716 * If LM/NTLM hash are present, converts them to hex string
717 * and write them along with user's name and Id to the smbpasswd
718 * file.
719 */
720 static int
smb_pwd_fputent(FILE * fp,const smb_pwbuf_t * pwbuf)721 smb_pwd_fputent(FILE *fp, const smb_pwbuf_t *pwbuf)
722 {
723 smb_passwd_t *pw = pwbuf->pw_pwd;
724 char hex_nthash[SMBAUTH_HEXHASH_SZ+1];
725 char hex_lmhash[SMBAUTH_HEXHASH_SZ+1];
726 int rc;
727
728 if ((pw->pw_flags & SMB_PWF_LM) == SMB_PWF_LM) {
729 (void) bintohex((char *)pw->pw_lmhash, SMBAUTH_HASH_SZ,
730 hex_lmhash, SMBAUTH_HEXHASH_SZ);
731 hex_lmhash[SMBAUTH_HEXHASH_SZ] = '\0';
732 } else {
733 (void) strcpy(hex_lmhash, (char *)pw->pw_lmhash);
734 }
735
736 if ((pw->pw_flags & SMB_PWF_NT) == SMB_PWF_NT) {
737 (void) bintohex((char *)pw->pw_nthash, SMBAUTH_HASH_SZ,
738 hex_nthash, SMBAUTH_HEXHASH_SZ);
739 hex_nthash[SMBAUTH_HEXHASH_SZ] = '\0';
740 } else {
741 (void) strcpy(hex_nthash, (char *)pw->pw_nthash);
742 }
743
744 rc = fprintf(fp, "%s:%u:%s:%s\n", pw->pw_name, pw->pw_uid,
745 hex_lmhash, hex_nthash);
746
747 if (rc <= 0)
748 return (SMB_PWE_WRITE_FAILED);
749
750 return (SMB_PWE_SUCCESS);
751 }
752
753 /*
754 * smb_pwd_lock
755 *
756 * A wrapper around smb_pwd_flck() which locks smb password
757 * file so that only one thread at a time is operational.
758 */
759 static int
smb_pwd_lock(void)760 smb_pwd_lock(void)
761 {
762 int res;
763
764 if (smb_pwd_flck()) {
765 switch (errno) {
766 case EINTR:
767 res = SMB_PWE_BUSY;
768 break;
769 case EACCES:
770 res = SMB_PWE_DENIED;
771 break;
772 case 0:
773 res = SMB_PWE_SUCCESS;
774 break;
775 }
776 } else
777 res = SMB_PWE_SUCCESS;
778
779 return (res);
780 }
781
782 /*
783 * smb_pwd_unlock
784 *
785 * A wrapper around smb_pwd_fulck() which unlocks
786 * smb password file.
787 */
788 static int
smb_pwd_unlock(void)789 smb_pwd_unlock(void)
790 {
791 if (smb_pwd_fulck())
792 return (SMB_PWE_SYSTEM_ERROR);
793
794 return (SMB_PWE_SUCCESS);
795 }
796
797 /*
798 * smb_pwd_flck
799 *
800 * Creates a lock file and grabs an exclusive (write) lock on it.
801 */
802 static int
smb_pwd_flck(void)803 smb_pwd_flck(void)
804 {
805 int seconds = 0;
806
807 (void) mutex_lock(&lck_lock);
808 for (;;) {
809 if (lck_pid != 0 && lck_pid != getpid()) {
810 /* somebody forked */
811 lck_pid = 0;
812 lck_tid = 0;
813 }
814
815 if (lck_tid == 0) {
816 if ((fildes = creat(SMB_PASSLCK, 0600)) == -1)
817 break;
818 flock.l_type = F_WRLCK;
819 if (fcntl(fildes, F_SETLK, &flock) != -1) {
820 lck_pid = getpid();
821 lck_tid = thr_self();
822 (void) mutex_unlock(&lck_lock);
823 return (0);
824 }
825 (void) close(fildes);
826 fildes = -1;
827 }
828
829 if (seconds++ >= S_WAITTIME) {
830 /*
831 * For compatibility with the past, pretend
832 * that we were interrupted by SIGALRM.
833 */
834 errno = EINTR;
835 break;
836 }
837
838 (void) mutex_unlock(&lck_lock);
839 (void) sleep(1);
840 (void) mutex_lock(&lck_lock);
841 }
842 (void) mutex_unlock(&lck_lock);
843
844 return (-1);
845 }
846
847 /*
848 * smb_pwd_fulck
849 *
850 * Unlocks smb password file for operations done via
851 * this library APIs.
852 */
853 static int
smb_pwd_fulck(void)854 smb_pwd_fulck(void)
855 {
856 (void) mutex_lock(&lck_lock);
857 if (lck_tid == thr_self() && fildes >= 0) {
858 flock.l_type = F_UNLCK;
859 (void) fcntl(fildes, F_SETLK, &flock);
860 (void) close(fildes);
861 fildes = -1;
862 lck_pid = 0;
863 lck_tid = 0;
864 (void) mutex_unlock(&lck_lock);
865 return (0);
866 }
867 (void) mutex_unlock(&lck_lock);
868 return (-1);
869 }
870
871 /*
872 * Local User Cache Functions
873 *
874 * Local user cache is implemented using AVL tree
875 */
876
877 /*
878 * smb_lucache_cmp
879 *
880 * AVL compare function, the key is username.
881 */
882 static int
smb_lucache_cmp(const void * p1,const void * p2)883 smb_lucache_cmp(const void *p1, const void *p2)
884 {
885 smb_ucnode_t *u1 = (smb_ucnode_t *)p1;
886 smb_ucnode_t *u2 = (smb_ucnode_t *)p2;
887 int rc;
888
889 rc = strcmp(u1->cn_user.su_name, u2->cn_user.su_name);
890
891 if (rc < 0)
892 return (-1);
893
894 if (rc > 0)
895 return (1);
896
897 return (0);
898 }
899
900 /*
901 * smb_lucache_update
902 *
903 * Updates the cache if needed. Whether an update is needed
904 * is determined based on smbpasswd file modification timestamp
905 */
906 static void
smb_lucache_update(void)907 smb_lucache_update(void)
908 {
909 struct stat64 stbuf;
910 int rc;
911
912 (void) mutex_lock(&smb_uch.uc_mtx);
913 switch (smb_uch.uc_state) {
914 default:
915 case SMB_UCHS_NOCACHE:
916 assert(0);
917 (void) mutex_unlock(&smb_uch.uc_mtx);
918 return;
919
920 case SMB_UCHS_CREATED:
921 case SMB_UCHS_UPDATED:
922 break;
923
924 case SMB_UCHS_UPDATING:
925 /* Want only one thread executing this function at a time */
926 (void) mutex_unlock(&smb_uch.uc_mtx);
927 return;
928
929 case SMB_UCHS_DESTROYING:
930 (void) mutex_unlock(&smb_uch.uc_mtx);
931 return;
932 }
933
934 /*
935 * smb_pwd_lock() is not called here so it can
936 * be checked quickly whether an updated is needed
937 */
938 if (stat64(SMB_PASSWD, &stbuf) < 0) {
939 (void) mutex_unlock(&smb_uch.uc_mtx);
940 if (errno != ENOENT)
941 return;
942
943 /* no smbpasswd file; empty the cache */
944 smb_lucache_flush();
945 return;
946 }
947
948 if (stbuf.st_size == 0) {
949 (void) mutex_unlock(&smb_uch.uc_mtx);
950
951 /* empty smbpasswd file; empty the cache */
952 smb_lucache_flush();
953 return;
954 }
955
956 if ((smb_uch.uc_timestamp.tv_sec == stbuf.st_mtim.tv_sec) &&
957 (smb_uch.uc_timestamp.tv_nsec == stbuf.st_mtim.tv_nsec)) {
958 (void) mutex_unlock(&smb_uch.uc_mtx);
959 /* No changes since the last cache update */
960 return;
961 }
962
963 smb_uch.uc_state = SMB_UCHS_UPDATING;
964 smb_uch.uc_refcnt++;
965 (void) mutex_unlock(&smb_uch.uc_mtx);
966
967 rc = smb_lucache_do_update();
968
969 (void) mutex_lock(&smb_uch.uc_mtx);
970 if ((rc == SMB_PWE_SUCCESS) && (stat64(SMB_PASSWD, &stbuf) == 0))
971 smb_uch.uc_timestamp = stbuf.st_mtim;
972 smb_uch.uc_state = SMB_UCHS_UPDATED;
973 smb_uch.uc_refcnt--;
974 (void) cond_broadcast(&smb_uch.uc_cv);
975 (void) mutex_unlock(&smb_uch.uc_mtx);
976 }
977
978 /*
979 * smb_lucache_do_update
980 *
981 * This function takes care of updating the AVL tree.
982 * If an entry has been updated, it'll be modified in place.
983 *
984 * New entries will be added to a temporary AVL tree then
985 * passwod file is unlocked and all the new entries will
986 * be transferred to the main cache from the temporary tree.
987 *
988 * This function MUST NOT be called directly
989 */
990 static int
smb_lucache_do_update(void)991 smb_lucache_do_update(void)
992 {
993 avl_tree_t tmp_cache;
994 smb_pwbuf_t pwbuf;
995 smb_passwd_t smbpw;
996 smb_ucnode_t uc_node;
997 smb_ucnode_t *uc_newnode;
998 smb_luser_t *user;
999 smb_sid_t *sid;
1000 idmap_stat idm_stat;
1001 int rc = SMB_PWE_SUCCESS;
1002 void *cookie = NULL;
1003 FILE *fp;
1004
1005 if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS)
1006 return (rc);
1007
1008 if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
1009 (void) smb_pwd_unlock();
1010 return (SMB_PWE_OPEN_FAILED);
1011 }
1012
1013 avl_create(&tmp_cache, smb_lucache_cmp,
1014 sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link));
1015
1016 bzero(&pwbuf, sizeof (smb_pwbuf_t));
1017 pwbuf.pw_pwd = &smbpw;
1018
1019 (void) rw_rdlock(&smb_uch.uc_cache_lck);
1020
1021 while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_NOPWD) != NULL) {
1022 uc_node.cn_user.su_name = smbpw.pw_name;
1023 uc_newnode = avl_find(&smb_uch.uc_cache, &uc_node, NULL);
1024 if (uc_newnode) {
1025 /* update the node info */
1026 uc_newnode->cn_user.su_ctrl = smbpw.pw_flags;
1027 continue;
1028 }
1029
1030 /* create a new node */
1031 if ((uc_newnode = malloc(sizeof (smb_ucnode_t))) == NULL) {
1032 rc = SMB_PWE_NO_MEMORY;
1033 break;
1034 }
1035
1036 bzero(uc_newnode, sizeof (smb_ucnode_t));
1037 user = &uc_newnode->cn_user;
1038 user->su_ctrl = smbpw.pw_flags;
1039
1040 idm_stat = smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, &sid);
1041 if (idm_stat != IDMAP_SUCCESS) {
1042 syslog(LOG_WARNING, "smb_pwdutil: couldn't obtain SID "
1043 "for uid=%u (%d)", smbpw.pw_uid, idm_stat);
1044 free(uc_newnode);
1045 continue;
1046 }
1047 (void) smb_sid_getrid(sid, &user->su_rid);
1048 smb_sid_free(sid);
1049
1050 user->su_name = strdup(smbpw.pw_name);
1051 if (user->su_name == NULL) {
1052 rc = SMB_PWE_NO_MEMORY;
1053 free(uc_newnode);
1054 break;
1055 }
1056
1057 avl_add(&tmp_cache, uc_newnode);
1058 }
1059
1060 (void) rw_unlock(&smb_uch.uc_cache_lck);
1061 (void) fclose(fp);
1062 (void) smb_pwd_unlock();
1063
1064 /* Destroy the temporary list */
1065 (void) rw_wrlock(&smb_uch.uc_cache_lck);
1066 while ((uc_newnode = avl_destroy_nodes(&tmp_cache, &cookie)) != NULL) {
1067 avl_add(&smb_uch.uc_cache, uc_newnode);
1068 }
1069 (void) rw_unlock(&smb_uch.uc_cache_lck);
1070
1071 avl_destroy(&tmp_cache);
1072
1073 return (rc);
1074 }
1075
1076 /*
1077 * smb_lucache_create
1078 *
1079 * Creates the AVL tree and initializes the global user cache handle.
1080 * This function doesn't populate the cache.
1081 * User cache is only created by smbd at startup
1082 */
1083 static void
smb_lucache_create(void)1084 smb_lucache_create(void)
1085 {
1086 (void) mutex_lock(&smb_uch.uc_mtx);
1087 if (smb_uch.uc_state != SMB_UCHS_NOCACHE) {
1088 (void) mutex_unlock(&smb_uch.uc_mtx);
1089 return;
1090 }
1091
1092 avl_create(&smb_uch.uc_cache, smb_lucache_cmp,
1093 sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link));
1094
1095 smb_uch.uc_state = SMB_UCHS_CREATED;
1096 bzero(&smb_uch.uc_timestamp, sizeof (timestruc_t));
1097 smb_uch.uc_refcnt = 0;
1098 (void) mutex_unlock(&smb_uch.uc_mtx);
1099 }
1100
1101 /*
1102 * smb_lucache_flush
1103 *
1104 * Removes and frees all the cache entries
1105 */
1106 static void
smb_lucache_flush(void)1107 smb_lucache_flush(void)
1108 {
1109 void *cookie = NULL;
1110 smb_ucnode_t *ucnode;
1111
1112 (void) rw_wrlock(&smb_uch.uc_cache_lck);
1113 while ((ucnode = avl_destroy_nodes(&smb_uch.uc_cache, &cookie))
1114 != NULL) {
1115 free(ucnode->cn_user.su_name);
1116 free(ucnode->cn_user.su_fullname);
1117 free(ucnode->cn_user.su_desc);
1118 free(ucnode);
1119 }
1120 (void) rw_unlock(&smb_uch.uc_cache_lck);
1121 }
1122
1123 /*
1124 * smb_lucache_destroy
1125 *
1126 * Destroys the cache.
1127 * This function is only called in smb_pwd_fini()
1128 * User cache is only destroyed by smbd upon shutdown
1129 */
1130 static void
smb_lucache_destroy(void)1131 smb_lucache_destroy(void)
1132 {
1133 (void) mutex_lock(&smb_uch.uc_mtx);
1134 switch (smb_uch.uc_state) {
1135 case SMB_UCHS_NOCACHE:
1136 case SMB_UCHS_DESTROYING:
1137 (void) mutex_unlock(&smb_uch.uc_mtx);
1138 return;
1139
1140 default:
1141 break;
1142 }
1143
1144 smb_uch.uc_state = SMB_UCHS_DESTROYING;
1145
1146 while (smb_uch.uc_refcnt > 0)
1147 (void) cond_wait(&smb_uch.uc_cv, &smb_uch.uc_mtx);
1148
1149 smb_lucache_flush();
1150
1151 avl_destroy(&smb_uch.uc_cache);
1152 smb_uch.uc_state = SMB_UCHS_NOCACHE;
1153 (void) mutex_unlock(&smb_uch.uc_mtx);
1154 }
1155
1156 /*
1157 * smb_lucache_lock
1158 *
1159 * Locks the user cache for reading and also
1160 * increment the handle reference count.
1161 */
1162 static int
smb_lucache_lock(void)1163 smb_lucache_lock(void)
1164 {
1165 (void) mutex_lock(&smb_uch.uc_mtx);
1166 switch (smb_uch.uc_state) {
1167 case SMB_UCHS_NOCACHE:
1168 assert(0);
1169 (void) mutex_unlock(&smb_uch.uc_mtx);
1170 return (SMB_PWE_DENIED);
1171
1172 case SMB_UCHS_DESTROYING:
1173 (void) mutex_unlock(&smb_uch.uc_mtx);
1174 return (SMB_PWE_DENIED);
1175 }
1176 smb_uch.uc_refcnt++;
1177 (void) mutex_unlock(&smb_uch.uc_mtx);
1178
1179 (void) rw_rdlock(&smb_uch.uc_cache_lck);
1180 return (SMB_PWE_SUCCESS);
1181 }
1182
1183 /*
1184 * smb_lucache_unlock
1185 *
1186 * Unlock the cache
1187 */
1188 static void
smb_lucache_unlock(void)1189 smb_lucache_unlock(void)
1190 {
1191 (void) rw_unlock(&smb_uch.uc_cache_lck);
1192
1193 (void) mutex_lock(&smb_uch.uc_mtx);
1194 smb_uch.uc_refcnt--;
1195 (void) cond_broadcast(&smb_uch.uc_cv);
1196 (void) mutex_unlock(&smb_uch.uc_mtx);
1197 }
1198
1199 /*
1200 * smb_lucache_num
1201 *
1202 * Returns the number of cache entries
1203 */
1204 static int
smb_lucache_num(void)1205 smb_lucache_num(void)
1206 {
1207 int num;
1208
1209 (void) mutex_lock(&smb_uch.uc_mtx);
1210 switch (smb_uch.uc_state) {
1211 case SMB_UCHS_NOCACHE:
1212 assert(0);
1213 (void) mutex_unlock(&smb_uch.uc_mtx);
1214 return (0);
1215
1216 case SMB_UCHS_DESTROYING:
1217 (void) mutex_unlock(&smb_uch.uc_mtx);
1218 return (0);
1219 }
1220 (void) mutex_unlock(&smb_uch.uc_mtx);
1221
1222 (void) rw_rdlock(&smb_uch.uc_cache_lck);
1223 num = (int)avl_numnodes(&smb_uch.uc_cache);
1224 (void) rw_unlock(&smb_uch.uc_cache_lck);
1225
1226 return (num);
1227 }
1228