r26252: Specify loadparm_context explicitly when creating sessions.
[kamenim/samba-autobuild/.git] / source4 / auth / gensec / gensec_gssapi.c
index 9f796dc9d12d2a470abbc1fc9aa9cafa34b4431e..b3e5352410c9cd43aebe90fe30835c4cad5ca098 100644 (file)
@@ -8,7 +8,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,
 
    
    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 "lib/events/events.h"
 #include "system/kerberos.h"
 #include "heimdal/lib/gssapi/gssapi/gssapi.h"
 #include "auth/kerberos/kerberos.h"
@@ -34,6 +34,7 @@
 #include "auth/credentials/credentials.h"
 #include "auth/credentials/credentials_krb5.h"
 #include "auth/gensec/gensec.h"
+#include "param/param.h"
 
 enum gensec_gssapi_sasl_state 
 {
@@ -64,7 +65,7 @@ struct gensec_gssapi_state {
 
        gss_cred_id_t delegated_cred_handle;
 
-       BOOL sasl; /* We have two different mechs in this file: One
+       bool sasl; /* We have two different mechs in this file: One
                    * for SASL wrapped GSSAPI and another for normal
                    * GSSAPI */
        enum gensec_gssapi_sasl_state sasl_state;
@@ -86,18 +87,29 @@ static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
        OM_uint32 disp_min_stat, disp_maj_stat;
        gss_buffer_desc maj_error_message;
        gss_buffer_desc min_error_message;
+       char *maj_error_string, *min_error_string;
        OM_uint32 msg_ctx = 0;
 
        char *ret;
 
        maj_error_message.value = NULL;
        min_error_message.value = NULL;
+       maj_error_message.length = 0;
+       min_error_message.length = 0;
        
        disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
                           mech, &msg_ctx, &maj_error_message);
        disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
                           mech, &msg_ctx, &min_error_message);
-       ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
+       
+       maj_error_string = talloc_strndup(mem_ctx, (char *)maj_error_message.value, maj_error_message.length);
+
+       min_error_string = talloc_strndup(mem_ctx, (char *)min_error_message.value, min_error_message.length);
+
+       ret = talloc_asprintf(mem_ctx, "%s: %s", maj_error_string, min_error_string);
+
+       talloc_free(maj_error_string);
+       talloc_free(min_error_string);
 
        gss_release_buffer(&disp_min_stat, &maj_error_message);
        gss_release_buffer(&disp_min_stat, &min_error_message);
@@ -106,7 +118,7 @@ static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
 }
 
 
