Make char* parameters const
[samba.git] / source / libsmb / libsmb_context.c
index 1505d50a430cbd8b26c81bb4987809d4045dbedb..ec163114126556a24f7be26c4f35909c7c648be4 100644 (file)
@@ -30,9 +30,8 @@
 /*
  * Is the logging working / configfile read ? 
  */
-static int SMBC_initialized = 0;
-
-
+static bool SMBC_initialized;
+static unsigned int initialized_ctx_count;
 
 /*
  * Get a new empty handle to fill in with your own info
@@ -40,74 +39,86 @@ static int SMBC_initialized = 0;
 SMBCCTX *
 smbc_new_context(void)
 {
-    SMBCCTX *context;
-    
-    context = SMB_MALLOC_P(SMBCCTX);
-    if (!context) {
-        errno = ENOMEM;
-        return NULL;
-    }
-    
-    
-    /* Initialize the context and establish reasonable defaults */
-    ZERO_STRUCTP(context);
-    
-    context->debug            = 0;
-    context->timeout          = 20000; /* 20 seconds */
-    
-    context->full_time_names           = False;
-    context->share_mode                = SMBC_SHAREMODE_DENY_NONE;
-    context->smb_encryption_level      = 0;
-    context->browse_max_lmb_count      = 3;    /* # LMBs to query */
-    context->urlencode_readdir_entries = False;
-    context->one_share_per_server      = False;
-    context->use_kerberos              = False;
-    context->fallback_after_kerberos   = False;
-    context->no_auto_anonymous_login   = False;
-    
-    context->server.get_auth_data_fn        = SMBC_get_auth_data;
-    context->server.check_server_fn         = SMBC_check_server;
-    context->server.remove_unused_server_fn = SMBC_remove_unused_server;
-    
-    context->cache.server_cache_data        = NULL;
-    context->cache.add_cached_server_fn     = SMBC_add_cached_server;
-    context->cache.get_cached_server_fn     = SMBC_get_cached_server;
-    context->cache.remove_cached_server_fn  = SMBC_remove_cached_server;
-    context->cache.purge_cached_server_fn   = SMBC_purge_cached_servers;
-    
-    context->posix_emu.open_fn             = SMBC_open_ctx;
-    context->posix_emu.creat_fn            = SMBC_creat_ctx;
-    context->posix_emu.read_fn             = SMBC_read_ctx;
-    context->posix_emu.write_fn            = SMBC_write_ctx;
-    context->posix_emu.close_fn            = SMBC_close_ctx;
-    context->posix_emu.unlink_fn           = SMBC_unlink_ctx;
-    context->posix_emu.rename_fn           = SMBC_rename_ctx;
-    context->posix_emu.lseek_fn            = SMBC_lseek_ctx;
-    context->posix_emu.ftruncate_fn        = SMBC_ftruncate_ctx;
-    context->posix_emu.stat_fn             = SMBC_stat_ctx;
-    context->posix_emu.fstat_fn            = SMBC_fstat_ctx;
-    context->posix_emu.opendir_fn          = SMBC_opendir_ctx;
-    context->posix_emu.closedir_fn         = SMBC_closedir_ctx;
-    context->posix_emu.readdir_fn          = SMBC_readdir_ctx;
-    context->posix_emu.getdents_fn         = SMBC_getdents_ctx;
-    context->posix_emu.mkdir_fn            = SMBC_mkdir_ctx;
-    context->posix_emu.rmdir_fn            = SMBC_rmdir_ctx;
-    context->posix_emu.telldir_fn          = SMBC_telldir_ctx;
-    context->posix_emu.lseekdir_fn         = SMBC_lseekdir_ctx;
-    context->posix_emu.fstatdir_fn         = SMBC_fstatdir_ctx;
-    context->posix_emu.chmod_fn            = SMBC_chmod_ctx;
-    context->posix_emu.utimes_fn           = SMBC_utimes_ctx;
-    context->posix_emu.setxattr_fn         = SMBC_setxattr_ctx;
-    context->posix_emu.getxattr_fn         = SMBC_getxattr_ctx;
-    context->posix_emu.removexattr_fn      = SMBC_removexattr_ctx;
-    context->posix_emu.listxattr_fn        = SMBC_listxattr_ctx;
-    
-    context->printing.open_print_job_fn   = SMBC_open_print_job_ctx;
-    context->printing.print_file_fn       = SMBC_print_file_ctx;
-    context->printing.list_print_jobs_fn  = SMBC_list_print_jobs_ctx;
-    context->printing.unlink_print_job_fn = SMBC_unlink_print_job_ctx;
-    
-    return context;
+        SMBCCTX *context;
+        
+        /*
+         * All newly added context fields should be placed in
+         * SMBC_internal_data, not directly in SMBCCTX.
+         */
+        context = SMB_MALLOC_P(SMBCCTX);
+        if (!context) {
+                errno = ENOMEM;
+                return NULL;
+        }
+        
+        ZERO_STRUCTP(context);
+        
+        context->internal = SMB_MALLOC_P(struct SMBC_internal_data);
+        if (!context->internal) {
+                SAFE_FREE(context);
+                errno = ENOMEM;
+                return NULL;
+        }
+        
+        /* Initialize the context and establish reasonable defaults */
+        ZERO_STRUCTP(context->internal);
+        
+        smbc_setDebug(context, 0);
+        smbc_setTimeout(context, 20000);
+        
+        smbc_setOptionFullTimeNames(context, False);
+        smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE);
+        smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE);
+        smbc_setOptionCaseSensitive(context, False);
+        smbc_setOptionBrowseMaxLmbCount(context, 3);    /* # LMBs to query */
+        smbc_setOptionUrlEncodeReaddirEntries(context, False);
+        smbc_setOptionOneSharePerServer(context, False);
+        
+        smbc_setFunctionAuthData(context, SMBC_get_auth_data);
+        smbc_setFunctionCheckServer(context, SMBC_check_server);
+        smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server);
+        
+        smbc_setOptionUserData(context, NULL);
+        smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server);
+        smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server);
+        smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server);
+        smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers);
+        
+        smbc_setFunctionOpen(context, SMBC_open_ctx);
+        smbc_setFunctionCreat(context, SMBC_creat_ctx);
+        smbc_setFunctionRead(context, SMBC_read_ctx);
+        smbc_setFunctionWrite(context, SMBC_write_ctx);
+        smbc_setFunctionClose(context, SMBC_close_ctx);
+        smbc_setFunctionUnlink(context, SMBC_unlink_ctx);
+        smbc_setFunctionRename(context, SMBC_rename_ctx);
+        smbc_setFunctionLseek(context, SMBC_lseek_ctx);
+        smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx);
+        smbc_setFunctionStat(context, SMBC_stat_ctx);
+        smbc_setFunctionStatVFS(context, SMBC_statvfs_ctx);
+        smbc_setFunctionFstatVFS(context, SMBC_fstatvfs_ctx);
+        smbc_setFunctionFstat(context, SMBC_fstat_ctx);
+        smbc_setFunctionOpendir(context, SMBC_opendir_ctx);
+        smbc_setFunctionClosedir(context, SMBC_closedir_ctx);
+        smbc_setFunctionReaddir(context, SMBC_readdir_ctx);
+        smbc_setFunctionGetdents(context, SMBC_getdents_ctx);
+        smbc_setFunctionMkdir(context, SMBC_mkdir_ctx);
+        smbc_setFunctionRmdir(context, SMBC_rmdir_ctx);
+        smbc_setFunctionTelldir(context, SMBC_telldir_ctx);
+        smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx);
+        smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx);
+        smbc_setFunctionChmod(context, SMBC_chmod_ctx);
+        smbc_setFunctionUtimes(context, SMBC_utimes_ctx);
+        smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx);
+        smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx);
+        smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx);
+        smbc_setFunctionListxattr(context, SMBC_listxattr_ctx);
+        
+        smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx);
+        smbc_setFunctionPrintFile(context, SMBC_print_file_ctx);
+        smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx);
+        smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx);
+        
+        return context;
 }
 
 /*
@@ -121,393 +132,283 @@ int
 smbc_free_context(SMBCCTX *context,
                   int shutdown_ctx)
 {
-    if (!context) {
-        errno = EBADF;
-        return 1;
-    }
-    
-    if (shutdown_ctx) {
-        SMBCFILE * f;
-        DEBUG(1,("Performing aggressive shutdown.\n"));
-        
-        f = context->files;
-        while (f) {
-            (context->posix_emu.close_fn)(context, f);
-            f = f->next;
+        if (!context) {
+                errno = EBADF;
+                return 1;
         }
-        context->files = NULL;
         
-        /* First try to remove the servers the nice way. */
-        if (context->cache.purge_cached_server_fn(context)) {
-            SMBCSRV * s;
-            SMBCSRV * next;
-            DEBUG(1, ("Could not purge all servers, "
-                      "Nice way shutdown failed.\n"));
-            s = context->servers;
-            while (s) {
-                DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
-                          s, s->cli->fd));
-                cli_shutdown(s->cli);
-                (context->cache.remove_cached_server_fn)(context,
-                                                         s);
-                next = s->next;
-                DLIST_REMOVE(context->servers, s);
-                SAFE_FREE(s);
-                s = next;
-            }
-            context->servers = NULL;
-        }
-    }
-    else {
-        /* This is the polite way */
-        if ((context->cache.purge_cached_server_fn)(context)) {
-            DEBUG(1, ("Could not purge all servers, "
-                      "free_context failed.\n"));
-            errno = EBUSY;
-            return 1;
-        }
-        if (context->servers) {
-            DEBUG(1, ("Active servers in context, "
-                      "free_context failed.\n"));
-            errno = EBUSY;
-            return 1;
+        if (shutdown_ctx) {
+                SMBCFILE * f;
+                DEBUG(1,("Performing aggressive shutdown.\n"));
+                
+                f = context->internal->files;
+                while (f) {
+                        smbc_getFunctionClose(context)(context, f);
+                        f = f->next;
+                }
+                context->internal->files = NULL;
+                
+                /* First try to remove the servers the nice way. */
+                if (smbc_getFunctionPurgeCachedServers(context)(context)) {
+                        SMBCSRV * s;
+                        SMBCSRV * next;
+                        DEBUG(1, ("Could not purge all servers, "
+                                  "Nice way shutdown failed.\n"));
+                        s = context->internal->servers;
+                        while (s) {
+                                DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
+                                          s, s->cli->fd));
+                                cli_shutdown(s->cli);
+                                smbc_getFunctionRemoveCachedServer(context)(context,
+                                                                         s);
+                                next = s->next;
+                                DLIST_REMOVE(context->internal->servers, s);
+                                SAFE_FREE(s);
+                                s = next;
+                        }
+                        context->internal->servers = NULL;
+                }
         }
