r26576: Allow the static module loading code to be used for the Python modules.
[samba.git] / source4 / auth / auth.c
index 0b044af495eb52328212186ff928e52757bec43d..4bfc92e8f9de350a39e325762035440b8dcba8dd 100644 (file)
@@ -6,7 +6,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "dlinklist.h"
-#include "lib/ldb/include/ldb.h"
+#include "lib/util/dlinklist.h"
 #include "auth/auth.h"
 #include "lib/events/events.h"
 #include "build.h"
+#include "param/param.h"
 
 /***************************************************************************
  Set a fixed challenge
@@ -43,7 +42,7 @@ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t
 /***************************************************************************
  Set a fixed challenge
 ***************************************************************************/
-BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx) 
+bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) 
 {
        return auth_ctx->challenge.may_be_modified;
 }
@@ -52,7 +51,7 @@ BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx)
  Try to get a challenge out of the various authentication modules.
  Returns a const char of length 8 bytes.
 ****************************************************************************/
-NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
+_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
 {
        NTSTATUS nt_status;
        struct auth_method_context *method;
@@ -94,7 +93,7 @@ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal
                NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
                auth_ctx->challenge.set_by              = "random";
 
-               auth_ctx->challenge.may_be_modified     = True;
+               auth_ctx->challenge.may_be_modified     = true;
        }
 
        DEBUG(10,("auth_get_challenge: challenge set by %s\n",
@@ -104,8 +103,25 @@ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal
        return NT_STATUS_OK;
 }
 
+struct auth_check_password_sync_state {
+       bool finished;
+       NTSTATUS status;
+       struct auth_serversupplied_info *server_info;
+};
+
+static void auth_check_password_sync_callback(struct auth_check_password_request *req,
+                                             void *private_data)
+{
+       struct auth_check_password_sync_state *s = talloc_get_type(private_data,
+                                                  struct auth_check_password_sync_state);
+
+       s->finished = true;
+       s->status = auth_check_password_recv(req, s, &s->server_info);
+}
+
 /**
  * Check a user's Plaintext, LM or NTLM password.
+ * (sync version)
  *
  * Check a user's password, as given in the user_info struct and return various
  * interesting details in the server_info struct.
@@ -114,13 +130,15 @@ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal
  * struct.  When the return is other than NT_STATUS_OK the contents 
  * of that structure is undefined.
  *
- * @param user_info Contains the user supplied components, including the passwords.
- *
- * @param auth_context Supplies the challenges and some other data. 
- *                  Must be created with make_auth_context(), and the challenges should be 
+ * @param auth_ctx Supplies the challenges and some other data. 
+ *                  Must be created with auth_context_create(), and the challenges should be 
  *                  filled in, either at creation or by calling the challenge geneation 
  *                  function auth_get_challenge().  
  *
+ * @param user_info Contains the user supplied components, including the passwords.
+ *
+ * @param mem_ctx The parent memory context for the server_info structure
+ *
  * @param server_info If successful, contains information about the authentication, 
  *                    including a SAM_ACCOUNT struct describing the user.
  *
@@ -132,83 +150,211 @@ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
                             TALLOC_CTX *mem_ctx,
                             const struct auth_usersupplied_info *user_info, 
                             struct auth_serversupplied_info **server_info)
+{
+       struct auth_check_password_sync_state *sync_state;
+       NTSTATUS status;
+
+       sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
+       NT_STATUS_HAVE_NO_MEMORY(sync_state);
+
+       auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
+
+       while (!sync_state->finished) {
+               event_loop_once(auth_ctx->event_ctx);
+       }
+
+       status = sync_state->status;
+
+       if (NT_STATUS_IS_OK(status)) {
+               *server_info = talloc_steal(mem_ctx, sync_state->server_info);
+       }
+
+       talloc_free(sync_state);
+       return status;
+}
+
+struct auth_check_password_request {
+       struct auth_context *auth_ctx;
+       const struct auth_usersupplied_info *user_info;
+       struct auth_serversupplied_info *server_info;
+       struct auth_method_context *method;
+       NTSTATUS status;
+       struct {
+               void (*fn)(struct auth_check_password_request *req, void *private_data);
+               void *private_data;
+       } callback;
+};
+
+static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te,
+                                                   struct timeval t, void *ptr)
+{
+       struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
+       req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
+       req->callback.fn(req, req->callback.private_data);
+}
+
+/**
+ * Check a user's Plaintext, LM or NTLM password.
+ * async send hook
+ *
+ * Check a user's password, as given in the user_info struct and return various
+ * interesting details in the server_info struct.
+ *
+ * The return value takes precedence over the contents of the server_info 
+ * struct.  When the return is other than NT_STATUS_OK the contents 
+ * of that structure is undefined.
+ *
+ * @param auth_ctx Supplies the challenges and some other data. 
+ *                  Must be created with make_auth_context(), and the challenges should be 
+ *                  filled in, either at creation or by calling the challenge geneation 
+ *                  function auth_get_challenge().  
+ *
+ * @param user_info Contains the user supplied components, including the passwords.
+ *
+ * @param callback A callback function which will be called when the operation is finished.
+ *                 The callback function needs to call auth_check_password_recv() to get the return values
+ *
+ * @param private_data A private pointer which will ba passed to the callback function
+ *
+ **/
+
+void auth_check_password_send(struct auth_context *auth_ctx,
+                             const struct auth_usersupplied_info *user_info,
+                             void (*callback)(struct auth_check_password_request *req, void *private_data),
+                             void *private_data)
 {
        /* if all the modules say 'not for me' this is reasonable */
        NTSTATUS nt_status;
        struct auth_method_context *method;
-       const char *method_name = "NO METHOD";
        const uint8_t *challenge;
-       struct auth_usersupplied_info *user_info_tmp; 
+       struct auth_usersupplied_info *user_info_tmp;
+       struct auth_check_password_request *req = NULL;
 
-       DEBUG(3,   ("auth_check_password:  Checking password for unmapped user [%s]\\[%s]@[%s]\n", 
+       DEBUG(3,   ("auth_check_password_send:  Checking password for unmapped user [%s]\\[%s]@[%s]\n", 
                    user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
 
+       req = talloc_zero(auth_ctx, struct auth_check_password_request);
+       if (!req) {
+               callback(NULL, private_data);
+               return;
+       }
+       req->auth_ctx                   = auth_ctx;
+       req->user_info                  = user_info;
+       req->callback.fn                = callback;
+       req->callback.private_data      = private_data;
+
        if (!user_info->mapped_state) {
-               nt_status = map_user_info(mem_ctx, user_info, &user_info_tmp);
-               if (!NT_STATUS_IS_OK(nt_status)) {
-                       return nt_status;
-               }
+               nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
+               if (!NT_STATUS_IS_OK(nt_status)) goto failed;
                user_info = user_info_tmp;
+               req->user_info  = user_info_tmp;
        }
 
-       DEBUGADD(3,("auth_check_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
+       DEBUGADD(3,("auth_check_password_send:  mapped user is: [%s]\\[%s]@[%s]\n", 
                    user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
 
        nt_status = auth_get_challenge(auth_ctx, &challenge);
-
        if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(0, ("auth_check_password:  Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
+               DEBUG(0, ("auth_check_password_send:  Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
                        (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
-               return nt_status;
+               goto failed;
        }
 
        if (auth_ctx->challenge.set_by) {
-               DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n",
+               DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
                                        auth_ctx->challenge.set_by));
        }
 
-       DEBUG(10, ("challenge is: \n"));
+       DEBUG(10, ("auth_check_password_send: challenge is: \n"));
        dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
 
        nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
        for (method = auth_ctx->methods; method; method = method->next) {
                NTSTATUS result;
+               struct timed_event *te = NULL;
 
                /* check if the module wants to chek the password */
-               result = method->ops->want_check(method, mem_ctx, user_info);
+               result = method->ops->want_check(method, req, user_info);
                if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
-                       DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
+                       DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
                        continue;
                }
 
-               method_name = method->ops->name;
                nt_status = result;
+               req->method     = method;
 
                if (!NT_STATUS_IS_OK(nt_status)) break;
 
-               nt_status = method->ops->check_password(method, mem_ctx, user_info, server_info);
-               break;
+               te = event_add_timed(auth_ctx->event_ctx, req,
+                                    timeval_zero(),
+                                    auth_check_password_async_timed_handler, req);
+               if (!te) {
+                       nt_status = NT_STATUS_NO_MEMORY;
+                       goto failed;
+               }
+               return;
        }
 
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n", 
-                        method_name, user_info->mapped.domain_name, user_info->mapped.account_name, 
-                        nt_errstr(nt_status)));
-               return nt_status;
-       }
+failed:
+       req->status = nt_status;
+       req->callback.fn(req, req->callback.private_data);
+}
+
+/**
+ * Check a user's Plaintext, LM or NTLM password.
+ * async receive function
+ *
+ * The return value takes precedence over the contents of the server_info 
+ * struct.  When the return is other than NT_STATUS_OK the contents 
+ * of that structure is undefined.
+ *
+ *
+ * @param req The async auth_check_password state, passes to the callers callback function
+ *
+ * @param mem_ctx The parent memory context for the server_info structure
+ *
+ * @param server_info If successful, contains information about the authentication, 
+ *                    including a SAM_ACCOUNT struct describing the user.
+ *
+ * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
+ *
+ **/
+
+NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct auth_serversupplied_info **server_info)
+{
+       NTSTATUS status;
+
+       NT_STATUS_HAVE_NO_MEMORY(req);
 
-       DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
-                method_name, (*server_info)->domain_name, (*server_info)->account_name));
+       if (NT_STATUS_IS_OK(req->status)) {
+               DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
+                        req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
 
-       return nt_status;
+               *server_info = talloc_steal(mem_ctx, req->server_info);
+       } else {
+               DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", 
+                        (req->method ? req->method->ops->name : "NO_METHOD"),
+                        req->user_info->mapped.domain_name,
+                        req->user_info->mapped.account_name, 
+                        nt_errstr(req->status)));
+       }
+
+       status = req->status;
+       talloc_free(req);
+       return status;
 }
 
 /***************************************************************************
  Make a auth_info struct for the auth subsystem
+ - Allow the caller to specify the methods to use
 ***************************************************************************/
-NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods, 
-                            struct auth_context **auth_ctx,
-                            struct event_context *ev) 
+NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, 
+                                    struct event_context *ev,
+                                    struct messaging_context *msg,
+                                    struct loadparm_context *lp_ctx,
+                                    struct auth_context **auth_ctx)
 {
        int i;
        struct auth_context *ctx;
@@ -218,22 +364,25 @@ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods,
                return NT_STATUS_INTERNAL_ERROR;
        }
 
