* kdc_util.c (): Added new helper functions
authorTheodore Tso <tytso@mit.edu>
Wed, 8 Nov 1995 08:03:31 +0000 (08:03 +0000)
committerTheodore Tso <tytso@mit.edu>
Wed, 8 Nov 1995 08:03:31 +0000 (08:03 +0000)
dbentry_has_key_for_enctype(), dbentry_supports_enctype(), and
select_session_keytype().

* kdc_preauth.c: Added support for the ENC_TIMESTAMP preauthentication
scheme.

* do_tgs_req.c (process_tgs_req): Fixed the keytype/enctype selection
criteria for the server key, and the ticket session key.

* do_as_req.c (process_as_req): Added calls to the kdc preauthentication
verification routines.  Fixed the keytype/enctype selection
criteria for the client key, the server key, and the ticket
session key.

* main.c (finish_realm): Make sure all parts of the realm structure are
freed properly.
(main): Free the kcontext krb5_context.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7058 dc483132-0cff-0310-8789-dd5450dbe970

src/kdc/ChangeLog
src/kdc/do_as_req.c
src/kdc/do_tgs_req.c
src/kdc/kdc_preauth.c
src/kdc/kdc_util.c
src/kdc/kdc_util.h
src/kdc/main.c

index 741224227f73c6513b82c82ce418544b1196e497..dbb44172b800295cc99faddde3b665dc7b9aa548 100644 (file)
@@ -1,3 +1,25 @@
+Wed Nov  8 02:57:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+       * kdc_util.c (): Added new helper functions
+               dbentry_has_key_for_enctype(), dbentry_supports_enctype(),
+               and select_session_keytype().
+
+       * kdc_preauth.c: Added support for the ENC_TIMESTAMP
+               preauthentication scheme.
+
+       * do_tgs_req.c (process_tgs_req): Fixed the keytype/enctype
+               selection criteria for the server key, and the ticket
+               session key.
+
+       * do_as_req.c (process_as_req): Added calls to the kdc
+               preauthentication verification routines.  Fixed the
+               keytype/enctype selection criteria for the client key, the
+               server key, and the ticket session key.
+
+       * main.c (finish_realm): Make sure all parts of the realm
+               structure are freed properly.
+               (main): Free the kcontext krb5_context.
+
 Fri Oct  6 00:07:49 1995  Theodore Y. Ts'o  <tytso@dcl>
 
        * kdc_preauth.c (get_preauth_hint_list): Fix missing indirection
index eef36e763fcfa270653fda6bcf473a7648d409de..ad9b10c228715eee093a7b2a1fc270fd5c051532 100644 (file)
@@ -46,49 +46,6 @@ static krb5_error_code prepare_error_as PROTOTYPE((krb5_kdc_req *,
                                                   int,
                                                   krb5_data *, 
                                                   krb5_data **));
-/*
- * This routine is called to verify the preauthentication information
- * for a V5 request.  Client contains information about the principal
- * from the database. Padata contains pre-auth info received from
- * the network.
- *
- * Returns 0 if the pre-authentication is valid, non-zero to indicate
- * an error code of some sort.
- */
-
-static krb5_error_code
-check_padata (client, src_addr, padata, pa_id, flags)
-    krb5_db_entry  *client;
-    krb5_address **src_addr;
-    krb5_pa_data **padata;
-    int *pa_id;                        /* Unique id which can be used for replay
-                                  of padata. */
-    int *flags;
-{
-    krb5_error_code retval;
-    krb5_keyblock tmpkey;
-    int i;
-
-    /*         Extract a client key from master key */
-    retval = 0;
-    for (i = 0; i < client->n_key_data; i++) {
-       if ((retval = krb5_dbekd_decrypt_key_data(kdc_context,
-                                                 &master_encblock,
-                                                 &client->key_data[i],
-                                                 &tmpkey, NULL))) {
-           krb5_klog_syslog(LOG_ERR,"AS_REQ: Unable to extract client key: %s",
-                            error_message(retval));
-           return retval;
-       }
-        retval = krb5_verify_padata(kdc_context, *padata, client->princ,
-                                   src_addr, &tmpkey, pa_id, flags);
-        memset((char *)tmpkey.contents, 0, tmpkey.length);
-        krb5_xfree(tmpkey.contents);
-       if (!retval) 
-           break;
-    }
-    return retval;
-}
 
 /*ARGSUSED*/
 krb5_error_code