-        if (context->files) {
-            DEBUG(1, ("Active files in context, "
-                      "free_context failed.\n"));
-            errno = EBUSY;
-            return 1;
+        else {
+                /* This is the polite way */
+                if (smbc_getFunctionPurgeCachedServers(context)(context)) {
+                        DEBUG(1, ("Could not purge all servers, "
+                                  "free_context failed.\n"));
+                        errno = EBUSY;
+                        return 1;
+                }
+                if (context->internal->servers) {
+                        DEBUG(1, ("Active servers in context, "
+                                  "free_context failed.\n"));
+                        errno = EBUSY;
+                        return 1;
+                }
+                if (context->internal->files) {
+                        DEBUG(1, ("Active files in context, "
+                                  "free_context failed.\n"));
+                        errno = EBUSY;
+                        return 1;
+                }
         }
-    }
-    
-    /* Things we have to clean up */
-    SAFE_FREE(context->workgroup);
-    SAFE_FREE(context->netbios_name);
-    SAFE_FREE(context->user);
-    
-    DEBUG(3, ("Context %p successfully freed\n", context));
-    SAFE_FREE(context);
-    return 0;
+        
+        /* 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));
+
+       SAFE_FREE(context->internal);
+        SAFE_FREE(context);
+
+       if (initialized_ctx_count) {
+               initialized_ctx_count--;
+       }
+
+       if (initialized_ctx_count == 0 && SMBC_initialized) {
+               gencache_shutdown();
+               secrets_shutdown();
+               gfree_all();
+               SMBC_initialized = false;
+       }
+        return 0;
 }
 
 
-/*
- * Each time the context structure is changed, we have binary backward
- * compatibility issues.  Instead of modifying the public portions of the
- * context structure to add new options, instead, we put them in the internal
- * portion of the context structure and provide a set function for these new
- * options.
+/**
+ * Deprecated interface.  Do not use.  Instead, use the various
+ * smbc_setOption*() functions or smbc_setFunctionAuthDataWithContext().
  */
 void
 smbc_option_set(SMBCCTX *context,
                 char *option_name,
                 ... /* option_value */)
 {
-    va_list ap;
-    union {
-        int i;
-        bool b;
-        smbc_get_auth_data_with_context_fn auth_fn;
-        void *v;
-        const char *s;
-    } option_value;
-    
-    va_start(ap, option_name);
-    
-    if (strcmp(option_name, "debug_to_stderr") == 0) {
-        /*
-         * Log to standard error instead of standard output.
-         */
-        option_value.b = (bool) va_arg(ap, int);
-        context->debug_stderr = option_value.b;
-        
-    } else if (strcmp(option_name, "full_time_names") == 0) {
-        /*
-         * Use new-style time attribute names, e.g. WRITE_TIME rather
-         * than the old-style names such as M_TIME.  This allows also
-         * setting/getting CREATE_TIME which was previously
-         * unimplemented.  (Note that the old C_TIME was supposed to
-         * be CHANGE_TIME but was confused and sometimes referred to
-         * CREATE_TIME.)
-         */
-        option_value.b = (bool) va_arg(ap, int);
-        context->full_time_names = option_value.b;
-        
-    } else if (strcmp(option_name, "open_share_mode") == 0) {
-        /*
-         * The share mode to use for files opened with
-         * SMBC_open_ctx().  The default is SMBC_SHAREMODE_DENY_NONE.
-         */
-        option_value.i = va_arg(ap, int);
-        context->share_mode = (smbc_share_mode) option_value.i;
-        
-    } else if (strcmp(option_name, "user_data") == 0) {
-        /*
-         * Save a user data handle which may be retrieved by the user
-         * with smbc_option_get()
-         */
-        option_value.v = va_arg(ap, void *);
-        context->user_data = option_value.v;
-    } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
-        /*
-         * Save an encoded value for encryption level.
-         * 0 = off, 1 = attempt, 2 = required.
-         */
-        option_value.s = va_arg(ap, const char *);
-        if (strcmp(option_value.s, "none") == 0) {
-            context->smb_encryption_level = 0;
-        } else if (strcmp(option_value.s, "request") == 0) {
-            context->smb_encryption_level = 1;
-        } else if (strcmp(option_value.s, "require") == 0) {
-            context->smb_encryption_level = 2;
+        va_list ap;
+        union {
+                int i;
+                bool b;
+                smbc_get_auth_data_with_context_fn auth_fn;
+                void *v;
+                const char *s;
+        } option_value;
+        
+        va_start(ap, option_name);
+        
+        if (strcmp(option_name, "debug_to_stderr") == 0) {
+                option_value.b = (bool) va_arg(ap, int);
+                smbc_setOptionDebugToStderr(context, option_value.b);
+                
+        } else if (strcmp(option_name, "full_time_names") == 0) {
+                option_value.b = (bool) va_arg(ap, int);
+                smbc_setOptionFullTimeNames(context, option_value.b);
+                
+        } else if (strcmp(option_name, "open_share_mode") == 0) {
+                option_value.i = va_arg(ap, int);
+                smbc_setOptionOpenShareMode(context, option_value.i);
+                
+        } else if (strcmp(option_name, "auth_function") == 0) {
+                option_value.auth_fn =
+                        va_arg(ap, smbc_get_auth_data_with_context_fn);
+                smbc_setFunctionAuthDataWithContext(context, option_value.auth_fn);
+                
+        } else if (strcmp(option_name, "user_data") == 0) {
+                option_value.v = va_arg(ap, void *);
+                smbc_setOptionUserData(context, option_value.v);
+                
+        } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+                option_value.s = va_arg(ap, const char *);
+                if (strcmp(option_value.s, "none") == 0) {
+                        smbc_setOptionSmbEncryptionLevel(context,
+                                                         SMBC_ENCRYPTLEVEL_NONE);
+                } else if (strcmp(option_value.s, "request") == 0) {
+                        smbc_setOptionSmbEncryptionLevel(context,
+                                                         SMBC_ENCRYPTLEVEL_REQUEST);
+                } else if (strcmp(option_value.s, "require") == 0) {
+                        smbc_setOptionSmbEncryptionLevel(context,
+                                                         SMBC_ENCRYPTLEVEL_REQUIRE);
+                }
+                
+        } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
+                option_value.i = va_arg(ap, int);
+                smbc_setOptionBrowseMaxLmbCount(context, option_value.i);
+                
+        } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
+                option_value.b = (bool) va_arg(ap, int);
+                smbc_setOptionUrlEncodeReaddirEntries(context, option_value.b);
+                
+        } else if (strcmp(option_name, "one_share_per_server") == 0) {
+                option_value.b = (bool) va_arg(ap, int);
+                smbc_setOptionOneSharePerServer(context, option_value.b);
+                
+        } else if (strcmp(option_name, "use_kerberos") == 0) {
+                option_value.b = (bool) va_arg(ap, int);
+                smbc_setOptionUseKerberos(context, option_value.b);
+                
+        } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
+                option_value.b = (bool) va_arg(ap, int);
+                smbc_setOptionFallbackAfterKerberos(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);
         }
