r25446: Merge some changes I made on the way home from SFO:
[kai/samba.git] / source4 / auth / gensec / gensec.c
index c0aba3924cef0d047c06fd1b833135f0c994f93b..9bbf31a7c797f52399b344f47f9cb64db6768afa 100644 (file)
@@ -4,11 +4,11 @@
    Generic Authentication Interface
 
    Copyright (C) Andrew Tridgell 2003
-   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
    
    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,
@@ -17,8 +17,7 @@
    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"
@@ -26,6 +25,9 @@
 #include "lib/events/events.h"
 #include "build.h"
 #include "librpc/rpc/dcerpc.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
 
 /* the list of currently registered GENSEC backends */
 static struct gensec_security_ops **generic_security_ops;
@@ -45,13 +47,20 @@ struct gensec_security_ops **gensec_security_all(void)
 
 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx, 
                                                       struct gensec_security_ops **old_gensec_list, 
-                                                      enum credentials_use_kerberos use_kerberos) 
+                                                      struct cli_credentials *creds)
 {
        struct gensec_security_ops **new_gensec_list;
        int i, j, num_mechs_in;
+       enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
+
+       if (creds) {
+               use_kerberos = cli_credentials_get_kerberos_state(creds);
+       }
 
        if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
-               talloc_reference(mem_ctx, old_gensec_list);
+               if (!talloc_reference(mem_ctx, old_gensec_list)) {
+                       return NULL;
+               }
                return old_gensec_list;
        }
 
@@ -103,17 +112,19 @@ struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gense
        struct gensec_security_ops **backends;
        backends = gensec_security_all();
        if (!gensec_security) {
-               talloc_reference(mem_ctx, backends);
+               if (!talloc_reference(mem_ctx, backends)) {
+                       return NULL;
+               }
                return backends;
        } else {
-               enum credentials_use_kerberos use_kerberos;
                struct cli_credentials *creds = gensec_get_credentials(gensec_security);
                if (!creds) {
-                       talloc_reference(mem_ctx, backends);
+                       if (!talloc_reference(mem_ctx, backends)) {
+                               return NULL;
+                       }
                        return backends;
                }
-               use_kerberos = cli_credentials_get_kerberos_state(creds);
-               return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
+               return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
        }
 }
 
@@ -168,8 +179,8 @@ const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security
        return NULL;
 }
 
-static const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
-                                                                     const char *sasl_name)
+const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
+                                                              const char *sasl_name)
 {
        int i;
        struct gensec_security_ops **backends;
@@ -465,8 +476,9 @@ const char **gensec_security_oids(struct gensec_security *gensec_security,
   @note  The mem_ctx is only a parent and may be NULL.
 */
 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, 
-                            struct gensec_security **gensec_security,
-                            struct event_context *ev) 
+                            struct event_context *ev,
+                            struct messaging_context *msg,
+                            struct gensec_security **gensec_security)
 {
        (*gensec_security) = talloc(mem_ctx, struct gensec_security);
        NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
@@ -489,6 +501,7 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
        }
 
        (*gensec_security)->event_ctx = ev;
+       (*gensec_security)->msg_ctx = msg;
 
        return NT_STATUS_OK;
 }
@@ -514,6 +527,7 @@ _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
 
        (*gensec_security)->subcontext = True;
        (*gensec_security)->event_ctx = parent->event_ctx;
+       (*gensec_security)->msg_ctx = parent->msg_ctx;
 
        return NT_STATUS_OK;
 }
@@ -529,10 +543,20 @@ _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
                             struct event_context *ev)
 {
        NTSTATUS status;
-       status = gensec_start(mem_ctx, gensec_security, ev);
+       struct event_context *new_ev = NULL;
+
+       if (ev == NULL) {
+               new_ev = event_context_init(mem_ctx);
+               NT_STATUS_HAVE_NO_MEMORY(new_ev);
+               ev = new_ev;
+       }
+
+       status = gensec_start(mem_ctx, ev, NULL, gensec_security);
        if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(new_ev);
                return status;
        }
+       talloc_steal((*gensec_security), new_ev);
        (*gensec_security)->gensec_role = GENSEC_CLIENT;
 
        return status;
@@ -545,11 +569,23 @@ _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
   @note  The mem_ctx is only a parent and may be NULL.
 */
 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, 
