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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * SMB/CIFS share cache implementation. 28 */ 29 30 #include <errno.h> 31 #include <synch.h> 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <syslog.h> 35 #include <thread.h> 36 #include <pthread.h> 37 #include <assert.h> 38 #include <libshare.h> 39 40 #include <smbsrv/libsmb.h> 41 #include <smbsrv/libsmbns.h> 42 #include <smbsrv/libmlsvc.h> 43 44 #include <smbsrv/lm.h> 45 #include <smbsrv/smb_share.h> 46 #include <smbsrv/cifs.h> 47 #include <smbsrv/nterror.h> 48 49 #define SMB_SHR_ERROR_THRESHOLD 3 50 51 /* 52 * Cache functions and vars 53 */ 54 #define SMB_SHR_HTAB_SZ 1024 55 56 /* 57 * Cache handle 58 * 59 * Shares cache is a hash table. 60 * 61 * sc_cache pointer to hash table handle 62 * sc_cache_lck synchronize cache read/write accesses 63 * sc_state cache state machine values 64 * sc_nops number of inflight/pending cache operations 65 * sc_mtx protects handle fields 66 */ 67 typedef struct smb_shr_cache { 68 HT_HANDLE *sc_cache; 69 rwlock_t sc_cache_lck; 70 mutex_t sc_mtx; 71 cond_t sc_cv; 72 uint32_t sc_state; 73 uint32_t sc_nops; 74 } smb_shr_cache_t; 75 76 /* 77 * Cache states 78 */ 79 #define SMB_SHR_CACHE_STATE_NONE 0 80 #define SMB_SHR_CACHE_STATE_CREATED 1 81 #define SMB_SHR_CACHE_STATE_DESTROYING 2 82 83 /* 84 * Cache lock modes 85 */ 86 #define SMB_SHR_CACHE_RDLOCK 0 87 #define SMB_SHR_CACHE_WRLOCK 1 88 89 static smb_shr_cache_t smb_shr_cache; 90 91 static uint32_t smb_shr_cache_create(void); 92 static void smb_shr_cache_destroy(void); 93 static uint32_t smb_shr_cache_lock(int); 94 static void smb_shr_cache_unlock(void); 95 static int smb_shr_cache_count(void); 96 static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *); 97 98 static smb_share_t *smb_shr_cache_findent(char *); 99 static uint32_t smb_shr_cache_addent(smb_share_t *); 100 static void smb_shr_cache_delent(char *); 101 static void smb_shr_cache_freent(HT_ITEM *); 102 103 /* 104 * sharemgr functions 105 */ 106 static void *smb_shr_sa_loadall(void *); 107 static void smb_shr_sa_loadgrp(sa_group_t); 108 static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t); 109 static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *); 110 111 /* 112 * share publishing 113 */ 114 #define SMB_SHR_PUBLISH 0 115 #define SMB_SHR_UNPUBLISH 1 116 117 typedef struct smb_shr_pitem { 118 list_node_t spi_lnd; 119 char spi_name[MAXNAMELEN]; 120 char spi_container[MAXPATHLEN]; 121 char spi_op; 122 } smb_shr_pitem_t; 123 124 /* 125 * publish queue states 126 */ 127 #define SMB_SHR_PQS_NOQUEUE 0 128 #define SMB_SHR_PQS_READY 1 /* the queue is ready */ 129 #define SMB_SHR_PQS_PUBLISHING 2 /* publisher thread is running */ 130 #define SMB_SHR_PQS_STOPPING 3 131 132 /* 133 * share publishing queue 134 */ 135 typedef struct smb_shr_pqueue { 136 list_t spq_list; 137 mutex_t spq_mtx; 138 cond_t spq_cv; 139 uint32_t spq_state; 140 } smb_shr_pqueue_t; 141 142 static smb_shr_pqueue_t ad_queue; 143 144 static int smb_shr_publisher_start(void); 145 static void smb_shr_publisher_stop(void); 146 static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *); 147 static void smb_shr_publisher_queue(const char *, const char *, char); 148 static void *smb_shr_publisher(void *); 149 static void smb_shr_publisher_flush(list_t *); 150 static void smb_shr_publish(const char *, const char *); 151 static void smb_shr_unpublish(const char *, const char *); 152 153 /* 154 * Utility/helper functions 155 */ 156 static uint32_t smb_shr_addipc(void); 157 static void smb_shr_set_oemname(smb_share_t *); 158 159 /* 160 * Starts the publisher thread and another thread which 161 * populates the share cache by share information stored 162 * by sharemgr 163 */ 164 int 165 smb_shr_start(void) 166 { 167 pthread_t load_thr; 168 pthread_attr_t tattr; 169 int rc; 170 171 if ((rc = smb_shr_publisher_start()) != 0) 172 return (rc); 173 174 if (smb_shr_cache_create() != NERR_Success) 175 return (ENOMEM); 176 177 if (smb_shr_addipc() != NERR_Success) 178 return (ENOMEM); 179 180 (void) pthread_attr_init(&tattr); 181 (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 182 rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0); 183 (void) pthread_attr_destroy(&tattr); 184 185 return (rc); 186 } 187 188 void 189 smb_shr_stop(void) 190 { 191 smb_shr_cache_destroy(); 192 smb_shr_publisher_stop(); 193 } 194 195 /* 196 * Return the total number of shares 197 */ 198 int 199 smb_shr_count(void) 200 { 201 int n_shares = 0; 202 203 if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) { 204 n_shares = smb_shr_cache_count(); 205 smb_shr_cache_unlock(); 206 } 207 208 return (n_shares); 209 } 210 211 /* 212 * smb_shr_iterinit 213 * 214 * Initialize given iterator for traversing hash table. 215 */ 216 void 217 smb_shr_iterinit(smb_shriter_t *shi) 218 { 219 bzero(shi, sizeof (smb_shriter_t)); 220 shi->si_first = B_TRUE; 221 } 222 223 /* 224 * smb_shr_iterate 225 * 226 * Iterate on the shares in the hash table. The iterator must be initialized 227 * before the first iteration. On subsequent calls, the iterator must be 228 * passed unchanged. 229 * 230 * Returns NULL on failure or when all shares are visited, otherwise 231 * returns information of visited share. 232 */ 233 smb_share_t * 234 smb_shr_iterate(smb_shriter_t *shi) 235 { 236 smb_share_t *share = NULL; 237 smb_share_t *cached_si; 238 239 if (shi == NULL) 240 return (NULL); 241 242 if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) { 243 if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) { 244 share = &shi->si_share; 245 bcopy(cached_si, share, sizeof (smb_share_t)); 246 } 247 smb_shr_cache_unlock(); 248 } 249 250 return (share); 251 } 252 253 /* 254 * Adds the given share to cache, publishes the share in ADS 255 * if it has an AD container, calls kernel to take a hold on 256 * the shared file system. If it can't take a hold on the 257 * shared file system, it's either because shared directory 258 * does not exist or some other error has occurred, in any 259 * case the share is removed from the cache. 260 * 261 * If the specified share is an autohome share which already 262 * exists in the cache, just increments the reference count. 263 */ 264 uint32_t 265 smb_shr_add(smb_share_t *si) 266 { 267 smb_share_t *cached_si; 268 uint32_t status; 269 int rc; 270 271 assert(si != NULL); 272 273 if (!smb_shr_chkname(si->shr_name)) 274 return (ERROR_INVALID_NAME); 275 276 if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) 277 return (NERR_InternalError); 278 279 cached_si = smb_shr_cache_findent(si->shr_name); 280 if (cached_si) { 281 if (si->shr_flags & SMB_SHRF_AUTOHOME) { 282 cached_si->shr_refcnt++; 283 status = NERR_Success; 284 } else { 285 status = NERR_DuplicateShare; 286 } 287 smb_shr_cache_unlock(); 288 return (status); 289 } 290 291 if ((status = smb_shr_cache_addent(si)) != NERR_Success) { 292 smb_shr_cache_unlock(); 293 return (status); 294 } 295 296 /* don't hold the lock across door call */ 297 smb_shr_cache_unlock(); 298 299 /* call kernel to take a hold on the shared file system */ 300 rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name); 301 302 if (rc == 0) { 303 smb_shr_publish(si->shr_name, si->shr_container); 304 return (NERR_Success); 305 } 306 307 if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) { 308 smb_shr_cache_delent(si->shr_name); 309 smb_shr_cache_unlock(); 310 } 311 312 /* 313 * rc == ENOENT means the shared directory doesn't exist 314 */ 315 return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError); 316 } 317 318 /* 319 * Removes the specified share from cache, removes it from AD 320 * if it has an AD container, and calls the kernel to release 321 * the hold on the shared file system. 322 * 323 * If this is an autohome share then decrement the reference 324 * count. If it reaches 0 then it proceeds with removing steps. 325 */ 326 uint32_t 327 smb_shr_remove(char *sharename) 328 { 329 smb_share_t *si; 330 char path[MAXPATHLEN]; 331 char container[MAXPATHLEN]; 332 333 assert(sharename != NULL); 334 335 if (!smb_shr_chkname(sharename)) 336 return (ERROR_INVALID_NAME); 337 338 if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) 339 return (NERR_InternalError); 340 341 if ((si = smb_shr_cache_findent(sharename)) == NULL) { 342 smb_shr_cache_unlock(); 343 return (NERR_NetNameNotFound); 344 } 345 346 if (si->shr_type & STYPE_IPC) { 347 /* IPC$ share cannot be removed */ 348 smb_shr_cache_unlock(); 349 return (ERROR_ACCESS_DENIED); 350 } 351 352 if (si->shr_flags & SMB_SHRF_AUTOHOME) { 353 if ((--si->shr_refcnt) > 0) { 354 smb_shr_cache_unlock(); 355 return (NERR_Success); 356 } 357 } 358 359 (void) strlcpy(path, si->shr_path, sizeof (path)); 360 (void) strlcpy(container, si->shr_container, sizeof (container)); 361 smb_shr_cache_delent(sharename); 362 smb_shr_cache_unlock(); 363 364 smb_shr_unpublish(sharename, container); 365 366 /* call kernel to release the hold on the shared file system */ 367 (void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename); 368 369 return (NERR_Success); 370 } 371 372 /* 373 * Rename a share. Check that the current name exists and the new name 374 * doesn't exist. The rename is performed by deleting the current share 375 * definition and creating a new share with the new name. 376 */ 377 uint32_t 378 smb_shr_rename(char *from_name, char *to_name) 379 { 380 smb_share_t *from_si; 381 smb_share_t to_si; 382 uint32_t status; 383 384 assert((from_name != NULL) && (to_name != NULL)); 385 386 if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name)) 387 return (ERROR_INVALID_NAME); 388 389 if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) 390 return (NERR_InternalError); 391 392 if ((from_si = smb_shr_cache_findent(from_name)) == NULL) { 393 smb_shr_cache_unlock(); 394 return (NERR_NetNameNotFound); 395 } 396 397 if (from_si->shr_type & STYPE_IPC) { 398 /* IPC$ share cannot be renamed */ 399 smb_shr_cache_unlock(); 400 return (ERROR_ACCESS_DENIED); 401 } 402 403 if (smb_shr_cache_findent(to_name) != NULL) { 404 smb_shr_cache_unlock(); 405 return (NERR_DuplicateShare); 406 } 407 408 bcopy(from_si, &to_si, sizeof (smb_share_t)); 409 (void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name)); 410 411 if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) { 412 smb_shr_cache_unlock(); 413 return (status); 414 } 415 416 smb_shr_cache_delent(from_name); 417 smb_shr_cache_unlock(); 418 419 smb_shr_unpublish(from_name, to_si.shr_container); 420 smb_shr_publish(to_name, to_si.shr_container); 421 422 return (NERR_Success); 423 } 424 425 /* 426 * Load the information for the specified share into the supplied share 427 * info structure. 428 */ 429 uint32_t 430 smb_shr_get(char *sharename, smb_share_t *si) 431 { 432 smb_share_t *cached_si; 433 uint32_t status = NERR_NetNameNotFound; 434 435 if (sharename == NULL || *sharename == '\0') 436 return (NERR_NetNameNotFound); 437 438 if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) { 439 cached_si = smb_shr_cache_findent(sharename); 440 if (cached_si != NULL) { 441 bcopy(cached_si, si, sizeof (smb_share_t)); 442 status = NERR_Success; 443 } 444 445 smb_shr_cache_unlock(); 446 } 447 448 return (status); 449 } 450 451 /* 452 * Modifies an existing share. Properties that can be modified are: 453 * 454 * o comment 455 * o AD container 456 * o host access 457 */ 458 uint32_t 459 smb_shr_modify(smb_share_t *new_si) 460 { 461 smb_share_t *si; 462 boolean_t adc_changed = B_FALSE; 463 char old_container[MAXPATHLEN]; 464 uint32_t access; 465 466 assert(new_si != NULL); 467 468 if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) 469 return (NERR_InternalError); 470 471 if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) { 472 smb_shr_cache_unlock(); 473 return (NERR_NetNameNotFound); 474 } 475 476 if (si->shr_type & STYPE_IPC) { 477 /* IPC$ share cannot be modified */ 478 smb_shr_cache_unlock(); 479 return (ERROR_ACCESS_DENIED); 480 } 481 482 if (strcmp(new_si->shr_cmnt, si->shr_cmnt) != 0) 483 (void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, 484 sizeof (si->shr_cmnt)); 485 486 adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0); 487 if (adc_changed) { 488 /* save current container - needed for unpublishing */ 489 (void) strlcpy(old_container, si->shr_container, 490 sizeof (old_container)); 491 (void) strlcpy(si->shr_container, new_si->shr_container, 492 sizeof (si->shr_container)); 493 } 494 495 access = (new_si->shr_flags & SMB_SHRF_ACC_ALL); 496 si->shr_flags |= access; 497 498 if (access & SMB_SHRF_ACC_NONE) 499 (void) strlcpy(si->shr_access_none, new_si->shr_access_none, 500 sizeof (si->shr_access_none)); 501 502 if (access & SMB_SHRF_ACC_RO) 503 (void) strlcpy(si->shr_access_ro, new_si->shr_access_ro, 504 sizeof (si->shr_access_ro)); 505 506 if (access & SMB_SHRF_ACC_RW) 507 (void) strlcpy(si->shr_access_rw, new_si->shr_access_rw, 508 sizeof (si->shr_access_rw)); 509 510 smb_shr_cache_unlock(); 511 512 if (adc_changed) { 513 smb_shr_unpublish(new_si->shr_name, old_container); 514 smb_shr_publish(new_si->shr_name, new_si->shr_container); 515 } 516 517 return (NERR_Success); 518 } 519 520 /* 521 * smb_shr_exists 522 * 523 * Returns B_TRUE if the share exists. Otherwise returns B_FALSE 524 */ 525 boolean_t 526 smb_shr_exists(char *sharename) 527 { 528 boolean_t exists = B_FALSE; 529 530 if (sharename == NULL || *sharename == '\0') 531 return (B_FALSE); 532 533 if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) { 534 exists = (smb_shr_cache_findent(sharename) != NULL); 535 smb_shr_cache_unlock(); 536 } 537 538 return (exists); 539 } 540 541 /* 542 * If the shared directory does not begin with a /, one will be 543 * inserted as a prefix. If ipaddr is not zero, then also return 544 * information about access based on the host level access lists, if 545 * present. Also return access check if there is an IP address and 546 * shr_accflags. 547 * 548 * The value of smb_chk_hostaccess is checked for an access match. 549 * -1 is wildcard match 550 * 0 is no match 551 * 1 is match 552 * 553 * Precedence is none is checked first followed by ro then rw if 554 * needed. If x is wildcard (< 0) then check to see if the other 555 * values are a match. If a match, that wins. 556 */ 557 void 558 smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr) 559 { 560 int acc = SMB_SHRF_ACC_OPEN; 561 562 /* 563 * Check to see if there area any share level access 564 * restrictions. 565 */ 566 if (ipaddr != 0 && (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) { 567 int none = SMB_SHRF_ACC_OPEN; 568 int rw = SMB_SHRF_ACC_OPEN; 569 int ro = SMB_SHRF_ACC_OPEN; 570 571 if (si->shr_flags & SMB_SHRF_ACC_NONE) 572 none = smb_chk_hostaccess(ipaddr, si->shr_access_none); 573 if (si->shr_flags & SMB_SHRF_ACC_RW) 574 rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw); 575 if (si->shr_flags & SMB_SHRF_ACC_RO) 576 ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro); 577 578 /* make first pass to get basic value */ 579 if (none != 0) 580 acc = SMB_SHRF_ACC_NONE; 581 else if (ro != 0) 582 acc = SMB_SHRF_ACC_RO; 583 else if (rw != 0) 584 acc = SMB_SHRF_ACC_RW; 585 586 /* make second pass to handle '*' case */ 587 if (none < 0) { 588 acc = SMB_SHRF_ACC_NONE; 589 if (ro > 0) 590 acc = SMB_SHRF_ACC_RO; 591 else if (rw > 0) 592 acc = SMB_SHRF_ACC_RW; 593 } else if (ro < 0) { 594 acc = SMB_SHRF_ACC_RO; 595 if (none > 0) 596 acc = SMB_SHRF_ACC_NONE; 597 else if (rw > 0) 598 acc = SMB_SHRF_ACC_RW; 599 } else if (rw < 0) { 600 acc = SMB_SHRF_ACC_RW; 601 if (none > 0) 602 acc = SMB_SHRF_ACC_NONE; 603 else if (ro > 0) 604 acc = SMB_SHRF_ACC_RO; 605 } 606 } 607 si->shr_access_value = acc; /* return access here */ 608 } 609 610 /* 611 * smb_shr_is_special 612 * 613 * Special share reserved for interprocess communication (IPC$) or 614 * remote administration of the server (ADMIN$). Can also refer to 615 * administrative shares such as C$, D$, E$, and so forth. 616 */ 617 int 618 smb_shr_is_special(char *sharename) 619 { 620 int len; 621 622 if (sharename == NULL) 623 return (0); 624 625 if ((len = strlen(sharename)) == 0) 626 return (0); 627 628 if (sharename[len - 1] == '$') 629 return (STYPE_SPECIAL); 630 631 return (0); 632 } 633 634 /* 635 * smb_shr_is_restricted 636 * 637 * Check whether or not there is a restriction on a share. Restricted 638 * shares are generally STYPE_SPECIAL, for example, IPC$. All the 639 * administration share names are restricted: C$, D$ etc. Returns B_TRUE 640 * if the share is restricted. Otherwise B_FALSE is returned to indicate 641 * that there are no restrictions. 642 */ 643 boolean_t 644 smb_shr_is_restricted(char *sharename) 645 { 646 static char *restricted[] = { 647 "IPC$" 648 }; 649 650 int i; 651 652 if (sharename == NULL) 653 return (B_FALSE); 654 655 for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) { 656 if (utf8_strcasecmp(restricted[i], sharename) == 0) 657 return (B_TRUE); 658 } 659 660 return (smb_shr_is_admin(sharename)); 661 } 662 663 /* 664 * smb_shr_is_admin 665 * 666 * Check whether or not access to the share should be restricted to 667 * administrators. This is a bit of a hack because what we're doing 668 * is checking for the default admin shares: C$, D$ etc.. There are 669 * other shares that have restrictions: see smb_shr_is_restricted(). 670 * 671 * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE 672 * is returned to indicate that there are no restrictions. 673 */ 674 boolean_t 675 smb_shr_is_admin(char *sharename) 676 { 677 if (sharename == NULL) 678 return (B_FALSE); 679 680 if (strlen(sharename) == 2 && 681 mts_isalpha(sharename[0]) && sharename[1] == '$') { 682 return (B_TRUE); 683 } 684 685 return (B_FALSE); 686 } 687 688 /* 689 * smb_shr_chkname 690 * 691 * Check for invalid characters in a share name. The list of invalid 692 * characters includes control characters and the following: 693 * 694 * " / \ [ ] : | < > + ; , ? * = 695 */ 696 boolean_t 697 smb_shr_chkname(char *sharename) 698 { 699 char *invalid = "\"/\\[]:|<>+;,?*="; 700 char *cp; 701 702 if (sharename == NULL) 703 return (B_FALSE); 704 705 if (strpbrk(sharename, invalid)) 706 return (B_FALSE); 707 708 for (cp = sharename; *cp != '\0'; cp++) { 709 if (iscntrl(*cp)) 710 return (B_FALSE); 711 } 712 713 return (B_TRUE); 714 } 715 716 /* 717 * smb_shr_get_realpath 718 * 719 * Derive the real path for a share from the path provided by a client. 720 * For instance, the real path of C:\ may be /cvol or the real path of 721 * F:\home may be /vol1/home. 722 * 723 * clntpath - path provided by the Windows client is in the 724 * format of <drive letter>:\<dir> 725 * realpath - path that will be stored as the directory field of 726 * the smb_share_t structure of the share. 727 * maxlen - maximum length of the realpath buffer 728 * 729 * Return LAN Manager network error code. 730 */ 731 uint32_t 732 smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen) 733 { 734 const char *p; 735 int len; 736 737 if ((p = strchr(clntpath, ':')) != NULL) 738 ++p; 739 else 740 p = clntpath; 741 742 (void) strlcpy(realpath, p, maxlen); 743 (void) strcanon(realpath, "/\\"); 744 (void) strsubst(realpath, '\\', '/'); 745 746 len = strlen(realpath); 747 if ((len > 1) && (realpath[len - 1] == '/')) 748 realpath[len - 1] = '\0'; 749 750 return (NERR_Success); 751 } 752 753 void 754 smb_shr_list(int offset, smb_shrlist_t *list) 755 { 756 smb_shriter_t iterator; 757 smb_share_t *si; 758 int n = 0; 759 760 bzero(list, sizeof (smb_shrlist_t)); 761 smb_shr_iterinit(&iterator); 762 763 while ((si = smb_shr_iterate(&iterator)) != NULL) { 764 if (--offset > 0) 765 continue; 766 767 if ((si->shr_flags & SMB_SHRF_TRANS) && 768 ((si->shr_type & STYPE_IPC) == 0)) { 769 bcopy(si, &list->sl_shares[n], sizeof (smb_share_t)); 770 if (++n == LMSHARES_PER_REQUEST) 771 break; 772 } 773 } 774 775 list->sl_cnt = n; 776 } 777 778 /* 779 * ============================================ 780 * Private helper/utility functions 781 * ============================================ 782 */ 783 784 /* 785 * Add IPC$ to the cache upon startup. 786 */ 787 static uint32_t 788 smb_shr_addipc(void) 789 { 790 smb_share_t ipc; 791 uint32_t status = NERR_InternalError; 792 793 bzero(&ipc, sizeof (smb_share_t)); 794 (void) strcpy(ipc.shr_name, "IPC$"); 795 (void) strcpy(ipc.shr_cmnt, "Remote IPC"); 796 ipc.shr_flags = SMB_SHRF_TRANS; 797 ipc.shr_type = STYPE_IPC; 798 799 if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) { 800 status = smb_shr_cache_addent(&ipc); 801 smb_shr_cache_unlock(); 802 } 803 804 return (status); 805 } 806 807 /* 808 * smb_shr_set_oemname 809 * 810 * Generate the OEM name for the specified share. If the name is 811 * shorter than 13 bytes the oemname will be saved in si->shr_oemname. 812 * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will 813 * be set in si->shr_flags. 814 */ 815 static void 816 smb_shr_set_oemname(smb_share_t *si) 817 { 818 unsigned int cpid = oem_get_smb_cpid(); 819 mts_wchar_t *unibuf; 820 char *oem_name; 821 int length; 822 823 length = strlen(si->shr_name) + 1; 824 825 oem_name = malloc(length); 826 unibuf = malloc(length * sizeof (mts_wchar_t)); 827 if ((oem_name == NULL) || (unibuf == NULL)) { 828 free(oem_name); 829 free(unibuf); 830 return; 831 } 832 833 (void) mts_mbstowcs(unibuf, si->shr_name, length); 834 835 if (unicodestooems(oem_name, unibuf, length, cpid) == 0) 836 (void) strcpy(oem_name, si->shr_name); 837 838 free(unibuf); 839 840 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) { 841 si->shr_flags |= SMB_SHRF_LONGNAME; 842 *si->shr_oemname = '\0'; 843 } else { 844 si->shr_flags &= ~SMB_SHRF_LONGNAME; 845 (void) strlcpy(si->shr_oemname, oem_name, 846 SMB_SHARE_OEMNAME_MAX); 847 } 848 849 free(oem_name); 850 } 851 852 /* 853 * ============================================ 854 * Cache management functions 855 * 856 * All cache functions are private 857 * ============================================ 858 */ 859 860 /* 861 * Create the share cache (hash table). 862 */ 863 static uint32_t 864 smb_shr_cache_create(void) 865 { 866 uint32_t status = NERR_Success; 867 868 (void) mutex_lock(&smb_shr_cache.sc_mtx); 869 switch (smb_shr_cache.sc_state) { 870 case SMB_SHR_CACHE_STATE_NONE: 871 smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ, 872 MAXNAMELEN, 0); 873 if (smb_shr_cache.sc_cache == NULL) { 874 status = NERR_InternalError; 875 break; 876 } 877 878 (void) ht_register_callback(smb_shr_cache.sc_cache, 879 smb_shr_cache_freent); 880 smb_shr_cache.sc_nops = 0; 881 smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED; 882 break; 883 884 default: 885 assert(0); 886 status = NERR_InternalError; 887 break; 888 } 889 (void) mutex_unlock(&smb_shr_cache.sc_mtx); 890 891 return (status); 892 } 893 894 /* 895 * Destroy the share cache (hash table). 896 * Wait for inflight/pending operations to finish or abort before 897 * destroying the cache. 898 */ 899 static void 900 smb_shr_cache_destroy(void) 901 { 902 (void) mutex_lock(&smb_shr_cache.sc_mtx); 903 if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) { 904 smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING; 905 while (smb_shr_cache.sc_nops > 0) 906 (void) cond_wait(&smb_shr_cache.sc_cv, 907 &smb_shr_cache.sc_mtx); 908 909 smb_shr_cache.sc_cache = NULL; 910 smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE; 911 } 912 (void) mutex_unlock(&smb_shr_cache.sc_mtx); 913 } 914 915 /* 916 * If the cache is in "created" state, lock the cache for read 917 * or read/write based on the specified mode. 918 * 919 * Whenever a lock is granted, the number of inflight cache 920 * operations is incremented. 921 */ 922 static uint32_t 923 smb_shr_cache_lock(int mode) 924 { 925 (void) mutex_lock(&smb_shr_cache.sc_mtx); 926 switch (smb_shr_cache.sc_state) { 927 case SMB_SHR_CACHE_STATE_CREATED: 928 smb_shr_cache.sc_nops++; 929 break; 930 931 case SMB_SHR_CACHE_STATE_DESTROYING: 932 (void) mutex_unlock(&smb_shr_cache.sc_mtx); 933 return (NERR_InternalError); 934 935 case SMB_SHR_CACHE_STATE_NONE: 936 default: 937 assert(0); 938 (void) mutex_unlock(&smb_shr_cache.sc_mtx); 939 return (NERR_InternalError); 940 941 } 942 (void) mutex_unlock(&smb_shr_cache.sc_mtx); 943 944 /* 945 * Lock has to be taken outside the mutex otherwise 946 * there could be a deadlock 947 */ 948 if (mode == SMB_SHR_CACHE_RDLOCK) 949 (void) rw_rdlock(&smb_shr_cache.sc_cache_lck); 950 else 951 (void) rw_wrlock(&smb_shr_cache.sc_cache_lck); 952 953 return (NERR_Success); 954 } 955 956 /* 957 * Decrement the number of inflight operations and then unlock. 958 */ 959 static void 960 smb_shr_cache_unlock(void) 961 { 962 (void) mutex_lock(&smb_shr_cache.sc_mtx); 963 assert(smb_shr_cache.sc_nops > 0); 964 smb_shr_cache.sc_nops--; 965 (void) cond_broadcast(&smb_shr_cache.sc_cv); 966 (void) mutex_unlock(&smb_shr_cache.sc_mtx); 967 968 (void) rw_unlock(&smb_shr_cache.sc_cache_lck); 969 } 970 971 /* 972 * Return the total number of shares 973 */ 974 static int 975 smb_shr_cache_count(void) 976 { 977 return (ht_get_total_items(smb_shr_cache.sc_cache)); 978 } 979 980 /* 981 * looks up the given share name in the cache and if it 982 * finds a match returns a pointer to the cached entry. 983 * Note that since a pointer is returned this function 984 * MUST be protected by smb_shr_cache_lock/unlock pair 985 */ 986 static smb_share_t * 987 smb_shr_cache_findent(char *sharename) 988 { 989 HT_ITEM *item; 990 991 (void) utf8_strlwr(sharename); 992 item = ht_find_item(smb_shr_cache.sc_cache, sharename); 993 if (item && item->hi_data) 994 return ((smb_share_t *)item->hi_data); 995 996 return (NULL); 997 } 998 999 /* 1000 * Return a pointer to the first/next entry in 1001 * the cache based on the given iterator. 1002 * 1003 * Calls to this function MUST be protected by 1004 * smb_shr_cache_lock/unlock. 1005 */ 1006 static smb_share_t * 1007 smb_shr_cache_iterate(smb_shriter_t *shi) 1008 { 1009 HT_ITEM *item; 1010 1011 if (shi->si_first) { 1012 item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter); 1013 shi->si_first = B_FALSE; 1014 } else { 1015 item = ht_findnext(&shi->si_hashiter); 1016 } 1017 1018 if (item && item->hi_data) 1019 return ((smb_share_t *)item->hi_data); 1020 1021 return (NULL); 1022 } 1023 1024 /* 1025 * Add the specified share to the cache. Memory needs to be allocated 1026 * for the cache entry and the passed information is copied to the 1027 * allocated space. 1028 */ 1029 static uint32_t 1030 smb_shr_cache_addent(smb_share_t *si) 1031 { 1032 smb_share_t *cache_ent; 1033 uint32_t status = NERR_Success; 1034 1035 if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL) 1036 return (ERROR_NOT_ENOUGH_MEMORY); 1037 1038 bcopy(si, cache_ent, sizeof (smb_share_t)); 1039 1040 (void) utf8_strlwr(cache_ent->shr_name); 1041 smb_shr_set_oemname(cache_ent); 1042 1043 if ((si->shr_type & STYPE_IPC) == 0) 1044 cache_ent->shr_type = STYPE_DISKTREE; 1045 cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name); 1046 1047 if (smb_shr_is_admin(cache_ent->shr_name)) 1048 cache_ent->shr_flags |= SMB_SHRF_ADMIN; 1049 1050 if (si->shr_flags & SMB_SHRF_AUTOHOME) 1051 cache_ent->shr_refcnt = 1; 1052 1053 if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent) 1054 == NULL) { 1055 syslog(LOG_DEBUG, "share: %s: cache update failed", 1056 cache_ent->shr_name); 1057 free(cache_ent); 1058 status = NERR_InternalError; 1059 } 1060 1061 return (status); 1062 } 1063 1064 /* 1065 * Delete the specified share from the cache. 1066 */ 1067 static void 1068 smb_shr_cache_delent(char *sharename) 1069 { 1070 (void) utf8_strlwr(sharename); 1071 (void) ht_remove_item(smb_shr_cache.sc_cache, sharename); 1072 } 1073 1074 /* 1075 * Call back to free the given cache entry. 1076 */ 1077 static void 1078 smb_shr_cache_freent(HT_ITEM *item) 1079 { 1080 if (item && item->hi_data) 1081 free(item->hi_data); 1082 } 1083 1084 /* 1085 * ============================================ 1086 * Interfaces to sharemgr 1087 * 1088 * All functions in this section are private 1089 * ============================================ 1090 */ 1091 1092 /* 1093 * Load shares from sharemgr 1094 */ 1095 /*ARGSUSED*/ 1096 static void * 1097 smb_shr_sa_loadall(void *args) 1098 { 1099 sa_handle_t handle; 1100 sa_group_t group, subgroup; 1101 char *gstate; 1102 boolean_t gdisabled; 1103 1104 if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) { 1105 syslog(LOG_ERR, "share: failed to get libshare API handle"); 1106 return (NULL); 1107 } 1108 1109 for (group = sa_get_group(handle, NULL); 1110 group != NULL; group = sa_get_next_group(group)) { 1111 gstate = sa_get_group_attr(group, "state"); 1112 if (gstate == NULL) 1113 continue; 1114 1115 gdisabled = (strcasecmp(gstate, "disabled") == 0); 1116 sa_free_attr_string(gstate); 1117 if (gdisabled) 1118 continue; 1119 1120 smb_shr_sa_loadgrp(group); 1121 1122 for (subgroup = sa_get_sub_group(group); 1123 subgroup != NULL; 1124 subgroup = sa_get_next_group(subgroup)) { 1125 smb_shr_sa_loadgrp(subgroup); 1126 } 1127 1128 } 1129 1130 sa_fini(handle); 1131 return (NULL); 1132 } 1133 1134 /* 1135 * Load the shares contained in the specified group. 1136 * 1137 * Don't process groups on which the smb protocol is disabled. 1138 * The top level ZFS group won't have the smb protocol enabled 1139 * but sub-groups will. 1140 * 1141 * We will tolerate a limited number of errors and then give 1142 * up on the current group. A typical error might be that the 1143 * shared directory no longer exists. 1144 */ 1145 static void 1146 smb_shr_sa_loadgrp(sa_group_t group) 1147 { 1148 sa_share_t share; 1149 sa_resource_t resource; 1150 int error_count = 0; 1151 1152 if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL) 1153 return; 1154 1155 for (share = sa_get_share(group, NULL); 1156 share != NULL; 1157 share = sa_get_next_share(share)) { 1158 for (resource = sa_get_share_resource(share, NULL); 1159 resource != NULL; 1160 resource = sa_get_next_resource(resource)) { 1161 if (smb_shr_sa_load(share, resource)) 1162 ++error_count; 1163 1164 if (error_count > SMB_SHR_ERROR_THRESHOLD) 1165 break; 1166 } 1167 1168 if (error_count > SMB_SHR_ERROR_THRESHOLD) 1169 break; 1170 } 1171 } 1172 1173 /* 1174 * Load a share definition from sharemgr and add it to the cache. 1175 */ 1176 static uint32_t 1177 smb_shr_sa_load(sa_share_t share, sa_resource_t resource) 1178 { 1179 smb_share_t si; 1180 uint32_t status; 1181 1182 if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) { 1183 syslog(LOG_DEBUG, "share: failed to load %s (%d)", 1184 si.shr_name, status); 1185 return (status); 1186 } 1187 1188 if ((status = smb_shr_add(&si)) != NERR_Success) { 1189 syslog(LOG_DEBUG, "share: failed to cache %s (%d)", 1190 si.shr_name, status); 1191 return (status); 1192 } 1193 1194 return (NERR_Success); 1195 } 1196 1197 /* 1198 * Read the specified share information from sharemgr and return 1199 * it in the given smb_share_t structure. 1200 * 1201 * Shares read from sharemgr are marked as permanent/persistent. 1202 */ 1203 static uint32_t 1204 smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si) 1205 { 1206 sa_property_t prop; 1207 sa_optionset_t opts; 1208 char *val = NULL; 1209 char *path; 1210 char *rname; 1211 1212 if ((path = sa_get_share_attr(share, "path")) == NULL) 1213 return (NERR_InternalError); 1214 1215 if ((rname = sa_get_resource_attr(resource, "name")) == NULL) { 1216 sa_free_attr_string(path); 1217 return (NERR_InternalError); 1218 } 1219 1220 bzero(si, sizeof (smb_share_t)); 1221 si->shr_flags = SMB_SHRF_PERM; 1222 1223 (void) strlcpy(si->shr_path, path, sizeof (si->shr_path)); 1224 (void) strlcpy(si->shr_name, rname, sizeof (si->shr_name)); 1225 1226 sa_free_attr_string(path); 1227 sa_free_attr_string(rname); 1228 1229 val = sa_get_resource_description(resource); 1230 if (val == NULL) 1231 val = sa_get_share_description(share); 1232 1233 if (val != NULL) { 1234 (void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt)); 1235 sa_free_share_description(val); 1236 } 1237 1238 opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 1239 if (opts == NULL) 1240 return (NERR_Success); 1241 1242 prop = (sa_property_t)sa_get_property(opts, SMB_SHROPT_AD_CONTAINER); 1243 if (prop != NULL) { 1244 if ((val = sa_get_property_attr(prop, "value")) != NULL) { 1245 (void) strlcpy(si->shr_container, val, 1246 sizeof (si->shr_container)); 1247 free(val); 1248 } 1249 } 1250 1251 prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE); 1252 if (prop != NULL) { 1253 if ((val = sa_get_property_attr(prop, "value")) != NULL) { 1254 (void) strlcpy(si->shr_access_none, val, 1255 sizeof (si->shr_access_none)); 1256 free(val); 1257 si->shr_flags |= SMB_SHRF_ACC_NONE; 1258 } 1259 } 1260 1261 prop = (sa_property_t)sa_get_property(opts, SHOPT_RO); 1262 if (prop != NULL) { 1263 if ((val = sa_get_property_attr(prop, "value")) != NULL) { 1264 (void) strlcpy(si->shr_access_ro, val, 1265 sizeof (si->shr_access_ro)); 1266 free(val); 1267 si->shr_flags |= SMB_SHRF_ACC_RO; 1268 } 1269 } 1270 1271 prop = (sa_property_t)sa_get_property(opts, SHOPT_RW); 1272 if (prop != NULL) { 1273 if ((val = sa_get_property_attr(prop, "value")) != NULL) { 1274 (void) strlcpy(si->shr_access_rw, val, 1275 sizeof (si->shr_access_rw)); 1276 free(val); 1277 si->shr_flags |= SMB_SHRF_ACC_RW; 1278 } 1279 } 1280 1281 sa_free_derived_optionset(opts); 1282 return (NERR_Success); 1283 } 1284 1285 /* 1286 * ============================================ 1287 * Share publishing functions 1288 * 1289 * All the functions are private 1290 * ============================================ 1291 */ 1292 1293 static void 1294 smb_shr_publish(const char *sharename, const char *container) 1295 { 1296 smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH); 1297 } 1298 1299 static void 1300 smb_shr_unpublish(const char *sharename, const char *container) 1301 { 1302 smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH); 1303 } 1304 1305 /* 1306 * In domain mode, put a share on the publisher queue. 1307 * This is a no-op if the smb service is in Workgroup mode. 1308 */ 1309 static void 1310 smb_shr_publisher_queue(const char *sharename, const char *container, char op) 1311 { 1312 smb_shr_pitem_t *item = NULL; 1313 1314 if (container == NULL || *container == '\0') 1315 return; 1316 1317 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 1318 return; 1319 1320 (void) mutex_lock(&ad_queue.spq_mtx); 1321 switch (ad_queue.spq_state) { 1322 case SMB_SHR_PQS_READY: 1323 case SMB_SHR_PQS_PUBLISHING: 1324 break; 1325 default: 1326 (void) mutex_unlock(&ad_queue.spq_mtx); 1327 return; 1328 } 1329 (void) mutex_unlock(&ad_queue.spq_mtx); 1330 1331 if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL) 1332 return; 1333 1334 item->spi_op = op; 1335 (void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name)); 1336 (void) strlcpy(item->spi_container, container, 1337 sizeof (item->spi_container)); 1338 1339 (void) mutex_lock(&ad_queue.spq_mtx); 1340 list_insert_tail(&ad_queue.spq_list, item); 1341 (void) cond_signal(&ad_queue.spq_cv); 1342 (void) mutex_unlock(&ad_queue.spq_mtx); 1343 } 1344 1345 /* 1346 * Publishing won't be activated if the smb service is running in 1347 * Workgroup mode. 1348 */ 1349 static int 1350 smb_shr_publisher_start(void) 1351 { 1352 pthread_t publish_thr; 1353 pthread_attr_t tattr; 1354 int rc; 1355 1356 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 1357 return (0); 1358 1359 (void) mutex_lock(&ad_queue.spq_mtx); 1360 if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) { 1361 (void) mutex_unlock(&ad_queue.spq_mtx); 1362 errno = EINVAL; 1363 return (-1); 1364 } 1365 1366 list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t), 1367 offsetof(smb_shr_pitem_t, spi_lnd)); 1368 ad_queue.spq_state = SMB_SHR_PQS_READY; 1369 (void) mutex_unlock(&ad_queue.spq_mtx); 1370 1371 (void) pthread_attr_init(&tattr); 1372 (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 1373 rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0); 1374 (void) pthread_attr_destroy(&tattr); 1375 1376 return (rc); 1377 } 1378 1379 static void 1380 smb_shr_publisher_stop(void) 1381 { 1382 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 1383 return; 1384 1385 (void) mutex_lock(&ad_queue.spq_mtx); 1386 switch (ad_queue.spq_state) { 1387 case SMB_SHR_PQS_READY: 1388 case SMB_SHR_PQS_PUBLISHING: 1389 ad_queue.spq_state = SMB_SHR_PQS_STOPPING; 1390 (void) cond_signal(&ad_queue.spq_cv); 1391 break; 1392 default: 1393 break; 1394 } 1395 (void) mutex_unlock(&ad_queue.spq_mtx); 1396 } 1397 1398 /* 1399 * This is the publisher daemon thread. While running, the thread waits 1400 * on a conditional variable until notified that a share needs to be 1401 * [un]published or that the thread should be terminated. 1402 * 1403 * Entries may remain in the outgoing queue if the Active Directory 1404 * service is inaccessible, in which case the thread wakes up every 60 1405 * seconds to retry. 1406 */ 1407 /*ARGSUSED*/ 1408 static void * 1409 smb_shr_publisher(void *arg) 1410 { 1411 smb_ads_handle_t *ah; 1412 smb_shr_pitem_t *shr; 1413 list_t publist; 1414 timestruc_t pubretry; 1415 char hostname[MAXHOSTNAMELEN]; 1416 1417 (void) mutex_lock(&ad_queue.spq_mtx); 1418 if (ad_queue.spq_state != SMB_SHR_PQS_READY) { 1419 (void) mutex_unlock(&ad_queue.spq_mtx); 1420 return (NULL); 1421 } 1422 ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING; 1423 (void) mutex_unlock(&ad_queue.spq_mtx); 1424 1425 (void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0); 1426 1427 list_create(&publist, sizeof (smb_shr_pitem_t), 1428 offsetof(smb_shr_pitem_t, spi_lnd)); 1429 1430 for (;;) { 1431 (void) mutex_lock(&ad_queue.spq_mtx); 1432 1433 while (list_is_empty(&ad_queue.spq_list) && 1434 (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) { 1435 if (list_is_empty(&publist)) { 1436 (void) cond_wait(&ad_queue.spq_cv, 1437 &ad_queue.spq_mtx); 1438 } else { 1439 pubretry.tv_sec = 60; 1440 pubretry.tv_nsec = 0; 1441 (void) cond_reltimedwait(&ad_queue.spq_cv, 1442 &ad_queue.spq_mtx, &pubretry); 1443 break; 1444 } 1445 } 1446 1447 if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) { 1448 (void) mutex_unlock(&ad_queue.spq_mtx); 1449 break; 1450 } 1451 1452 /* 1453 * Transfer queued items to the local list so that 1454 * the mutex can be released. 1455 */ 1456 while ((shr = list_head(&ad_queue.spq_list)) != NULL) { 1457 list_remove(&ad_queue.spq_list, shr); 1458 list_insert_tail(&publist, shr); 1459 } 1460 1461 (void) mutex_unlock(&ad_queue.spq_mtx); 1462 1463 if ((ah = smb_ads_open()) != NULL) { 1464 smb_shr_publisher_send(ah, &publist, hostname); 1465 smb_ads_close(ah); 1466 } 1467 } 1468 1469 (void) mutex_lock(&ad_queue.spq_mtx); 1470 smb_shr_publisher_flush(&ad_queue.spq_list); 1471 list_destroy(&ad_queue.spq_list); 1472 ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE; 1473 (void) mutex_unlock(&ad_queue.spq_mtx); 1474 1475 smb_shr_publisher_flush(&publist); 1476 list_destroy(&publist); 1477 return (NULL); 1478 } 1479 1480 /* 1481 * Remove items from the specified queue and [un]publish them. 1482 */ 1483 static void 1484 smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host) 1485 { 1486 smb_shr_pitem_t *shr; 1487 1488 while ((shr = list_head(publist)) != NULL) { 1489 (void) mutex_lock(&ad_queue.spq_mtx); 1490 if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) { 1491 (void) mutex_unlock(&ad_queue.spq_mtx); 1492 return; 1493 } 1494 (void) mutex_unlock(&ad_queue.spq_mtx); 1495 1496 list_remove(publist, shr); 1497 1498 if (shr->spi_op == SMB_SHR_PUBLISH) 1499 (void) smb_ads_publish_share(ah, shr->spi_name, 1500 NULL, shr->spi_container, host); 1501 else 1502 (void) smb_ads_remove_share(ah, shr->spi_name, 1503 NULL, shr->spi_container, host); 1504 1505 free(shr); 1506 } 1507 } 1508 1509 /* 1510 * Flush all remaining items from the specified list/queue. 1511 */ 1512 static void 1513 smb_shr_publisher_flush(list_t *lst) 1514 { 1515 smb_shr_pitem_t *shr; 1516 1517 while ((shr = list_head(lst)) != NULL) { 1518 list_remove(lst, shr); 1519 free(shr); 1520 } 1521 } 1522