-    } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
-        /*
-         * From how many local master browsers should the list of
-         * workgroups be retrieved?  It can take up to 12 minutes or
-         * longer after a server becomes a local master browser, for
-         * it to have the entire browse list (the list of
-         * workgroups/domains) from an entire network.  Since a client
-         * never knows which local master browser will be found first,
-         * the one which is found first and used to retrieve a browse
-         * list may have an incomplete or empty browse list.  By
-         * requesting the browse list from multiple local master
-         * browsers, a more complete list can be generated.  For small
-         * networks (few workgroups), it is recommended that this
-         * value be set to 0, causing the browse lists from all found
-         * local master browsers to be retrieved and merged.  For
-         * networks with many workgroups, a suitable value for this
-         * variable is probably somewhere around 3. (Default: 3).
-         */
-        option_value.i = va_arg(ap, int);
-        context->browse_max_lmb_count = option_value.i;
-        
-    } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
-        /*
-         * There is a difference in the desired return strings from
-         * smbc_readdir() depending upon whether the filenames are to
-         * be displayed to the user, or whether they are to be
-         * appended to the path name passed to smbc_opendir() to call
-         * a further smbc_ function (e.g. open the file with
-         * smbc_open()).  In the former case, the filename should be
-         * in "human readable" form.  In the latter case, the smbc_
-         * functions expect a URL which must be url-encoded.  Those
-         * functions decode the URL.  If, for example, smbc_readdir()
-         * returned a file name of "abc%20def.txt", passing a path
-         * with this file name attached to smbc_open() would cause
-         * smbc_open to attempt to open the file "abc def.txt" since
-         * the %20 is decoded into a space.
-         *
-         * Set this option to True if the names returned by
-         * smbc_readdir() should be url-encoded such that they can be
-         * passed back to another smbc_ call.  Set it to False if the
-         * names returned by smbc_readdir() are to be presented to the
-         * user.
-         *
-         * For backwards compatibility, this option defaults to False.
-         */
-        option_value.b = (bool) va_arg(ap, int);
-        context->urlencode_readdir_entries = option_value.b;
-        
-    } else if (strcmp(option_name, "one_share_per_server") == 0) {
-        /*
-         * Some Windows versions appear to have a limit to the number
-         * of concurrent SESSIONs and/or TREE CONNECTions.  In
-         * one-shot programs (i.e. the program runs and then quickly
-         * ends, thereby shutting down all connections), it is
-         * probably reasonable to establish a new connection for each
-         * share.  In long-running applications, the limitation can be
-         * avoided by using only a single connection to each server,
-         * and issuing a new TREE CONNECT when the share is accessed.
-         */
-        option_value.b = (bool) va_arg(ap, int);
-        context->one_share_per_server = option_value.b;
-        
-    } else if (strcmp(option_name, "use_kerberos") == 0) {
-        option_value.b = (bool) va_arg(ap, int);
-        context->use_kerberos = option_value.b;
-        
-    } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
-        option_value.b = (bool) va_arg(ap, int);
-        context->fallback_after_kerberos = option_value.b;
         