@@ -205,33 +162,18 @@ krb5_data **response;                     /* filled in with a response packet */
        goto errout;
     }
       
-    for (i = 0; i < request->nktypes; i++) {
-       if (!valid_enctype(request->ktype[i]))
-           continue;
-
-       if (request->ktype[i] == ENCTYPE_DES_CBC_MD5 &&
-           !isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5))
-           continue;
-
-       /*
-        * Find the server key of the appropriate type.  If we could specify
-        * a kvno, it would be supplied here.
-        */
-       if (!krb5_dbe_find_enctype(kdc_context, &server, request->ktype[i],
-                                  -1,          /* Ignore salttype */
-                                  -1,          /* Get highest kvno */
-                                  &server_key))
-           goto got_a_key;
+    /*
+     * Select the keytype for the ticket session key.
+     */
+    if ((useenctype = select_session_keytype(kdc_context, &server,
+                                            request->nktypes,
+                                            request->ktype)) == 0) {
+       /* unsupported ktype */
+       status = "BAD_ENCRYPTION_TYPE";
+       errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+       goto errout;
     }
-    
-    /* unsupported ktype */
-    status = "BAD_ENCRYPTION_TYPE";
-    errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
-    goto errout;
-
-got_a_key:;
-    useenctype = request->ktype[i];
-    krb5_use_enctype(kdc_context, &eblock, request->ktype[i]);
+    krb5_use_enctype(kdc_context, &eblock, useenctype);
     
     if ((errcode = krb5_random_key(kdc_context, &eblock,
                                  krb5_enctype_array[useenctype]->random_sequence,
@@ -318,8 +260,7 @@ got_a_key:;
      * Check the preauthentication if it is there.
      */
     if (request->padata) {
-       errcode = check_padata(&client,request->addresses,
-                             request->padata, &pa_id, &pa_flags);
+       errcode = check_padata(kdc_context, &client, request, &enc_tkt_reply);
        if (errcode) {
 #ifdef KRBCONF_KDC_MODIFIES_KDB
            /*
@@ -342,13 +283,6 @@ got_a_key:;
 #endif
            goto errout;
        } 
-       setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);
-       /*
-        * If pa_type is one in which additional hardware authentication
-        * was performed set TKT_FLG_HW_AUTH too.
-        */
-       if (pa_flags & KRB5_PREAUTH_FLAGS_HARDWARE)
-            setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
     }
 
     /*
@@ -365,16 +299,31 @@ got_a_key:;
 
     ticket_reply.enc_part2 = &enc_tkt_reply;
 
+    /*
+     * Find the server key
+     */
+    if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
+                                        -1, /* ignore keytype */
+                                        -1,            /* Ignore salttype */
+                                        0,             /* Get highest kvno */
+                                        &server_key))) {
+       status = "FINDING_SERVER_KEY";
+       goto errout;
+    }
+
     /* convert server.key into a real key (it may be encrypted
        in the database) */
     if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock, 
-                                             server_key,
-                                              &encrypting_key, NULL))) {
+                                              server_key, &encrypting_key,
+                                              NULL))) {
        status = "DECRYPT_SERVER_KEY";
        goto errout;
     }
-    errcode = krb5_encrypt_tkt_part(kdc_context, &eblock, &encrypting_key, 
-                                  &ticket_reply);
+    if ((encrypting_key.enctype == ENCTYPE_DES_CBC_CRC) &&
+       (isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5)))
+       encrypting_key.enctype = ENCTYPE_DES_CBC_MD5;
+       
+    errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key, &ticket_reply);
     memset((char *)encrypting_key.contents, 0, encrypting_key.length);
     krb5_xfree(encrypting_key.contents);
     if (errcode) {
@@ -385,19 +334,16 @@ got_a_key:;
 
     /*
      * Find the appropriate client key.  We search in the order specified
-     * by the key/salt list.
+     * by request keytype list.
      */
     client_key = (krb5_key_data *) NULL;
-    for (i=0; i<kdc_active_realm->realm_nkstypes; i++) {
-       krb5_key_salt_tuple     *kslist;
-
-       kslist = (krb5_key_salt_tuple *) kdc_active_realm->realm_kstypes;
-       if (!krb5_dbe_find_enctype(kdc_context,
-                                  &client,
-                                  kslist[i].ks_enctype,
-                                  kslist[i].ks_salttype,
-                                  -1,
-                                  &client_key))
+    for (i = 0; i < request->nktypes; i++) {
+       useenctype = request->ktype[i];
+       if (!valid_enctype(useenctype))
+           continue;
+
+       if (!krb5_dbe_find_enctype(kdc_context, &client, useenctype, -1,
+                                  0, &client_key))
            break;
     }
     if (!(client_key)) {
@@ -486,11 +432,12 @@ got_a_key:;
 
     /* convert client.key_data into a real key */
     if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock, 
-                                             client_key,
-                                              &encrypting_key, NULL))) {
+                                              client_key, &encrypting_key,
+                                              NULL))) {
        status = "DECRYPT_CLIENT_KEY";
        goto errout;
     }
