r8520: fixed a pile of warnings from the build farm gcc -Wall output on
[kamenim/samba.git] / source4 / auth / auth.c
index 62e2b93ecb9f0f6bde12a446befc533972e6c967..d05aa54e50a16750c7ad56994ae6ebc823f53b39 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    Password and authentication handling
    Copyright (C) Andrew Bartlett         2001-2002
+   Copyright (C) Stefan Metzmacher       2005
    
    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
 */
 
 #include "includes.h"
+#include "dlinklist.h"
+#include "auth/auth.h"
+#include "lib/events/events.h"
 
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_AUTH
+/***************************************************************************
+ Set a fixed challenge
+***************************************************************************/
+NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
+{
+       auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
+       NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
+
+       auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
+       NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
+
+       return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Set a fixed challenge
+***************************************************************************/
+BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx) 
+{
+       return auth_ctx->challenge.may_be_modified;
+}
 
 /****************************************************************************
  Try to get a challenge out of the various authentication modules.
  Returns a const char of length 8 bytes.
 ****************************************************************************/
-
-static const uint8_t *get_ntlm_challenge(struct auth_context *auth_context) 
+NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
 {
-       DATA_BLOB challenge = data_blob(NULL, 0);
-       const char *challenge_set_by = NULL;
-       struct auth_methods *auth_method;
-       TALLOC_CTX *mem_ctx;
-
-       if (auth_context->challenge.length) {
-               DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", 
-                         auth_context->challenge_set_by));
-               return auth_context->challenge.data;
+       NTSTATUS nt_status;
+       struct auth_method_context *method;
+
+       if (auth_ctx->challenge.data.length) {
+               DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
+                         auth_ctx->challenge.set_by));
+               *_chal = auth_ctx->challenge.data.data;
+               return NT_STATUS_OK;
        }
 
-       auth_context->challenge_may_be_modified = False;
+       for (method = auth_ctx->methods; method; method = method->next) {
+               DATA_BLOB challenge = data_blob(NULL,0);
 
-       for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
-               if (auth_method->get_chal == NULL) {
-                       DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
+               nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
+               if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
                        continue;
                }
 
-               DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name));
-               if (challenge_set_by != NULL) {
-                       DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge.  Challenge by %s ignored.\n", 
-                                 challenge_set_by, auth_method->name));
-                       continue;
-               }
+               NT_STATUS_NOT_OK_RETURN(nt_status);
 
-               mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name);
-               if (!mem_ctx) {
-                       smb_panic("talloc_init() failed!");
+               if (challenge.length != 8) {
+                       DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
+                               (unsigned)challenge.length, method->ops->name));
+                       return NT_STATUS_INTERNAL_ERROR;
                }
-               
-               challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx);
-               if (!challenge.length) {
-                       DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", 
-                                 auth_method->name));
-               } else {
-                       DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name));
-                       auth_context->challenge = challenge;
-                       challenge_set_by = auth_method->name;
-                       auth_context->challenge_set_method = auth_method;
-               }
-               talloc_destroy(mem_ctx);
-       }
-       
-       if (!challenge_set_by) {
-               uint8_t chal[8];
-               
-               generate_random_buffer(chal, sizeof(chal));
-               auth_context->challenge = data_blob_talloc(auth_context, 
-                                                          chal, sizeof(chal));
-               
-               challenge_set_by = "random";
-               auth_context->challenge_may_be_modified = True;
-       } 
-       
-       DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
-       DEBUG(5, ("challenge is: \n"));
-       dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
-       
-       SMB_ASSERT(auth_context->challenge.length == 8);
 
-       auth_context->challenge_set_by=challenge_set_by;
+               auth_ctx->challenge.data        = challenge;
+               auth_ctx->challenge.set_by      = method->ops->name;
 
-       return auth_context->challenge.data;
-}
+               break;
+       }
 