-    } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
-        option_value.b = (bool) va_arg(ap, int);
-        context->no_auto_anonymous_login = option_value.b;
-    }
-    
-    va_end(ap);
+        va_end(ap);
 }
 
 
 /*
- * Retrieve the current value of an option
+ * Deprecated interface.  Do not use.  Instead, use the various
+ * smbc_getOption*() functions.
  */
 void *
 smbc_option_get(SMBCCTX *context,
                 char *option_name)
 {
-    if (strcmp(option_name, "debug_stderr") == 0) {
-        /*
-         * Log to standard error instead of standard output.
-         */
+        if (strcmp(option_name, "debug_stderr") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->debug_stderr;
+                return (void *) (intptr_t) smbc_getOptionDebugToStderr(context);
 #else
-        return (void *) context->debug_stderr;
+                return (void *) smbc_getOptionDebugToStderr(context);
 #endif
-        
-    } else if (strcmp(option_name, "full_time_names") == 0) {
-        /*
-         * Use new-style time attribute names, e.g. WRITE_TIME rather
-         * than the old-style names such as M_TIME.  This allows also
-         * setting/getting CREATE_TIME which was previously
-         * unimplemented.  (Note that the old C_TIME was supposed to
-         * be CHANGE_TIME but was confused and sometimes referred to
-         * CREATE_TIME.)
-         */
+                
+        } else if (strcmp(option_name, "full_time_names") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->full_time_names;
+                return (void *) (intptr_t) smbc_getOptionFullTimeNames(context);
 #else
-        return (void *) context->full_time_names;
+                return (void *) smbc_getOptionFullTimeNames(context);
 #endif
-        
-    } else if (strcmp(option_name, "user_data") == 0) {
-        /*
-         * Return the user data handle which was saved by the user
-         * with smbc_option_set()
-         */
-        return context->user_data;
-        
-    } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
-        /*
-         * Return the current smb encrypt negotiate option as a string.
-         */
-        switch (context->smb_encryption_level) {
-        case 0:
-            return (void *) "none";
-        case 1:
-            return (void *) "request";
-        case 2:
-            return (void *) "require";
-        }
-        
-    } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
-        /*
-         * Return the current smb encrypt status option as a bool.
-         * false = off, true = on. We don't know what server is
-         * being requested, so we only return true if all servers
-         * are using an encrypted connection.
-         */
-        SMBCSRV *s;
-        unsigned int num_servers = 0;
-        
-        for (s = context->servers; s; s = s->next) {
-            num_servers++;
-            if (s->cli->trans_enc_state == NULL) {
-                return (void *)false;
-            }
-        }
+                
+        } else if (strcmp(option_name, "open_share_mode") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) (bool) (num_servers > 0);
+                return (void *) (intptr_t) smbc_getOptionOpenShareMode(context);
 #else
-        return (void *) (bool) (num_servers > 0);
+                return (void *) smbc_getOptionOpenShareMode(context);
 #endif
-        
-    } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
-        /*
-         * From how many local master browsers should the list of
-         * workgroups be retrieved?  It can take up to 12 minutes or
-         * longer after a server becomes a local master browser, for
-         * it to have the entire browse list (the list of
-         * workgroups/domains) from an entire network.  Since a client
-         * never knows which local master browser will be found first,
-         * the one which is found first and used to retrieve a browse
-         * list may have an incomplete or empty browse list.  By
-         * requesting the browse list from multiple local master
-         * browsers, a more complete list can be generated.  For small
-         * networks (few workgroups), it is recommended that this
-         * value be set to 0, causing the browse lists from all found
-         * local master browsers to be retrieved and merged.  For
-         * networks with many workgroups, a suitable value for this
-         * variable is probably somewhere around 3. (Default: 3).
-         */
+                
+        } else if (strcmp(option_name, "auth_function") == 0) {
+                return (void *) smbc_getFunctionAuthDataWithContext(context);
+                
+        } else if (strcmp(option_name, "user_data") == 0) {
+                return smbc_getOptionUserData(context);
+                
+        } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+                switch(smbc_getOptionSmbEncryptionLevel(context))
+                {
+                case 0:
+                        return (void *) "none";
+                case 1:
+                        return (void *) "request";
+                case 2:
+                        return (void *) "require";
+                }
+                
+        } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
+                SMBCSRV *s;
+                unsigned int num_servers = 0;
+                
+                for (s = context->internal->servers; s; s = s->next) {
+                        num_servers++;
+                        if (s->cli->trans_enc_state == NULL) {
+                                return (void *)false;
+                        }
+                }
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->browse_max_lmb_count;
+                return (void *) (intptr_t) (bool) (num_servers > 0);
 #else