+    encrypting_key.enctype = useenctype;
 
     errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, 
                                  &eblock, &encrypting_key,  &reply, response);
index feb72ef84098ce66103dce9fde44238a6437f94d..33aa25a3ef1ec1d1e217ef146fede5ef2abf4001 100644 (file)
@@ -63,7 +63,6 @@ krb5_data **response;                 /* filled in with a response packet */
 {
     krb5_keyblock * subkey;
     krb5_encrypt_block eblock;
-    krb5_enctype second_ticket_ktype = ENCTYPE_UNKNOWN;
     krb5_kdc_req *request = 0;
     krb5_db_entry server;
     krb5_kdc_rep reply;
@@ -80,6 +79,7 @@ krb5_data **response;                 /* filled in with a response packet */
     krb5_keyblock *session_key = 0;
     krb5_timestamp until, rtime;
     krb5_keyblock encrypting_key;
+    krb5_key_data  *server_key;
     char *cname = 0, *sname = 0, *tmp = 0, *fromstring = 0;
     krb5_last_req_entry *nolrarray[2], nolrentry;
 /*    krb5_address *noaddrarray[1]; */
@@ -87,7 +87,6 @@ krb5_data **response;                 /* filled in with a response packet */
     int        errcode, errcode2;
     register int i;
     int firstpass = 1;
-    int ok_key_data = 0;
     const char *status = 0;
     
     retval = decode_krb5_tgs_req(pkt, &request);
@@ -181,7 +180,7 @@ tgt_again:
        goto cleanup;
     }
 
-    if ((retval = krb5_timeofday(kdc_context, &kdc_time))) {
+    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
        status = "TIME_OF_DAY";
        goto cleanup;
     }
@@ -195,48 +194,72 @@ tgt_again:
     }
 
     /*
-     * If we are using user-to-user authentication, then the resulting
-     * ticket has to use the same encryption system as was used to
-     * encrypt the ticket, since that's the same encryption system
-     * that's used for the ticket session key --- and that's what we
-     * use to encrypt the ticket!
+     * We pick the session keytype here....
+     * 
+     * Some special care needs to be taken in the user-to-user
+     * case, since we don't know what keytypes the application server
+     * which is doing user-to-user authentication can support.  We
+     * know that it at least must be able to support the encryption
+     * type of the session key in the TGT, since otherwise it won't be
+     * able to decrypt the U2U ticket!  So we use that in preference
+     * to anything else.
      */
-    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY))
-       second_ticket_ktype = request->second_ticket[st_idx]->enc_part.enctype;
-           
-    for (i = 0; i < request->nktypes; i++) {
-       krb5_enctype ok_enctype;
-       
-       if (!valid_enctype(request->ktype[i]))
-           continue;
-
-       if (second_ticket_ktype != ENCTYPE_UNKNOWN &&
-           second_ticket_ktype != request->ktype[i])
-           continue;
-
-       if (request->ktype[i] == ENCTYPE_DES_CBC_MD5 &&
-           !isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5))
-           continue;
+    useenctype = 0;
+    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
+       krb5_keyblock * st_sealing_key;
+       krb5_kvno       st_srv_kvno;
+       krb5_enctype    etype;
 