-static int gensec_gssapi_destory(struct gensec_gssapi_state *gensec_gssapi_state)
+static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state)
 {
        OM_uint32 maj_stat, min_stat;
        
@@ -130,7 +142,8 @@ static int gensec_gssapi_destory(struct gensec_gssapi_state *gensec_gssapi_state
        return 0;
 }
 
-static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
+static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security,
+                                   struct loadparm_context *lp_ctx)
 {
        struct gensec_gssapi_state *gensec_gssapi_state;
        krb5_error_code ret;
@@ -143,9 +156,9 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        
        gensec_gssapi_state->gss_exchange_count = 0;
        gensec_gssapi_state->max_wrap_buf_size
-               = lp_parm_int(-1, "gensec_gssapi", "max wrap buf size", 65536);
+               = lp_parm_int(lp_ctx, NULL, "gensec_gssapi", "max wrap buf size", 65536);
                
-       gensec_gssapi_state->sasl = False;
+       gensec_gssapi_state->sasl = false;
        gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
 
        gensec_security->private_data = gensec_gssapi_state;
@@ -158,16 +171,16 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
        
        gensec_gssapi_state->want_flags = 0;
-       if (lp_parm_bool(-1, "gensec_gssapi", "mutual", True)) {
+       if (lp_parm_bool(lp_ctx, NULL, "gensec_gssapi", "mutual", true)) {
                gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
        }
-       if (lp_parm_bool(-1, "gensec_gssapi", "delegation", True)) {
+       if (lp_parm_bool(lp_ctx, NULL, "gensec_gssapi", "delegation", true)) {
                gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
        }
-       if (lp_parm_bool(-1, "gensec_gssapi", "replay", True)) {
+       if (lp_parm_bool(lp_ctx, NULL, "gensec_gssapi", "replay", true)) {
                gensec_gssapi_state->want_flags |= GSS_C_REPLAY_FLAG;
        }
-       if (lp_parm_bool(-1, "gensec_gssapi", "sequence", True)) {
+       if (lp_parm_bool(lp_ctx, NULL, "gensec_gssapi", "sequence", true)) {
                gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
        }
 
@@ -178,7 +191,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 
        gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 
-       talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
+       talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor);
 
        if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
                gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
@@ -190,7 +203,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
                gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
        }
 
-       gensec_gssapi_state->gss_oid = gss_mech_krb5;
+       gensec_gssapi_state->gss_oid = GSS_C_NULL_OID;
        
        send_to_kdc.func = smb_krb5_send_and_recv_func;
        send_to_kdc.ptr = gensec_security->event_ctx;
@@ -198,13 +211,41 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
        if (ret) {
                DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
+               talloc_free(gensec_gssapi_state);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+       if (lp_realm(lp_ctx) && *lp_realm(lp_ctx)) {
+               char *upper_realm = strupper_talloc(gensec_gssapi_state, lp_realm(lp_ctx));
+               if (!upper_realm) {
+                       DEBUG(1,("gensec_krb5_start: could not uppercase realm: %s\n", lp_realm(lp_ctx)));
+                       talloc_free(gensec_gssapi_state);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               ret = gsskrb5_set_default_realm(upper_realm);
+               talloc_free(upper_realm);
+               if (ret) {
+                       DEBUG(1,("gensec_krb5_start: gsskrb5_set_default_realm failed\n"));
+                       talloc_free(gensec_gssapi_state);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+       }
+
+       /* don't do DNS lookups of any kind, it might/will fail for a netbios name */
+       ret = gsskrb5_set_dns_canonicalize(lp_parm_bool(lp_ctx, NULL, "krb5", "set_dns_canonicalize", false));
+       if (ret) {
+               DEBUG(1,("gensec_krb5_start: gsskrb5_set_dns_canonicalize failed\n"));
+               talloc_free(gensec_gssapi_state);
                return NT_STATUS_INTERNAL_ERROR;
        }
+
        ret = smb_krb5_init_context(gensec_gssapi_state, 
+                                   gensec_security->event_ctx,
+                                   lp_ctx,
                                    &gensec_gssapi_state->smb_krb5_context);
        if (ret) {
                DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
                         error_message(ret)));
+               talloc_free(gensec_gssapi_state);
                return NT_STATUS_INTERNAL_ERROR;
        }
        return NT_STATUS_OK;
@@ -218,7 +259,7 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
        struct cli_credentials *machine_account;
        struct gssapi_creds_container *gcc;
 
-       nt_status = gensec_gssapi_start(gensec_security);
+       nt_status = gensec_gssapi_start(gensec_security, global_loadparm);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
        }
@@ -252,7 +293,7 @@ static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_s
 
        if (NT_STATUS_IS_OK(nt_status)) {
                gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-               gensec_gssapi_state->sasl = True;
+               gensec_gssapi_state->sasl = true;
        }
        return nt_status;
 }
@@ -283,29 +324,28 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       nt_status = gensec_gssapi_start(gensec_security);
+       nt_status = gensec_gssapi_start(gensec_security, global_loadparm);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
        }
 
        gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
 
-       principal = gensec_get_target_principal(gensec_security);
-       if (principal && lp_client_use_spnego_principal()) {
-               name_token.value  = discard_const_p(uint8_t, principal);
-               name_token.length = strlen(principal);
+       gensec_gssapi_state->gss_oid = gss_mech_krb5;
 
+       principal = gensec_get_target_principal(gensec_security);
+       if (principal && lp_client_use_spnego_principal(global_loadparm)) {
                name_type = GSS_C_NULL_OID;
        } else {
                principal = talloc_asprintf(gensec_gssapi_state, "%s@%s", 
                                            gensec_get_target_service(gensec_security), 
                                            hostname);
 
-               name_token.value  = discard_const_p(uint8_t, principal);
-               name_token.length = strlen(principal);
-
                name_type = GSS_C_NT_HOSTBASED_SERVICE;
        }               
+       name_token.value  = discard_const_p(uint8_t, principal);
+       name_token.length = strlen(principal);
+
 
        maj_stat = gss_import_name (&min_stat,
                                    &name_token,
@@ -322,16 +362,21 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        switch (ret) {
        case 0:
                break;
+       case KRB5KDC_ERR_PREAUTH_FAILED:
+               return NT_STATUS_LOGON_FAILURE;
        case KRB5_KDC_UNREACH:
-               DEBUG(3, ("Cannot reach a KDC we require\n"));
+               DEBUG(3, ("Cannot reach a KDC we require to contact %s\n", principal));
                return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
        default:
-               DEBUG(1, ("Aquiring initiator credentails failed\n"));
+               DEBUG(1, ("Aquiring initiator credentials failed\n"));
                return NT_STATUS_UNSUCCESSFUL;
        }
 
        gensec_gssapi_state->client_cred = gcc;
-
+       if (!talloc_reference(gensec_gssapi_state, gcc)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
        return NT_STATUS_OK;
 }
 
@@ -343,7 +388,7 @@ static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_s
 
        if (NT_STATUS_IS_OK(nt_status)) {
                gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-               gensec_gssapi_state->sasl = True;
+               gensec_gssapi_state->sasl = true;
        }
        return nt_status;
 }
@@ -390,7 +435,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
        OM_uint32 maj_stat, min_stat;
        OM_uint32 min_stat2;
        gss_buffer_desc input_token, output_token;
-       gss_OID gss_oid_p;
+       gss_OID gss_oid_p = NULL;
        input_token.length = in.length;
        input_token.value = in.data;
 
@@ -409,10 +454,13 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                                        0, 
                                                        gensec_gssapi_state->input_chan_bindings,
                                                        &input_token, 
-                                                       NULL, 
+                                                       &gss_oid_p,
                                                        &output_token, 
                                                        &gensec_gssapi_state->got_flags, /* ret flags */
                                                        NULL);
+                       if (gss_oid_p) {
+                               gensec_gssapi_state->gss_oid = gss_oid_p;
+                       }
                        break;
                }
                case GENSEC_SERVER:
