the beginnings of kerberos support in smbd. It doesn't work yet, but
authorAndrew Tridgell <tridge@samba.org>
Thu, 18 Oct 2001 10:26:06 +0000 (10:26 +0000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 18 Oct 2001 10:26:06 +0000 (10:26 +0000)
it should give something for others to hack on and possibly find what
I'm doing wrong.
(This used to be commit 353c290f059347265b9be2aa1010c2956da06485)

source3/include/includes.h
source3/libsmb/asn1.c
source3/libsmb/cliconnect.c
source3/libsmb/clikrb5.c
source3/libsmb/clispnego.c
source3/smbd/negprot.c
source3/smbd/sesssetup.c

index 3a6282a006c37ee00c5a36dc4e25cd6fc10f61be..38692d9906a6ca6a76239528491f57beea7a090a 100644 (file)
 #include <iconv.h>
 #endif
 
+#if HAVE_KRB5
+#include <krb5.h>
+#endif
+
 /*
  * Define VOLATILE if needed.
  */
index 59763408cfe46922786579c4516bbd168da6a2ba..a8c0eebb94c3d900c3cceaa1feb28a38d8b8d659 100644 (file)
@@ -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)
index 6a01744240b1c19d7d7394b1ad9ee7d08a4d8c42..4fba54900dc274e79de9d5ef7401a6b71689f8ed 100644 (file)
@@ -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 */
index 68e941f2aac37a24fed88486a0b8337e20097185..51b6e6e8cf7f85a785ed16f6e6fc402c015a3bac 100644 (file)
@@ -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"));
index 78cae3315a856aad33760017e13bdae9b3c59a78..c421d759134da340a3403a38868cec9c8ab77528 100644 (file)
@@ -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
index cf14640a72fd5796a2584e9ca96603d48316f899..678156b528e5ebb95a4c96040a0b795c5f0ac748 100644 (file)
@@ -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;
index a833b7e7068722dbd6c2c60a21641d2b0bcff32c..7eb8f4e694dea1acb2e127e45bf16413a799f33c 100644 (file)
 
 #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);