-        return (void *) context->browse_max_lmb_count;
+                return (void *) (bool) (num_servers > 0);
 #endif
-        
-    } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
-        /*
-         * There is a difference in the desired return strings from
-         * smbc_readdir() depending upon whether the filenames are to
-         * be displayed to the user, or whether they are to be
-         * appended to the path name passed to smbc_opendir() to call
-         * a further smbc_ function (e.g. open the file with
-         * smbc_open()).  In the former case, the filename should be
-         * in "human readable" form.  In the latter case, the smbc_
-         * functions expect a URL which must be url-encoded.  Those
-         * functions decode the URL.  If, for example, smbc_readdir()
-         * returned a file name of "abc%20def.txt", passing a path
-         * with this file name attached to smbc_open() would cause
-         * smbc_open to attempt to open the file "abc def.txt" since
-         * the %20 is decoded into a space.
-         *
-         * Set this option to True if the names returned by
-         * smbc_readdir() should be url-encoded such that they can be
-         * passed back to another smbc_ call.  Set it to False if the
-         * names returned by smbc_readdir() are to be presented to the
-         * user.
-         *
-         * For backwards compatibility, this option defaults to False.
-         */
+                
+        } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->urlencode_readdir_entries;
+                return (void *) (intptr_t) smbc_getOptionBrowseMaxLmbCount(context);
 #else
-        return (void *) (bool) context->urlencode_readdir_entries;
+                return (void *) smbc_getOptionBrowseMaxLmbCount(context);
 #endif
-        
-    } else if (strcmp(option_name, "one_share_per_server") == 0) {
-        /*
-         * Some Windows versions appear to have a limit to the number
-         * of concurrent SESSIONs and/or TREE CONNECTions.  In
-         * one-shot programs (i.e. the program runs and then quickly
-         * ends, thereby shutting down all connections), it is
-         * probably reasonable to establish a new connection for each
-         * share.  In long-running applications, the limitation can be
-         * avoided by using only a single connection to each server,
-         * and issuing a new TREE CONNECT when the share is accessed.
-         */
+                
+        } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->one_share_per_server;
+                return (void *)(intptr_t) smbc_getOptionUrlEncodeReaddirEntries(context);
 #else
-        return (void *) (bool) context->one_share_per_server;
+                return (void *) (bool) smbc_getOptionUrlEncodeReaddirEntries(context);
 #endif
-        
-    } else if (strcmp(option_name, "use_kerberos") == 0) {
+                
+        } else if (strcmp(option_name, "one_share_per_server") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->use_kerberos;
+                return (void *) (intptr_t) smbc_getOptionOneSharePerServer(context);
 #else
-        return (void *) (bool) context->use_kerberos;
+                return (void *) (bool) smbc_getOptionOneSharePerServer(context);
 #endif
-        
-    } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
+                
+        } else if (strcmp(option_name, "use_kerberos") == 0) {
 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-        return (void *) (intptr_t) context->fallback_after_kerberos;
+                return (void *) (intptr_t) smbc_getOptionUseKerberos(context);
 #else
-        return (void *) (bool) context->fallback_after_kerberos;
+                return (void *) (bool) smbc_getOptionUseKerberos(context);
 #endif
-        
-    } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
+                
+        } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+                return (void *)(intptr_t) smbc_getOptionFallbackAfterKerberos(context);
+#else
+                return (void *) (bool) smbc_getOptionFallbackAfterKerberos(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) context->no_auto_anonymous_login;
+                return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context);
 #else
-        return (void *) (bool) context->no_auto_anonymous_login;
+                return (void *) (bool) smbc_getOptionNoAutoAnonymousLogin(context);
 #endif
-    }
-    
-    return NULL;
+        }
+        
+        return NULL;
 }
 
 
@@ -521,175 +422,199 @@ smbc_option_get(SMBCCTX *context,
 SMBCCTX *
 smbc_init_context(SMBCCTX *context)
 {
-    int pid;
-    char *user = NULL;
-    char *home = NULL;
-    extern bool in_client;
-    
-    if (!context) {
-        errno = EBADF;
-        return NULL;
-    }
-    
-    /* Do not initialise the same client twice */
-    if (context->initialized) {
-        return 0;
-    }
-    
-    if (!context->server.get_auth_data_fn ||
-        context->debug < 0 ||
-        context->debug > 100) {
-        
-        errno = EINVAL;
-        return NULL;
-        
-    }
-    
-    if (!SMBC_initialized) {
-        /*
-         * Do some library-wide intializations the first time we get
-         * called
-         */
-        bool conf_loaded = False;
-        TALLOC_CTX *frame = talloc_stackframe();
+        int pid;
+        char *user = NULL;
+        char *home = NULL;
         
-        /* Set this to what the user wants */
-        DEBUGLEVEL = context->debug;
-        
-        load_case_tables();
+        if (!context) {
+                errno = EBADF;
+                return NULL;
+        }
         
-        setup_logging("libsmbclient", True);
-        if (context->debug_stderr) {
-            dbf = x_stderr;
-            x_setbuf(x_stderr, NULL);
+        /* Do not initialise the same client twice */
+        if (context->internal->initialized) {
+                return NULL;
         }
         
-        /* Here we would open the smb.conf file if needed ... */
+        if ((!smbc_getFunctionAuthData(context) &&
+             !smbc_getFunctionAuthDataWithContext(context)) ||
+            smbc_getDebug(context) < 0 ||
+            smbc_getDebug(context) > 100) {
+                
+                errno = EINVAL;
+                return NULL;
+                
+        }
         
-        in_client = True; /* FIXME, make a param */
+        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);
+        }
         
-        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;
+        if (!smbc_getUser(context)) {
+                /*
+                 * FIXME: Is this the best way to get the user info?
+                 */
+                user = getenv("USER");
+                /* walk around as "guest" if no username can be found */
+                if (!user) {
+                        user = SMB_STRDUP("guest");
                 } else {
-                    DEBUG(5, ("Could not load config file: %s\n",
-                              conf));
+                        user = SMB_STRDUP(user);
+                }
+
+                if (!user) {
+                        errno = ENOMEM;
+                        return NULL;
                 }
-                SAFE_FREE(conf);
-            }
+
+                smbc_setUser(context, user);
         }
         
-        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;
+        if (!smbc_getNetbiosName(context)) {
                 /*
-                 * We loaded the global config file.  Now lets
-                 * load user-specific modifications to the
-                 * global config.
+                 * We try to get our netbios name from the config. If that
+                 * fails we fall back on constructing our netbios name from
+                 * our hostname etc
                  */
-                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);
+                char *netbios_name;
+                if (global_myname()) {
+                        netbios_name = SMB_STRDUP(global_myname());
+                } else {
+                        /*
+                         * Hmmm, I want to get hostname as well, but I am too
+                         * lazy for the moment
+                         */
+                        pid = sys_getpid();
+                        netbios_name = (char *)SMB_MALLOC(17);
+                        if (!netbios_name) {
+                                errno = ENOMEM;
+                                return NULL;
+                        }
+                        slprintf(netbios_name, 16,
+                                 "smbc%s%d", smbc_getUser(context), pid);
+                }
+
+                if (!netbios_name) {
+                        errno = ENOMEM;
+                        return NULL;
                 }
-            }
+                
+                smbc_setNetbiosName(context, netbios_name);
         }
         