-                            struct gensec_security **gensec_security,
-                            struct event_context *ev)
+                            struct event_context *ev,
+                            struct messaging_context *msg,
+                            struct gensec_security **gensec_security)
 {
        NTSTATUS status;
-       status = gensec_start(mem_ctx, gensec_security, ev);
+
+       if (!ev) {
+               DEBUG(0,("gensec_server_start: no event context given!\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       if (!msg) {
+               DEBUG(0,("gensec_server_start: no messaging context given!\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       status = gensec_start(mem_ctx, ev, msg, gensec_security);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -696,11 +732,12 @@ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
  */
 
 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, 
-                                       const char **sasl_names) 
+                                                const char **sasl_names) 
 {
-       NTSTATUS nt_status;
+       NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
        TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
        const struct gensec_security_ops **ops;
+       int i;
        if (!mem_ctx) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -712,7 +749,12 @@ _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_
                talloc_free(mem_ctx);
                return NT_STATUS_INVALID_PARAMETER;
        }
-       nt_status = gensec_start_mech_by_ops(gensec_security, ops[0]);
+       for (i=0; ops[i]; i++) {
+               nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
+               if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
+                       break;
+               }
+       }
        talloc_free(mem_ctx);
        return nt_status;
 }
@@ -815,25 +857,25 @@ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size
        return gensec_security->ops->sig_size(gensec_security, data_size);
 }
 
-size_t gensec_max_input_size(struct gensec_security *gensec_security) 
+size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) 
 {
-       if (!gensec_security->ops->max_input_size) {
-               return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
+       if (!gensec_security->ops->max_wrapped_size) {
+               return (1 << 17);
        }
        
-       return gensec_security->ops->max_input_size(gensec_security);
+       return gensec_security->ops->max_wrapped_size(gensec_security);
 }
 
-size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) 
+size_t gensec_max_input_size(struct gensec_security *gensec_security) 
 {
-       if (!gensec_security->ops->max_wrapped_size) {
-               return (1 << 17);
+       if (!gensec_security->ops->max_input_size) {
+               return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
        }
        
-       return gensec_security->ops->max_wrapped_size(gensec_security);
+       return gensec_security->ops->max_input_size(gensec_security);
 }
 
-_PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
+NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
                     TALLOC_CTX *mem_ctx, 
                     const DATA_BLOB *in, 
                     DATA_BLOB *out) 
@@ -844,7 +886,7 @@ _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
        return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
 }
 
-_PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
+NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
                       TALLOC_CTX *mem_ctx, 
                       const DATA_BLOB *in, 
                       DATA_BLOB *out) 
@@ -904,17 +946,6 @@ _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_
        return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
 }
 
-struct gensec_update_request {
-       struct gensec_security *gensec_security;
-       DATA_BLOB in;
-       DATA_BLOB out;
-       NTSTATUS status;
-       struct {
-               void (*fn)(struct gensec_update_request *req, void *private_data);
-               void *private_data;
-       } callback;
-};
-
 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
                                              struct timeval t, void *ptr)
 {
@@ -1019,6 +1050,8 @@ _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
 {
        gensec_security->credentials = talloc_reference(gensec_security, credentials);
+       NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
+       gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
        return NT_STATUS_OK;
 }
 
@@ -1066,7 +1099,7 @@ _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_se
 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
 {
        gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
-       if (!gensec_security->target.hostname) {
+       if (hostname && !gensec_security->target.hostname) {
                return NT_STATUS_NO_MEMORY;
        }
        return NT_STATUS_OK;
@@ -1075,7 +1108,7 @@ _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_secu
 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
 {
        /* We allow the target hostname to be overriden for testing purposes */
-       const char *target_hostname = lp_parm_string(-1, "gensec", "target_hostname");
+       const char *target_hostname = lp_parm_string(global_loadparm, NULL, "gensec", "target_hostname");
        if (target_hostname) {
                return target_hostname;
        }
@@ -1173,7 +1206,7 @@ const char *gensec_get_target_principal(struct gensec_security *gensec_security)
 */
 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
 {
-       if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
+       if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
                DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
                return NT_STATUS_OK;
        }
@@ -1193,7 +1226,7 @@ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
                return NT_STATUS_NO_MEMORY;
        }
 
-       generic_security_ops[gensec_num_backends] = discard_const(ops);
+       generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
        gensec_num_backends++;
        generic_security_ops[gensec_num_backends] = NULL;
 
@@ -1219,6 +1252,10 @@ const struct gensec_critical_sizes *gensec_interface_version(void)
        return &critical_sizes;
 }
 
+static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
+       return (*gs2)->priority - (*gs1)->priority;
+}
+
 /*
   initialise the GENSEC subsystem
 */
@@ -1232,12 +1269,14 @@ NTSTATUS gensec_init(void)
        if (initialized) return NT_STATUS_OK;
        initialized = True;
        
-       shared_init = load_samba_modules(NULL, "gensec");
+       shared_init = load_samba_modules(NULL, global_loadparm, "gensec");
 
        run_init_functions(static_init);
        run_init_functions(shared_init);
 
        talloc_free(shared_init);
+
+       qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
        
        return NT_STATUS_OK;
 }