+       if (!auth_ctx->challenge.set_by) {
+               uint8_t chal[8];
+               generate_random_buffer(chal, 8);
 
-/**
- * Check user is in correct domain (if required)
- *
- * @param user Only used to fill in the debug message
- * 
- * @param domain The domain to be verified
- *
- * @return True if the user can connect with that domain, 
- *         False otherwise.
-**/
+               auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
+               NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
+               auth_ctx->challenge.set_by              = "random";
 
-static BOOL check_domain_match(const char *user, const char *domain) 
-{
-       /*
-        * If we aren't serving to trusted domains, we must make sure that
-        * the validation request comes from an account in the same domain
-        * as the Samba server
-        */
-
-       if (!lp_allow_trusted_domains() &&
-           !(strequal("", domain) || 
-             strequal(lp_workgroup(), domain) || 
-             is_myname(domain))) {
-               DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
-               return False;
-       } else {
-               return True;
+               auth_ctx->challenge.may_be_modified     = True;
        }
+
+       DEBUG(10,("auth_get_challenge: challenge set by %s\n",
+                auth_ctx->challenge.set_by));
+
+       *_chal = auth_ctx->challenge.data.data;
+       return NT_STATUS_OK;
 }
 
 /**
@@ -152,40 +127,38 @@ static BOOL check_domain_match(const char *user, const char *domain)
  *
  **/
 
-static NTSTATUS check_ntlm_password(struct auth_context *auth_context,
-                                   const struct auth_usersupplied_info *user_info, 
-                                   struct auth_serversupplied_info **server_info)
+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)
 {
        /* if all the modules say 'not for me' this is reasonable */
        NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
-       struct auth_methods *auth_method;
-       TALLOC_CTX *mem_ctx;
+       struct auth_method_context *method;
+       const char *method_name = "NO METHOD";
+       const uint8_t *challenge;
 
-       if (!user_info || !auth_context || !server_info)
-               return NT_STATUS_LOGON_FAILURE;
+       DEBUG(3,   ("auth_check_password:  Checking password for unmapped user [%s]\\[%s]@[%s]\n", 
+                   user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
 
-       DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
-                 user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
+       DEBUGADD(3,("auth_check_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
+                   user_info->domain_name, user_info->account_name, user_info->workstation_name));
 
-       DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
-                 user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
+       nt_status = auth_get_challenge(auth_ctx, &challenge);
 
-       if (auth_context->challenge.length == 0) {
-               /* get a challenge, if we have not asked for one yet */
-               get_ntlm_challenge(auth_context);
+       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",
+                       (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
+               return nt_status;
        }
 
-       if (auth_context->challenge.length != 8) {
-               DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
-               return NT_STATUS_LOGON_FAILURE;
+       if (auth_ctx->challenge.set_by) {
+               DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n",
+                                       auth_ctx->challenge.set_by));
        }
 
-       if (auth_context->challenge_set_by)
-               DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
-                                       auth_context->challenge_set_by));
-
        DEBUG(10, ("challenge is: \n"));
-       dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
+       dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
 
 #ifdef DEBUG_PASSWORD
        DEBUG(100, ("user_info has passwords of length %d and %d\n", 
@@ -196,205 +169,94 @@ static NTSTATUS check_ntlm_password(struct auth_context *auth_context,
        dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
 #endif
 
-       /* This needs to be sorted:  If it doesn't match, what should we do? */
-       if (!check_domain_match(user_info->smb_name.str, user_info->domain.str))
-               return NT_STATUS_LOGON_FAILURE;
-
-       for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
+       for (method = auth_ctx->methods; method; method = method->next) {
                NTSTATUS result;
-               
-               mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 
-                                           user_info->domain.str, user_info->smb_name.str);
 
-               result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
+               result = method->ops->check_password(method, mem_ctx, user_info, server_info);
 
                /* check if the module did anything */
-               if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
-                       DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
-                       talloc_destroy(mem_ctx);
-                       continue;
-               }
-
-               nt_status = result;
-
-               if (NT_STATUS_IS_OK(nt_status)) {
-                       DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 
-                                 auth_method->name, user_info->smb_name.str));
-               } else {
-                       DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
-                                 auth_method->name, user_info->smb_name.str, nt_errstr(nt_status)));
-               }
-
-               talloc_destroy(mem_ctx);
-
-               if ( NT_STATUS_IS_OK(nt_status))
-               {
-                               break;                  
+               if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
+                       method_name = method->ops->name;
+                       nt_status = result;
+                       break;
                }
-       }
 
