r2286: Fixes towards krb5 logins into Samba's CIFS server.
authorAndrew Bartlett <abartlet@samba.org>
Sat, 11 Sep 2004 23:09:26 +0000 (23:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:58:39 +0000 (12:58 -0500)
These fixes aim particularly at allowing PAC-less logins, as I don't
yet generate a PAC in the lorikeet-heimdal KDC.

This is for the benifit of a Kerbeors-enabled domain join, which seems
to be progressing quite well!

Andrew Bartlett

source/libcli/auth/clikrb5.c
source/libcli/auth/gensec_krb5.c
source/libcli/auth/kerberos.h
source/libcli/auth/kerberos_verify.c

index f6f8520b3c0e340d03394564833ae3faadc9ee54..78492d23526ff96858e5672c3ab5f0f9863c3ab9 100644 (file)
 }
 #endif
 
void get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, 
-                           DATA_BLOB *auth_data, krb5_ticket *tkt)
DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, 
+                           krb5_ticket *tkt)
 {
+       DATA_BLOB auth_data = data_blob(NULL, 0); 
 #if defined(HAVE_KRB5_TKT_ENC_PART2)
-       if (tkt && tkt->enc_part2)
-               *auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
+       if (tkt && tkt->enc_part2 
+           && tkt->enc_part2->authorization_data
+           && tkt->enc_part2->authorization_data[0]
+           && tkt->enc_part2->authorization_data[0]->length)
+               auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
                        tkt->enc_part2->authorization_data[0]->length);
 #else
        if (tkt && tkt->ticket.authorization_data && tkt->ticket.authorization_data->len)
-               *auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data,
+               auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data,
                        tkt->ticket.authorization_data->val->ad_data.length);
 #endif
+       return auth_data;
 }
 
  krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
index 569fd81206604d366c4b4b82d46188dff3827681..4a97d51c4014c90db109d6fcc368775fd50d9deb 100644 (file)
@@ -38,13 +38,14 @@ enum GENSEC_KRB5_STATE {
 struct gensec_krb5_state {
        TALLOC_CTX *mem_ctx;
        DATA_BLOB session_key;
-       struct PAC_LOGON_INFO logon_info;
+       struct PAC_LOGON_INFO *logon_info;
        enum GENSEC_KRB5_STATE state_position;
        krb5_context krb5_context;
        krb5_auth_context krb5_auth_context;
        krb5_ccache krb5_ccache;
        krb5_data ticket;
        krb5_keyblock krb5_keyblock;
+       char *peer_principal;
 };
 
 #ifdef KRB5_DO_VERIFY_PAC
@@ -56,6 +57,7 @@ static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data,
        krb5_error_code ret;
        krb5_crypto crypto;
        Checksum cksum;
+       int i;
 
        cksum.cksumtype         = (CKSUMTYPE)sig->type;
        cksum.checksum.length   = sizeof(sig->signature);
@@ -70,21 +72,19 @@ static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data,
                DEBUG(0,("krb5_crypto_init() failed\n"));
                return NT_STATUS_FOOBAR;
        }
-{
-int i;
-for (i=0; i < 40; i++) {
-       keyusage = i;
-       ret = krb5_verify_checksum(gensec_krb5_state->krb5_context,
-                                       crypto,
-                                       keyusage,
-                                       pac_data.data,
-                                       pac_data.length,
-                                       &cksum);
-       if (!ret) {
-               DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage));
-               break;
+       for (i=0; i < 40; i++) {
+               keyusage = i;
+               ret = krb5_verify_checksum(gensec_krb5_state->krb5_context,
+                                          crypto,
+                                          keyusage,
+                                          pac_data.data,
+                                          pac_data.length,
+                                          &cksum);
+               if (!ret) {
+                       DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage));
+                       break;
+               }
        }
-}}
        krb5_crypto_destroy(gensec_krb5_state->krb5_context, crypto);
 
        if (ret) {
@@ -99,7 +99,7 @@ for (i=0; i < 40; i++) {
 #endif
 
 static NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx,
-                               struct PAC_LOGON_INFO *logon_info_out,
+                               struct PAC_LOGON_INFO **logon_info_out,
                                DATA_BLOB blob,
                                struct gensec_krb5_state *gensec_krb5_state)
 {
@@ -220,7 +220,7 @@ static NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx,
        }
 #endif
        DEBUG(0,("account_name: %s [%s]\n",logon_info->account_name.string, logon_info->full_name.string));
-       *logon_info_out = *logon_info;
+       *logon_info_out = logon_info;
 
        return status;
 }
