r25035: Fix some more warnings, use service pointer rather than service number in...
[jelmer/samba4-debian.git] / source / auth / gensec / gensec_gssapi.c
index a59aa8a07c1c9eaa8a31f214a9b1d3184457cc0c..8a7e8090ebb726c5fd1659d0f4e97cd562905ce6 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 
 {
@@ -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);
@@ -143,7 +155,7 @@ 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(NULL, "gensec_gssapi", "max wrap buf size", 65536);
                
        gensec_gssapi_state->sasl = False;
        gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
@@ -158,16 +170,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(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(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(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(NULL, "gensec_gssapi", "sequence", true)) {
                gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
        }
 
@@ -218,7 +230,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        }
 
        /* don't do DNS lookups of any kind, it might/will fail for a netbios name */
-       ret = gsskrb5_set_dns_canonicalize(FALSE);
+       ret = gsskrb5_set_dns_canonicalize(lp_parm_bool(NULL, "krb5", "set_dns_canonicalize", false));
        if (ret) {
                DEBUG(1,("gensec_krb5_start: gsskrb5_set_dns_canonicalize failed\n"));
                talloc_free(gensec_gssapi_state);
@@ -226,6 +238,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        }
 
        ret = smb_krb5_init_context(gensec_gssapi_state, 
+                                   gensec_security->event_ctx,
                                    &gensec_gssapi_state->smb_krb5_context);
        if (ret) {
                DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
@@ -320,20 +333,17 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
 
        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);
-
                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,
@@ -350,8 +360,10 @@ 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"));
@@ -359,7 +371,10 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        }
 
        gensec_gssapi_state->client_cred = gcc;
-
+       if (!talloc_reference(gensec_gssapi_state, gcc)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
        return NT_STATUS_OK;
 }
 
@@ -1215,7 +1230,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);
 
@@ -1300,7 +1317,7 @@ 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(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,
@@ -1341,7 +1358,10 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                        return NT_STATUS_NO_MEMORY;
                }
 
+               cli_credentials_set_event_context(session_info->credentials, gensec_security->event_ctx);
                cli_credentials_set_conf(session_info->credentials);
+               /* 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,
@@ -1350,6 +1370,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;
        }