X-Git-Url: http://git.samba.org/samba.git/?p=ira%2Fwip.git;a=blobdiff_plain;f=source3%2Flibsmb%2Flibsmb_context.c;h=c44d92c99a4a7362beb49f5eb5729ced07cae430;hp=4c12d18ab7b62a7dca92a2f22e671f6a9e27ab61;hb=08fa57335a2e1ac44764330c0d95aaf099aa0c15;hpb=09ac816b36e45fd537af2f7fe7c57a11f5c744f5 diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index 4c12d18ab7b..c44d92c99a4 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -30,8 +30,104 @@ /* * Is the logging working / configfile read ? */ -static bool SMBC_initialized; -static unsigned int initialized_ctx_count; +static bool SMBC_initialized = false; +static unsigned int initialized_ctx_count = 0; +static void *initialized_ctx_count_mutex = NULL; + +/* + * Do some module- and library-wide intializations + */ +static void +SMBC_module_init(void * punused) +{ + bool conf_loaded = False; + char *home = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + load_case_tables(); + + setup_logging("libsmbclient", True); + + /* Here we would open the smb.conf file if needed ... */ + + lp_set_in_client(True); + + home = getenv("HOME"); + if (home) { + char *conf = NULL; + if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { + if (lp_load(conf, True, False, False, True)) { + conf_loaded = True; + } else { + DEBUG(5, ("Could not load config file: %s\n", + conf)); + } + SAFE_FREE(conf); + } + } + + if (!conf_loaded) { + /* + * Well, if that failed, try the get_dyn_CONFIGFILE + * Which points to the standard locn, and if that + * fails, silently ignore it and use the internal + * defaults ... + */ + + if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { + DEBUG(5, ("Could not load config file: %s\n", + get_dyn_CONFIGFILE())); + } else if (home) { + char *conf; + /* + * We loaded the global config file. Now lets + * load user-specific modifications to the + * global config. + */ + if (asprintf(&conf, + "%s/.smb/smb.conf.append", + home) > 0) { + if (!lp_load(conf, True, False, False, False)) { + DEBUG(10, + ("Could not append config file: " + "%s\n", + conf)); + } + SAFE_FREE(conf); + } + } + } + + load_interfaces(); /* Load the list of interfaces ... */ + + reopen_logs(); /* Get logging working ... */ + + /* + * Block SIGPIPE (from lib/util_sock.c: write()) + * It is not needed and should not stop execution + */ + BlockSignals(True, SIGPIPE); + + /* Create the mutex we'll use to protect initialized_ctx_count */ + if (SMB_THREAD_CREATE_MUTEX("initialized_ctx_count_mutex", + initialized_ctx_count_mutex) != 0) { + smb_panic("SMBC_module_init: " + "failed to create 'initialized_ctx_count' mutex"); + } + + + TALLOC_FREE(frame); +} + + +static void +SMBC_module_terminate(void) +{ + secrets_shutdown(); + gfree_all(); + SMBC_initialized = false; +} + /* * Get a new empty handle to fill in with your own info @@ -41,6 +137,9 @@ smbc_new_context(void) { SMBCCTX *context; + /* The first call to this function should initialize the module */ + SMB_THREAD_ONCE(&SMBC_initialized, SMBC_module_init, NULL); + /* * All newly added context fields should be placed in * SMBC_internal_data, not directly in SMBCCTX. @@ -69,10 +168,14 @@ smbc_new_context(void) smbc_setOptionFullTimeNames(context, False); smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE); smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE); + smbc_setOptionUseCCache(context, True); smbc_setOptionCaseSensitive(context, False); smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */ smbc_setOptionUrlEncodeReaddirEntries(context, False); smbc_setOptionOneSharePerServer(context, False); + if (getenv("LIBSMBCLIENT_NO_CCACHE") == NULL) { + smbc_setOptionUseCCache(context, true); + } smbc_setFunctionAuthData(context, SMBC_get_auth_data); smbc_setFunctionCheckServer(context, SMBC_check_server); @@ -192,30 +295,36 @@ smbc_free_context(SMBCCTX *context, } /* Things we have to clean up */ - free(smbc_getWorkgroup(context)); smbc_setWorkgroup(context, NULL); - - free(smbc_getNetbiosName(context)); smbc_setNetbiosName(context, NULL); - - free(smbc_getUser(context)); smbc_setUser(context, NULL); DEBUG(3, ("Context %p successfully freed\n", context)); + /* Free any DFS auth context. */ + TALLOC_FREE(context->internal->auth_info); + SAFE_FREE(context->internal); SAFE_FREE(context); + /* Protect access to the count of contexts in use */ + if (SMB_THREAD_LOCK(initialized_ctx_count_mutex) != 0) { + smb_panic("error locking 'initialized_ctx_count'"); + } + if (initialized_ctx_count) { initialized_ctx_count--; } - if (initialized_ctx_count == 0 && SMBC_initialized) { - gencache_shutdown(); - secrets_shutdown(); - gfree_all(); - SMBC_initialized = false; + if (initialized_ctx_count == 0) { + SMBC_module_terminate(); + } + + /* Unlock the mutex */ + if (SMB_THREAD_UNLOCK(initialized_ctx_count_mutex) != 0) { + smb_panic("error unlocking 'initialized_ctx_count'"); } + return 0; } @@ -294,6 +403,10 @@ smbc_option_set(SMBCCTX *context, option_value.b = (bool) va_arg(ap, int); smbc_setOptionFallbackAfterKerberos(context, option_value.b); + } else if (strcmp(option_name, "use_ccache") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionUseCCache(context, option_value.b); + } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { option_value.b = (bool) va_arg(ap, int); smbc_setOptionNoAutoAnonymousLogin(context, option_value.b); @@ -400,6 +513,13 @@ smbc_option_get(SMBCCTX *context, return (void *) (bool) smbc_getOptionFallbackAfterKerberos(context); #endif + } else if (strcmp(option_name, "use_ccache") == 0) { +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) smbc_getOptionUseCCache(context); +#else + return (void *) (bool) smbc_getOptionUseCCache(context); +#endif + } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context); @@ -423,8 +543,6 @@ SMBCCTX * smbc_init_context(SMBCCTX *context) { int pid; - char *user = NULL; - char *home = NULL; if (!context) { errno = EBADF; @@ -436,6 +554,16 @@ smbc_init_context(SMBCCTX *context) return NULL; } + if (context->internal->debug_stderr) { + /* + * Hmmm... Do we want a unique dbf per-thread? For now, we'll just + * leave it up to the user. If any one context spefies debug to + * stderr then all will be. + */ + dbf = x_stderr; + x_setbuf(x_stderr, NULL); + } + if ((!smbc_getFunctionAuthData(context) && !smbc_getFunctionAuthDataWithContext(context)) || smbc_getDebug(context) < 0 || @@ -446,93 +574,11 @@ smbc_init_context(SMBCCTX *context) } - if (!SMBC_initialized) { - /* - * Do some library-wide intializations the first time we get - * called - */ - bool conf_loaded = False; - TALLOC_CTX *frame = talloc_stackframe(); - - load_case_tables(); - - setup_logging("libsmbclient", True); - if (context->internal->debug_stderr) { - dbf = x_stderr; - x_setbuf(x_stderr, NULL); - } - - /* Here we would open the smb.conf file if needed ... */ - - lp_set_in_client(True); - - home = getenv("HOME"); - if (home) { - char *conf = NULL; - if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { - if (lp_load(conf, True, False, False, True)) { - conf_loaded = True; - } else { - DEBUG(5, ("Could not load config file: %s\n", - conf)); - } - SAFE_FREE(conf); - } - } - - if (!conf_loaded) { - /* - * Well, if that failed, try the get_dyn_CONFIGFILE - * Which points to the standard locn, and if that - * fails, silently ignore it and use the internal - * defaults ... - */ - - if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { - DEBUG(5, ("Could not load config file: %s\n", - get_dyn_CONFIGFILE())); - } else if (home) { - char *conf; - /* - * We loaded the global config file. Now lets - * load user-specific modifications to the - * global config. - */ - if (asprintf(&conf, - "%s/.smb/smb.conf.append", - home) > 0) { - if (!lp_load(conf, True, False, False, False)) { - DEBUG(10, - ("Could not append config file: " - "%s\n", - conf)); - } - SAFE_FREE(conf); - } - } - } - - load_interfaces(); /* Load the list of interfaces ... */ - - reopen_logs(); /* Get logging working ... */ - - /* - * Block SIGPIPE (from lib/util_sock.c: write()) - * It is not needed and should not stop execution - */ - BlockSignals(True, SIGPIPE); - - /* Done with one-time initialisation */ - SMBC_initialized = true; - - TALLOC_FREE(frame); - } - if (!smbc_getUser(context)) { /* * FIXME: Is this the best way to get the user info? */ - user = getenv("USER"); + char *user = getenv("USER"); /* walk around as "guest" if no username can be found */ if (!user) { user = SMB_STRDUP("guest"); @@ -546,6 +592,12 @@ smbc_init_context(SMBCCTX *context) } smbc_setUser(context, user); + SAFE_FREE(user); + + if (!smbc_getUser(context)) { + errno = ENOMEM; + return NULL; + } } if (!smbc_getNetbiosName(context)) { @@ -578,6 +630,12 @@ smbc_init_context(SMBCCTX *context) } smbc_setNetbiosName(context, netbios_name); + SAFE_FREE(netbios_name); + + if (!smbc_getNetbiosName(context)) { + errno = ENOMEM; + return NULL; + } } DEBUG(1, ("Using netbios name %s.\n", smbc_getNetbiosName(context))); @@ -599,6 +657,12 @@ smbc_init_context(SMBCCTX *context) } smbc_setWorkgroup(context, workgroup); + SAFE_FREE(workgroup); + + if (!smbc_getWorkgroup(context)) { + errno = ENOMEM; + return NULL; + } } DEBUG(1, ("Using workgroup %s.\n", smbc_getWorkgroup(context))); @@ -607,13 +671,20 @@ smbc_init_context(SMBCCTX *context) if (smbc_getTimeout(context) > 0 && smbc_getTimeout(context) < 1000) smbc_setTimeout(context, 1000); - /* - * FIXME: Should we check the function pointers here? - */ - context->internal->initialized = True; + + /* Protect access to the count of contexts in use */ + if (SMB_THREAD_LOCK(initialized_ctx_count_mutex) != 0) { + smb_panic("error locking 'initialized_ctx_count'"); + } + initialized_ctx_count++; + /* Unlock the mutex */ + if (SMB_THREAD_UNLOCK(initialized_ctx_count_mutex) != 0) { + smb_panic("error unlocking 'initialized_ctx_count'"); + } + return context; } @@ -625,32 +696,20 @@ smbc_version(void) return samba_version_string(); } - /* * Set the credentials so DFS will work when following referrals. + * This function is broken and must be removed. No SMBCCTX arg... + * JRA. */ + void smbc_set_credentials(const char *workgroup, - const char *user, - const char *password, - smbc_bool use_kerberos, - const char *signing_state) + const char *user, + const char *password, + smbc_bool use_kerberos, + const char *signing_state) { - struct user_auth_info *auth_info; - - auth_info = user_auth_info_init(talloc_tos()); - if (auth_info == NULL) { - return; - } - set_cmdline_auth_info_username(auth_info, user); - set_cmdline_auth_info_password(auth_info, password); - set_cmdline_auth_info_use_kerberos(auth_info, use_kerberos); - if (! set_cmdline_auth_info_signing_state(auth_info, signing_state)) { - DEBUG(0, ("Invalid signing state: %s", signing_state)); - } - set_global_myworkgroup(workgroup); - cli_cm_set_credentials(auth_info); - TALLOC_FREE(auth_info); + d_printf("smbc_set_credentials is obsolete. Replace with smbc_set_credentials_with_fallback().\n"); } void smbc_set_credentials_with_fallback(SMBCCTX *context, @@ -660,12 +719,29 @@ void smbc_set_credentials_with_fallback(SMBCCTX *context, { smbc_bool use_kerberos = false; const char *signing_state = "off"; - - if (! context || - ! workgroup || ! *workgroup || - ! user || ! *user || - ! password || ! *password) { + struct user_auth_info *auth_info = NULL; + + if (! context) { + + return; + } + + if (! workgroup || ! *workgroup) { + workgroup = smbc_getWorkgroup(context); + } + + if (! user) { + user = smbc_getUser(context); + } + + if (! password) { + password = ""; + } + auth_info = user_auth_info_init(NULL); + + if (! auth_info) { + DEBUG(0, ("smbc_set_credentials_with_fallback: allocation fail\n")); return; } @@ -681,10 +757,17 @@ void smbc_set_credentials_with_fallback(SMBCCTX *context, signing_state = "force"; } - smbc_set_credentials(workgroup, user, password, - use_kerberos, signing_state); + set_cmdline_auth_info_username(auth_info, user); + set_cmdline_auth_info_password(auth_info, password); + set_cmdline_auth_info_use_kerberos(auth_info, use_kerberos); + set_cmdline_auth_info_signing_state(auth_info, signing_state); + set_cmdline_auth_info_fallback_after_kerberos(auth_info, + smbc_getOptionFallbackAfterKerberos(context)); + set_cmdline_auth_info_use_ccache( + auth_info, smbc_getOptionUseCCache(context)); + set_global_myworkgroup(workgroup); - if (smbc_getOptionFallbackAfterKerberos(context)) { - cli_cm_set_fallback_after_kerberos(); - } + TALLOC_FREE(context->internal->auth_info); + + context->internal->auth_info = auth_info; }