diff options
-rw-r--r-- | source3/include/includes.h | 4 | ||||
-rw-r--r-- | source3/libsmb/asn1.c | 18 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 4 | ||||
-rw-r--r-- | source3/libsmb/clikrb5.c | 4 | ||||
-rw-r--r-- | source3/libsmb/clispnego.c | 23 | ||||
-rw-r--r-- | source3/smbd/negprot.c | 3 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 100 |
7 files changed, 141 insertions, 15 deletions
diff --git a/source3/include/includes.h b/source3/include/includes.h index 3a6282a006..38692d9906 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -365,6 +365,10 @@ #include <iconv.h> #endif +#if HAVE_KRB5 +#include <krb5.h> +#endif + /* * Define VOLATILE if needed. */ diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c index 59763408cf..a8c0eebb94 100644 --- a/source3/libsmb/asn1.c +++ b/source3/libsmb/asn1.c @@ -156,6 +156,24 @@ BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v) return !data->has_error; } +/* check a BOOLEAN */ +BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v) +{ + uint8 b = 0; + + asn1_read_uint8(data, &b); + if (b != ASN1_BOOLEAN) { + data->has_error = True; + return False; + } + asn1_read_uint8(data, &b); + if (b != v) { + data->has_error = True; + return False; + } + return !data->has_error; +} + /* load a ASN1_DATA structure with a lump of data, ready to be parsed */ BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 6a01744240..4fba54900d 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -392,6 +392,10 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principle, c if (!negTokenTarg.data) return False; +#if 0 + file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length); +#endif + blob2 = cli_session_setup_blob(cli, negTokenTarg); /* we don't need this blob for kerberos */ diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index 68e941f2aa..51b6e6e8cf 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -22,8 +22,6 @@ #include "includes.h" #if HAVE_KRB5 -#include <krb5.h> - /* we can't use krb5_mk_req because w2k wants the service to be in a particular format */ @@ -105,7 +103,7 @@ DATA_BLOB krb5_get_ticket(char *service, char *realm) if ((retval = krb5_mk_req2(context, &auth_context, - AP_OPTS_MUTUAL_REQUIRED, + 0, service, realm, ccdef, &packet))) { DEBUG(1,("krb5_mk_req2 failed\n")); diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index 78cae3315a..c421d75913 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -241,6 +241,29 @@ static DATA_BLOB spnego_gen_krb5_wrap(DATA_BLOB ticket) return ret; } +/* + parse a krb5 GSS-API wrapper packet giving a ticket +*/ +BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket) +{ + BOOL ret; + ASN1_DATA data; + + asn1_load(&data, blob); + asn1_start_tag(&data, ASN1_APPLICATION(0)); + asn1_check_OID(&data, OID_KERBEROS5); + asn1_check_BOOLEAN(&data, 0); + *ticket = data_blob(data.data, asn1_tag_remaining(&data)); + asn1_read(&data, ticket->data, ticket->length); + asn1_end_tag(&data); + + ret = !data.has_error; + + asn1_free(&data); + + return ret; +} + /* generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index cf14640a72..678156b528 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -164,10 +164,7 @@ static int negprot_spnego(char *p, uint8 cryptkey[8]) extern pstring global_myname; uint8 guid[16]; const char *OIDs[] = {OID_NTLMSSP, -#if 0 - /* not till we add kerberos in the server */ OID_KERBEROS5_OLD, -#endif NULL}; char *principle; int len; diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index a833b7e706..7eb8f4e694 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -22,6 +22,71 @@ #include "includes.h" +#if HAVE_KRB5 +/**************************************************************************** +reply to a session setup spnego negotiate packet for kerberos +****************************************************************************/ +static int reply_spnego_kerberos(connection_struct *conn, char *outbuf, + DATA_BLOB *secblob) +{ + DATA_BLOB ticket; + krb5_context context; + krb5_principal server; + krb5_auth_context auth_context = NULL; + krb5_keytab keytab = NULL; + krb5_data packet; + krb5_ticket *tkt = NULL; + int ret; + char *realm, *client; + fstring service; + extern pstring global_myname; + + realm = lp_realm(); + + if (!spnego_parse_krb5_wrap(*secblob, &ticket)) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + /* the service is the wins name lowercase with $ tacked on */ + fstrcpy(service, global_myname); + strlower(service); + fstrcat(service, "$"); + + ret = krb5_init_context(&context); + if (ret) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + ret = krb5_build_principal(context, &server, strlen(realm), + realm, service, NULL); + if (ret) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + packet.length = ticket.length; + packet.data = (krb5_pointer)ticket.data; + + if ((ret = krb5_rd_req(context, &auth_context, &packet, + server, keytab, NULL, &tkt))) { + DEBUG(3,("krb5_rd_req failed with code %08x\n", ret)); + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + if ((ret = krb5_unparse_name(context, tkt->enc_part2->client, + &client))) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + DEBUG(3,("Ticket name is [%s]\n", client)); + + /* well, if we got a client above then I think we have authenticated the user + but fail it for now until I understand it */ + + + return ERROR_NT(NT_STATUS_LOGON_FAILURE); +} +#endif + /**************************************************************************** send a security blob via a session setup reply @@ -50,9 +115,6 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, return send_smb(smbd_server_fd(),outbuf); } - - - /**************************************************************************** reply to a session setup spnego negotiate packet ****************************************************************************/ @@ -65,6 +127,7 @@ static int reply_spnego_negotiate(connection_struct *conn, char *outbuf, uint32 ntlmssp_command, neg_flags; DATA_BLOB sess_key, chal, spnego_chal; uint8 cryptkey[8]; + BOOL got_kerberos = False; /* parse out the OIDs and the first sec blob */ if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { @@ -73,20 +136,33 @@ static int reply_spnego_negotiate(connection_struct *conn, char *outbuf, for (i=0;OIDs[i];i++) { DEBUG(3,("Got OID %s\n", OIDs[i])); + if (strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) { + got_kerberos = True; + } free(OIDs[i]); } DEBUG(3,("Got secblob of size %d\n", secblob.length)); +#if HAVE_KRB5 + if (got_kerberos) { + int ret = reply_spnego_kerberos(conn, outbuf, &secblob); + data_blob_free(&secblob); + return ret; + } +#endif + /* parse the NTLMSSP packet */ #if 0 file_save("secblob.dat", secblob.data, secblob.length); #endif - msrpc_parse(&secblob, "CddB", - "NTLMSSP", - &ntlmssp_command, - &neg_flags, - &sess_key); + if (!msrpc_parse(&secblob, "CddB", + "NTLMSSP", + &ntlmssp_command, + &neg_flags, + &sess_key)) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } data_blob_free(&secblob); data_blob_free(&sess_key); @@ -97,7 +173,9 @@ static int reply_spnego_negotiate(connection_struct *conn, char *outbuf, DEBUG(3,("Got neg_flags=%08x\n", neg_flags)); - last_challenge(cryptkey); + if (!last_challenge(cryptkey)) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } /* Give them the challenge. For now, ignore neg_flags and just return the flags we want. Obviously this is not correct */ @@ -252,6 +330,10 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,cha /* pull the spnego blob */ blob1 = data_blob(p, SVAL(inbuf, smb_vwv7)); +#if 0 + file_save("negotiate.dat", blob1.data, blob1.length); +#endif + if (blob1.data[0] == ASN1_APPLICATION(0)) { /* its a negTokenTarg packet */ ret = reply_spnego_negotiate(conn, outbuf, blob1); |