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