-       if (NT_STATUS_IS_OK(nt_status)) {
-               if (NT_STATUS_IS_OK(nt_status)) {
-                       DEBUG((*server_info)->guest ? 5 : 2, 
-                             ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] succeeded\n", 
-                              (*server_info)->guest ? "guest " : "", 
-                              user_info->smb_name.str, 
-                              user_info->internal_username.str));
-               }
+               DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
        }
 
        if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n", 
-                         user_info->smb_name.str, user_info->internal_username.str, 
-                         nt_errstr(nt_status)));
-               ZERO_STRUCTP(server_info);
-       }
-       return nt_status;
-}
-
-/***************************************************************************
- Clear out a auth_context, and destroy the attached TALLOC_CTX
-***************************************************************************/
-
-void free_auth_context(struct auth_context **auth_context)
-{
-       struct auth_methods *auth_method;
-       
-       if (*auth_context) {
-               /* Free private data of context's authentication methods */
-               for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) {
-                       if (auth_method->free_private_data) {
-                               auth_method->free_private_data (&auth_method->private_data);
-                               auth_method->private_data = NULL;
-                       }
-               }
-
-               talloc_free(*auth_context);
-               *auth_context = NULL;
+               DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n", 
+                        method_name, user_info->domain_name, user_info->account_name, 
+                        nt_errstr(nt_status)));
+               return nt_status;
        }
-}
-
-/***************************************************************************
- Make a auth_info struct
-***************************************************************************/
 