-       ok_enctype = request->ktype[i];
+       /*
+        * Get the key for the second ticket, and decrypt it.
+        */
+       if ((errcode = kdc_get_server_key(request->second_ticket[st_idx],
+                                        &st_sealing_key,
+                                        &st_srv_kvno))) {
+           status = "2ND_TKT_SERVER";
+           goto cleanup;
+       }
+       errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
+                                      request->second_ticket[st_idx]);
+       krb5_free_keyblock(kdc_context, st_sealing_key);
+       if (errcode) {
+           status = "2ND_TKT_DECRYPT";
+           goto cleanup;
+       }
+       
+       etype = request->second_ticket[st_idx]->enc_part2->session->enctype;
+       if (!valid_enctype(etype)) {
+           status = "BAD_ETYPE_IN_2ND_TKT";
+           errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+           goto cleanup;
+       }
+       
+       for (i = 0; i < request->nktypes; i++) {
+           if (request->ktype[i] == etype) {
+               useenctype = etype;
+               break;
+           }
+       }
+    }
 
-        for (ok_key_data = 0; ok_key_data < server.n_key_data; ok_key_data++)
-            if (server.key_data[ok_key_data].key_data_type[0] == ok_enctype)
-                goto got_a_key;
+    /*
+     * Select the keytype for the ticket session key.
+     */
+    if ((useenctype == 0) &&
+       (useenctype = select_session_keytype(kdc_context, &server,
+                                            request->nktypes,
+                                            request->ktype)) == 0) {
+       /* unsupported ktype */
+       status = "BAD_ENCRYPTION_TYPE";
+       errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+       goto cleanup;
     }
     
-    /* unsupported ktype */
-    errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
-    status = "BAD_ENCRYPTION_TYPE";
-    goto cleanup;
-
-got_a_key:;
-    useenctype = request->ktype[i];
     krb5_use_enctype(kdc_context, &eblock, useenctype);
