1/* 2 Unix SMB/Netbios implementation. 3 SMB client library implementation 4 Copyright (C) Andrew Tridgell 1998 5 Copyright (C) Richard Sharpe 2000, 2002 6 Copyright (C) John Terpstra 2000 7 Copyright (C) Tom Jansen (Ninja ISD) 2002 8 Copyright (C) Derrell Lipman 2003-2008 9 Copyright (C) Jeremy Allison 2007, 2008 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "includes.h" 26#include "libsmbclient.h" 27#include "libsmb_internal.h" 28 29 30/* 31 * Is the logging working / configfile read ? 32 */ 33static bool SMBC_initialized = false; 34static unsigned int initialized_ctx_count = 0; 35static void *initialized_ctx_count_mutex = NULL; 36 37/* 38 * Do some module- and library-wide intializations 39 */ 40static void 41SMBC_module_init(void * punused) 42{ 43 bool conf_loaded = False; 44 char *home = NULL; 45 TALLOC_CTX *frame = talloc_stackframe(); 46 47 load_case_tables(); 48 49 setup_logging("libsmbclient", True); 50 51 /* Here we would open the smb.conf file if needed ... */ 52 53 lp_set_in_client(True); 54 55 home = getenv("HOME"); 56 /* 57 if (home) { 58 char *conf = NULL; 59 if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { 60 if (lp_load(conf, True, False, False, True)) { 61 conf_loaded = True; 62 } else { 63 DEBUG(5, ("Could not load config file: %s\n", 64 conf)); 65 } 66 SAFE_FREE(conf); 67 } 68 } 69 */ 70 71 if (!conf_loaded) { 72 /* 73 * Well, if that failed, try the get_dyn_CONFIGFILE 74 * Which points to the standard locn, and if that 75 * fails, silently ignore it and use the internal 76 * defaults ... 77 */ 78 79 if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { 80 DEBUG(5, ("Could not load config file: %s\n", 81 get_dyn_CONFIGFILE())); 82 } else if (home) { 83 char *conf; 84 /* 85 * We loaded the global config file. Now lets 86 * load user-specific modifications to the 87 * global config. 88 */ 89 if (asprintf(&conf, 90 "%s/.smb/smb.conf.append", 91 home) > 0) { 92 if (!lp_load(conf, True, False, False, False)) { 93 DEBUG(10, 94 ("Could not append config file: " 95 "%s\n", 96 conf)); 97 } 98 SAFE_FREE(conf); 99 } 100 } 101 } 102 103 load_interfaces(); /* Load the list of interfaces ... */ 104 105 reopen_logs(); /* Get logging working ... */ 106 107 /* 108 * Block SIGPIPE (from lib/util_sock.c: write()) 109 * It is not needed and should not stop execution 110 */ 111 BlockSignals(True, SIGPIPE); 112 113 /* Create the mutex we'll use to protect initialized_ctx_count */ 114 if (SMB_THREAD_CREATE_MUTEX("initialized_ctx_count_mutex", 115 initialized_ctx_count_mutex) != 0) { 116 smb_panic("SMBC_module_init: " 117 "failed to create 'initialized_ctx_count' mutex"); 118 } 119 120 121 TALLOC_FREE(frame); 122} 123 124 125static void 126SMBC_module_terminate(void) 127{ 128 secrets_shutdown(); 129 gfree_all(); 130 SMBC_initialized = false; 131} 132 133 134/* 135 * Get a new empty handle to fill in with your own info 136 */ 137SMBCCTX * 138smbc_new_context(void) 139{ 140 SMBCCTX *context; 141 142 /* The first call to this function should initialize the module */ 143 SMB_THREAD_ONCE(&SMBC_initialized, SMBC_module_init, NULL); 144 145 /* 146 * All newly added context fields should be placed in 147 * SMBC_internal_data, not directly in SMBCCTX. 148 */ 149 context = SMB_MALLOC_P(SMBCCTX); 150 if (!context) { 151 errno = ENOMEM; 152 return NULL; 153 } 154 155 ZERO_STRUCTP(context); 156 157 context->internal = SMB_MALLOC_P(struct SMBC_internal_data); 158 if (!context->internal) { 159 SAFE_FREE(context); 160 errno = ENOMEM; 161 return NULL; 162 } 163 164 /* Initialize the context and establish reasonable defaults */ 165 ZERO_STRUCTP(context->internal); 166 167 smbc_setDebug(context, 0); 168 smbc_setTimeout(context, 20000); 169 170 smbc_setOptionFullTimeNames(context, False); 171 smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE); 172 smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE); 173 smbc_setOptionUseCCache(context, True); 174 smbc_setOptionCaseSensitive(context, False); 175 smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */ 176 smbc_setOptionUrlEncodeReaddirEntries(context, False); 177 smbc_setOptionOneSharePerServer(context, False); 178 if (getenv("LIBSMBCLIENT_NO_CCACHE") == NULL) { 179 smbc_setOptionUseCCache(context, true); 180 } 181 182 smbc_setFunctionAuthData(context, SMBC_get_auth_data); 183 smbc_setFunctionCheckServer(context, SMBC_check_server); 184 smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server); 185 186 smbc_setOptionUserData(context, NULL); 187 smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server); 188 smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server); 189 smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server); 190 smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers); 191 192 smbc_setFunctionOpen(context, SMBC_open_ctx); 193 smbc_setFunctionCreat(context, SMBC_creat_ctx); 194 smbc_setFunctionRead(context, SMBC_read_ctx); 195 smbc_setFunctionWrite(context, SMBC_write_ctx); 196 smbc_setFunctionClose(context, SMBC_close_ctx); 197 smbc_setFunctionUnlink(context, SMBC_unlink_ctx); 198 smbc_setFunctionRename(context, SMBC_rename_ctx); 199 smbc_setFunctionLseek(context, SMBC_lseek_ctx); 200 smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx); 201 smbc_setFunctionStat(context, SMBC_stat_ctx); 202 smbc_setFunctionStatVFS(context, SMBC_statvfs_ctx); 203 smbc_setFunctionFstatVFS(context, SMBC_fstatvfs_ctx); 204 smbc_setFunctionFstat(context, SMBC_fstat_ctx); 205 smbc_setFunctionOpendir(context, SMBC_opendir_ctx); 206 smbc_setFunctionClosedir(context, SMBC_closedir_ctx); 207 smbc_setFunctionReaddir(context, SMBC_readdir_ctx); 208 smbc_setFunctionGetdents(context, SMBC_getdents_ctx); 209 smbc_setFunctionMkdir(context, SMBC_mkdir_ctx); 210 smbc_setFunctionRmdir(context, SMBC_rmdir_ctx); 211 smbc_setFunctionTelldir(context, SMBC_telldir_ctx); 212 smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx); 213 smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx); 214 smbc_setFunctionChmod(context, SMBC_chmod_ctx); 215 smbc_setFunctionUtimes(context, SMBC_utimes_ctx); 216 smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx); 217 smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx); 218 smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx); 219 smbc_setFunctionListxattr(context, SMBC_listxattr_ctx); 220 221 smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx); 222 smbc_setFunctionPrintFile(context, SMBC_print_file_ctx); 223 smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx); 224 smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx); 225 226 return context; 227} 228 229/* 230 * Free a context 231 * 232 * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed 233 * and thus you'll be leaking memory if not handled properly. 234 * 235 */ 236int 237smbc_free_context(SMBCCTX *context, 238 int shutdown_ctx) 239{ 240 if (!context) { 241 errno = EBADF; 242 return 1; 243 } 244 245 if (shutdown_ctx) { 246 SMBCFILE * f; 247 DEBUG(1,("Performing aggressive shutdown.\n")); 248 249 f = context->internal->files; 250 while (f) { 251 smbc_getFunctionClose(context)(context, f); 252 f = f->next; 253 } 254 context->internal->files = NULL; 255 256 /* First try to remove the servers the nice way. */ 257 if (smbc_getFunctionPurgeCachedServers(context)(context)) { 258 SMBCSRV * s; 259 SMBCSRV * next; 260 DEBUG(1, ("Could not purge all servers, " 261 "Nice way shutdown failed.\n")); 262 s = context->internal->servers; 263 while (s) { 264 DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", 265 s, s->cli->fd)); 266 cli_shutdown(s->cli); 267 smbc_getFunctionRemoveCachedServer(context)(context, 268 s); 269 next = s->next; 270 DLIST_REMOVE(context->internal->servers, s); 271 SAFE_FREE(s); 272 s = next; 273 } 274 context->internal->servers = NULL; 275 } 276 } 277 else { 278 /* This is the polite way */ 279 if (smbc_getFunctionPurgeCachedServers(context)(context)) { 280 DEBUG(1, ("Could not purge all servers, " 281 "free_context failed.\n")); 282 errno = EBUSY; 283 return 1; 284 } 285 if (context->internal->servers) { 286 DEBUG(1, ("Active servers in context, " 287 "free_context failed.\n")); 288 errno = EBUSY; 289 return 1; 290 } 291 if (context->internal->files) { 292 DEBUG(1, ("Active files in context, " 293 "free_context failed.\n")); 294 errno = EBUSY; 295 return 1; 296 } 297 } 298 299 /* Things we have to clean up */ 300 smbc_setWorkgroup(context, NULL); 301 smbc_setNetbiosName(context, NULL); 302 smbc_setUser(context, NULL); 303 304 DEBUG(3, ("Context %p successfully freed\n", context)); 305 306 /* Free any DFS auth context. */ 307 TALLOC_FREE(context->internal->auth_info); 308 309 SAFE_FREE(context->internal); 310 SAFE_FREE(context); 311 312 /* Protect access to the count of contexts in use */ 313 if (SMB_THREAD_LOCK(initialized_ctx_count_mutex) != 0) { 314 smb_panic("error locking 'initialized_ctx_count'"); 315 } 316 317 if (initialized_ctx_count) { 318 initialized_ctx_count--; 319 } 320 321 if (initialized_ctx_count == 0) { 322 SMBC_module_terminate(); 323 } 324 325 /* Unlock the mutex */ 326 if (SMB_THREAD_UNLOCK(initialized_ctx_count_mutex) != 0) { 327 smb_panic("error unlocking 'initialized_ctx_count'"); 328 } 329 330 return 0; 331} 332 333 334/** 335 * Deprecated interface. Do not use. Instead, use the various 336 * smbc_setOption*() functions or smbc_setFunctionAuthDataWithContext(). 337 */ 338void 339smbc_option_set(SMBCCTX *context, 340 char *option_name, 341 ... /* option_value */) 342{ 343 va_list ap; 344 union { 345 int i; 346 bool b; 347 smbc_get_auth_data_with_context_fn auth_fn; 348 void *v; 349 const char *s; 350 } option_value; 351 352 va_start(ap, option_name); 353 354 if (strcmp(option_name, "debug_to_stderr") == 0) { 355 option_value.b = (bool) va_arg(ap, int); 356 smbc_setOptionDebugToStderr(context, option_value.b); 357 358 } else if (strcmp(option_name, "full_time_names") == 0) { 359 option_value.b = (bool) va_arg(ap, int); 360 smbc_setOptionFullTimeNames(context, option_value.b); 361 362 } else if (strcmp(option_name, "open_share_mode") == 0) { 363 option_value.i = va_arg(ap, int); 364 smbc_setOptionOpenShareMode(context, option_value.i); 365 366 } else if (strcmp(option_name, "auth_function") == 0) { 367 option_value.auth_fn = 368 va_arg(ap, smbc_get_auth_data_with_context_fn); 369 smbc_setFunctionAuthDataWithContext(context, option_value.auth_fn); 370 371 } else if (strcmp(option_name, "user_data") == 0) { 372 option_value.v = va_arg(ap, void *); 373 smbc_setOptionUserData(context, option_value.v); 374 375 } else if (strcmp(option_name, "smb_encrypt_level") == 0) { 376 option_value.s = va_arg(ap, const char *); 377 if (strcmp(option_value.s, "none") == 0) { 378 smbc_setOptionSmbEncryptionLevel(context, 379 SMBC_ENCRYPTLEVEL_NONE); 380 } else if (strcmp(option_value.s, "request") == 0) { 381 smbc_setOptionSmbEncryptionLevel(context, 382 SMBC_ENCRYPTLEVEL_REQUEST); 383 } else if (strcmp(option_value.s, "require") == 0) { 384 smbc_setOptionSmbEncryptionLevel(context, 385 SMBC_ENCRYPTLEVEL_REQUIRE); 386 } 387 388 } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { 389 option_value.i = va_arg(ap, int); 390 smbc_setOptionBrowseMaxLmbCount(context, option_value.i); 391 392 } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { 393 option_value.b = (bool) va_arg(ap, int); 394 smbc_setOptionUrlEncodeReaddirEntries(context, option_value.b); 395 396 } else if (strcmp(option_name, "one_share_per_server") == 0) { 397 option_value.b = (bool) va_arg(ap, int); 398 smbc_setOptionOneSharePerServer(context, option_value.b); 399 400 } else if (strcmp(option_name, "use_kerberos") == 0) { 401 option_value.b = (bool) va_arg(ap, int); 402 smbc_setOptionUseKerberos(context, option_value.b); 403 404 } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { 405 option_value.b = (bool) va_arg(ap, int); 406 smbc_setOptionFallbackAfterKerberos(context, option_value.b); 407 408 } else if (strcmp(option_name, "use_ccache") == 0) { 409 option_value.b = (bool) va_arg(ap, int); 410 smbc_setOptionUseCCache(context, option_value.b); 411 412 } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { 413 option_value.b = (bool) va_arg(ap, int); 414 smbc_setOptionNoAutoAnonymousLogin(context, option_value.b); 415 } 416 417 va_end(ap); 418} 419 420 421/* 422 * Deprecated interface. Do not use. Instead, use the various 423 * smbc_getOption*() functions. 424 */ 425void * 426smbc_option_get(SMBCCTX *context, 427 char *option_name) 428{ 429 if (strcmp(option_name, "debug_stderr") == 0) { 430#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 431 return (void *) (intptr_t) smbc_getOptionDebugToStderr(context); 432#else 433 return (void *) smbc_getOptionDebugToStderr(context); 434#endif 435 436 } else if (strcmp(option_name, "full_time_names") == 0) { 437#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 438 return (void *) (intptr_t) smbc_getOptionFullTimeNames(context); 439#else 440 return (void *) smbc_getOptionFullTimeNames(context); 441#endif 442 443 } else if (strcmp(option_name, "open_share_mode") == 0) { 444#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 445 return (void *) (intptr_t) smbc_getOptionOpenShareMode(context); 446#else 447 return (void *) smbc_getOptionOpenShareMode(context); 448#endif 449 450 } else if (strcmp(option_name, "auth_function") == 0) { 451 return (void *) smbc_getFunctionAuthDataWithContext(context); 452 453 } else if (strcmp(option_name, "user_data") == 0) { 454 return smbc_getOptionUserData(context); 455 456 } else if (strcmp(option_name, "smb_encrypt_level") == 0) { 457 switch(smbc_getOptionSmbEncryptionLevel(context)) 458 { 459 case 0: 460 return (void *) "none"; 461 case 1: 462 return (void *) "request"; 463 case 2: 464 return (void *) "require"; 465 } 466 467 } else if (strcmp(option_name, "smb_encrypt_on") == 0) { 468 SMBCSRV *s; 469 unsigned int num_servers = 0; 470 471 for (s = context->internal->servers; s; s = s->next) { 472 num_servers++; 473 if (s->cli->trans_enc_state == NULL) { 474 return (void *)false; 475 } 476 } 477#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 478 return (void *) (intptr_t) (bool) (num_servers > 0); 479#else 480 return (void *) (bool) (num_servers > 0); 481#endif 482 483 } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { 484#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 485 return (void *) (intptr_t) smbc_getOptionBrowseMaxLmbCount(context); 486#else 487 return (void *) smbc_getOptionBrowseMaxLmbCount(context); 488#endif 489 490 } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { 491#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 492 return (void *)(intptr_t) smbc_getOptionUrlEncodeReaddirEntries(context); 493#else 494 return (void *) (bool) smbc_getOptionUrlEncodeReaddirEntries(context); 495#endif 496 497 } else if (strcmp(option_name, "one_share_per_server") == 0) { 498#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 499 return (void *) (intptr_t) smbc_getOptionOneSharePerServer(context); 500#else 501 return (void *) (bool) smbc_getOptionOneSharePerServer(context); 502#endif 503 504 } else if (strcmp(option_name, "use_kerberos") == 0) { 505#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 506 return (void *) (intptr_t) smbc_getOptionUseKerberos(context); 507#else 508 return (void *) (bool) smbc_getOptionUseKerberos(context); 509#endif 510 511 } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { 512#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 513 return (void *)(intptr_t) smbc_getOptionFallbackAfterKerberos(context); 514#else 515 return (void *) (bool) smbc_getOptionFallbackAfterKerberos(context); 516#endif 517 518 } else if (strcmp(option_name, "use_ccache") == 0) { 519#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 520 return (void *) (intptr_t) smbc_getOptionUseCCache(context); 521#else 522 return (void *) (bool) smbc_getOptionUseCCache(context); 523#endif 524 525 } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { 526#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 527 return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context); 528#else 529 return (void *) (bool) smbc_getOptionNoAutoAnonymousLogin(context); 530#endif 531 } 532 533 return NULL; 534} 535 536 537/* 538 * Initialize the library, etc. 539 * 540 * We accept a struct containing handle information. 541 * valid values for info->debug from 0 to 100, 542 * and insist that info->fn must be non-null. 543 */ 544SMBCCTX * 545smbc_init_context(SMBCCTX *context) 546{ 547 int pid; 548 549 if (!context) { 550 errno = EBADF; 551 return NULL; 552 } 553 554 /* Do not initialise the same client twice */ 555 if (context->internal->initialized) { 556 return NULL; 557 } 558 559 if (context->internal->debug_stderr) { 560 /* 561 * Hmmm... Do we want a unique dbf per-thread? For now, we'll just 562 * leave it up to the user. If any one context spefies debug to 563 * stderr then all will be. 564 */ 565 dbf = x_stderr; 566 x_setbuf(x_stderr, NULL); 567 } 568 569 if ((!smbc_getFunctionAuthData(context) && 570 !smbc_getFunctionAuthDataWithContext(context)) || 571 smbc_getDebug(context) < 0 || 572 smbc_getDebug(context) > 100) { 573 574 errno = EINVAL; 575 return NULL; 576 577 } 578 579 if (!smbc_getUser(context)) { 580 /* 581 * FIXME: Is this the best way to get the user info? 582 */ 583 char *user = getenv("USER"); 584 /* walk around as "guest" if no username can be found */ 585 if (!user) { 586 user = SMB_STRDUP("guest"); 587 } else { 588 user = SMB_STRDUP(user); 589 } 590 591 if (!user) { 592 errno = ENOMEM; 593 return NULL; 594 } 595 596 smbc_setUser(context, user); 597 SAFE_FREE(user); 598 599 if (!smbc_getUser(context)) { 600 errno = ENOMEM; 601 return NULL; 602 } 603 } 604 605 if (!smbc_getNetbiosName(context)) { 606 /* 607 * We try to get our netbios name from the config. If that 608 * fails we fall back on constructing our netbios name from 609 * our hostname etc 610 */ 611 char *netbios_name; 612 if (global_myname()) { 613 netbios_name = SMB_STRDUP(global_myname()); 614 } else { 615 /* 616 * Hmmm, I want to get hostname as well, but I am too 617 * lazy for the moment 618 */ 619 pid = sys_getpid(); 620 netbios_name = (char *)SMB_MALLOC(17); 621 if (!netbios_name) { 622 errno = ENOMEM; 623 return NULL; 624 } 625 slprintf(netbios_name, 16, 626 "smbc%s%d", smbc_getUser(context), pid); 627 } 628 629 if (!netbios_name) { 630 errno = ENOMEM; 631 return NULL; 632 } 633 634 smbc_setNetbiosName(context, netbios_name); 635 SAFE_FREE(netbios_name); 636 637 if (!smbc_getNetbiosName(context)) { 638 errno = ENOMEM; 639 return NULL; 640 } 641 } 642 643 DEBUG(1, ("Using netbios name %s.\n", smbc_getNetbiosName(context))); 644 645 if (!smbc_getWorkgroup(context)) { 646 char *workgroup; 647 648 if (lp_workgroup()) { 649 workgroup = SMB_STRDUP(lp_workgroup()); 650 } 651 else { 652 /* TODO: Think about a decent default workgroup */ 653 workgroup = SMB_STRDUP("samba"); 654 } 655 656 if (!workgroup) { 657 errno = ENOMEM; 658 return NULL; 659 } 660 661 smbc_setWorkgroup(context, workgroup); 662 SAFE_FREE(workgroup); 663 664 if (!smbc_getWorkgroup(context)) { 665 errno = ENOMEM; 666 return NULL; 667 } 668 } 669 670 DEBUG(1, ("Using workgroup %s.\n", smbc_getWorkgroup(context))); 671 672 /* shortest timeout is 1 second */ 673 if (smbc_getTimeout(context) > 0 && smbc_getTimeout(context) < 1000) 674 smbc_setTimeout(context, 1000); 675 676 context->internal->initialized = True; 677 678 /* Protect access to the count of contexts in use */ 679 if (SMB_THREAD_LOCK(initialized_ctx_count_mutex) != 0) { 680 smb_panic("error locking 'initialized_ctx_count'"); 681 } 682 683 initialized_ctx_count++; 684 685 /* Unlock the mutex */ 686 if (SMB_THREAD_UNLOCK(initialized_ctx_count_mutex) != 0) { 687 smb_panic("error unlocking 'initialized_ctx_count'"); 688 } 689 690 return context; 691} 692 693 694/* Return the verion of samba, and thus libsmbclient */ 695const char * 696smbc_version(void) 697{ 698 return samba_version_string(); 699} 700 701/* 702 * Set the credentials so DFS will work when following referrals. 703 * This function is broken and must be removed. No SMBCCTX arg... 704 * JRA. 705 */ 706 707void 708smbc_set_credentials(const char *workgroup, 709 const char *user, 710 const char *password, 711 smbc_bool use_kerberos, 712 const char *signing_state) 713{ 714 d_printf("smbc_set_credentials is obsolete. Replace with smbc_set_credentials_with_fallback().\n"); 715} 716 717void smbc_set_credentials_with_fallback(SMBCCTX *context, 718 const char *workgroup, 719 const char *user, 720 const char *password) 721{ 722 smbc_bool use_kerberos = false; 723 const char *signing_state = "off"; 724 struct user_auth_info *auth_info = NULL; 725 726 if (! context) { 727 728 return; 729 } 730 731 if (! workgroup || ! *workgroup) { 732 workgroup = smbc_getWorkgroup(context); 733 } 734 735 if (! user) { 736 user = smbc_getUser(context); 737 } 738 739 if (! password) { 740 password = ""; 741 } 742 743 auth_info = user_auth_info_init(NULL); 744 745 if (! auth_info) { 746 DEBUG(0, ("smbc_set_credentials_with_fallback: allocation fail\n")); 747 return; 748 } 749 750 if (smbc_getOptionUseKerberos(context)) { 751 use_kerberos = True; 752 } 753 754 if (lp_client_signing()) { 755 signing_state = "on"; 756 } 757 758 if (lp_client_signing() == Required) { 759 signing_state = "force"; 760 } 761 762 set_cmdline_auth_info_username(auth_info, user); 763 set_cmdline_auth_info_password(auth_info, password); 764 set_cmdline_auth_info_use_kerberos(auth_info, use_kerberos); 765 set_cmdline_auth_info_signing_state(auth_info, signing_state); 766 set_cmdline_auth_info_fallback_after_kerberos(auth_info, 767 smbc_getOptionFallbackAfterKerberos(context)); 768 set_cmdline_auth_info_use_ccache( 769 auth_info, smbc_getOptionUseCCache(context)); 770 set_global_myworkgroup(workgroup); 771 772 TALLOC_FREE(context->internal->auth_info); 773 774 context->internal->auth_info = auth_info; 775} 776