From 636fbd1028bf22d9a93ae5029f6881e144f58fe1 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Wed, 13 May 2009 14:37:17 -0400 Subject: Thread-safe protection: libsmbclient initialization - Begin converting init functions to use SMB_THREAD_ONCE. libsmbclient module-wide initialization is now moved into a separate function and called via SMB_THREAD_ONCE. - libsmbclient counts users (contexts) so that it can release global resources when the last context is closed. That count of contexts is now protected by a mutex. Derrell --- source3/libsmb/libsmb_context.c | 227 +++++++++++++++++++++++----------------- 1 file changed, 133 insertions(+), 94 deletions(-) (limited to 'source3/libsmb/libsmb_context.c') diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index f09e9c6287..03cd00d2c1 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -30,8 +30,112 @@ /* * 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); + +#if 0 /* need a place to put this (thread local storage) */ + if (context->internal->debug_stderr) { + dbf = x_stderr; + x_setbuf(x_stderr, NULL); + } +#endif + + /* 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); +} + + +void +SMBC_module_terminate(void) +{ + gencache_shutdown(); + secrets_shutdown(); + gfree_all(); + SMBC_initialized = false; +} + /* * Get a new empty handle to fill in with your own info @@ -41,6 +145,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. @@ -209,16 +316,24 @@ smbc_free_context(SMBCCTX *context, 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; } @@ -427,7 +542,6 @@ smbc_init_context(SMBCCTX *context) { int pid; char *user = NULL; - char *home = NULL; if (!context) { errno = EBADF; @@ -449,88 +563,6 @@ 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? @@ -610,13 +642,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; } -- cgit