r4325: add the GENSEC_FEATURE_DCE_STYLE flag
[samba.git] / source4 / libcli / auth / gensec.c
index 4470d6d21a866c4660fbf9f46ed35faadd0336c7..8009df4e4050baf70bb343a29cb4308d5180ab04 100644 (file)
@@ -22,6 +22,7 @@
 */
 
 #include "includes.h"
+#include "auth/auth.h"
 
 /* the list of currently registered GENSEC backends */
 const static struct gensec_security_ops **generic_security_ops;
@@ -114,26 +115,16 @@ const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
        return oid_list;
 }
 
-static NTSTATUS gensec_start(struct gensec_security **gensec_security) 
+/*
+  note that memory context is the parent context to hang this gensec context off. It may be NULL.
+*/
+static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security) 
 {
-       TALLOC_CTX *mem_ctx;
-       /* awaiting a correct fix from metze */
-       if (!gensec_init()) {
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       mem_ctx = talloc_init("gensec_security struct");
-       if (!mem_ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
        (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
        if (!(*gensec_security)) {
-               talloc_destroy(mem_ctx);
                return NT_STATUS_NO_MEMORY;
        }
 
-       (*gensec_security)->mem_ctx = mem_ctx;
        (*gensec_security)->ops = NULL;
 
        ZERO_STRUCT((*gensec_security)->user);
@@ -141,11 +132,12 @@ static NTSTATUS gensec_start(struct gensec_security **gensec_security)
        ZERO_STRUCT((*gensec_security)->default_user);
 
        (*gensec_security)->default_user.name = "";
-       (*gensec_security)->default_user.domain = talloc_strdup(mem_ctx, lp_workgroup());
-       (*gensec_security)->default_user.realm = talloc_strdup(mem_ctx, lp_realm());
+       (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
+       (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
 
        (*gensec_security)->subcontext = False;
        (*gensec_security)->want_features = 0;
+       (*gensec_security)->have_features = 0;
        return NT_STATUS_OK;
 }
 
@@ -158,7 +150,7 @@ static NTSTATUS gensec_start(struct gensec_security **gensec_security)
 NTSTATUS gensec_subcontext_start(struct gensec_security *parent, 
                                 struct gensec_security **gensec_security)
 {
-       (*gensec_security) = talloc_p(parent->mem_ctx, struct gensec_security);
+       (*gensec_security) = talloc_p(parent, struct gensec_security);
        if (!(*gensec_security)) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -172,10 +164,10 @@ NTSTATUS gensec_subcontext_start(struct gensec_security *parent,
        return NT_STATUS_OK;
 }
 
-NTSTATUS gensec_client_start(struct gensec_security **gensec_security)
+NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
 {
        NTSTATUS status;
-       status = gensec_start(gensec_security);
+       status = gensec_start(mem_ctx, gensec_security);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -187,10 +179,10 @@ NTSTATUS gensec_client_start(struct gensec_security **gensec_security)
        return status;
 }
 
-NTSTATUS gensec_server_start(struct gensec_security **gensec_security)
+NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
 {
        NTSTATUS status;
-       status = gensec_start(gensec_security);
+       status = gensec_start(mem_ctx, gensec_security);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -210,7 +202,7 @@ static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
                if (gensec_security->ops->client_start) {
                        status = gensec_security->ops->client_start(gensec_security);
                        if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
+                               DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
                                          gensec_security->ops->name, nt_errstr(status))); 
                        }
                        return status;
@@ -219,7 +211,7 @@ static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
                if (gensec_security->ops->server_start) {
                        status = gensec_security->ops->server_start(gensec_security);
                        if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
+                               DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
                                          gensec_security->ops->name, nt_errstr(status))); 
                        }
                        return status;
@@ -240,12 +232,13 @@ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
                DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
                return NT_STATUS_INVALID_PARAMETER;
        }
+       gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
        if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
-               gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
+               gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
        }
        if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
-               gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
-               gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
+               gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
+               gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
        }
 
        return gensec_start_mech(gensec_security);
@@ -319,6 +312,16 @@ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
        if (!gensec_security->ops->unseal_packet) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+               if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+                       return gensec_check_packet(gensec_security, mem_ctx, 
+                                                  data, length, 
+                                                  whole_pdu, pdu_length, 
+                                                  sig);
+               }
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
                                                   data, length, 
                                                   whole_pdu, pdu_length, 
@@ -334,7 +337,7 @@ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
        if (!gensec_security->ops->check_packet) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
-       if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
        
@@ -350,7 +353,13 @@ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
        if (!gensec_security->ops->seal_packet) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
-       if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+               if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+                       return gensec_sign_packet(gensec_security, mem_ctx, 
+                                                 data, length, 
+                                                 whole_pdu, pdu_length, 
+                                                 sig);
+               }
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -366,7 +375,7 @@ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
        if (!gensec_security->ops->sign_packet) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
-       if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
        
@@ -378,7 +387,7 @@ size_t gensec_sig_size(struct gensec_security *gensec_security)
        if (!gensec_security->ops->sig_size) {
                return 0;
        }
-       if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
                return 0;
        }
        
@@ -391,10 +400,6 @@ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
        if (!gensec_security->ops->session_key) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
-       if (!(gensec_security->want_features & GENSEC_WANT_SESSION_KEY)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-       
        return gensec_security->ops->session_key(gensec_security, session_key);
 }
 