-static NTSTATUS make_auth_context(TALLOC_CTX *mem_ctx, struct auth_context **auth_context) 
-{
-       *auth_context = talloc_p(mem_ctx, struct auth_context);
-       if (!*auth_context) {
-               DEBUG(0,("make_auth_context: talloc failed!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-       ZERO_STRUCTP(*auth_context);
+       DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
+                method_name, (*server_info)->domain_name, (*server_info)->account_name));
 
-       (*auth_context)->check_ntlm_password = check_ntlm_password;
-       (*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
-       
-       return NT_STATUS_OK;
+       return nt_status;
 }
 
 /***************************************************************************
  Make a auth_info struct for the auth subsystem
 ***************************************************************************/
-
-static NTSTATUS make_auth_context_text_list(TALLOC_CTX *mem_ctx, 
-                                           struct auth_context **auth_context, char **text_list
+NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods, 
+                            struct auth_context **auth_ctx,
+                            struct event_context *ev
 {
-       struct auth_methods *list = NULL;
-       struct auth_methods *t = NULL;
-       NTSTATUS nt_status;
+       int i;
+       struct auth_context *ctx;
 
-       if (!text_list) {
-               DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
-               return NT_STATUS_UNSUCCESSFUL;
+       if (!methods) {
+               DEBUG(0,("auth_context_create: No auth method list!?\n"));
+               return NT_STATUS_INTERNAL_ERROR;
        }
-       
-       if (!NT_STATUS_IS_OK(nt_status = make_auth_context(mem_ctx, auth_context)))
-               return nt_status;
-       
-       for (;*text_list; text_list++) {
-               char *module_name = smb_xstrdup(*text_list);
-               char *module_params = NULL;
-               char *p;
-               const struct auth_operations *ops;
-
-               DEBUG(5,("make_auth_context_text_list: Attempting to find an auth method to match %s\n",
-                                       *text_list));
-
-               p = strchr(module_name, ':');
-               if (p) {
-                       *p = 0;
-                       module_params = p+1;
-                       trim_string(module_params, " ", " ");
-               }
 
-               trim_string(module_name, " ", " ");
-
-               ops = auth_backend_byname(module_name);
-               if (!ops) {
-                       DEBUG(5,("make_auth_context_text_list: Found auth method %s\n", *text_list));
-                       SAFE_FREE(module_name);
-                       break;
-               }
-
-               if (NT_STATUS_IS_OK(ops->init(*auth_context, module_params, &t))) {
-                       DEBUG(5,("make_auth_context_text_list: auth method %s has a valid init\n",
-                                               *text_list));
-                       DLIST_ADD_END(list, t, struct auth_methods *);
-               } else {
-                       DEBUG(0,("make_auth_context_text_list: auth method %s did not correctly init\n",
-                                               *text_list));
+       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.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;
                }
-               SAFE_FREE(module_name);
        }
-       
-       (*auth_context)->auth_method_list = list;
-       
-       return nt_status;
-}
 
-/***************************************************************************
- Make a auth_context struct for the auth subsystem
-***************************************************************************/
+       ctx->event_ctx = ev;
 
-NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, struct auth_context **auth_context) 
-{
-       char **auth_method_list = NULL; 
-       NTSTATUS nt_status;
+       for (i=0; methods[i] ; i++) {
+               struct auth_method_context *method;
+
+               method = talloc(ctx, struct auth_method_context);
+               NT_STATUS_HAVE_NO_MEMORY(method);
 
-       if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) {
-               return NT_STATUS_NO_MEMORY;
+               method->ops = auth_backend_byname(methods[i]);
+               if (!method->ops) {
+                       DEBUG(1,("auth_context_create: failed to find method=%s\n",
+                               methods[i]));
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               method->auth_ctx        = ctx;
+               method->depth           = i;
+               DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
        }
 
-       nt_status = make_auth_context_text_list(mem_ctx, auth_context, auth_method_list);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               str_list_free(&auth_method_list);
-               return nt_status;
+       if (!ctx->methods) {
+               return NT_STATUS_INTERNAL_ERROR;
        }
-       
-       str_list_free(&auth_method_list);
-       return nt_status;
-}
 
-/***************************************************************************
- Make a auth_info struct with a fixed challenge
-***************************************************************************/
+       *auth_ctx = ctx;
 
-NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, 
-                                struct auth_context **auth_context, uint8_t chal[8]) 
-{
-       NTSTATUS nt_status;
-       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(mem_ctx, auth_context))) {
-               return nt_status;
-       }
-       
-       (*auth_context)->challenge = data_blob_talloc(*auth_context, chal, 8);
-       (*auth_context)->challenge_set_by = "fixed";
-       return nt_status;
+       return NT_STATUS_OK;
 }
 
 /* the list of currently registered AUTH backends */
-static struct {
+static struct auth_backend {
        const struct auth_operations *ops;
 } *backends = NULL;
 static int num_backends;
@@ -405,7 +267,7 @@ static int num_backends;
   The 'name' can be later used by other backends to find the operations
   structure for this backend.
 */
-static NTSTATUS auth_register(const void *_ops)
+NTSTATUS auth_register(const void *_ops)
 {
        const struct auth_operations *ops = _ops;
        struct auth_operations *new_ops;
@@ -417,7 +279,7 @@ static NTSTATUS auth_register(const void *_ops)
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       backends = Realloc(backends, sizeof(backends[0]) * (num_backends+1));
+       backends = realloc_p(backends, struct auth_backend, num_backends+1);
        if (!backends) {
                smb_panic("out of memory in auth_register");
        }
@@ -461,43 +323,15 @@ const struct auth_critical_sizes *auth_interface_version(void)
        static const struct auth_critical_sizes critical_sizes = {
                AUTH_INTERFACE_VERSION,
                sizeof(struct auth_operations),
-               sizeof(struct auth_methods),
+               sizeof(struct auth_method_context),
                sizeof(struct auth_context),
                sizeof(struct auth_usersupplied_info),
-               sizeof(struct auth_serversupplied_info),
-               sizeof(struct auth_str),
+               sizeof(struct auth_serversupplied_info)
        };
 
        return &critical_sizes;
 }
 
-/*
-  initialise the AUTH subsystem
-*/
-BOOL auth_init(void)
-{
-       NTSTATUS status;
-       
-       /* ugly cludge, to go away */
-       static BOOL initialised;
-
-       if (initialised) {
-               return True;
-       }
-
-       status = register_subsystem("auth", auth_register); 
-       if (!NT_STATUS_IS_OK(status)) {
-               return False;
-       }
-
-       /* FIXME: Perhaps panic if a basic backend, such as SAM, fails to initialise? */
-       static_init_auth;
-
-       initialised = True;
-       DEBUG(3,("AUTH subsystem version %d initialised\n", AUTH_INTERFACE_VERSION));
-       return True;
-}
-
 NTSTATUS server_service_auth_init(void)
 {
        return NT_STATUS_OK;