-    retval = krb5_random_key(kdc_context, &eblock, 
+    errcode = krb5_random_key(kdc_context, &eblock, 
                             krb5_enctype_array[useenctype]->random_sequence,
                             &session_key);
-    if (retval) {
+    if (errcode) {
        /* random key failed */
        status = "RANDOM_KEY_FAILED";
        goto cleanup;
@@ -399,7 +422,7 @@ got_a_key:;
            goto cleanup;
        }
        /* do any necessary key pre-processing */
-       if ((retval = krb5_process_key(kdc_context, &eblock,
+       if ((errcode = krb5_process_key(kdc_context, &eblock,
                                      header_ticket->enc_part2->session))) {
            status = "AUTH_PROCESS_KEY";
            free(scratch.data);
@@ -407,7 +430,7 @@ got_a_key:;
        }
 
        /* call the encryption routine */
-       if ((retval = krb5_decrypt(kdc_context, (krb5_pointer) request->authorization_data.ciphertext.data,
+       if ((errcode = krb5_decrypt(kdc_context, (krb5_pointer) request->authorization_data.ciphertext.data,
                                  (krb5_pointer) scratch.data,
                                  scratch.length, &eblock, 0))) {
            status = "AUTH_ENCRYPT_FAIL";
@@ -415,20 +438,20 @@ got_a_key:;
            free(scratch.data);
            goto cleanup;
        }
-       if ((retval = krb5_finish_key(kdc_context, &eblock))) {
+       if ((errcode = krb5_finish_key(kdc_context, &eblock))) {
            status = "AUTH_FINISH_KEY";
            free(scratch.data);
            goto cleanup;
        }
        /* scratch now has the authorization data, so we decode it */
-       retval = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
+       errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
        free(scratch.data);
-       if (retval) {
+       if (errcode) {
            status = "AUTH_DECODE";
            goto cleanup;
        }
 
-       if ((retval =
+       if ((errcode =
             concat_authorization_data(request->unenc_authdata,
                                       header_ticket->enc_part2->authorization_data, 
                                       &enc_tkt_reply.authorization_data))) {
@@ -470,7 +493,7 @@ got_a_key:;
        enc_tkt_transited.tr_contents.data = 0;
        enc_tkt_transited.tr_contents.length = 0;
        enc_tkt_reply.transited = enc_tkt_transited;
-       if ((retval =
+       if ((errcode =
             add_to_transited(&header_ticket->enc_part2->transited.tr_contents,
                              &enc_tkt_reply.transited.tr_contents,
                              header_ticket->server,
@@ -491,32 +514,13 @@ got_a_key:;
      * the second ticket.
      */
     if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
-       krb5_keyblock *st_sealing_key;
-       krb5_kvno st_srv_kvno;
-
-       if ((retval = kdc_get_server_key(request->second_ticket[st_idx],
-                                        &st_sealing_key,
-                                        &st_srv_kvno))) {
-           status = "2ND_TKT_SERVER";
-           goto cleanup;
-       }
-
-       /* decrypt the ticket */
-       retval = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
-                                      request->second_ticket[st_idx]);
-       krb5_free_keyblock(kdc_context, st_sealing_key);
-       if (retval) {
-           status = "2ND_TKT_DECRYPT";
-           goto cleanup;
-       }
-
        /*
         * Make sure the client for the second ticket matches
         * requested server.
         */
        if (!krb5_principal_compare(kdc_context, request->server,
                                    request->second_ticket[st_idx]->enc_part2->client)) {
-               if ((retval = krb5_unparse_name(kdc_context,
+               if ((errcode = krb5_unparse_name(kdc_context,
                                                request->second_ticket[st_idx]->enc_part2->client,
                                                &tmp)))
                        tmp = 0;
@@ -530,7 +534,7 @@ got_a_key:;
        ticket_reply.enc_part.enctype =
                request->second_ticket[st_idx]->enc_part2->session->enctype;
        krb5_use_enctype(kdc_context, &eblock, ticket_reply.enc_part.enctype);
-       if ((retval = krb5_encrypt_tkt_part(kdc_context, &eblock,
+       if ((errcode = krb5_encrypt_tkt_part(kdc_context, 
                                            request->second_ticket[st_idx]->enc_part2->session,
                                            &ticket_reply))) {
            status = "2ND_TKT_ENCRYPT";
@@ -538,25 +542,35 @@ got_a_key:;
        }
        st_idx++;
     } else {
+       /*
+        * Find the server key
+        */
+       if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
+                                            -1, /* ignore keytype */
+                                            -1, /* Ignore salttype */
+                                            0,         /* Get highest kvno */
+                                            &server_key))) {
+           status = "FINDING_SERVER_KEY";
+           goto cleanup;
+       }
        /* convert server.key into a real key (it may be encrypted
-          in the database) */
-       if ((retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock,
-                                                 &server.key_data[ok_key_data],
-                                                 &encrypting_key, NULL))) {
-           status = "CONV_KEY";
+        *        in the database) */
+       if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
+                                                  &master_encblock, 
+                                                  server_key, &encrypting_key,
+                                                  NULL))) {
+           status = "DECRYPT_SERVER_KEY";
            goto cleanup;
        }
-
-       ticket_reply.enc_part.kvno = server.key_data[ok_key_data].key_data_kvno;
-       ticket_reply.enc_part.enctype = useenctype;
-       krb5_use_enctype(kdc_context, &eblock, ticket_reply.enc_part.enctype);
-       retval = krb5_encrypt_tkt_part(kdc_context, &eblock, &encrypting_key, 
-                                      &ticket_reply);
-
+       if ((encrypting_key.enctype == ENCTYPE_DES_CBC_CRC) &&
+           (isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5)))
+           encrypting_key.enctype = ENCTYPE_DES_CBC_MD5;
+       ticket_reply.enc_part.kvno = server_key->key_data_kvno;
+       errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
+                                       &ticket_reply);
        memset((char *)encrypting_key.contents, 0, encrypting_key.length);
        krb5_xfree(encrypting_key.contents);
-
-       if (retval) {
+       if (errcode) {
            status = "TKT_ENCRYPT";
            goto cleanup;
        }
@@ -598,11 +612,11 @@ got_a_key:;
                    header_ticket->enc_part2->session->enctype;
     krb5_use_enctype(kdc_context, &eblock, reply.enc_part.enctype);
 
-    retval = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, 
+    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, 
                                 &eblock, subkey ? subkey :
                                 header_ticket->enc_part2->session,
                                 &reply, response);
-    if (retval) {
+    if (errcode) {
        status = "ENCODE_KDC_REP";
     } else {
        status = "ISSUE";
index dab3d79133796d24cb6f4691307002f7d6572671..5670625cf8b43e792b13f62916138dbc65f8e144 100644 (file)
 #include <stdio.h>
 
 typedef krb5_error_code (verify_proc)
-    KRB5_PROTOTYPE((krb5_context, krb5_principal client,
-                   krb5_address **src_addr,
-                   krb5_data *data));
+    KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client,
+                   krb5_kdc_req *request,
+                   krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data));
 
 typedef krb5_error_code (edata_proc)
-    KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client,
-                   krb5_pa_data *data));
+    KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client, krb5_pa_data *data));
 
 typedef struct _krb5_preauth_systems {
     int                type;
@@ -44,30 +43,81 @@ typedef struct _krb5_preauth_systems {
     verify_proc        *verify;
 } krb5_preauth_systems;
 
+static verify_proc verify_enc_timestamp;
+
 /*
  * Preauth property flags
  */
-#define PA_ENCRYPT     0x00000001
-#define PA_HARDWARE    0x00000002
+#define PA_HARDWARE    0x00000001
+#define PA_REQUIRED    0x00000002
+#define PA_SUFFICIENT  0x00000004
 
 static krb5_preauth_systems preauth_systems[] = {
     {
-        KRB5_PADATA_ENC_UNIX_TIME,
-        PA_ENCRYPT,
+        KRB5_PADATA_ENC_TIMESTAMP,
         0,
-       0,
-    },
-    {
-       KRB5_PADATA_ENC_SANDIA_SECURID,
-       PA_ENCRYPT | PA_HARDWARE,
-       0,
-       0,
+        0,
+       verify_enc_timestamp,
     },
     { -1,}
 };
 
 #define MAX_PREAUTH_SYSTEMS (sizeof(preauth_systems)/sizeof(preauth_systems[0]))
 
+static krb5_error_code
+find_pa_system(type, preauth)
+    int                        type;
+    krb5_preauth_systems       **preauth;
+{
+    krb5_preauth_systems       *ap = preauth_systems;
+    
+    while ((ap->type != -1) && (ap->type != type))
+       ap++;
+    if (ap->type == -1)
+       return(KRB5_PREAUTH_BAD_TYPE);
+    *preauth = ap;
+    return 0;
+} 
+
+krb5_error_code
+krb5_decrypt_data(context, key, ivec, enc_data, data)
+    krb5_context       context;
+    krb5_keyblock *    key;
+    krb5_pointer       ivec;
+    krb5_enc_data *    enc_data;
+    krb5_data *                data;
+{
+    krb5_error_code    retval;
+    krb5_encrypt_block eblock;
+
+    krb5_use_enctype(context, &eblock, key->enctype);
+    data->length = enc_data->ciphertext.length;
+    if (!(data->data = malloc(data->length)))
+       return ENOMEM;
+
+    if ((retval = krb5_process_key(context, &eblock, key)) != 0)
+       goto cleanup;
+
+    if ((retval = krb5_decrypt(context,
+                              (krb5_pointer) enc_data->ciphertext.data,
+                              (krb5_pointer) data->data,
+                              enc_data->ciphertext.length, &eblock, ivec))) {
+       krb5_finish_key(context, &eblock);
+        goto cleanup;
+    }
+    (void) krb5_finish_key(context, &eblock);
+
+    return 0;
+
+cleanup:
+    if (data->data) {
+       free(data->data);
+       data->data = 0;
+    }
+    return retval;
+}
+
+    
 const char *missing_required_preauth(client, server, enc_tkt_reply)
     krb5_db_entry *client, *server;
     krb5_enc_tkt_part *enc_tkt_reply;
@@ -142,5 +192,128 @@ errout:
     return;
 }
 
+/*
+ * This routine is called to verify the preauthentication information
+ * for a V5 request.
+ *     
+ * Returns 0 if the pre-authentication is valid, non-zero to indicate
+ * an error code of some sort.
+ */
+
+krb5_error_code
+check_padata (context, client, request, enc_tkt_reply)
+    krb5_context       context;
+    krb5_db_entry *    client;
+    krb5_kdc_req *     request;
+    krb5_enc_tkt_part * enc_tkt_reply;
+{
+    krb5_error_code retval;
+    krb5_pa_data **padata;
+    krb5_preauth_systems *pa_sys;
+
+    if (request->padata == 0)
+       return 0;
+
+    for (padata = request->padata; *padata; padata++) {
+       if (find_pa_system((*padata)->pa_type, &pa_sys))
+           continue;
+       if (pa_sys->verify == 0)
+           continue;
+       retval = pa_sys->verify(context, client, request,
+                               enc_tkt_reply, *padata);
+       if (retval) {
+           if (pa_sys->flags & PA_REQUIRED)
+               break;
+       } else {
+           if (pa_sys->flags & PA_SUFFICIENT)
+               break;
+       }
+    }
+    return retval;
+}
+
+static krb5_error_code
+verify_enc_timestamp(context, client, request, enc_tkt_reply, pa)
+    krb5_context       context;
+    krb5_db_entry *    client;
+    krb5_kdc_req *     request;
+    krb5_enc_tkt_part * enc_tkt_reply;
+    krb5_pa_data *     pa;
+{
+    krb5_pa_enc_ts *           pa_enc = 0;
+    krb5_error_code            retval;
+    krb5_data                  scratch;
+    krb5_data                  enc_ts_data;
+    krb5_enc_data              *enc_data = 0;
+    krb5_keyblock              key;
+    krb5_key_data *            client_key;
+    krb5_int32                 start;
+    krb5_timestamp             timenow;
+    
+    enc_ts_data.data = 0;
+    scratch.data = pa->contents;
+    scratch.length = pa->length;
+    
+    if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0)
+       goto cleanup;
+
+    start = 0;
+    while (1) {
+       if ((retval = krb5_dbe_search_enctype(context, client,
+                                             &start, enc_data->enctype,
+                                             -1, 0, &client_key)))
+           goto cleanup;
+
+       if ((retval = krb5_dbekd_decrypt_key_data(context, &master_encblock, 
+                                                 client_key, &key, NULL)))
+           goto cleanup;
+       key.enctype = enc_data->enctype;
+
+       retval = krb5_decrypt_data(context, key, 0, enc_data, &enc_ts_data);
+       memset((char *)key.contents, 0, key.length);
+       krb5_xfree(key.contents);
+
+       if (retval == 0)
+           break;
+    }
+
+    if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0)
+       goto cleanup;
+
+    if ((retval = krb5_timeofday(context, &timenow)) != 0)
+       goto cleanup;
+    
+    if (labs(timenow - pa_enc->patimestamp) > context->clockskew) {
+       retval = KRB5KRB_AP_ERR_SKEW;
+       goto cleanup;
+    }
+
+    setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
+
+    retval = 0;
+    
+cleanup:
+    if (enc_data) {
+       if (enc_data->ciphertext.data)
+           krb5_xfree(enc_data->ciphertext.data);
+       free(enc_data);
+    }
+    if (enc_ts_data.data)
+       krb5_xfree(enc_ts_data.data);
+    if (pa_enc)
+       krb5_xfree(pa_enc);
+    return retval;
+}
+
 
-                       
+#if 0                  
+
+       setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);
+       /*
+        * If pa_type is one in which additional hardware authentication
+        * was performed set TKT_FLG_HW_AUTH too.
+        */
+       if (pa_flags & KRB5_PREAUTH_FLAGS_HARDWARE)
+            setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
+
+#endif
index 32f3983546d2d24509314d75693e251697b3407a..49573bf9579741d7e1486ec0a80b83563cb27f49 100644 (file)
@@ -1229,3 +1229,91 @@ const char **status;
     
     return 0;
 }
+
+/*
+ * This function returns 1 if the dbentry has a key for a specified
+ * keytype, and 0 if not.
+ */
+int
+dbentry_has_key_for_enctype(context, client, enctype)
+    krb5_context       context;
+    krb5_db_entry *    client;
+    krb5_enctype       enctype;
+{
+    krb5_error_code    retval;
+    krb5_key_data      *datap;
+
+    retval = krb5_dbe_find_enctype(context, client, enctype,
+                                  -1, 0, &datap);
+    if (retval)
+       return 0;
+    else
+       return 1;
+}
+
+/*
+ * This function returns 1 if the entity referenced by this
+ * structure can support the a particular encryption system, and 0 if
+ * not.
+ *
+ * XXX eventually this information should be looked up in the
+ * database.  Since it isn't, we use some hueristics and attribute
+ * options bits for now.
+ */
+int
+dbentry_supports_enctype(context, client, enctype)
+    krb5_context       context;
+    krb5_db_entry *    client;
+    krb5_enctype       enctype;
+{
+    /*
+     * If it's DES_CBC_MD5, there's a bit in the attribute mask which
+     * checks to see if we support it.
+     *
+     * In theory everything's supposed to support DES_CBC_MD5, but
+     * that's not the reality....
+     */
+    if (enctype == ENCTYPE_DES_CBC_MD5)
+       return isflagset(client->attributes, KRB5_KDB_SUPPORT_DESMD5);
+
+    /*
+     * XXX we assume everything can understand DES_CBC_CRC
+     */
+    if (enctype == ENCTYPE_DES_CBC_CRC)
+       return 1;
+    
+    /*
+     * If we have a key for the encryption system, we assume it's
+     * supported.
+     */
+    return dbentry_has_key_for_enctype(context, client, enctype);
+}
+
+/*
+ * This function returns the keytype which should be selected for the
+ * session key.  It is based on the ordered list which the user
+ * requested, and what the KDC and the application server can support.
+ */
+krb5_enctype
+select_session_keytype(context, server, nktypes, ktype)
+    krb5_context       context;
+    krb5_db_entry *    server;
+    int                        nktypes;
+    krb5_enctype       *ktype;
+{
+    int                i;
+    
+    for (i = 0; i < nktypes; i++) {
+       if (!valid_enctype(ktype[i]))
+           continue;
+
+       if (dbentry_supports_enctype(context, server, ktype[i]))
+           return (ktype[i]);
+    }
+    return 0;
+}
+
+
+   
+    
+    
index e2811316904f091820c0e452827153a8bdafe7c4..f1b742506c7d3d5b8242e3151f6186a25a593b75 100644 (file)
@@ -73,6 +73,22 @@ int validate_tgs_request PROTOTYPE((krb5_kdc_req *, krb5_db_entry,
 int fetch_asn1_field PROTOTYPE((unsigned char *, unsigned int, unsigned int,
                                 krb5_data *));
 
+int
+dbentry_has_key_for_enctype PROTOTYPE((krb5_context context,
+                                      krb5_db_entry *client,
+                                      krb5_enctype enctype));
+    
+int
+dbentry_supports_enctype PROTOTYPE((krb5_context context,
+                                   krb5_db_entry *client,
+                                   krb5_enctype enctype));
+
+krb5_enctype
+select_session_keytype PROTOTYPE((krb5_context context,
+                                 krb5_db_entry *server,
+                                 int nktypes,
+                                 krb5_enctype *ktypes));
+
 /* do_as_req.c */
 krb5_error_code process_as_req PROTOTYPE((krb5_kdc_req *,
                                          const krb5_fulladdr *,
index fa4572c8cbd75de782e65709c3a4ef7de6c3f9b3..b698a0fa3ab8b2a468aae2b8b7b640806d266926 100644 (file)
@@ -254,11 +254,22 @@ finish_realm(rdp)
        free(rdp->realm_mpname);
     if (rdp->realm_stash)
        free(rdp->realm_stash);
+    if (rdp->realm_ports)
+       free(rdp->realm_ports);
+    if (rdp->realm_kstypes)
+       free(rdp->realm_kstypes);
     if (rdp->realm_context) {
        if (rdp->realm_mprinc)
            krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
-       if (rdp->realm_mkey.length && rdp->realm_mkey.contents)
-           krb5_free_keyblock(rdp->realm_context, &rdp->realm_mkey);
+       if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
+           memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
+           free(rdp->realm_mkey.contents);
+       }
+       if (rdp->realm_tgskey.length && rdp->realm_tgskey.contents) {
+           memset(rdp->realm_tgskey.contents, 0, rdp->realm_tgskey.length);
+           free(rdp->realm_tgskey.contents);
+       }
+       krb5_finish_key(rdp->realm_context, &rdp->realm_encblock);
        krb5_db_fini(rdp->realm_context);
        if (rdp->realm_tgsprinc)
            krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
@@ -872,6 +883,7 @@ char *argv[];
     krb5_klog_syslog(LOG_INFO, "shutting down");
     krb5_klog_close(kdc_context);
     finish_realms(argv[0]);
+    krb5_free_context(kcontext);
     return errout;
 }