*** empty log message ***
authorJohn Kohl <jtkohl@mit.edu>
Tue, 23 Jan 1990 14:54:12 +0000 (14:54 +0000)
committerJohn Kohl <jtkohl@mit.edu>
Tue, 23 Jan 1990 14:54:12 +0000 (14:54 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@168 dc483132-0cff-0310-8789-dd5450dbe970

src/kdc/do_as_req.c [new file with mode: 0644]

diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
new file mode 100644 (file)
index 0000000..f527575
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/mit-copyright.h>.
+ *
+ * KDC Routines to deal with AS_REQ's
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_do_as_req_c >>>[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/copyright.h>
+
+#include <krb5/krb5.h>
+#include <krb5/krb5_err.h>
+#include <krb5/kdb.h>
+#include <krb5/asn.1/KRB5-types.h>
+#include <krb5/asn.1/krb5_free.h>
+#include <krb5/asn.1/asn1defs.h>
+#include <krb5/asn.1/KRB5-types-aux.h>
+#include <krb5/asn.1/encode.h>
+#include <errno.h>
+#include <com_err.h>
+
+extern krb5_cs_table_entry *csarray[];
+extern int max_cryptosystem;           /* max entry in array */
+extern krb5_data empty_string;         /* initialized to {0, ""} */
+extern krb5_timestamp infinity;                /* greater than every valid timestamp */
+extern krb5_deltat max_life_for_realm; /* XXX should be a parameter? */
+extern krb5_deltat max_renewable_life_for_realm; /* XXX should be a parameter? */
+
+static krb5_error_code prepare_error PROTOTYPE((int,
+                                               krb5_data *));
+/*
+ * Do all the processing required for a AS_REQ
+ */
+
+/* XXX needs lots of cleanup and modularizing */
+
+#define isset(flagfield, flag) (flagfield & flag)
+#define set(flagfield, flag) (flagfield &= flag)
+
+#ifndef        min
+#define        min(a, b)       ((a) < (b) ? (a) : (b))
+#define        max(a, b)       ((a) > (b) ? (a) : (b))
+#endif
+
+krb5_error_code
+process_as_req(request, response)
+register krb5_as_req *request;
+krb5_data **response;                  /* filled in with a response packet */
+{
+
+    krb5_db_entry client, server;
+    krb5_kdc_rep reply;
+    krb5_enc_kdc_rep_part reply_encpart;
+    krb5_ticket ticket_reply;
+    krb5_enc_tkt_part enc_tkt_reply;
+    krb5_error_code retval;
+    int nprincs;
+    krb5_boolean more;
+    krb5_timestamp kdc_time;
+    krb5_keyblock *session_key;
+    krb5_encrypt_block eblock;
+    krb5_data *scratch;
+
+    krb5_timestamp until, rtime;
+
+    nprincs = 1;
+    if (retval = krb5_db_get_principal(request->client, &client, &nprincs,
+                                      &more))
+       return(retval);
+    if (more) {
+       krb5_db_free_principal(&client, nprincs);
+       return(prepare_error(request, KDC_ERR_PRINCIPAL_NOT_UNIQUE, response));
+    } else if (nprincs != 1) {
+       krb5_db_free_principal(&client, nprincs);
+       return(prepare_error(request, KDC_ERR_C_PRINCIPAL_UNKNOWN, response));
+    }  
+       
+    nprincs = 1;
+    if (retval = krb5_db_get_principal(request->server, &server, &nprincs,
+                                      &more))
+       return(retval);
+    if (more) {
+       krb5_db_free_principal(&client, 1);
+       krb5_db_free_principal(&server, nprincs);
+       return(prepare_error(request, KDC_ERR_PRINCIPAL_NOT_UNIQUE, response));
+    } else if (nprincs != 1) {
+       krb5_db_free_principal(&client, 1);
+       krb5_db_free_principal(&server, nprincs);
+       return(prepare_error(request, KDC_ERR_S_PRINCIPAL_UNKNOWN, response));
+    }
+
+    if (retval = krb5_timeofday(&kdc_time))
+       return(retval);
+
+    if (request->etype > max_cryptosystem ||
+       !csarray[request->etype]->system) {
+       /* unsupported etype */
+
+#define cleanup() {krb5_db_free_principal(&client, 1); krb5_db_free_principal(&server, 1); }
+
+       cleanup();
+       return(prepare_error(request, KDC_ERR_ETYPE_NOSUPP, response));
+    }
+
+    if (retval = (*(csarray[request->etype]->system->random_key))(csarray[request->etype]->random_sequence, &session_key)) {
+       /* random key failed */
+       cleanup();
+       return(retval);
+    }
+
+#undef cleanup
+#define cleanup() {krb5_db_free_principal(&client, 1); krb5_db_free_principal(&server, 1); bzero((char *)session_key, sizeof(*session_key)+session_key->length-1); }
+
+
+    ticket_reply.server = request->server;
+    ticket_reply.etype = request->etype;
+    ticket_reply.skvno = server.kvno;
+
+    enc_tkt_reply.flags = 0;
+
+        /* It should be noted that local policy may affect the  */
+        /* processing of any of these flags.  For example, some */
+        /* realms may refuse to issue renewable tickets         */
+
+    if (isset(request->kdc_options, KDC_OPT_FORWARDED) ||
+       isset(request->kdc_options, KDC_OPT_PROXY) ||
+       isset(request->kdc_options, KDC_OPT_RENEW) ||
+       isset(request->kdc_options, KDC_OPT_VALIDATE) ||
+       isset(request->kdc_options, KDC_OPT_REUSE_SKEY) ||
+       isset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
+       /* none of these options is valid for an AS request */
+       cleanup();
+       return(prepare_error(request, KDC_ERR_BADOPTION, response));
+    }
+
+    if (isset(request->kdc_options, KDC_OPT_FORWARDABLE))
+       set(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+
+    if (isset(request->kdc_options, KDC_OPT_PROXIABLE))
+       set(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
+
+    if (isset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
+       set(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
+
+    if (isset(request->kdc_options, KDC_OPT_DUPLICATE_SKEY))
+       set(enc_tkt_reply.flags, TKT_FLG_DUPLICATE_SKEY);
+
+
+    enc_tkt_reply.session = session_key;
+    enc_tkt_reply.client = request->client;
+    enc_tkt_reply.transited = empty_string; /* equivalent of "" */
+    enc_tkt_reply.times.authtime = kdc_time;
+
+    if (isset(request->kdc_options, KDC_OPT_POSTDATED)) {
+       if (against_postdate_policy(request->from)) {
+           cleanup();
+           return(prepare_error(request, KDC_ERR_POLICY, response));
+       }
+       set(enc_tkt_reply.flags, TKT_FLG_INVALID);
+       enc_tkt_reply.times.starttime = request->from;
+    } else
+       enc_tkt_reply.times.starttime = kdc_time;
+    
+
+    until = (request->till == 0) ? infinity : request->till;
+
+    enc_tkt_reply.times.endtime =
+       min(until,
+           min(enc_tkt_reply.times.starttime + client.max_life,
+               min(enc_tkt_reply.times.starttime + server.max_life,
+                   enc_tkt_reply.times.starttime + max_life_for_realm)));
+
+    if (isset(request->kdc_options, KDC_OPT_RENEWABLE_OK) && 
+       request->till && (enc_tkt_reply.times.endtime < request->till)) {
+
+       /* we set the RENEWABLE option for later processing */
+
+       set(request->kdc_options, KDC_OPT_RENEWABLE);
+       request->rtime = request->till;
+    }
+    rtime = (request->rtime == 0) ? infinity : request->rtime;
+
+    if (isset(request->kdc_options, KDC_OPT_RENEWABLE)) {
+       set(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
+       enc_tkt_reply.times.renew_till =
+           min(rtime, min(enc_tkt_reply.times.starttime +
+                          client.max_renewable_life,
+                          min(enc_tkt_reply.times.starttime +
+                              server.max_renewable_life,
+                              enc_tkt_reply.times.starttime +
+                              max_renewable_life_for_realm)));
+    } else
+       enc_tkt_reply.times.renew_till = 0; /* XXX */
+
+    enc_tkt_reply.caddrs = request->addresses;
+    enc_tkt_reply.authorization_data = 0; /* XXX? */
+
+    /* encrypt the encrypted part */
+    /*  Encode the to-be-encrypted part. */
+    if (retval = encode_krb5_enc_tkt_part(&enc_tkt_reply, &scratch)) {
+       cleanup();
+       return retval;
+    }
+
+#undef cleanup
+#define cleanup() {krb5_db_free_principal(&client, 1); krb5_db_free_principal(&server, 1); bzero((char *)session_key, sizeof(*session_key)+session_key->length-1); bzero(scratch->data, scratch->length); krb5_free_data(scratch); }
+
+    /* put together an eblock for this encryption */
+
+    eblock.crypto_entry = csarray[request->etype]->system;
+    ticket_reply.enc_part.length = krb5_encrypt_size(scratch->length,
+                                                    eblock.crypto_entry);
+    if (!(ticket_reply.enc_part.data = malloc(ticket_reply.enc_part.length))) {
+       cleanup();
+       return ENOMEM;
+    }
+    if (retval = (*eblock.crypto_entry->process_key)(&eblock, server.key)) {
+       free(ticket_reply.enc_part.data);
+       cleanup();
+       return retval;
+    }
+    if (retval = (*eblock.crypto_entry->encrypt_func)((krb5_pointer) scratch->data, (krb5_pointer) ticket_reply.enc_part.data, scratch->length, &eblock)) {
+       free(ticket_reply.enc_part.data);
+       (void) (*eblock.crypto_entry->finish_key)(&eblock);
+       cleanup();
+       return retval;
+    }
+
+    /* ticket is now complete-- do some cleanup */
+    bzero(scratch->data, scratch->length);
+    krb5_free_data(scratch);
+    krb5_db_free_principal(&server, 1);
+
+#undef cleanup
+#define cleanup() {krb5_db_free_principal(&client, 1);bzero((char *)session_key, sizeof(*session_key)+session_key->length-1); bzero(ticket_reply.enc_part.data, ticket_reply.enc_part.length); free(ticket_reply.enc_part.data);}
+
+    if (retval = (*eblock.crypto_entry->finish_key)(&eblock)) {
+       cleanup();
+       return retval;
+    }
+
+    /* XXX need separate etypes for ticket encryption and kdc_rep encryption */
+
+
+    /* Start assembling the response */
+    reply.client = request->client;
+    reply.etype = request->etype;
+    reply.ckvno = client.kvno;
+    reply.ticket = &ticket_reply;
+
+
+    reply_encpart.session = session_key;
+    reply_encpart.last_req = 0;                /* XXX */
+    reply_encpart.ctime = request->ctime;
+    reply_encpart.key_exp = client.expiration;
+    reply_encpart.flags = enc_tkt_reply.flags;
+    reply_encpart.server = ticket_reply.server;
+
+    /* copy the time fields EXCEPT for authtime; it's location
+       is used for ktime */
+    reply_encpart.times = enc_tkt_reply.times;
+    reply_encpart.times.authtime = kdc_time;
+
+    reply_encpart.caddrs = enc_tkt_reply.caddrs;
+
+    /* finished with session key */
+    bzero((char *)session_key, sizeof(*session_key)+session_key->length-1);
+
+#undef cleanup
+#define cleanup() { krb5_db_free_principal(&client, 1); bzero(ticket_reply.enc_part.data, ticket_reply.enc_part.length); free(ticket_reply.enc_part.data);}
+
+    /* now encode/encrypt the response */
+
+    if (retval = encode_krb5_enc_kdc_rep_part(&reply_encpart, &scratch)) {
+       cleanup();
+       return retval;
+    }
+#undef cleanup
+#define cleanup() { krb5_db_free_principal(&client, 1); bzero(ticket_reply.enc_part.data, ticket_reply.enc_part.length); free(ticket_reply.enc_part.data); bzero(scratch->data, scratch->length); krb5_free_data(scratch); }
+
+    /* put together an eblock for this encryption */
+
+    eblock.crypto_entry = csarray[request->etype]->system;
+    reply.enc_part.length = krb5_encrypt_size(scratch->length,
+                                             eblock.crypto_entry);
+    if (!(reply.enc_part.data = malloc(reply.enc_part.length))) {
+       cleanup();
+       return ENOMEM;
+    }
+    if (retval = (*eblock.crypto_entry->process_key)(&eblock, client.key)) {
+       free(reply.enc_part.data);
+       cleanup();
+       return retval;
+    }
+    if (retval = (*eblock.crypto_entry->encrypt_func)((krb5_pointer) scratch->data, (krb5_pointer) reply.enc_part.data, scratch->length, &eblock)) {
+       free(reply.enc_part.data);
+       (void) (*eblock.crypto_entry->finish_key)(&eblock);
+       cleanup();
+       return retval;
+    }
+
+    /* some more cleanup */
+    bzero(scratch->data, scratch->length);
+    krb5_free_data(scratch);
+    krb5_db_free_principal(&client, 1);
+
+#undef cleanup
+#define cleanup() { bzero(ticket_reply.enc_part.data, ticket_reply.enc_part.length); free(ticket_reply.enc_part.data); bzero(reply.enc_part.data,reply.enc_part.length); free(reply.enc_part.data); }
+
+    if (retval = (*eblock.crypto_entry->finish_key)(&eblock)) {
+       cleanup();
+       return retval;
+    }
+
+    /* now it's ready to be encoded for the wire! */
+
+    retval = encode_krb5_kdc_rep(&reply, response);
+    cleanup();
+    return retval;
+
+}
+
+static krb5_error_code
+prepare_error (request, error, response)
+register krb5_as_req *request;
+int error;
+krb5_data **response;
+{
+    krb5_error errpkt;
+    krb5_error_code retval;
+
+
+    errpkt.ctime = request->ctime;
+    errpkt.cmsec = 0;
+
+    if (retval = krb5_mstimeofday(&errpkt.stime, &errpkt.smsec))
+       return(retval);
+    errpkt.error = error;
+    errpkt.server = request->server;
+    errpkt.client = request->client;
+    errpkt.text.length = strlen(error_message(error+KRB5KDC_ERR_NONE))+1;
+    if (!(errpkt.text.data = malloc(errpkt.text.length)))
+       return ENOMEM;
+    (void) strcpy(errpkt.text.data, error_message(error+KRB5KDC_ERR_NONE));
+
+    retval = encode_krb5_error(&errpkt, &response);
+    free(errpkt.text.data);
+    return retval;
+}