r23456: Update Samba4 to current lorikeet-heimdal.
[samba.git] / source4 / heimdal / lib / krb5 / init_creds_pw.c
index f6f6eac7d5b739fae4edea7837c4c8100c4b1d2e..a58435a9eaf7ff0db00e965e64704aad26d26b77 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "krb5_locl.h"
 
-RCSID("$Id: init_creds_pw.c,v 1.105 2007/01/09 10:44:59 lha Exp $");
+RCSID("$Id: init_creds_pw.c 20262 2007-02-18 00:33:01Z lha $");
 
 typedef struct krb5_get_init_creds_ctx {
     KDCOptions flags;
@@ -55,6 +55,7 @@ typedef struct krb5_get_init_creds_ctx {
     krb5_get_init_creds_tristate req_pac;
 
     krb5_pk_init_ctx pk_init_ctx;
+    int ic_flags;
 } krb5_get_init_creds_ctx;
 
 static krb5_error_code
@@ -285,12 +286,16 @@ get_init_creds_common(krb5_context context,
        ctx->key_proc = options->opt_private->key_proc;
        ctx->req_pac = options->opt_private->req_pac;
        ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
+       ctx->ic_flags = options->opt_private->flags;
     } else
        ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
 
     if (ctx->key_proc == NULL)
        ctx->key_proc = default_s2k_func;
 
+    if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
+       ctx->flags.canonicalize = 1;
+
     ctx->pre_auth_types = NULL;
     ctx->addrs = NULL;
     ctx->etypes = NULL;
@@ -834,6 +839,8 @@ static PA_DATA *
 find_pa_data(const METHOD_DATA *md, int type)
 {
     int i;
+    if (md == NULL)
+       return NULL;
     for (i = 0; i < md->len; i++)
        if (md->val[i].padata_type == type)
            return &md->val[i];
@@ -1347,6 +1354,15 @@ init_cred_loop(krb5_context context,
 
     {
        krb5_keyblock *key = NULL;
+       unsigned flags = 0;
+
+       if (ctx->flags.request_anonymous)
+           flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
+       if (ctx->flags.canonicalize) {
+           flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
+           flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
+           flags |= EXTRACT_TICKET_MATCH_REALM;
+       }
 
        ret = process_pa_data_to_key(context, ctx, creds, 
                                     &ctx->as_req, &rep, hi, &key);
@@ -1361,12 +1377,65 @@ init_cred_loop(krb5_context context,
                                   KRB5_KU_AS_REP_ENC_PART,
                                   NULL,
                                   ctx->nonce,
-                                  FALSE,
-                                  ctx->flags.request_anonymous,
+                                  flags,
                                   NULL,
                                   NULL);
        krb5_free_keyblock(context, key);
     }
+    /*
+     * Verify referral data
+     */
+    if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) &&
+       (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) == 0)
+    {
+       PA_ClientCanonicalized canon;
+       krb5_crypto crypto;
+       krb5_data data;
+       PA_DATA *pa;
+       size_t len;
+
+       pa = find_pa_data(rep.kdc_rep.padata, KRB5_PADATA_CLIENT_CANONICALIZED);
+       if (pa == NULL) {
+           ret = EINVAL;
+           krb5_set_error_string(context, "Client canonicalizion not signed");
+           goto out;
+       }
+       
+       ret = decode_PA_ClientCanonicalized(pa->padata_value.data, 
+                                           pa->padata_value.length,
+                                           &canon, &len);
+       if (ret) {
+           krb5_set_error_string(context, "Failed to decode "
+                                 "PA_ClientCanonicalized");
+           goto out;
+       }
+
+       ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
+                          &canon.names, &len, ret);
+       if (ret) 
+           goto out;
+       if (data.length != len)
+           krb5_abortx(context, "internal asn.1 error");
+
+       ret = krb5_crypto_init(context, &creds->session, 0, &crypto);
+       if (ret) {
+           free(data.data);
+           free_PA_ClientCanonicalized(&canon);
+           goto out;
+       }
+
+       ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
+                                  data.data, data.length,
+                                  &canon.canon_checksum);
+       krb5_crypto_destroy(context, crypto);
+       free(data.data);
+       free_PA_ClientCanonicalized(&canon);
+       if (ret) {
+           krb5_set_error_string(context, "Failed to verify "
+                                 "client canonicalized data");
+           goto out;
+       }
+    }
 out:
     krb5_data_free(&ctx->req_buffer);
     free_METHOD_DATA(&md);