@@ -428,7 +476,9 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                                          &gensec_gssapi_state->got_flags, 
                                                          NULL, 
                                                          &gensec_gssapi_state->delegated_cred_handle);
-                       gensec_gssapi_state->gss_oid = gss_oid_p;
+                       if (gss_oid_p) {
+                               gensec_gssapi_state->gss_oid = gss_oid_p;
+                       }
                        break;
                }
                default:
@@ -484,9 +534,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        gss_release_buffer(&min_stat2, &output_token);
                        
                        return NT_STATUS_MORE_PROCESSING_REQUIRED;
-               } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
-                          && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
-                                     gensec_gssapi_state->gss_oid->length) == 0)) {
+               } else if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
                        switch (min_stat) {
                        case KRB5_KDC_UNREACH:
                                DEBUG(3, ("Cannot reach a KDC we require: %s\n",
@@ -586,7 +634,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
 
                        maj_stat = gss_wrap(&min_stat, 
                                            gensec_gssapi_state->gssapi_context, 
-                                           False,
+                                           false,
                                            GSS_C_QOP_DEFAULT,
                                            &input_token,
                                            &conf_state,
@@ -651,7 +699,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
 
                        maj_stat = gss_wrap(&min_stat, 
                                            gensec_gssapi_state->gssapi_context, 
-                                           False,
+                                           false,
                                            GSS_C_QOP_DEFAULT,
                                            &input_token,
                                            &conf_state,
@@ -1064,7 +1112,7 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi
 }
 
 /* Try to figure out what features we actually got on the connection */
-static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
+static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
                                       uint32_t feature) 
 {
        struct gensec_gssapi_state *gensec_gssapi_state
@@ -1089,9 +1137,8 @@ static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
        }
        if (feature & GENSEC_FEATURE_SESSION_KEY) {
                /* Only for GSSAPI/Krb5 */
-               if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
-                   && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
-                       return True;
+               if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
+                       return true;
                }
        }
        if (feature & GENSEC_FEATURE_DCE_STYLE) {
@@ -1099,9 +1146,9 @@ static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
        }
        /* We can always do async (rather than strict request/reply) packets.  */
        if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
-               return True;
+               return true;
        }
-       return False;
+       return false;
 }
 
 /*
@@ -1185,7 +1232,9 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                return NT_STATUS_FOOBAR;
        }
 
-       principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
+       principal_string = talloc_strndup(mem_ctx, 
+                                         (const char *)name_token.value, 
+                                         name_token.length);
 
        gss_release_buffer(&min_stat, &name_token);
 
@@ -1270,10 +1319,10 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                        talloc_free(mem_ctx);
                        return nt_status;
                }
-       } else if (!lp_parm_bool(-1, "gensec", "require_pac", False)) {
+       } else if (!lp_parm_bool(global_loadparm, NULL, "gensec", "require_pac", false)) {
                DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s\n",
                          gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-               nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
+               nt_status = sam_get_server_info_principal(mem_ctx, global_loadparm, principal_string,
                                                          &server_info);
 
                if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1311,7 +1360,10 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                        return NT_STATUS_NO_MEMORY;
                }
 
-               cli_credentials_set_conf(session_info->credentials);
+               cli_credentials_set_event_context(session_info->credentials, gensec_security->event_ctx);
+               cli_credentials_set_conf(session_info->credentials, global_loadparm);
+               /* Just so we don't segfault trying to get at a username */
+               cli_credentials_set_anonymous(session_info->credentials);
                
                ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
                                                           gensec_gssapi_state->delegated_cred_handle,