-        load_interfaces();  /* Load the list of interfaces ... */
+        DEBUG(1, ("Using netbios name %s.\n", smbc_getNetbiosName(context)));
         
-        reopen_logs();  /* Get logging working ... */
+        if (!smbc_getWorkgroup(context)) {
+                char *workgroup;
+
+                if (lp_workgroup()) {
+                        workgroup = SMB_STRDUP(lp_workgroup());
+                }
+                else {
+                        /* TODO: Think about a decent default workgroup */
+                        workgroup = SMB_STRDUP("samba");
+                }
+
+                if (!workgroup) {
+                        errno = ENOMEM;
+                        return NULL;
+                }
+
+                smbc_setWorkgroup(context, workgroup);
+        }
         
-        /*
-         * Block SIGPIPE (from lib/util_sock.c: write())
-         * It is not needed and should not stop execution
-         */
-        BlockSignals(True, SIGPIPE);
+        DEBUG(1, ("Using workgroup %s.\n", smbc_getWorkgroup(context)));
         
-        /* Done with one-time initialisation */
-        SMBC_initialized = 1;
+        /* shortest timeout is 1 second */
+        if (smbc_getTimeout(context) > 0 && smbc_getTimeout(context) < 1000)
+                smbc_setTimeout(context, 1000);
         
-        TALLOC_FREE(frame);
-    }
-    
-    if (!context->user) {
-        /*
-         * FIXME: Is this the best way to get the user info?
-         */
-        user = getenv("USER");
-        /* walk around as "guest" if no username can be found */
-        if (!user) context->user = SMB_STRDUP("guest");
-        else context->user = SMB_STRDUP(user);
-    }
-    
-    if (!context->netbios_name) {
         /*
-         * We try to get our netbios name from the config. If that
-         * fails we fall back on constructing our netbios name from
-         * our hostname etc
+         * FIXME: Should we check the function pointers here?
          */
-        if (global_myname()) {
-            context->netbios_name = SMB_STRDUP(global_myname());
-        }
-        else {
-            /*
-             * Hmmm, I want to get hostname as well, but I am too
-             * lazy for the moment
-             */
-            pid = sys_getpid();
-            context->netbios_name = (char *)SMB_MALLOC(17);
-            if (!context->netbios_name) {
-                errno = ENOMEM;
-                return NULL;
-            }
-            slprintf(context->netbios_name, 16,
-                     "smbc%s%d", context->user, pid);
-        }
-    }
-    
-    DEBUG(1, ("Using netbios name %s.\n", context->netbios_name));
-    
-    if (!context->workgroup) {
-        if (lp_workgroup()) {
-            context->workgroup = SMB_STRDUP(lp_workgroup());
-        }
-        else {
-            /* TODO: Think about a decent default workgroup */
-            context->workgroup = SMB_STRDUP("samba");
-        }
-    }
-    
-    DEBUG(1, ("Using workgroup %s.\n", context->workgroup));
-    
-    /* shortest timeout is 1 second */
-    if (context->timeout > 0 && context->timeout < 1000)
-        context->timeout = 1000;
-    
-    /*
-     * FIXME: Should we check the function pointers here?
-     */
-    
-    context->initialized = True;
-    
-    return context;
+        
+        context->internal->initialized = True;
+       initialized_ctx_count++;
+
+        return context;
 }
 
 
