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