BSD 4_3_Net_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 1 Jun 1991 06:55:43 +0000 (22:55 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 1 Jun 1991 06:55:43 +0000 (22:55 -0800)
Work on file usr/src/kerberosIV/krb/krb_get_in_tkt.c

Synthesized-from: CSRG/cd2/net.2

usr/src/kerberosIV/krb/krb_get_in_tkt.c [new file with mode: 0644]

diff --git a/usr/src/kerberosIV/krb/krb_get_in_tkt.c b/usr/src/kerberosIV/krb/krb_get_in_tkt.c
new file mode 100644 (file)
index 0000000..207ad58
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * $Source: /usr/src/kerberosIV/krb/RCS/krb_get_in_tkt.c,v $
+ * $Author: karels $
+ *
+ * Copyright 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#ifndef lint
+static char *rcsid_krb_get_in_tkt_c =
+"$Header: /usr/src/kerberosIV/krb/RCS/krb_get_in_tkt.c,v 4.21 91/06/01 13:54:58 karels Exp $";
+#endif /* lint */
+
+#include <mit-copyright.h>
+#include <des.h>
+#include <krb.h>
+#include <prot.h>
+
+#include <stdio.h>
+#include <strings.h>
+#include <errno.h>
+
+/* use the bsd time.h struct defs for PC too! */
+#include <sys/time.h>
+#include <sys/types.h>
+
+int     swap_bytes;
+
+/*
+ * decrypt_tkt(): Given user, instance, realm, passwd, key_proc
+ * and the cipher text sent from the KDC, decrypt the cipher text
+ * using the key returned by key_proc.
+ */
+
+static int decrypt_tkt(user, instance, realm, arg, key_proc, cipp)
+  char *user;
+  char *instance;
+  char *realm;
+  char *arg;
+  int (*key_proc)();
+  KTEXT *cipp;
+{
+    KTEXT cip = *cipp;
+    C_Block key;               /* Key for decrypting cipher */
+    Key_schedule key_s;
+
+#ifndef NOENCRYPTION
+    /* Attempt to decrypt it */
+#endif
+    
+    /* generate a key */
+    
+    {
+       register int rc;
+       rc = (*key_proc)(user,instance,realm,arg,key);
+       if (rc)
+           return(rc);
+    }
+    
+#ifndef NOENCRYPTION
+    key_sched(key,key_s);
+    pcbc_encrypt((C_Block *)cip->dat,(C_Block *)cip->dat,
+                (long) cip->length,key_s,key,0);
+#endif /* !NOENCRYPTION */
+    /* Get rid of all traces of key */
+    bzero((char *)key,sizeof(key));
+    bzero((char *)key_s,sizeof(key_s));
+
+    return(0);
+}
+
+/*
+ * krb_get_in_tkt() gets a ticket for a given principal to use a given
+ * service and stores the returned ticket and session key for future
+ * use.
+ *
+ * The "user", "instance", and "realm" arguments give the identity of
+ * the client who will use the ticket.  The "service" and "sinstance"
+ * arguments give the identity of the server that the client wishes
+ * to use.  (The realm of the server is the same as the Kerberos server
+ * to whom the request is sent.)  The "life" argument indicates the
+ * desired lifetime of the ticket; the "key_proc" argument is a pointer
+ * to the routine used for getting the client's private key to decrypt
+ * the reply from Kerberos.  The "decrypt_proc" argument is a pointer
+ * to the routine used to decrypt the reply from Kerberos; and "arg"
+ * is an argument to be passed on to the "key_proc" routine.
+ *
+ * If all goes well, krb_get_in_tkt() returns INTK_OK, otherwise it
+ * returns an error code:  If an AUTH_MSG_ERR_REPLY packet is returned
+ * by Kerberos, then the error code it contains is returned.  Other
+ * error codes returned by this routine include INTK_PROT to indicate
+ * wrong protocol version, INTK_BADPW to indicate bad password (if
+ * decrypted ticket didn't make sense), INTK_ERR if the ticket was for
+ * the wrong server, TKT_FIL_ACC if the ticket store couldn't be initialized
+ * or ticket couldn't be saved.
+ *
+ * The format of the message sent to Kerberos is as follows:
+ *
+ * Size                        Variable                Field
+ * ----                        --------                -----
+ *
+ * 1 byte              KRB_PROT_VERSION        protocol version number
+ * 1 byte              AUTH_MSG_KDC_REQUEST |  message type
+ *                     HOST_BYTE_ORDER         local byte order in lsb
+ * string              user                    client's name
+ * string              instance                client's instance
+ * string              realm                   client's realm
+ * 4 bytes             tlocal.tv_sec           timestamp in seconds
+ * 1 byte              life                    desired lifetime
+ * string              service                 service's name
+ * string              sinstance               service's instance
+ */
+
+krb_get_in_tkt(user, instance, realm, service, sinstance, life,
+              key_proc, decrypt_proc, arg)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    int (*key_proc)();
+    int (*decrypt_proc)();
+    char *arg;
+{
+    KTEXT_ST pkt_st;
+    KTEXT pkt = &pkt_st;       /* Packet to KDC */
+    KTEXT_ST rpkt_st;
+    KTEXT rpkt = &rpkt_st;     /* Returned packet */
+    KTEXT_ST cip_st;
+    KTEXT cip = &cip_st;       /* Returned Ciphertext */
+    KTEXT_ST tkt_st;
+    KTEXT tkt = &tkt_st;       /* Current ticket */
+    C_Block ses;                /* Session key for tkt */
+    int kvno;                  /* Kvno for session key */
+    unsigned char *v = pkt->dat; /* Prot vers no */
+    unsigned char *t = (pkt->dat+1); /* Prot msg type */
+
+    char s_name[SNAME_SZ];
+    char s_instance[INST_SZ];
+    char rlm[REALM_SZ];
+    int lifetime;
+    int msg_byte_order;
+    int kerror;
+    unsigned long exp_date;
+    char *ptr;
+
+    struct timeval t_local;
+
+    unsigned long rep_err_code;
+
+    unsigned long kdc_time;   /* KDC time */
+
+    /* BUILD REQUEST PACKET */
+
+    /* Set up the fixed part of the packet */
+    *v = (unsigned char) KRB_PROT_VERSION;
+    *t = (unsigned char) AUTH_MSG_KDC_REQUEST;
+    *t |= HOST_BYTE_ORDER;
+
+    /* Now for the variable info */
+    (void) strcpy((char *)(pkt->dat+2),user); /* aname */
+    pkt->length = 3 + strlen(user);
+    (void) strcpy((char *)(pkt->dat+pkt->length),
+                 instance);    /* instance */
+    pkt->length += 1 + strlen(instance);
+    (void) strcpy((char *)(pkt->dat+pkt->length),realm); /* realm */
+    pkt->length += 1 + strlen(realm);
+
+    (void) gettimeofday(&t_local,(struct timezone *) 0);
+    /* timestamp */
+    bcopy((char *)&(t_local.tv_sec),(char *)(pkt->dat+pkt->length), 4);
+    pkt->length += 4;
+
+    *(pkt->dat+(pkt->length)++) = (char) life;
+    (void) strcpy((char *)(pkt->dat+pkt->length),service);
+    pkt->length += 1 + strlen(service);
+    (void) strcpy((char *)(pkt->dat+pkt->length),sinstance);
+    pkt->length += 1 + strlen(sinstance);
+
+    rpkt->length = 0;
+
+    /* SEND THE REQUEST AND RECEIVE THE RETURN PACKET */
+
+    if (kerror = send_to_kdc(pkt, rpkt, realm)) return(kerror);
+
+    /* check packet version of the returned packet */
+    if (pkt_version(rpkt) != KRB_PROT_VERSION)
+        return(INTK_PROT);
+
+    /* Check byte order */
+    msg_byte_order = pkt_msg_type(rpkt) & 1;
+    swap_bytes = 0;
+    if (msg_byte_order != HOST_BYTE_ORDER) {
+        swap_bytes++;
+    }
+
+    switch (pkt_msg_type(rpkt) & ~1) {
+    case AUTH_MSG_KDC_REPLY:
+        break;
+    case AUTH_MSG_ERR_REPLY:
+        bcopy(pkt_err_code(rpkt),(char *) &rep_err_code,4);
+        if (swap_bytes) swap_u_long(rep_err_code);
+        return((int)rep_err_code);
+    default:
+        return(INTK_PROT);
+    }
+
+    /* EXTRACT INFORMATION FROM RETURN PACKET */
+
+    /* get the principal's expiration date */
+    bcopy(pkt_x_date(rpkt),(char *) &exp_date,sizeof(exp_date));
+    if (swap_bytes) swap_u_long(exp_date);
+
+    /* Extract the ciphertext */
+    cip->length = pkt_clen(rpkt);       /* let clen do the swap */
+
+    if ((cip->length < 0) || (cip->length > sizeof(cip->dat)))
+       return(INTK_PROT);              /* no appropriate error code
+                                        currently defined for INTK_ */
+    /* copy information from return packet into "cip" */
+    bcopy((char *) pkt_cipher(rpkt),(char *)(cip->dat),cip->length);
+
+    /* Attempt to decrypt the reply. */
+    if (decrypt_proc == NULL)
+       decrypt_proc = decrypt_tkt;
+    (*decrypt_proc)(user, instance, realm, arg, key_proc, &cip);
+
+    ptr = (char *) cip->dat;
+
+    /* extract session key */
+    bcopy(ptr,(char *)ses,8);
+    ptr += 8;
+
+    if ((strlen(ptr) + (ptr - (char *) cip->dat)) > cip->length)
+       return(INTK_BADPW);
+
+    /* extract server's name */
+    (void) strcpy(s_name,ptr);
+    ptr += strlen(s_name) + 1;
+
+    if ((strlen(ptr) + (ptr - (char *) cip->dat)) > cip->length)
+       return(INTK_BADPW);
+
+    /* extract server's instance */
+    (void) strcpy(s_instance,ptr);
+    ptr += strlen(s_instance) + 1;
+
+    if ((strlen(ptr) + (ptr - (char *) cip->dat)) > cip->length)
+       return(INTK_BADPW);
+
+    /* extract server's realm */
+    (void) strcpy(rlm,ptr);
+    ptr += strlen(rlm) + 1;
+
+    /* extract ticket lifetime, server key version, ticket length */
+    /* be sure to avoid sign extension on lifetime! */
+    lifetime = (unsigned char) ptr[0];
+    kvno = (unsigned char) ptr[1];
+    tkt->length = (unsigned char) ptr[2];
+    ptr += 3;
+    
+    if ((tkt->length < 0) ||
+       ((tkt->length + (ptr - (char *) cip->dat)) > cip->length))
+       return(INTK_BADPW);
+
+    /* extract ticket itself */
+    bcopy(ptr,(char *)(tkt->dat),tkt->length);
+    ptr += tkt->length;
+
+    if (strcmp(s_name, service) || strcmp(s_instance, sinstance) ||
+        strcmp(rlm, realm))    /* not what we asked for */
+       return(INTK_ERR);       /* we need a better code here XXX */
+
+    /* check KDC time stamp */
+    bcopy(ptr,(char *)&kdc_time,4); /* Time (coarse) */
+    if (swap_bytes) swap_u_long(kdc_time);
+
+    ptr += 4;
+
+    (void) gettimeofday(&t_local,(struct timezone *) 0);
+    if (abs((int)(t_local.tv_sec - kdc_time)) > CLOCK_SKEW) {
+        return(RD_AP_TIME);            /* XXX should probably be better
+                                          code */
+    }
+
+    /* initialize ticket cache */
+    if (in_tkt(user,instance) != KSUCCESS)
+       return(TKT_FIL_ACC);
+
+    /* stash ticket, session key, etc. for future use */
+    if (kerror = save_credentials(s_name, s_instance, rlm, ses,
+                                 lifetime, kvno, tkt, t_local.tv_sec))
+       return(TKT_FIL_ACC);
+
+    return(INTK_OK);
+}