r26580: Include sentinel in build.h, in case the list is empty.
[samba.git] / source4 / auth / gensec / gensec.c
index ecdac8564a7651943908bdf0470a5b9103b83010..cd2066d9fd5f93044fa92e68497a9794350410f0 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;
        }
 
@@ -76,13 +85,13 @@ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
                }
                switch (use_kerberos) {
                case CRED_DONT_USE_KERBEROS:
-                       if (old_gensec_list[i]->kerberos == False) {
+                       if (old_gensec_list[i]->kerberos == false) {
                                new_gensec_list[j] = old_gensec_list[i];
                                j++;
                        }
                        break;
                case CRED_MUST_USE_KERBEROS:
-                       if (old_gensec_list[i]->kerberos == True) {
+                       if (old_gensec_list[i]->kerberos == true) {
                                new_gensec_list[j] = old_gensec_list[i];
                                j++;
                        }
@@ -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;
@@ -442,7 +453,7 @@ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
 /**
  * Return all the security subsystems currently enabled on a GENSEC context.
  * 
- * This is taken from a list attached to the cli_credentails, and
+ * This is taken from a list attached to the cli_credentials, and
  * skips the OID in 'skip'.  (Typically the SPNEGO OID)
  * 
  */
@@ -466,6 +477,7 @@ const char **gensec_security_oids(struct gensec_security *gensec_security,
 */
 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, 
                             struct event_context *ev,
+                            struct loadparm_context *lp_ctx,
                             struct messaging_context *msg,
                             struct gensec_security **gensec_security)
 {
@@ -478,7 +490,7 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
        ZERO_STRUCT((*gensec_security)->peer_addr);
        ZERO_STRUCT((*gensec_security)->my_addr);
 
-       (*gensec_security)->subcontext = False;
+       (*gensec_security)->subcontext = false;
        (*gensec_security)->want_features = 0;
        
        if (ev == NULL) {
@@ -491,6 +503,7 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
 
        (*gensec_security)->event_ctx = ev;
        (*gensec_security)->msg_ctx = msg;
+       (*gensec_security)->lp_ctx = lp_ctx;
 
        return NT_STATUS_OK;
 }
@@ -514,9 +527,10 @@ _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
        (*gensec_security)->ops = NULL;
        (*gensec_security)->private_data = NULL;
 
-       (*gensec_security)->subcontext = True;
+       (*gensec_security)->subcontext = true;
        (*gensec_security)->event_ctx = parent->event_ctx;
        (*gensec_security)->msg_ctx = parent->msg_ctx;
+       (*gensec_security)->lp_ctx = parent->lp_ctx;
 
        return NT_STATUS_OK;
 }
@@ -529,7 +543,8 @@ _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
 */
 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, 
                             struct gensec_security **gensec_security,
-                            struct event_context *ev)
+                            struct event_context *ev,
+                            struct loadparm_context *lp_ctx)
 {
        NTSTATUS status;
        struct event_context *new_ev = NULL;
@@ -540,7 +555,7 @@ _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
                ev = new_ev;
        }
 
-       status = gensec_start(mem_ctx, ev, NULL, gensec_security);
+       status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(new_ev);
                return status;
@@ -559,6 +574,7 @@ _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
 */
 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, 
                             struct event_context *ev,
+                            struct loadparm_context *lp_ctx,
                             struct messaging_context *msg,
                             struct gensec_security **gensec_security)
 {
@@ -574,7 +590,7 @@ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
                return NT_STATUS_INTERNAL_ERROR;
        }
 
-       status = gensec_start(mem_ctx, ev, msg, gensec_security);
+       status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -721,11 +737,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;
        }
@@ -737,7 +754,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;
 }
@@ -840,25 +862,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) 
@@ -869,7 +891,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) 
@@ -929,17 +951,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)
 {
@@ -1024,11 +1035,11 @@ _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
  *
  */
 
-_PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
+_PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
                         uint32_t feature) 
 {
        if (!gensec_security->ops->have_feature) {
-               return False;
+               return false;
        }
        
        /* We might 'have' features that we don't 'want', because the
@@ -1044,6 +1055,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;
 }
 
@@ -1091,7 +1104,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;
@@ -1100,7 +1113,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(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
        if (target_hostname) {
                return target_hostname;
        }
@@ -1198,7 +1211,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;
        }
@@ -1218,7 +1231,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;
 
@@ -1244,25 +1257,31 @@ 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
 */
-NTSTATUS gensec_init(void)
+NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
 {
-       static BOOL initialized = False;
+       static bool initialized = false;
 
-       init_module_fn static_init[] = STATIC_gensec_MODULES;
+       init_module_fn static_init[] = { STATIC_gensec_MODULES };
        init_module_fn *shared_init;
 
        if (initialized) return NT_STATUS_OK;
-       initialized = True;
+       initialized = true;
        
-       shared_init = load_samba_modules(NULL, "gensec");
+       shared_init = load_samba_modules(NULL, lp_ctx, "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;
 }