@@ -542,16 +542,22 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALL
                        return nt_status;
                }
 
-               /* decode and verify the pac */
-               nt_status = gensec_krb5_decode_pac(gensec_krb5_state->mem_ctx, &gensec_krb5_state->logon_info, pac,
-                                                   gensec_krb5_state);
+               if (pac.data) {
+                       /* decode and verify the pac */
+                       nt_status = gensec_krb5_decode_pac(gensec_krb5_state->mem_ctx, &gensec_krb5_state->logon_info, pac,
+                                                          gensec_krb5_state);
+               } else {
+                       /* NULL PAC, we might need to figure this information out the hard way */
+                       gensec_krb5_state->logon_info = NULL;
+               }
 
                if (NT_STATUS_IS_OK(nt_status)) {
                        gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
                        /* wrap that up in a nice GSS-API wrapping */
                        *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REP);
+
+                       gensec_krb5_state->peer_principal = talloc_steal(gensec_krb5_state->mem_ctx, principal);
                }
-               SAFE_FREE(principal);
                return nt_status;
        }
        case GENSEC_KRB5_DONE:
@@ -597,88 +603,88 @@ static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security,
                return NT_STATUS_NO_USER_SESSION_KEY;
        }
 }
-/*
-struct gensec_krb5_state {
-       TALLOC_CTX *mem_ctx;
-       DATA_BLOB session_key;
-       struct PAC_LOGON_INFO logon_info;
-       enum GENSEC_KRB5_STATE state_position;
-       krb5_context krb5_context;
-       krb5_auth_context krb5_auth_context;
-       krb5_ccache krb5_ccache;
-       krb5_data ticket;
-       krb5_keyblock krb5_keyblock;
-};
-struct auth_session_info 
-{
-       TALLOC_CTX *mem_ctx;
 
-       int refcount;
-       
-       NT_USER_TOKEN *nt_user_token;
-
-       struct auth_serversupplied_info *server_info;
-
-       DATA_BLOB session_key;
-
-       const char *workstation;
-};
-*/
 static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security,
                                     struct auth_session_info **session_info_out) 
 {
+       NTSTATUS nt_status;
        struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
        TALLOC_CTX *mem_ctx;
+       struct auth_serversupplied_info *server_info = NULL;
        struct auth_session_info *session_info = NULL;
-       struct PAC_LOGON_INFO *logon_info = &gensec_krb5_state->logon_info;
+       struct PAC_LOGON_INFO *logon_info = gensec_krb5_state->logon_info;
        struct nt_user_token *ptoken;
        struct dom_sid *sid;
+       char *p;
+       char *principal;
 
        *session_info_out = NULL;
 
-       mem_ctx = talloc_init("krb5: session_info");
-
-       session_info = talloc_p(mem_ctx, struct auth_session_info);
-       if (!session_info) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       session_info->mem_ctx = mem_ctx;
-       session_info->refcount = 1;
-       session_info->server_info = NULL;
-       
-       ptoken = talloc_p(session_info->mem_ctx, struct nt_user_token);
-       if (!ptoken) {
-               return NT_STATUS_NO_MEMORY;
+       nt_status = make_server_info(&server_info, gensec_krb5_state->peer_principal);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
        }
 
-       ptoken->num_sids = 0;
+       server_info->guest = False;
 
-       ptoken->user_sids = talloc_array_p(mem_ctx, struct dom_sid*, logon_info->groups_count + 2);
-       if (!ptoken->user_sids) {
+       principal = talloc_strdup(server_info->mem_ctx, gensec_krb5_state->peer_principal);
+       p = strchr(principal, '@');
+       if (p) {
+               *p = '\0';
+       }
+       server_info->account_name = principal;
+       server_info->domain = talloc_strdup(server_info->mem_ctx, p++);
+       if (!server_info->domain) {
+               free_server_info(&server_info);
                return NT_STATUS_NO_MEMORY;
        }
 
+       nt_status = make_session_info(server_info, &session_info);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               free_server_info(&server_info);
+               return nt_status;
+       }
 
-       sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid);
-       ptoken->user_sids[0] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->user_rid);
-       ptoken->num_sids++;
-       sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid);
-       ptoken->user_sids[1] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->group_rid);
-       ptoken->num_sids++;
+       /* IF we have the PAC - otherwise (TODO) we need to get this
+        * data from elsewere - local ldb, or lookup of some
+        * kind... */
 