@@ -697,587 +622,63 @@ smbc_init_context(SMBCCTX *context)
 const char *
 smbc_version(void)
 {
-    return samba_version_string();
-}
-
-
-/** Get the netbios name used for making connections */
-char *
-smbc_getNetbiosName(SMBCCTX *c)
-{
-    return c->netbios_name;
-}
-
-/** Set the netbios name used for making connections */
-void
-smbc_setNetbiosName(SMBCCTX *c, char * netbios_name)
-{
-    c->netbios_name = netbios_name;
-}
-
-/** Get the workgroup used for making connections */
-char *
-smbc_getWorkgroup(SMBCCTX *c)
-{
-    return c->workgroup;
-}
-
-/** Set the workgroup used for making connections */
-void
-smbc_setWorkgroup(SMBCCTX *c, char * workgroup)
-{
-    c->workgroup = workgroup;
-}
-
-/** Get the username used for making connections */
-char *
-smbc_getUser(SMBCCTX *c)
-{
-    return c->user;
-}
-
-/** Set the username used for making connections */
-void
-smbc_setUser(SMBCCTX *c, char * user)
-{
-    c->user = user;
-}
-
-/** Get the debug level */
-int
-smbc_getDebug(SMBCCTX *c)
-{
-    return c->debug;
-}
-
-/** Set the debug level */
-void
-smbc_setDebug(SMBCCTX *c, int debug)
-{
-    c->debug = debug;
-}
-
-/**
- * Get the timeout used for waiting on connections and response data
- * (in milliseconds)
- */
-int
-smbc_getTimeout(SMBCCTX *c)
-{
-    return c->timeout;
-}
-
-/**
- * Set the timeout used for waiting on connections and response data
- * (in milliseconds)
- */
-void
-smbc_setTimeout(SMBCCTX *c, int timeout)
-{
-    c->timeout = timeout;
-}
-
-/** Get the function for obtaining authentication data */
-
-smbc_get_auth_data_fn
-smbc_getFunctionAuthData(SMBCCTX *c)
-{
-    return c->server.get_auth_data_fn;
-}
-
-/** Set the function for obtaining authentication data */
-void
-smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn)
-{
-    c->server.get_auth_data_fn = fn;
-}
-
-/** Get the function for checking if a server is still good */
-smbc_check_server_fn
-smbc_getFunctionCheckServer(SMBCCTX *c)
-{
-    return c->server.check_server_fn;
-}
-
-/** Set the function for checking if a server is still good */
-void
-smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn)
-{
-    c->server.check_server_fn = fn;
-}
-
-/** Get the function for removing a server if unused */
-smbc_remove_unused_server_fn
-smbc_getFunctionRemoveUnusedServer(SMBCCTX *c)
-{
-    return c->server.remove_unused_server_fn;
-}
-
-/** Set the function for removing a server if unused */
-void
-smbc_setFunctionRemoveUnusedServer(SMBCCTX *c,
-                                   smbc_remove_unused_server_fn fn)
-{
-    c->server.remove_unused_server_fn = fn;
-}
-
-/** Get the function to store private data of the server cache */
-struct
-smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c)
-{
-    return c->cache.server_cache_data;
-}
-
-/** Set the function to store private data of the server cache */
-void
-smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache)
-{
-    c->cache.server_cache_data = cache;
-}
-
-
-/** Get the function for adding a cached server */
-smbc_add_cached_srv_fn
-smbc_getFunctionAddCachedServer(SMBCCTX *c)
-{
-    return c->cache.add_cached_server_fn;
-}
-
-/** Set the function for adding a cached server */
-void
-smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn)
-{
-    c->cache.add_cached_server_fn = fn;
-}
-
-/** Get the function for server cache lookup */
-smbc_get_cached_srv_fn
-smbc_getFunctionGetCachedServer(SMBCCTX *c)
-{
-    return c->cache.get_cached_server_fn;
-}
-
-/** Set the function for server cache lookup */
-void
-smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn)
-{
-    c->cache.get_cached_server_fn = fn;
-}
-
-/** Get the function for server cache removal */
-smbc_remove_cached_srv_fn
-smbc_getFunctionRemoveCachedServer(SMBCCTX *c)
-{
-    return c->cache.remove_cached_server_fn;
-}
-
-/** Set the function for server cache removal */
-void
-smbc_setFunctionRemoveCachedServer(SMBCCTX *c,
-                                   smbc_remove_cached_srv_fn fn)
-{
-    c->cache.remove_cached_server_fn = fn;
-}
-
-/**
- * Get the function for server cache purging.  This function tries to
- * remove all cached servers (e.g. on disconnect)
- */
-smbc_purge_cached_srv_fn
-smbc_getFunctionPurgeCachedServers(SMBCCTX *c)
-{
-    return c->cache.purge_cached_server_fn;
-}
-
-/**
- * Set the function for server cache purging.  This function tries to
- * remove all cached servers (e.g. on disconnect)
- */
-void
-smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn)
-{
-    c->cache.purge_cached_server_fn = fn;
-}
-
-/**
- * Callable functions for files.
- */
-
-smbc_open_fn
-smbc_getFunctionOpen(SMBCCTX *c)
-{
-    return c->posix_emu.open_fn;
-}
-
-void
-smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn)
-{
-    c->posix_emu.open_fn = fn;
-}
-
-smbc_creat_fn
-smbc_getFunctionCreat(SMBCCTX *c)
-{
-    return c->posix_emu.creat_fn;
-}
-
-void
-smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn)
-{
-    c->posix_emu.creat_fn = fn;
-}
-
-smbc_read_fn
-smbc_getFunctionRead(SMBCCTX *c)
-{
-    return c->posix_emu.read_fn;
-}
-
-void
-smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn)
-{
-    c->posix_emu.read_fn = fn;
-}
-
-smbc_write_fn
-smbc_getFunctionWrite(SMBCCTX *c)
-{
-    return c->posix_emu.write_fn;
-}
-
-void
-smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn)
-{
-    c->posix_emu.write_fn = fn;
-}
-
-smbc_unlink_fn
-smbc_getFunctionUnlink(SMBCCTX *c)
-{
-    return c->posix_emu.unlink_fn;
-}
-
-void
-smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn)
-{
-    c->posix_emu.unlink_fn = fn;
-}
-
-smbc_rename_fn
-smbc_getFunctionRename(SMBCCTX *c)
-{
-    return c->posix_emu.rename_fn;
-}
-
-void
-smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn)
-{
-    c->posix_emu.rename_fn = fn;
-}
-
-smbc_lseek_fn
-smbc_getFunctionLseek(SMBCCTX *c)
-{
-    return c->posix_emu.lseek_fn;
-}
-
-void
-smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn)
-{
-    c->posix_emu.lseek_fn = fn;
-}
-
-smbc_stat_fn
-smbc_getFunctionStat(SMBCCTX *c)
-{
-    return c->posix_emu.stat_fn;
-}
-
-void
-smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn)
-{
-    c->posix_emu.stat_fn = fn;
-}
-
-smbc_fstat_fn
-smbc_getFunctionFstat(SMBCCTX *c)
-{
-    return c->posix_emu.fstat_fn;
-}
-
-void
-smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn)
-{
-    c->posix_emu.fstat_fn = fn;
-}
-
-smbc_ftruncate_fn
-smbc_getFunctionFtruncate(SMBCCTX *c)
-{
-    return c->posix_emu.ftruncate_fn;
-}
-
-void
-smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn)
-{
-    c->posix_emu.ftruncate_fn = fn;
-}
-
-smbc_close_fn
-smbc_getFunctionClose(SMBCCTX *c)
-{
-    return c->posix_emu.close_fn;
-}
-
-void
-smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn)
-{
-    c->posix_emu.close_fn = fn;
-}
-
-
-/**
- * Callable functions for directories.
- */
-
-smbc_opendir_fn
-smbc_getFunctionOpendir(SMBCCTX *c)
-{
-    return c->posix_emu.opendir_fn;
-}
-
-void
-smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn)
-{
-    c->posix_emu.opendir_fn = fn;
-}
-
-smbc_closedir_fn
-smbc_getFunctionClosedir(SMBCCTX *c)
-{
-    return c->posix_emu.closedir_fn;
-}
-
-void
-smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn)
-{
-    c->posix_emu.closedir_fn = fn;
-}
-
-smbc_readdir_fn
-smbc_getFunctionReaddir(SMBCCTX *c)
-{
-    return c->posix_emu.readdir_fn;
-}
-
-void
-smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn)
-{
-    c->posix_emu.readdir_fn = fn;
-}
-
-smbc_getdents_fn
-smbc_getFunctionGetdents(SMBCCTX *c)
-{
-    return c->posix_emu.getdents_fn;
-}
-
-void
-smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn)
-{
-    c->posix_emu.getdents_fn = fn;
-}
-
-smbc_mkdir_fn
-smbc_getFunctionMkdir(SMBCCTX *c)
-{
-    return c->posix_emu.mkdir_fn;
-}
-
-void
-smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn)
-{
-    c->posix_emu.mkdir_fn = fn;
-}
-
-smbc_rmdir_fn
-smbc_getFunctionRmdir(SMBCCTX *c)
-{
-    return c->posix_emu.rmdir_fn;
-}
-
-void
-smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn)
-{
-    c->posix_emu.rmdir_fn = fn;
-}
-
-smbc_telldir_fn
-smbc_getFunctionTelldir(SMBCCTX *c)
-{
-    return c->posix_emu.telldir_fn;
-}
-
-void
-smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn)
-{
-    c->posix_emu.telldir_fn = fn;
-}
-
-smbc_lseekdir_fn
-smbc_getFunctionLseekdir(SMBCCTX *c)
-{
-    return c->posix_emu.lseekdir_fn;
-}
-
-void
-smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn)
-{
-    c->posix_emu.lseekdir_fn = fn;
-}
-
-smbc_fstatdir_fn
-smbc_getFunctionFstatdir(SMBCCTX *c)
-{
-    return c->posix_emu.fstatdir_fn;
-}
-
-void
-smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn)
-{
-    c->posix_emu.fstatdir_fn = fn;
-}
-
-
-/**
- * Callable functions applicable to both files and directories.
- */
-
-smbc_chmod_fn
-smbc_getFunctionChmod(SMBCCTX *c)
-{
-    return c->posix_emu.chmod_fn;
-}
-
-void
-smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn)
-{
-    c->posix_emu.chmod_fn = fn;
-}
-
-smbc_utimes_fn
-smbc_getFunctionUtimes(SMBCCTX *c)
-{
-    return c->posix_emu.utimes_fn;
-}
-
-void
-smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn)
-{
-    c->posix_emu.utimes_fn = fn;
-}
-
-smbc_setxattr_fn
-smbc_getFunctionSetxattr(SMBCCTX *c)
-{
-    return c->posix_emu.setxattr_fn;
-}
-
-void
-smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn)
-{
-    c->posix_emu.setxattr_fn = fn;
-}
-
-smbc_getxattr_fn
-smbc_getFunctionGetxattr(SMBCCTX *c)
-{
-    return c->posix_emu.getxattr_fn;
-}
-
-void
-smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn)
-{
-    c->posix_emu.getxattr_fn = fn;
-}
-
-smbc_removexattr_fn
-smbc_getFunctionRemovexattr(SMBCCTX *c)
-{
-    return c->posix_emu.removexattr_fn;
-}
-
-void
-smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn)
-{
-    c->posix_emu.removexattr_fn = fn;
+        return SAMBA_VERSION_STRING;
 }
 
