From edccfc91928c323f18febb7b90e41e0ddbfd8c7c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 15 Mar 2007 19:18:18 +0000 Subject: r21845: Refactor the sessionsetupX code a little to allow us to return a NT_STATUS_TIME_DIFFERENCE_AT_DC error to a client when there's clock skew. Will help people debug this. Prepare us for being able to return the correct sessionsetupX "NT_STATUS_MORE_PROCESSING_REQUIRED" error with associated krb5 clock skew error to allow clients to re-sync time with us when we're eventually able to be a KDC. Jeremy. (This used to be commit c426340fc79a6b446033433b8de599130adffe28) --- source3/configure.in | 14 +++ source3/include/includes.h | 5 + source3/libads/kerberos_verify.c | 103 +++++++++++------ source3/libads/krb5_errs.c | 2 + source3/libsmb/clikrb5.c | 33 ++++++ source3/smbd/sesssetup.c | 235 ++++++++++++++++++++++++++++++++------- 6 files changed, 319 insertions(+), 73 deletions(-) diff --git a/source3/configure.in b/source3/configure.in index 5cd07924f6..0b2f8bd905 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -3886,6 +3886,20 @@ if test x"$with_ads_support" != x"no"; then [Whether the type krb5_addresses type exists]) fi + AC_CACHE_CHECK([whether krb5_mk_error takes 3 arguments MIT or 9 Heimdal], + samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE, [ + AC_TRY_COMPILE([#include ], + [ + krb5_mk_error(0,0,0);], + samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE=yes, + samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE=no)]) + + if test x"$samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE" = x"yes"; then + AC_DEFINE(HAVE_SHORT_KRB5_MK_ERROR_INTERFACE,1, + [whether krb5_mk_error takes 3 arguments MIT or 9 Heimdal]) + fi + + # # # Now the decisions whether we can support krb5 diff --git a/source3/include/includes.h b/source3/include/includes.h index c71acd3866..5b81cfbfab 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -1181,6 +1181,11 @@ void smb_krb5_get_init_creds_opt_free(krb5_context context, krb5_get_init_creds_opt *opt); krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context, krb5_get_init_creds_opt **opt); +krb5_error_code smb_krb5_mk_error(krb5_context context, + krb5_error_code error_code, + const krb5_principal server, + krb5_data *reply); + #endif /* HAVE_KRB5 */ diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index 2c114b1240..0ec03ef4bf 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -7,6 +7,7 @@ Copyright (C) Guenther Deschner 2003, 2005 Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 Copyright (C) Andrew Bartlett 2004-2005 + Copyright (C) Jeremy Allison 2007 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 @@ -37,9 +38,12 @@ const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int ); ads_keytab_add_entry function for details. ***********************************************************************************/ -static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) +static BOOL ads_keytab_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) { krb5_error_code ret = 0; BOOL auth_ok = False; @@ -51,6 +55,11 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut fstring my_name, my_fqdn; int i; int number_matched_principals = 0; + krb5_data packet; + + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; /* Generate the list of principal names which we expect * clients might want to use for authenticating to the file @@ -103,11 +112,11 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut } number_matched_principals++; - p_packet->length = ticket->length; - p_packet->data = (char *)ticket->data; + packet.length = ticket->length; + packet.data = (char *)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, p_packet, + ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, kt_entry.principal, keytab, NULL, pp_tkt, keyblock); @@ -125,7 +134,8 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut * entries - Guenther */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || - ret == KRB5KRB_AP_ERR_TKT_EXPIRED) { + ret == KRB5KRB_AP_ERR_TKT_EXPIRED || + ret == KRB5KRB_AP_ERR_SKEW) { break; } } else { @@ -184,6 +194,7 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut if (keytab) { krb5_kt_close(context, keytab); } + *perr = ret; return auth_ok; } @@ -191,32 +202,40 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut Try to verify a ticket using the secrets.tdb. ***********************************************************************************/ -static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, - krb5_principal host_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) +static krb5_error_code ads_secrets_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + krb5_principal host_princ, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) { krb5_error_code ret = 0; BOOL auth_ok = False; char *password_s = NULL; krb5_data password; krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 }; + krb5_data packet; int i; + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; + #if defined(ENCTYPE_ARCFOUR_HMAC) enctypes[2] = ENCTYPE_ARCFOUR_HMAC; #endif - ZERO_STRUCTP(keyblock); - if (!secrets_init()) { DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); + *perr = KRB5_CONFIG_CANTOPEN; return False; } password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!password_s) { DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n")); + *perr = KRB5_LIBOS_CANTREADPWD; return False; } @@ -225,14 +244,15 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ - p_packet->length = ticket->length; - p_packet->data = (char *)ticket->data; + packet.length = ticket->length; + packet.data = (char *)ticket->data; /* We need to setup a auth context with each possible encoding type in turn. */ for (i=0;enctypes[i];i++) { krb5_keyblock *key = NULL; if (!(key = SMB_MALLOC_P(krb5_keyblock))) { + ret = ENOMEM; goto out; } @@ -243,7 +263,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au krb5_auth_con_setuseruserkey(context, auth_context, key); - if (!(ret = krb5_rd_req(context, &auth_context, p_packet, + if (!(ret = krb5_rd_req(context, &auth_context, &packet, NULL, NULL, NULL, pp_tkt))) { DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", @@ -260,7 +280,8 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au /* successfully decrypted but ticket is just not valid at the moment */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || - ret == KRB5KRB_AP_ERR_TKT_EXPIRED) { + ret == KRB5KRB_AP_ERR_TKT_EXPIRED || + ret == KRB5KRB_AP_ERR_SKEW) { break; } @@ -270,7 +291,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au out: SAFE_FREE(password_s); - + *perr = ret; return auth_ok; } @@ -280,9 +301,11 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au ***********************************************************************************/ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, - const char *realm, time_t time_offset, - const DATA_BLOB *ticket, - char **principal, PAC_DATA **pac_data, + const char *realm, + time_t time_offset, + const DATA_BLOB *ticket, + char **principal, + PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key) { @@ -296,20 +319,22 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, krb5_rcache rcache = NULL; krb5_keyblock *keyblock = NULL; time_t authtime; - int ret; - + krb5_error_code ret = 0; + krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; - BOOL got_replay_mutex = False; - BOOL auth_ok = False; + BOOL got_replay_mutex = False; BOOL got_auth_data = False; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); - ZERO_STRUCTP(ap_rep); - ZERO_STRUCTP(session_key); + + *principal = NULL; + *pac_data = NULL; + *ap_rep = data_blob(NULL,0); + *session_key = data_blob(NULL,0); initialize_krb5_error_table(); ret = krb5_init_context(&context); @@ -339,6 +364,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } asprintf(&host_princ_s, "%s$", global_myname()); + if (!host_princ_s) { + goto out; + } + strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { @@ -353,6 +382,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, if (!grab_server_mutex("replay cache mutex")) { DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); + ret = KRB5_CC_IO; goto out; } @@ -375,11 +405,11 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } if (lp_use_kerberos_keytab()) { - auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt, &keyblock); + auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); } if (!auth_ok) { auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, - ticket, &packet, &tkt, &keyblock); + ticket, &tkt, &keyblock, &ret); } release_server_mutex(); @@ -395,6 +425,15 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); + /* Try map the error return in case it's something like + * a clock skew error. + */ + sret = krb5_to_nt_status(ret); + if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { + sret = NT_STATUS_LOGON_FAILURE; + } + DEBUG(10,("ads_verify_ticket: returning error %s\n", + nt_errstr(sret) )); goto out; } @@ -409,8 +448,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } *ap_rep = data_blob(packet.data, packet.length); - SAFE_FREE(packet.data); - packet.length = 0; + if (packet.data) { + kerberos_free_data_contents(context, &packet); + ZERO_STRUCT(packet); + } get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); diff --git a/source3/libads/krb5_errs.c b/source3/libads/krb5_errs.c index 89cfc2d143..c153bee96e 100644 --- a/source3/libads/krb5_errs.c +++ b/source3/libads/krb5_errs.c @@ -59,6 +59,8 @@ static const struct { {KRB5_CC_NOTFOUND, NT_STATUS_NO_SUCH_FILE}, {KRB5_FCC_NOFILE, NT_STATUS_NO_SUCH_FILE}, {KRB5KDC_ERR_NONE, NT_STATUS_OK}, + {KRB5_RC_MALLOC, NT_STATUS_NO_MEMORY}, + {ENOMEM, NT_STATUS_NO_MEMORY}, {0, NT_STATUS_OK} }; diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index 43dfddda47..659197214f 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -75,6 +75,7 @@ static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, krb5_error_code ret; char *utf8_name; + *principal = NULL; if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) { return ENOMEM; } @@ -97,6 +98,7 @@ static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, krb5_error_code ret; char *utf8_name; + *unix_name = NULL; ret = krb5_unparse_name(context, principal, &utf8_name); if (ret) { return ret; @@ -1430,6 +1432,37 @@ done: SAFE_FREE(opt); opt = NULL; #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */ +} + + krb5_error_code smb_krb5_mk_error(krb5_context context, + krb5_error_code error_code, + const krb5_principal server, + krb5_data *reply) +{ +#ifdef HAVE_SHORT_KRB5_MK_ERROR_INTERFACE /* MIT */ + /* + * The MIT interface is *terrible*. + * We have to construct this ourselves... + */ + krb5_error e; + + memset(&e, 0, sizeof(e)); + krb5_us_timeofday(context, &e.stime, &e.susec); + e.server = server; + e.error = error_code - krb5_err_base; + + return krb5_mk_error(context, &e, reply); +#else /* Heimdal. */ + return krb5_mk_error(context, + error_code, + NULL, + NULL, /* e_data */ + NULL, + server, + NULL, + NULL, + reply); +#endif } #else /* HAVE_KRB5 */ diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 7a5f8be47f..e678d959d8 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -158,13 +158,75 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) #ifdef HAVE_KRB5 + +#if 0 +/* Experiment that failed. See "only happens with a KDC" comment below. */ +/**************************************************************************** + Cerate a clock skew error blob for a Windows client. +****************************************************************************/ + +static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out) +{ + krb5_context context = NULL; + krb5_error_code kerr = 0; + krb5_data reply; + krb5_principal host_princ = NULL; + char *host_princ_s = NULL; + BOOL ret = False; + + *pblob_out = data_blob(NULL,0); + + kerr = krb5_init_context(&context); + if (kerr) { + return False; + } + /* Create server principal. */ + asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm()); + if (!host_princ_s) { + goto out; + } + strlower_m(host_princ_s); + + kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ); + if (kerr) { + DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n", + host_princ_s, error_message(kerr) )); + goto out; + } + + kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply); + if (kerr) { + DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n", + error_message(kerr) )); + goto out; + } + + *pblob_out = data_blob(reply.data, reply.length); + kerberos_free_data_contents(context,&reply); + ret = True; + + out: + + if (host_princ_s) { + SAFE_FREE(host_princ_s); + } + if (host_princ) { + krb5_free_principal(context, host_princ); + } + krb5_free_context(context); + return ret; +} +#endif + /**************************************************************************** -reply to a session setup spnego negotiate packet for kerberos + Reply to a session setup spnego negotiate packet for kerberos. ****************************************************************************/ + static int reply_spnego_kerberos(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - DATA_BLOB *secblob) + DATA_BLOB *secblob, + BOOL *p_invalidate_vuid) { TALLOC_CTX *mem_ctx; DATA_BLOB ticket; @@ -191,9 +253,13 @@ static int reply_spnego_kerberos(connection_struct *conn, ZERO_STRUCT(ap_rep_wrapped); ZERO_STRUCT(response); + /* Normally we will always invalidate the intermediate vuid. */ + *p_invalidate_vuid = True; + mem_ctx = talloc_init("reply_spnego_kerberos"); - if (mem_ctx == NULL) + if (mem_ctx == NULL) { return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY)); + } if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) { talloc_destroy(mem_ctx); @@ -205,9 +271,50 @@ static int reply_spnego_kerberos(connection_struct *conn, data_blob_free(&ticket); if (!NT_STATUS_IS_OK(ret)) { - DEBUG(1,("Failed to verify incoming ticket!\n")); +#if 0 + /* Experiment that failed. See "only happens with a KDC" comment below. */ + + if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { + + /* + * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED + * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded + * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its + * clock and continues rather than giving an error. JRA. + * -- Looks like this only happens with a KDC. JRA. + */ + + BOOL ok = make_krb5_skew_error(&ap_rep); + if (!ok) { + talloc_destroy(mem_ctx); + return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + } + ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR); + response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD); + reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED); + + /* + * In this one case we don't invalidate the intermediate vuid. + * as we're expecting the client to re-use it for the next + * sessionsetupX packet. JRA. + */ + + *p_invalidate_vuid = False; + + data_blob_free(&ap_rep); + data_blob_free(&ap_rep_wrapped); + data_blob_free(&response); + talloc_destroy(mem_ctx); + return -1; /* already replied */ + } +#else + if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { + ret = NT_STATUS_LOGON_FAILURE; + } +#endif + DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); talloc_destroy(mem_ctx); - return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + return ERROR_NT(nt_status_squash(ret)); } DEBUG(3,("Ticket name is [%s]\n", client)); @@ -523,32 +630,19 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out } /**************************************************************************** - Reply to a session setup spnego negotiate packet. + Is this a krb5 mechanism ? ****************************************************************************/ -static int reply_spnego_negotiate(connection_struct *conn, - char *inbuf, - char *outbuf, - uint16 vuid, - int length, int bufsize, - DATA_BLOB blob1, - AUTH_NTLMSSP_STATE **auth_ntlmssp_state) +static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5) { char *OIDs[ASN1_MAX_OIDS]; - DATA_BLOB secblob; int i; - DATA_BLOB chal; -#ifdef HAVE_KRB5 - BOOL got_kerberos_mechanism = False; -#endif - NTSTATUS nt_status; - /* parse out the OIDs and the first sec blob */ - if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { - /* Kill the intermediate vuid */ - invalidate_vuid(vuid); + *p_is_krb5 = False; - return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + /* parse out the OIDs and the first sec blob */ + if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) { + return NT_STATUS_LOGON_FAILURE; } /* only look at the first OID for determining the mechToken -- @@ -564,24 +658,53 @@ static int reply_spnego_negotiate(connection_struct *conn, #ifdef HAVE_KRB5 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) { - got_kerberos_mechanism = True; + *p_is_krb5 = True; } #endif for (i=0;OIDs[i];i++) { - DEBUG(3,("Got OID %s\n", OIDs[i])); + DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i])); free(OIDs[i]); } - DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length)); + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a session setup spnego negotiate packet. +****************************************************************************/ + +static int reply_spnego_negotiate(connection_struct *conn, + char *inbuf, + char *outbuf, + uint16 vuid, + int length, int bufsize, + DATA_BLOB blob1, + AUTH_NTLMSSP_STATE **auth_ntlmssp_state) +{ + DATA_BLOB secblob; + DATA_BLOB chal; + BOOL got_kerberos_mechanism = False; + NTSTATUS status; + + status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism); + if (!NT_STATUS_IS_OK(status)) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + return ERROR_NT(nt_status_squash(status)); + } + + DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length)); #ifdef HAVE_KRB5 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { + BOOL destroy_vuid = True; int ret = reply_spnego_kerberos(conn, inbuf, outbuf, - length, bufsize, &secblob); + length, bufsize, &secblob, &destroy_vuid); data_blob_free(&secblob); - /* Kill the intermediate vuid */ - invalidate_vuid(vuid); - + if (destroy_vuid) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + } return ret; } #endif @@ -590,28 +713,27 @@ static int reply_spnego_negotiate(connection_struct *conn, auth_ntlmssp_end(auth_ntlmssp_state); } - nt_status = auth_ntlmssp_start(auth_ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { + status = auth_ntlmssp_start(auth_ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); - - return ERROR_NT(nt_status_squash(nt_status)); + return ERROR_NT(nt_status_squash(status)); } - nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, + status = auth_ntlmssp_update(*auth_ntlmssp_state, secblob, &chal); data_blob_free(&secblob); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state, - &chal, nt_status, True); + &chal, status, True); data_blob_free(&chal); /* already replied */ return -1; } - + /**************************************************************************** Reply to a session setup spnego auth packet. ****************************************************************************/ @@ -622,8 +744,10 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, DATA_BLOB blob1, AUTH_NTLMSSP_STATE **auth_ntlmssp_state) { - DATA_BLOB auth, auth_reply; - NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; + DATA_BLOB auth = data_blob(NULL,0); + DATA_BLOB auth_reply = data_blob(NULL,0); + DATA_BLOB secblob = data_blob(NULL,0); + NTSTATUS status = NT_STATUS_INVALID_PARAMETER; if (!spnego_parse_auth(blob1, &auth)) { #if 0 @@ -634,6 +758,33 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } + + if (auth.data[0] == ASN1_APPLICATION(0)) { + /* Might be a second negTokenTarg packet */ + + BOOL got_krb5_mechanism = False; + status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism); + if (NT_STATUS_IS_OK(status)) { + DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length)); +#ifdef HAVE_KRB5 + if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { + BOOL destroy_vuid = True; + int ret = reply_spnego_kerberos(conn, inbuf, outbuf, + length, bufsize, &secblob, &destroy_vuid); + data_blob_free(&secblob); + data_blob_free(&auth); + if (destroy_vuid) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + } + return ret; + } +#endif + } + } + + /* If we get here it wasn't a negTokenTarg auth packet. */ + data_blob_free(&secblob); if (!*auth_ntlmssp_state) { /* Kill the intermediate vuid */ @@ -643,14 +794,14 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } - nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, + status = auth_ntlmssp_update(*auth_ntlmssp_state, auth, &auth_reply); data_blob_free(&auth); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state, - &auth_reply, nt_status, True); + &auth_reply, status, True); data_blob_free(&auth_reply); -- cgit