-       for (;ptoken->num_sids < logon_info->groups_count; ptoken->num_sids++) {
+       if (logon_info) {
+               ptoken = talloc_p(session_info->mem_ctx, struct nt_user_token);
+               if (!ptoken) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               ptoken->num_sids = 0;
+               
+               ptoken->user_sids = talloc_array_p(mem_ctx, struct dom_sid*, logon_info->groups_count + 2);
+               if (!ptoken->user_sids) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               
+               sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid);
+               ptoken->user_sids[0] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->user_rid);
+               ptoken->num_sids++;
                sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid);
-               ptoken->user_sids[ptoken->num_sids] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->groups[ptoken->num_sids - 2].rid);
+               ptoken->user_sids[1] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->group_rid);
+               ptoken->num_sids++;
+               
+               for (;ptoken->num_sids < logon_info->groups_count; ptoken->num_sids++) {
+                       sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid);
+                       ptoken->user_sids[ptoken->num_sids] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->groups[ptoken->num_sids - 2].rid);
+               }
+               
+               debug_nt_user_token(DBGC_AUTH, 0, ptoken);
+               
+               session_info->nt_user_token = ptoken;
+       } else {
+               session_info->nt_user_token = NULL;
        }
-       
-       debug_nt_user_token(DBGC_AUTH, 0, ptoken);
-
-       session_info->nt_user_token = ptoken;
 
        session_info->session_key = data_blob_talloc(session_info->mem_ctx, 
-                                                       gensec_krb5_state->session_key.data,
-                                                       gensec_krb5_state->session_key.length);
+                                                    gensec_krb5_state->session_key.data,
+                                                    gensec_krb5_state->session_key.length);
 
        session_info->workstation = NULL;
 
index e35079a4ee7505019e26de6b6c452a502ac54dc5..9d6a5e81ae424725fdbf0ad147e45fa286018051 100644 (file)
@@ -65,8 +65,8 @@ krb5_error_code ads_krb5_mk_req(krb5_context context,
                                const char *principal,
                                krb5_ccache ccache, 
                                krb5_data *outbuf);
-void get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, 
-                           DATA_BLOB *auth_data, krb5_ticket *tkt);
+DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, 
+                                krb5_ticket *tkt);
 NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, 
                           krb5_context context,
                           krb5_auth_context auth_context,
index 88bf391cfa0ff8e52fd49c58edd51792211971a0..843189c884fe0df1a16b269f39115092f6db23f4 100644 (file)
@@ -32,6 +32,9 @@ static DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data)
        DATA_BLOB pac_contents = data_blob(NULL, 0);
        ASN1_DATA data;
        int data_type;
+       if (!auth_data->length) {
+               return data_blob(NULL, 0);
+       }
 
        asn1_load(&data, *auth_data);
        asn1_start_tag(&data, ASN1_SEQUENCE(0));
@@ -95,7 +98,7 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut
                        goto out;
                }
                /* Look for a CIFS ticket */
-               if (!StrnCaseCmp(princ_name, "cifs/", 5)) {
+               if (!StrnCaseCmp(princ_name, "cifs/", 5) || (!StrnCaseCmp(princ_name, "host/", 5))) {
 #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK
                        krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.keyblock);
 #else
@@ -254,6 +257,8 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au
        char *myname;
        BOOL auth_ok = False;
 
+       char *malloc_principal;
+
        ZERO_STRUCT(packet);
        ZERO_STRUCTP(auth_data);
        ZERO_STRUCTP(ap_rep);
@@ -329,7 +334,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au
        file_save("/tmp/ticket.dat", ticket->data, ticket->length);
 #endif
 
-       get_auth_data_from_tkt(mem_ctx, auth_data, tkt);
+       *auth_data = get_auth_data_from_tkt(mem_ctx, tkt);
 
        *auth_data = unwrap_pac(mem_ctx, auth_data);
 
@@ -342,13 +347,21 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au
 #endif
 
        if ((ret = krb5_unparse_name(context, get_principal_from_tkt(tkt),
-                                    principal))) {
+                                    &malloc_principal))) {
                DEBUG(3,("ads_verify_ticket: krb5_unparse_name failed (%s)\n", 
                         error_message(ret)));
                sret = NT_STATUS_LOGON_FAILURE;
                goto out;
        }
 
+       *principal = talloc_strdup(mem_ctx, malloc_principal);
+       SAFE_FREE(malloc_principal);
+       if (!principal) {
+               DEBUG(3,("ads_verify_ticket: talloc_strdup() failed\n"));
+               sret = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
        sret = NT_STATUS_OK;
 
  out: