mirror of
https://github.com/samba-team/samba.git
synced 2025-11-25 00:23:52 +03:00
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 commit is contained in:
committed by
Gerald (Jerry) Carter
parent
bd9439cc7d
commit
c426340fc7
@@ -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.h>],
|
||||
[
|
||||
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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
Copyright (C) Guenther Deschner 2003, 2005
|
||||
Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 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,
|
||||
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_data *p_packet, krb5_ticket **pp_tkt,
|
||||
krb5_keyblock **keyblock)
|
||||
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 char *realm,
|
||||
time_t time_offset,
|
||||
const DATA_BLOB *ticket,
|
||||
char **principal, PAC_DATA **pac_data,
|
||||
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);
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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. */
|
||||
/****************************************************************************
|
||||
reply to a session setup spnego negotiate packet for kerberos
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
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,10 +271,51 @@ 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(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;
|
||||
|
||||
*p_is_krb5 = False;
|
||||
|
||||
/* parse out the OIDs and the first sec blob */
|
||||
if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
|
||||
/* Kill the intermediate vuid */
|
||||
invalidate_vuid(vuid);
|
||||
|
||||
return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
|
||||
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);
|
||||
if (destroy_vuid) {
|
||||
/* Kill the intermediate vuid */
|
||||
invalidate_vuid(vuid);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -590,21 +713,20 @@ 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);
|
||||
|
||||
@@ -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
|
||||
@@ -635,6 +759,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 */
|
||||
invalidate_vuid(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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user