r14664: r13868@cabra: derrell | 2006-03-22 17:04:30 -0500
authorDerrell Lipman <derrell@samba.org>
Wed, 22 Mar 2006 22:05:19 +0000 (22:05 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:15:42 +0000 (11:15 -0500)
 Implement enhancement request 3505.  Two additional features are added here.
 There is now a method of saving an opaque user data handle in the smbc_
 context, and there is now a way to request that the context be passed to the
 authentication function.  See examples/libsmbclient/testbrowse.c for an example
 of using these features.
(This used to be commit 203b4911c16bd7e10198a6f0e63960f2813025ef)

examples/libsmbclient/get_auth_data_fn.h
examples/libsmbclient/testbrowse.c
source3/include/libsmb_internal.h
source3/include/libsmbclient.h
source3/libsmb/libsmbclient.c

index 2954039..eb49388 100644 (file)
@@ -7,7 +7,6 @@ get_auth_data_fn(const char * pServer,
                  int maxLenUsername,
                  char * pPassword,
                  int maxLenPassword)
-    
 {
     char temp[128];
     
index ca126c9..96f78aa 100644 (file)
@@ -24,6 +24,16 @@ static void browse(char * path,
                    int indent);
 
 
+static void
+get_auth_data_with_context_fn(SMBCCTX * context,
+                              const char * pServer,
+                              const char * pShare,
+                              char * pWorkgroup,
+                              int maxLenWorkgroup,
+                              char * pUsername,
+                              int maxLenUsername,
+                              char * pPassword,
+                              int maxLenPassword);
 
 int
 main(int argc, char * argv[])
@@ -31,6 +41,7 @@ main(int argc, char * argv[])
     int                         debug = 0;
     int                         debug_stderr = 0;
     int                         no_auth = 0;
+    int                         context_auth = 0;
     int                         scan = 0;
     int                         iterations = -1;
     int                         again;
@@ -63,6 +74,10 @@ main(int argc, char * argv[])
                 "noauth", 'A', POPT_ARG_NONE, &no_auth,
                 0, "Do not request authentication data", "integer"
             },
+            {
+                "contextauth", 'C', POPT_ARG_NONE, &context_auth,
+                0, "Use new authentication function with context", "integer"
+            },
             {
                 NULL
             }
@@ -94,12 +109,21 @@ main(int argc, char * argv[])
 
     /* Set mandatory options (is that a contradiction in terms?) */
     context->debug = debug;
-    context->callbacks.auth_fn = (no_auth ? no_auth_data_fn : get_auth_data_fn);
+    if (context_auth) {
+        context->callbacks.auth_fn = NULL;
+        smbc_option_set(context,
+                        "auth_function",
+                        (void *) get_auth_data_with_context_fn);
+        smbc_option_set(context, "user_data", "hello world");
+    } else {
+        context->callbacks.auth_fn =
+            (no_auth ? no_auth_data_fn : get_auth_data_fn);
+    }
 
     /* If we've been asked to log to stderr instead of stdout... */
     if (debug_stderr) {
         /* ... then set the option to do so */
-        smbc_option_set(context, "debug_stderr");
+        smbc_option_set(context, "debug_stderr", (void *) 1);
     }
        
     /* Initialize the context using the previously specified options */
@@ -161,6 +185,29 @@ no_auth_data_fn(const char * pServer,
     return;
 }
 
+
+static void
+get_auth_data_with_context_fn(SMBCCTX * context,
+                              const char * pServer,
+                              const char * pShare,
+                              char * pWorkgroup,
+                              int maxLenWorkgroup,
+                              char * pUsername,
+                              int maxLenUsername,
+                              char * pPassword,
+                              int maxLenPassword)
+{
+    printf("Authenticating with context 0x%lx", context);
+    if (context != NULL) {
+        char *user_data = smbc_option_get(context, "user_data");
+        printf(" with user data %s", user_data);
+    }
+    printf("\n");
+
+    get_auth_data_fn(pServer, pShare, pWorkgroup, maxLenWorkgroup,
+                     pUsername, maxLenUsername, pPassword, maxLenPassword);
+}
+
 static void browse(char * path, int scan, int indent)
 {
     char *                      p;
index 0426430..5aca125 100644 (file)
@@ -79,6 +79,18 @@ struct smbc_internal_data {
          * Log to standard error instead of the more typical standard output
          */
         BOOL _debug_stderr;
+
+        /*
+         * Authentication function which includes the context.  This will be
+         * used if set; otherwise context->callbacks.auth_fn() will be used.
+         */
+        smbc_get_auth_data_with_context_fn _auth_fn_with_context;
+
+        /*
+         * An opaque (to this library) user data handle which can be set
+         * and retrieved with smbc_option_set() and smbc_option_get().
+         */
+        void * _user_data;
 };     
 
 
index 6d3a0cd..ba92259 100644 (file)
@@ -204,7 +204,7 @@ typedef struct _SMBCCTX SMBCCTX;
 
 
 /**@ingroup callback
- * Authentication callback function type.
+ * Authentication callback function type (traditional method)
  * 
  * Type for the the authentication function called by the library to
  * obtain authentication credentals
@@ -237,6 +237,43 @@ typedef void (*smbc_get_auth_data_fn)(const char *srv,
                                       char *wg, int wglen, 
                                       char *un, int unlen,
                                       char *pw, int pwlen);
+/**@ingroup callback
+ * Authentication callback function type (method that includes context)
+ * 
+ * Type for the the authentication function called by the library to
+ * obtain authentication credentals
+ *
+ * @param c         Pointer to the smb context
+ *
+ * @param srv       Server being authenticated to
+ *
+ * @param shr       Share being authenticated to
+ *
+ * @param wg        Pointer to buffer containing a "hint" for the
+ *                  workgroup to be authenticated.  Should be filled in
+ *                  with the correct workgroup if the hint is wrong.
+ * 
+ * @param wglen     The size of the workgroup buffer in bytes
+ *
+ * @param un        Pointer to buffer containing a "hint" for the
+ *                  user name to be use for authentication. Should be
+ *                  filled in with the correct workgroup if the hint is
+ *                  wrong.
+ * 
+ * @param unlen     The size of the username buffer in bytes
+ *
+ * @param pw        Pointer to buffer containing to which password 
+ *                  copied
+ * 
+ * @param pwlen     The size of the password buffer in bytes
+ *           
+ */
+typedef void (*smbc_get_auth_data_with_context_fn)(SMBCCTX *c,
+                                                   const char *srv, 
+                                                   const char *shr,
+                                                   char *wg, int wglen, 
+                                                   char *un, int unlen,
+                                                   char *pw, int pwlen);
 
 
 /**@ingroup callback
@@ -422,14 +459,15 @@ struct _SMBCCTX {
        int        (*unlink_print_job)(SMBCCTX *c, const char *fname, int id);
 
 
-       /** Callbacks
-        * These callbacks _always_ have to be initialized because they will not be checked
-        * at dereference for increased speed.
-        */
+        /*
+        ** Callbacks
+        * These callbacks _always_ have to be initialized because they will
+        * not be checked at dereference for increased speed.
+        */
        struct _smbc_callbacks {
                /** authentication function callback: called upon auth requests
                 */
-               smbc_get_auth_data_fn auth_fn;
+                smbc_get_auth_data_fn auth_fn;
                
                /** check if a server is still good
                 */
@@ -578,6 +616,41 @@ SMBCCTX * smbc_new_context(void);
 int smbc_free_context(SMBCCTX * context, int shutdown_ctx);
 
 
+/**@ingroup misc
+ * 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.
+ *
+ * @param context   A pointer to a SMBCCTX obtained from smbc_new_context()
+ *
+ * @param option_name
+ *                  The name of the option for which the value is to be set
+ *
+ * @param option_value
+ *                  The new value of the option being set
+ *
+ */
+void
+smbc_option_set(SMBCCTX *context,
+                char *option_name,
+                void *option_value);
+/*
+ * Retrieve the current value of an option
+ *
+ * @param context   A pointer to a SMBCCTX obtained from smbc_new_context()
+ *
+ * @param option_name
+ *                  The name of the option for which the value is to be
+ *                  retrieved
+ *
+ * @return          The value of the specified option.
+ */
+void *
+smbc_option_get(SMBCCTX *context,
+                char *option_name);
+
 /**@ingroup misc
  * Initialize a SBMCCTX (a context).
  *
@@ -585,16 +658,19 @@ int smbc_free_context(SMBCCTX * context, int shutdown_ctx);
  *
  * @param context   A pointer to a SMBCCTX obtained from smbc_new_context()
  *
- * @return          A pointer to the given SMBCCTX on success, NULL on error with errno set:
+ * @return          A pointer to the given SMBCCTX on success,
+ *                  NULL on error with errno set:
  *                  - EBADF  NULL context given
  *                  - ENOMEM Out of memory
  *                  - ENOENT The smb.conf file would not load
  *
  * @see             smbc_new_context()
  *
- * @note            my_context = smbc_init_context(smbc_new_context()) is perfectly safe, 
- *                  but it might leak memory on smbc_context_init() failure. Avoid this.
- *                  You'll have to call smbc_free_context() yourself on failure.  
+ * @note            my_context = smbc_init_context(smbc_new_context())
+ *                  is perfectly safe, but it might leak memory on
+ *                  smbc_context_init() failure. Avoid this.
+ *                  You'll have to call smbc_free_context() yourself
+ *                  on failure.  
  */
 
 SMBCCTX * smbc_init_context(SMBCCTX * context);
index b807028..2436cc9 100644 (file)
@@ -552,10 +552,21 @@ find_server(SMBCCTX *context,
                                                   workgroup, username);
 
        if (!auth_called && !srv && (!username[0] || !password[0])) {
-               context->callbacks.auth_fn(server, share,
-                                           workgroup, sizeof(fstring),
-                                           username, sizeof(fstring),
-                                           password, sizeof(fstring));
+                if (context->internal->_auth_fn_with_context != NULL) {
+                         context->internal->_auth_fn_with_context(
+                                context,
+                                server, share,
+                                workgroup, sizeof(fstring),
+                                username, sizeof(fstring),
+                                password, sizeof(fstring));
+                } else {
+                        context->callbacks.auth_fn(
+                                server, share,
+                                workgroup, sizeof(fstring),
+                                username, sizeof(fstring),
+                                password, sizeof(fstring));
+                }
+
                /*
                  * However, smbc_auth_fn may have picked up info relating to
                  * an existing connection, so try for an existing connection
@@ -657,10 +668,20 @@ smbc_server(SMBCCTX *context,
                  */
                 if (srv->cli.cnum == (uint16) -1) {
                         /* Ensure we have accurate auth info */
-                        context->callbacks.auth_fn(server, share,
-                                                   workgroup, sizeof(fstring),
-                                                   username, sizeof(fstring),
-                                                   password, sizeof(fstring));
+                        if (context->internal->_auth_fn_with_context != NULL) {
+                                context->internal->_auth_fn_with_context(
+                                        context,
+                                        server, share,
+                                        workgroup, sizeof(fstring),
+                                        username, sizeof(fstring),
+                                        password, sizeof(fstring));
+                        } else {
+                                context->callbacks.auth_fn(
+                                        server, share,
+                                        workgroup, sizeof(fstring),
+                                        username, sizeof(fstring),
+                                        password, sizeof(fstring));
+                        }
 
                         if (! cli_send_tconX(&srv->cli, share, "?????",
                                              password, strlen(password)+1)) {
@@ -901,10 +922,20 @@ smbc_attr_server(SMBCCTX *context,
                 /* We didn't find a cached connection.  Get the password */
                 if (*password == '\0') {
                         /* ... then retrieve it now. */
-                        context->callbacks.auth_fn(server, share,
-                                                   workgroup, sizeof(fstring),
-                                                   username, sizeof(fstring),
-                                                   password, sizeof(fstring));
+                        if (context->internal->_auth_fn_with_context != NULL) {
+                                context->internal->_auth_fn_with_context(
+                                        context,
+                                        server, share,
+                                        workgroup, sizeof(fstring),
+                                        username, sizeof(fstring),
+                                        password, sizeof(fstring));
+                        } else {
+                                context->callbacks.auth_fn(
+                                        server, share,
+                                        workgroup, sizeof(fstring),
+                                        username, sizeof(fstring),
+                                        password, sizeof(fstring));
+                        }
                 }
         
                 zero_ip(&ip);
@@ -5976,8 +6007,51 @@ smbc_option_set(SMBCCTX *context,
                 /*
                  * Log to standard error instead of standard output.
                  */
-                context->internal->_debug_stderr = True;
+                context->internal->_debug_stderr =
+                        (option_value == NULL ? False : True);
+        } else if (strcmp(option_name, "auth_function") == 0) {
+                /*
+                 * Use the new-style authentication function which includes
+                 * the context.
+                 */
+                context->internal->_auth_fn_with_context = option_value;
+        } else if (strcmp(option_name, "user_data") == 0) {
+                /*
+                 * Save a user data handle which may be retrieved by the user
+                 * with smbc_option_get()
+                 */
+                context->internal->_user_data = option_value;
+        }
+}
+
+
+/*
+ * Retrieve the current value of an option
+ */
+void *
+smbc_option_get(SMBCCTX *context,
+                char *option_name)
+{
+        if (strcmp(option_name, "debug_stderr") == 0) {
+                /*
+                 * Log to standard error instead of standard output.
+                 */
+                return (void *) context->internal->_debug_stderr;
+        } else if (strcmp(option_name, "auth_function") == 0) {
+                /*
+                 * Use the new-style authentication function which includes
+                 * the context.
+                 */
+                return (void *) context->internal->_auth_fn_with_context;
+        } else if (strcmp(option_name, "user_data") == 0) {
+                /*
+                 * Save a user data handle which may be retrieved by the user
+                 * with smbc_option_get()
+                 */
+                return context->internal->_user_data;
         }
+
+        return NULL;
 }
 
 
@@ -6006,7 +6080,8 @@ smbc_init_context(SMBCCTX *context)
                 return 0;
         }
 
-        if (!context->callbacks.auth_fn ||
+        if ((!context->callbacks.auth_fn &&
+             !context->internal->_auth_fn_with_context) ||
             context->debug < 0 ||
             context->debug > 100) {