This commit was manufactured by cvs2svn to create tag
[krb5.git] / src / lib / krb5 / krb / mk_req_ext.c
index a2624e8c36f21fab4c01d1dcbe95dfd64a3a81f9..88daab56704bd2d734af8da6004204e412a30260 100644 (file)
@@ -1,28 +1,35 @@
 /*
- * $Source$
- * $Author$
+ * lib/krb5/krb/mk_req_ext.c
  *
- * Copyright 1990 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
  *
- * For copying and distribution information, please see the file
- * <krb5/copyright.h>.
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
  *
  * krb5_mk_req_extended()
  */
 
-#if !defined(lint) && !defined(SABER)
-static char rcsid_mk_req_ext_c[] =
-"$Id$";
-#endif /* !lint & !SABER */
 
-#include <krb5/copyright.h>
-#include <krb5/krb5.h>
-#include <krb5/asn1.h>
-
-#include <krb5/libos.h>
-#include <krb5/libos-proto.h>
-
-#include <krb5/ext-proto.h>
+#include "k5-int.h"
+#include "auth_con.h"
 
 /*
  Formats a KRB_AP_REQ message into outbuf, with more complete options than
@@ -50,144 +57,196 @@ static char rcsid_mk_req_ext_c[] =
  The outbuf buffer storage is allocated, and should be freed by the
  caller when finished.
 
+ On an error return, the credentials pointed to by creds might have been
+ augmented with additional fields from the obtained credentials; the entire
+ credentials should be released by calling krb5_free_creds().
+
  returns system errors
 */