+       if (!ev) {
+               DEBUG(0,("auth_context_create: called with out event context\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       if (!msg) {
+               DEBUG(0,("auth_context_create: called with out messaging context\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
        ctx = talloc(mem_ctx, struct auth_context);
        NT_STATUS_HAVE_NO_MEMORY(ctx);
        ctx->challenge.set_by           = NULL;
-       ctx->challenge.may_be_modified  = False;
+       ctx->challenge.may_be_modified  = false;
        ctx->challenge.data             = data_blob(NULL, 0);
        ctx->methods                    = NULL;
-       
-       if (ev == NULL) {
-               ev = event_context_init(ctx);
-               if (ev == NULL) {
-                       talloc_free(ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
-       ctx->event_ctx = ev;
+       ctx->event_ctx                  = ev;
+       ctx->msg_ctx                    = msg;
+       ctx->lp_ctx                     = lp_ctx;
 
        for (i=0; methods[i] ; i++) {
                struct auth_method_context *method;
@@ -260,6 +409,31 @@ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods,
 
        return NT_STATUS_OK;
 }
+/***************************************************************************
+ Make a auth_info struct for the auth subsystem
+ - Uses default auth_methods, depending on server role and smb.conf settings
+***************************************************************************/
+NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, 
+                            struct event_context *ev,
+                            struct messaging_context *msg,
+                            struct loadparm_context *lp_ctx,
+                            struct auth_context **auth_ctx)
+{
+       const char **auth_methods = NULL;
+       switch (lp_server_role(lp_ctx)) {
+       case ROLE_STANDALONE:
+               auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
+               break;
+       case ROLE_DOMAIN_MEMBER:
+               auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
+               break;
+       case ROLE_DOMAIN_CONTROLLER:
+               auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
+               break;
+       }
+       return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
+}
+
 
 /* the list of currently registered AUTH backends */
 static struct auth_backend {
@@ -273,9 +447,8 @@ static int num_backends;
   The 'name' can be later used by other backends to find the operations
   structure for this backend.
 */
-NTSTATUS auth_register(const void *_ops)
+NTSTATUS auth_register(const struct auth_operations *ops)
 {
-       const struct auth_operations *ops = _ops;
        struct auth_operations *new_ops;
        
        if (auth_backend_byname(ops->name) != NULL) {
@@ -285,13 +458,14 @@ NTSTATUS auth_register(const void *_ops)
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       backends = realloc_p(backends, struct auth_backend, num_backends+1);
-       if (!backends) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       backends = talloc_realloc(talloc_autofree_context(), backends, 
+                                 struct auth_backend, num_backends+1);
+       NT_STATUS_HAVE_NO_MEMORY(backends);
 
-       new_ops = smb_xmemdup(ops, sizeof(*ops));
-       new_ops->name = smb_xstrdup(ops->name);
+       new_ops = talloc_memdup(backends, ops, sizeof(*ops));
+       NT_STATUS_HAVE_NO_MEMORY(new_ops);
+       new_ops->name = talloc_strdup(new_ops, ops->name);
+       NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
 
        backends[num_backends].ops = new_ops;
 
@@ -340,20 +514,14 @@ const struct auth_critical_sizes *auth_interface_version(void)
 
 NTSTATUS auth_init(void)
 {
-       static BOOL initialized = False;
+       static bool initialized = false;
 
-       init_module_fn static_init[] = STATIC_auth_MODULES;
-       init_module_fn *shared_init;
+       init_module_fn static_init[] = { STATIC_auth_MODULES, NULL };
        
        if (initialized) return NT_STATUS_OK;
-       initialized = True;
+       initialized = true;
        
-       shared_init = load_samba_modules(NULL, "auth");
-
        run_init_functions(static_init);
-       run_init_functions(shared_init);
-
-       talloc_free(shared_init);
        
        return NT_STATUS_OK;    
 }