diff options
Diffstat (limited to 'kerberosIV/krb/krb_get_in_tkt.c')
-rw-r--r-- | kerberosIV/krb/krb_get_in_tkt.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/kerberosIV/krb/krb_get_in_tkt.c b/kerberosIV/krb/krb_get_in_tkt.c new file mode 100644 index 00000000000..1ce8c9926b7 --- /dev/null +++ b/kerberosIV/krb/krb_get_in_tkt.c @@ -0,0 +1,331 @@ +/* + * This software may now be redistributed outside the US. + * + * $Source: /cvs/OpenBSD/src/kerberosIV/krb/Attic/krb_get_in_tkt.c,v $ + * + * $Locker: $ + */ + +/* + Copyright (C) 1989 by the Massachusetts Institute of Technology + + Export of this software from the United States of America is assumed + to 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. 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. + + */ + +#include "krb_locl.h" + +#include <sys/time.h> + +int swap_bytes; + +static int +pkt_clen(pkt) + KTEXT pkt; +{ + static unsigned short temp,temp2; + int clen = 0; + + /* Start of ticket list */ + unsigned char *ptr = pkt_a_realm(pkt) + 10 + + strlen((char *)pkt_a_realm(pkt)); + + /* Finally the length */ + bcopy((char *)(++ptr),(char *)&temp,2); /* alignment */ + if (swap_bytes) { + /* assume a short is 2 bytes?? */ + swab((char *)&temp,(char *)&temp2,2); + temp = temp2; + } + + clen = (int) temp; + + if (krb_debug) + printf("Clen is %d\n",clen); + return(clen); +} + +/* + * 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; + des_cblock key; /* Key for decrypting cipher */ + des_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 + des_key_sched(&key,key_s); + des_pcbc_encrypt((des_cblock *)cip->dat,(des_cblock *)cip->dat, + (long) cip->length,key_s,&key,DES_DECRYPT); +#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 or the ticket store couldn't be initialized. + * + * 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 + */ + +int +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 */ + des_cblock 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_ERR); /* 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(INTK_ERR); + + /* 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(kerror); + + return(INTK_OK); +} |