@@ -436,16 +441,16 @@ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_
 
 void gensec_end(struct gensec_security **gensec_security)
 {
+       if (!*gensec_security) {
+               return;
+       }
        if ((*gensec_security)->ops) {
                (*gensec_security)->ops->end(*gensec_security);
        }
        (*gensec_security)->private_data = NULL;
 
-       if (!(*gensec_security)->subcontext) {
-               /* don't destory this if this is a subcontext - it belongs to the parent */
-               talloc_destroy((*gensec_security)->mem_ctx);
-       }
-       gensec_security = NULL;
+       talloc_free(*gensec_security);
+       *gensec_security = NULL;
 }
 
 /** 
@@ -459,6 +464,21 @@ void gensec_want_feature(struct gensec_security *gensec_security,
        gensec_security->want_features |= feature;
 }
 
+/** 
+ * Check the requirement for a certain feature on the connection
+ *
+ */
+
+BOOL gensec_have_feature(struct gensec_security *gensec_security,
+                        uint32 feature) 
+{
+       if (gensec_security->have_features & feature) {
+               return True;
+       }
+
+       return False;
+}
+
 /** 
  * Set a username on a GENSEC context - ensures it is talloc()ed 
  *
@@ -467,7 +487,7 @@ void gensec_want_feature(struct gensec_security *gensec_security,
 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user) 
 {
        char *p;
-       char *u = talloc_strdup(gensec_security->mem_ctx, user);
+       char *u = talloc_strdup(gensec_security, user);
        if (!u) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -476,12 +496,12 @@ NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, c
        
        if (p) {
                *p = '\0';
-               gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, u);
+               gensec_security->user.name = talloc_strdup(gensec_security, u);
                if (!gensec_security->user.name) {
                        return NT_STATUS_NO_MEMORY;
                }
                
-               gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, p+1);
+               gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
                if (!gensec_security->user.realm) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -495,11 +515,11 @@ NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, c
        
        if (p) {
                *p = '\0';
-               gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, u);
+               gensec_security->user.domain = talloc_strdup(gensec_security, u);
                if (!gensec_security->user.domain) {
                        return NT_STATUS_NO_MEMORY;
                }
-               gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, p+1);
+               gensec_security->user.name = talloc_strdup(gensec_security, p+1);
                if (!gensec_security->user.name) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -521,7 +541,7 @@ NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, c
 
 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user) 
 {
-       gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, user);
+       gensec_security->user.name = talloc_strdup(gensec_security, user);
        if (!gensec_security->user.name) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -548,7 +568,7 @@ const char *gensec_get_username(struct gensec_security *gensec_security)
 
 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain) 
 {
-       gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, domain);
+       gensec_security->user.domain = talloc_strdup(gensec_security, domain);
        if (!gensec_security->user.domain) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -577,7 +597,7 @@ const char *gensec_get_domain(struct gensec_security *gensec_security)
 
 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm) 
 {
-       gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, realm);
+       gensec_security->user.realm = talloc_strdup(gensec_security, realm);
        if (!gensec_security->user.realm) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -625,7 +645,7 @@ char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLO
 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
                             const char *password) 
 {
-       gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
+       gensec_security->user.password = talloc_strdup(gensec_security, password);
        if (!gensec_security->user.password) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -639,7 +659,7 @@ NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
 
 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
 {
-       gensec_security->target.principal = talloc_strdup(gensec_security->mem_ctx, principal);
+       gensec_security->target.principal = talloc_strdup(gensec_security, principal);
        if (!gensec_security->target.principal) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -653,7 +673,7 @@ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, co
 
 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
 {
-       gensec_security->target.service = talloc_strdup(gensec_security->mem_ctx, service);
+       gensec_security->target.service = talloc_strdup(gensec_security, service);
        if (!gensec_security->target.service) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -667,7 +687,7 @@ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, cons
 
 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
 {
-       gensec_security->target.hostname = talloc_strdup(gensec_security->mem_ctx, hostname);
+       gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
        if (!gensec_security->target.hostname) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -732,10 +752,15 @@ NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
   The 'name' can be later used by other backends to find the operations
   structure for this backend.
 */
-static NTSTATUS gensec_register(const void *_ops)
+NTSTATUS gensec_register(const void *_ops)
 {
        const struct gensec_security_ops *ops = _ops;
        
+       if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
+               DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
+               return NT_STATUS_OK;
+       }
+
        if (gensec_security_by_name(ops->name) != NULL) {
                /* its already registered! */
                DEBUG(0,("GENSEC backend '%s' already registered\n", 
@@ -743,7 +768,9 @@ static NTSTATUS gensec_register(const void *_ops)
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (gensec_num_backends+1));
+       generic_security_ops = realloc_p(generic_security_ops, 
+                                        const struct gensec_security_ops *, 
+                                        gensec_num_backends+1);
        if (!generic_security_ops) {
                smb_panic("out of memory in gensec_register");
        }
@@ -777,25 +804,8 @@ const struct gensec_critical_sizes *gensec_interface_version(void)
 /*
   initialise the GENSEC subsystem
 */
-BOOL gensec_init(void)
+NTSTATUS gensec_init(void)
 {
-       static BOOL initialised;
-       NTSTATUS status;
-
-       /* this is *completely* the wrong way to do this */
-       if (initialised) {
-               return True;
-       }
-
-       status = register_subsystem("gensec", gensec_register); 
-       if (!NT_STATUS_IS_OK(status)) {
-               return False;
-       }
-
-       static_init_gensec;
        gensec_dcerpc_schannel_init();
-
-       initialised = True;
-       DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));
-       return True;
+       return NT_STATUS_OK;
 }