@@ -1320,6 +1372,10 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                        talloc_free(mem_ctx);
                        return NT_STATUS_NO_MEMORY;
                }
+               
+               /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
+               cli_credentials_set_kerberos_state(session_info->credentials, CRED_MUST_USE_KERBEROS);
+
                /* It has been taken from this place... */
                gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
        }
@@ -1331,11 +1387,40 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
 }
 
 static const char *gensec_gssapi_krb5_oids[] = { 
-       GENSEC_OID_KERBEROS5,
        GENSEC_OID_KERBEROS5_OLD,
+       GENSEC_OID_KERBEROS5,
+       NULL 
+};
+
+static const char *gensec_gssapi_spnego_oids[] = { 
+       GENSEC_OID_SPNEGO,
        NULL 
 };
 
+/* As a server, this could in theory accept any GSSAPI mech */
+static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
+       .name           = "gssapi_spnego",
+       .sasl_name      = "GSS-SPNEGO",
+       .auth_type      = DCERPC_AUTH_TYPE_SPNEGO,
+       .oid            = gensec_gssapi_spnego_oids,
+       .client_start   = gensec_gssapi_client_start,
+       .server_start   = gensec_gssapi_server_start,
+       .magic          = gensec_gssapi_magic,
+       .update         = gensec_gssapi_update,
+       .session_key    = gensec_gssapi_session_key,
+       .session_info   = gensec_gssapi_session_info,
+       .sign_packet    = gensec_gssapi_sign_packet,
+       .check_packet   = gensec_gssapi_check_packet,
+       .seal_packet    = gensec_gssapi_seal_packet,
+       .unseal_packet  = gensec_gssapi_unseal_packet,
+       .wrap           = gensec_gssapi_wrap,
+       .unwrap         = gensec_gssapi_unwrap,
+       .have_feature   = gensec_gssapi_have_feature,
+       .enabled        = false,
+       .kerberos       = true,
+       .priority       = GENSEC_GSSAPI
+};
+
 /* As a server, this could in theory accept any GSSAPI mech */
 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
        .name           = "gssapi_krb5",
@@ -1354,8 +1439,8 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
        .wrap           = gensec_gssapi_wrap,
        .unwrap         = gensec_gssapi_unwrap,
        .have_feature   = gensec_gssapi_have_feature,
-       .enabled        = True,
-       .kerberos       = True,
+       .enabled        = true,
+       .kerberos       = true,
        .priority       = GENSEC_GSSAPI
 };
 
@@ -1373,8 +1458,8 @@ static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
        .wrap             = gensec_gssapi_wrap,
        .unwrap           = gensec_gssapi_unwrap,
        .have_feature     = gensec_gssapi_have_feature,
-       .enabled          = True,
-       .kerberos         = True,
+       .enabled          = true,
+       .kerberos         = true,
        .priority         = GENSEC_GSSAPI
 };
 
@@ -1382,6 +1467,13 @@ NTSTATUS gensec_gssapi_init(void)
 {
        NTSTATUS ret;
 
+       ret = gensec_register(&gensec_gssapi_spnego_security_ops);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(0,("Failed to register '%s' gensec backend!\n",
+                       gensec_gssapi_spnego_security_ops.name));
+               return ret;
+       }
+
        ret = gensec_register(&gensec_gssapi_krb5_security_ops);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(0,("Failed to register '%s' gensec backend!\n",