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