-static krb5_error_code generate_authenticator PROTOTYPE((krb5_authenticator *,
-                                                        const krb5_creds *,
-                                                        const krb5_checksum *));
-
-krb5_error_code
-krb5_mk_req_extended(ap_req_options, checksum, times, kdc_options, ccache,
-                    creds, outbuf)
-const krb5_flags ap_req_options;
-const krb5_checksum *checksum;
-const krb5_ticket_times *times;
-const krb5_flags kdc_options;
-krb5_ccache ccache;
-krb5_creds *creds;
-krb5_data *outbuf;
+
+static krb5_error_code 
+krb5_generate_authenticator PROTOTYPE((krb5_context,
+                                      krb5_authenticator *, krb5_principal,
+                                      const krb5_checksum *, krb5_keyblock *,
+                                      krb5_int32, krb5_authdata ** ));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, in_creds,
+                    outbuf)
+    krb5_context         context;
+    krb5_auth_context  FAR * auth_context;
+    const krb5_flags     ap_req_options;
+    krb5_data          FAR * in_data;
+    krb5_creds                 FAR * in_creds;
+    krb5_data          FAR * outbuf;
 {
-    krb5_error_code retval;
+    krb5_error_code      retval;
+    krb5_checksum        checksum;
+    krb5_checksum        *checksump = 0;
+    krb5_auth_context    new_auth_context;
+
     krb5_ap_req request;
-    krb5_authenticator authent;
-    krb5_data *scratch;
-    krb5_enctype etype;
-    krb5_encrypt_block eblock;
+    krb5_data *scratch = 0;
     krb5_data *toutbuf;
 
-    if ((ap_req_options & AP_OPTS_USE_SESSION_KEY) &&
-       !creds->ticket.length)
+    request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
+    request.authenticator.ciphertext.data = 0;
+    request.ticket = 0;
+    
+    if (!in_creds->ticket.length) 
        return(KRB5_NO_TKT_SUPPLIED);
 
-    if (!creds->ticket.length) {
-       /* go get creds */
-       creds->times = *times;          /* XXX do we need times? */
-       if (retval = krb5_get_credentials(kdc_options,
-                                         ccache,
-                                         creds))
-           return(retval);
-    }
-    /* verify a valid etype is available */
-    if (!valid_keytype(creds->keyblock.keytype))
-       return KRB5_PROG_KEYTYPE_NOSUPP;
-
-    etype = krb5_keytype_array[creds->keyblock.keytype]->system->proto_enctype;
-
-    if (!valid_etype(etype))
-       return KRB5_PROG_ETYPE_NOSUPP;
-
-    request.ap_options = ap_req_options;
     /* we need a native ticket */
-    if (retval = krb5_decode_ticket(&creds->ticket, &request.ticket))
-       return(retval);                 /* XXX who cleans up creds? */
-
-#define cleanup_ticket() krb5_free_ticket(request.ticket)
-    if (retval = generate_authenticator(&authent, creds, checksum)) {
-       cleanup_ticket();
-       return retval;
-    }
-    /* encode it before encrypting */
-    retval = encode_krb5_authenticator(&authent, &scratch);
-    if (retval) {
-       cleanup_ticket();
+    if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
        return(retval);
+    
+    /* verify that the ticket is not expired */
+    if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
+       goto cleanup;
+
+    /* generate auth_context if needed */
+    if (*auth_context == NULL) {
+       if ((retval = krb5_auth_con_init(context, &new_auth_context)))
+           goto cleanup;
+       *auth_context = new_auth_context;
     }
 
-#define cleanup_scratch() { (void) bzero(scratch->data, scratch->length); krb5_free_data(scratch); }
-
-    /* put together an eblock for this encryption */
-
-    eblock.crypto_entry = krb5_csarray[etype]->system;
-    request.authenticator.length = krb5_encrypt_size(scratch->length,
-                                                    eblock.crypto_entry);
-    /* add padding area, and zero it */
-    if (!(scratch->data = realloc(scratch->data, request.authenticator.length))) {
-       /* may destroy scratch->data */
-       xfree(scratch);
-       retval = ENOMEM;
-       goto clean_ticket;
-    }
-    bzero(scratch->data + scratch->length,
-         request.authenticator.length - scratch->length);
-    if (!(request.authenticator.data = malloc(request.authenticator.length))) {
-       retval = ENOMEM;
-       goto clean_scratch;
+    /* set auth context keyblock */
+    if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock, 
+                                    &((*auth_context)->keyblock))))
+       goto cleanup;
+
+    /* generate seq number if needed */
+    if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
+     || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
+      && ((*auth_context)->local_seq_number == 0)) 
+       if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
+                                    &(*auth_context)->local_seq_number)))
+           goto cleanup;
+       
+
+    /* generate subkey if needed */
+    if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->local_subkey)) {
+       /* Provide some more fodder for random number code.
+          This isn't strong cryptographically; the point here is not
+          to guarantee randomness, but to make it less likely that multiple
+          sessions could pick the same subkey.  */
+       struct {
+           krb5_int32 sec, usec;
+       } rnd_data;
+       krb5_data d;
+       krb5_crypto_us_timeofday (&rnd_data.sec, &rnd_data.usec);
+       d.length = sizeof (rnd_data);
+       d.data = (char *) &rnd_data;
+       (void) krb5_c_random_seed (context, &d);
+
+       if ((retval = krb5_generate_subkey(context, &(in_creds)->keyblock, 
+                                          &(*auth_context)->local_subkey)))
+           goto cleanup;
     }
 
-#define cleanup_encpart() {(void) bzero(request.authenticator.data, request.authenticator.length); free(request.authenticator.data); request.authenticator.length = 0; request.authenticator.data = 0;}
-
-    /* do any necessary key pre-processing */
-    if (retval = krb5_process_key(&eblock, &creds->keyblock)) {
-       goto clean_encpart;
+    if (in_data) {
+       if ((*auth_context)->req_cksumtype == 0x8003) {
+           /* XXX Special hack for GSSAPI */
+           checksum.checksum_type = 0x8003;
+           checksum.length = in_data->length;
+           checksum.contents = (krb5_octet *) in_data->data;
+       } else {
+           if ((retval = krb5_c_make_checksum(context, 
+                                              (*auth_context)->req_cksumtype,
+                                              (*auth_context)->keyblock,
+                                              KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+                                              in_data, &checksum)))
+               goto cleanup_cksum;
+       }
+       checksump = &checksum;
     }
 
-#define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
-
-    /* call the encryption routine */
-    if (retval = krb5_encrypt((krb5_pointer) scratch->data,
-                             (krb5_pointer) request.authenticator.data,
-                             scratch->length, &eblock, 0)) {
-       goto clean_prockey;
+    /* Generate authenticator */
+    if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
+                                       krb5_authenticator))) == NULL) {
+       retval = ENOMEM;
+       goto cleanup_cksum;
     }
 
