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