-smbc_listxattr_fn
-smbc_getFunctionListxattr(SMBCCTX *c)
-{
-    return c->posix_emu.listxattr_fn;
-}
-
-void
-smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn)
-{
-    c->posix_emu.listxattr_fn = fn;
-}
 
-
-/**
- * Callable functions related to printing
+/*
+ * Set the credentials so DFS will work when following referrals.
  */
-
-smbc_print_file_fn
-smbc_getFunctionPrintFile(SMBCCTX *c)
-{
-    return c->printing.print_file_fn;
-}
-
 void
-smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn)
+smbc_set_credentials(const char *workgroup,
+                     const char *user,
+                     const char *password,
+                     smbc_bool use_kerberos,
+                     const char *signing_state)
 {
-    c->printing.print_file_fn = fn;
+        
+        set_cmdline_auth_info_username(user);
+        set_cmdline_auth_info_password(password);
+        set_cmdline_auth_info_use_kerberos(use_kerberos);
+        if (! set_cmdline_auth_info_signing_state(signing_state)) {
+                DEBUG(0, ("Invalid signing state: %s", signing_state));
+        }
+        set_global_myworkgroup(workgroup);
+        cli_cm_set_credentials();
 }
 
-smbc_open_print_job_fn
-smbc_getFunctionOpenPrintJob(SMBCCTX *c)
+void smbc_set_credentials_with_fallback(SMBCCTX *context,
+                                       const char *workgroup,
+                                       const char *user,
+                                       const char *password)
 {
-    return c->printing.open_print_job_fn;
-}
+       smbc_bool use_kerberos = false;
+       const char *signing_state = "off";
+       
+       if (!context ||
+           ! workgroup || ! *workgroup ||
+           ! user || ! *user ||
+           ! password || ! *password) {
+           
+               return;
+       }
 
-void
-smbc_setFunctionOpenPrintJob(SMBCCTX *c,
-                             smbc_open_print_job_fn fn)
-{
-    c->printing.open_print_job_fn = fn;
-}
+       if (smbc_getOptionUseKerberos(context)) {
+               use_kerberos = True;
+       }
 
-smbc_list_print_jobs_fn
-smbc_getFunctionListPrintJobs(SMBCCTX *c)
-{
-    return c->printing.list_print_jobs_fn;
-}
+       if (lp_client_signing()) {
+               signing_state = "on";
+       }
 
-void
-smbc_setFunctionListPrintJobs(SMBCCTX *c,
-                              smbc_list_print_jobs_fn fn)
-{
-    c->printing.list_print_jobs_fn = fn;
-}
+       if (lp_client_signing() == Required) {
+               signing_state = "force";
+       }
 
-smbc_unlink_print_job_fn
-smbc_getFunctionUnlinkPrintJob(SMBCCTX *c)
-{
-    return c->printing.unlink_print_job_fn;
-}
+       smbc_set_credentials(workgroup, user, password,
+                             use_kerberos, signing_state);
 
-void
-smbc_setFunctionUnlinkPrintJob(SMBCCTX *c,
-                                smbc_unlink_print_job_fn fn)
-{
-    c->printing.unlink_print_job_fn = fn;
+       if (smbc_getOptionFallbackAfterKerberos(context)) {
+               cli_cm_set_fallback_after_kerberos();
+       }
 }
-