-    /* authenticator now assembled-- do some cleanup */
-    cleanup_scratch();
+    if ((retval = krb5_generate_authenticator(context,
+                                             (*auth_context)->authentp,
+                                             (in_creds)->client, checksump,
+                                             (*auth_context)->local_subkey,
+                                             (*auth_context)->local_seq_number,
+                                             (in_creds)->authdata)))
+       goto cleanup_cksum;
+       
+    /* encode the authenticator */
+    if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
+                                           &scratch)))
+       goto cleanup_cksum;
+    
+    /* Null out these fields, to prevent pointer sharing problems;
+     * they were supplied by the caller
+     */
+    (*auth_context)->authentp->client = NULL;
+    (*auth_context)->authentp->checksum = NULL;
+    (*auth_context)->authentp->authorization_data = NULL;
 
-    if (retval = krb5_finish_key(&eblock)) {
-       cleanup_encpart();
-       return retval;
+    /* call the encryption routine */
+    if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
+                                     KRB5_KEYUSAGE_AP_REQ_AUTH,
+                                     scratch, &request.authenticator)))
+       goto cleanup_cksum;
+
+    if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
+       goto cleanup_cksum;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *outbuf = *toutbuf;
+#else
+    memcpy(outbuf, toutbuf, sizeof(krb5_data));
+#endif
+
+    krb5_xfree(toutbuf);
+
+cleanup_cksum:
+    if (checksump && checksump->checksum_type != 0x8003)
+      free(checksump->contents);
+
+cleanup:
+    if (request.ticket)
+       krb5_free_ticket(context, request.ticket);
+    if (request.authenticator.ciphertext.data) {
+       (void) memset(request.authenticator.ciphertext.data, 0,
+                     request.authenticator.ciphertext.length);
+       free(request.authenticator.ciphertext.data);
     }
-
-    if (!(retval = encode_krb5_ap_req(&request, &toutbuf))) {
-       *outbuf = *toutbuf;
-       xfree(toutbuf);
+    if (scratch) {
+       memset(scratch->data, 0, scratch->length);
+        krb5_xfree(scratch->data);
+       krb5_xfree(scratch);
     }
-    cleanup_ticket();
-    cleanup_encpart();
-    return retval;
-
- clean_prockey:
-    cleanup_prockey();
- clean_encpart:
-    cleanup_encpart();
- clean_scratch:
-    cleanup_scratch();
- clean_ticket:
-    cleanup_ticket();
-
     return retval;
 }
 
 static krb5_error_code
-generate_authenticator(authent, creds, cksum)
-krb5_authenticator *authent;
-const krb5_creds *creds;
-const krb5_checksum *cksum;
+krb5_generate_authenticator(context, authent, client, cksum, key, seq_number, authorization)
+    krb5_context context;
+    krb5_authenticator *authent;
+    krb5_principal client;
+    const krb5_checksum *cksum;
+    krb5_keyblock *key;
+    krb5_int32 seq_number;
+    krb5_authdata **authorization;
 {
-    authent->client = creds->client;
+    krb5_error_code retval;
+    
+    authent->client = client;
     authent->checksum = (krb5_checksum *)cksum;
-
-    /* cmsec is unsigned, time is signed, hence the cast */
-    return(krb5_ms_timeofday(&authent->ctime, 
-                            (krb5_int16 *)&authent->cmsec));
+    if (key) {
+       retval = krb5_copy_keyblock(context, key, &authent->subkey);
+       if (retval)
+           return retval;
+    } else
+       authent->subkey = 0;
+    authent->seq_number = seq_number;
+    authent->authorization_data = authorization;
+
+    return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
 }