From 5fbbfcee82f10f3b07a967ecaa9095f127103920 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Fri, 26 Jan 2001 04:20:57 +0000 Subject: [PATCH] * prot_client.c: New file; client-side protocol support * prot_common.c (krb4prot_decode_header): Decode the first two bytes of a krb4 packet. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12949 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb4/ChangeLog | 7 + src/lib/krb4/prot_client.c | 370 +++++++++++++++++++++++++++++++++++++ src/lib/krb4/prot_common.c | 16 ++ 3 files changed, 393 insertions(+) create mode 100644 src/lib/krb4/prot_client.c diff --git a/src/lib/krb4/ChangeLog b/src/lib/krb4/ChangeLog index 9954a8771..dda52e26f 100644 --- a/src/lib/krb4/ChangeLog +++ b/src/lib/krb4/ChangeLog @@ -1,3 +1,10 @@ +2001-01-25 Tom Yu + + * prot_client.c: New file; client-side protocol support. + + * prot_common.c (krb4prot_decode_header): Decode the first two + bytes of a krb4 packet. + 2001-01-24 Tom Yu * prot_common.c: Fix up some error returns. diff --git a/src/lib/krb4/prot_client.c b/src/lib/krb4/prot_client.c new file mode 100644 index 000000000..d254e8949 --- /dev/null +++ b/src/lib/krb4/prot_client.c @@ -0,0 +1,370 @@ +/* + * lib/krb4/prot_client.c + * + * Copyright 2001 by the Massachusetts Institute of Technology. All + * Rights Reserved. + * + * 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. + * + * Contains protocol encoders and decoders used by a krb4 client. + */ + +#include "krb.h" +#include "prot.h" +#include + +/* + * encode_kdc_request + * + * Packet format is originally from g_in_tkt.c. + * + * 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 KRB5_CALLCONV +krb4prot_encode_kdc_request(char *pname, char *pinst, char *prealm, + KRB4_32 tlocal, int life, + char *sname, char *sinst, + char *preauth, int preauthlen, + int chklen, /* check input str len? */ + int le, /* little-endian? */ + KTEXT pkt) +{ + unsigned char *p; + int ret; + size_t snamelen, sinstlen; + + p = pkt->dat; + + *p++ = KRB_PROT_VERSION; + *p++ = AUTH_MSG_KDC_REQUEST | (le ? LSB_FIRST : MSB_FIRST); + + ret = krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen, + pkt, &p); + if (ret) + return ret; + + snamelen = strlen(sname) + 1; + sinstlen = strlen(sinst) + 1; + if (chklen && (snamelen > ANAME_SZ || sinstlen > INST_SZ)) + return KRB4PROT_ERR_OVERRUN; + if ((sizeof(pkt->dat) - (p - pkt->dat)) + < (4 + 1 + snamelen + sinstlen + preauthlen)) + return KRB4PROT_ERR_OVERRUN; + + /* timestamp */ + KRB4_PUT32(p, tlocal, le); + + *p++ = life; + + memcpy(p, sname, snamelen); + p += snamelen; + memcpy(p, sinst, sinstlen); + p += sinstlen; + + if (preauthlen) + memcpy(p, preauth, (size_t)preauthlen); + p += preauthlen; + + pkt->length = p - pkt->dat; + return KRB4PROT_OK; +} + +/* + * decode_kdc_reply + */ +int KRB5_CALLCONV +krb4prot_decode_kdc_reply(KTEXT pkt, + int *le, + char *pname, char *pinst, char *prealm, + long *time_ws, int *n, + unsigned long *x_date, int *kvno, + KTEXT ciph) +{ + unsigned char *p; + int msg_type; + int ret; + unsigned int ciph_len; + + p = pkt->dat; + if (pkt->length < 2) + return KRB4PROT_ERR_UNDERRUN; + if (*p++ != KRB_PROT_VERSION) + return KRB4PROT_ERR_PROT_VERS; + msg_type = *p++; + *le = msg_type & 1; + msg_type &= ~1; + if (msg_type != AUTH_MSG_KDC_REPLY) + return KRB4PROT_ERR_MSG_TYPE; + + ret = krb4prot_decode_naminstrlm(ciph, &p, pname, pinst, prealm); + if (ret) + return ret; + +#define PKT_REMAIN (pkt->length - (p - pkt->dat)) + + if (PKT_REMAIN < (4 /* time */ + + 1 /* number of tickets */ + + 4 /* exp date */ + + 1 /* kvno */ + + 2)) /* ciph length */ + return KRB4PROT_ERR_UNDERRUN; + if (time_ws != NULL) + KRB4_GET32(*time_ws, p, *le); /* XXX signed/unsigned */ + else + p += 4; + if (n != NULL) + *n = *p++; + else + p++; + if (x_date != NULL) + KRB4_GET32(*x_date, p, *le); + else + p += 4; + if (kvno != NULL) + *kvno = *p++; + else + p++; + KRB4_GET16(ciph_len, p, *le); + if (PKT_REMAIN < ciph_len) + return KRB4PROT_ERR_UNDERRUN; + ciph->length = ciph_len; + memcpy(ciph->dat, p, (size_t)ciph->length); + return KRB4PROT_OK; +#undef PKT_REMAIN +} + +int KRB5_CALLCONV +krb4prot_decode_ciph(KTEXT ciph, int le, + C_Block session, + char *name, char *inst, char *realm, + int *life, int *kvno, + KTEXT tkt, unsigned long *kdc_time) +{ + unsigned char *p; + int ret; + + p = ciph->dat; + if (ciph->length < 8) + return KRB4PROT_ERR_UNDERRUN; + memcpy(session, p, 8); + p += 8; + ret = krb4prot_decode_naminstrlm(ciph, &p, name, inst, realm); + if (ret) + return ret; +#define CIPH_REMAIN (ciph->length - (p - ciph->dat)) + if (CIPH_REMAIN < (1 /* life */ + + 1 /* kvno */ + + 1)) /* tkt->length */ + return KRB4PROT_ERR_UNDERRUN; + if (life != NULL) + *life = *p++; + else + p++; + if (kvno != NULL) + *kvno = *p++; + else + p++; + tkt->length = *p++; + if (CIPH_REMAIN < (tkt->length + + 4)) /* kdc_time */ + return KRB4PROT_ERR_UNDERRUN; + memcpy(tkt->dat, p, (size_t)tkt->length); + p += tkt->length; + + if (kdc_time != NULL) + KRB4_GET32(*kdc_time, p, le); + + return KRB4PROT_OK; +#undef CIPH_REMAIN +} + +/* + * encode_apreq + * + * The following was originally from mk_req.c. + * + * unsigned char KRB_PROT_VERSION protocol version no. + * unsigned char AUTH_MSG_APPL_REQUEST message type + * (least significant + * bit of above) HOST_BYTE_ORDER local byte ordering + * unsigned char kvno from ticket server's key version + * string realm server's realm + * unsigned char tl ticket length + * unsigned char idl request id length + * binary ticket->dat ticket for server + * binary req_id->dat request id + */ +int KRB5_CALLCONV +krb4prot_encode_apreq(int kvno, char *realm, + KTEXT tkt, KTEXT req_id, + int chklen, /* check str len? */ + int le, /* little-endian? */ + KTEXT pkt) +{ + unsigned char *p; + size_t realmlen; + + p = pkt->dat; + /* Assume >= 3 bytes in a KTEXT. */ + *p++ = KRB_PROT_VERSION; + *p++ = AUTH_MSG_APPL_REQUEST | (le ? LSB_FIRST : MSB_FIRST); + + *p++ = kvno; + + realmlen = strlen(realm) + 1; + if (chklen && realmlen > REALM_SZ) + return KRB4PROT_ERR_OVERRUN; + if (tkt->length > 255 || req_id->length > 255) + return KRB4PROT_ERR_OVERRUN; + if ((sizeof(pkt->dat) - (p - pkt->dat)) + < (realmlen + + 1 /* tkt->length */ + + 1 /* req_id->length */ + + tkt->length + req_id->length)) + return KRB4PROT_ERR_OVERRUN; + + memcpy(p, realm, realmlen); + p += realmlen; + + *p++ = tkt->length; + *p++ = req_id->length; + memcpy(p, tkt->dat, (size_t)tkt->length); + p += tkt->length; + memcpy(p, req_id->dat, (size_t)req_id->length); + p += req_id->length; + + pkt->length = p - pkt->dat; + return KRB4PROT_OK; +} + +/* + * encode_authent + * + * Encodes an authenticator (called req_id in some of the code for + * some weird reason). Does not encrypt. + * + * The following packet layout is originally from mk_req.c. It is + * rounded up to the next multiple of 8 bytes. + * + * string cr.pname {name, instance, and + * string cr.pinst realm of principal + * string myrealm making this request} + * 4 bytes checksum checksum argument given + * unsigned char time_usecs time (microseconds) + * 4 bytes time_secs time (seconds) + */ +int KRB5_CALLCONV +krb4prot_encode_authent(char *pname, char *pinst, char *prealm, + KRB4_32 checksum, + int time_usec, long time_sec, + int chklen, /* check str lens? */ + int le, /* little-endian? */ + KTEXT pkt) +{ + unsigned char *p; + int ret; + + p = pkt->dat; + ret = krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen, + pkt, &p); + if (ret) + return ret; + if ((sizeof(pkt->dat) - (p - pkt->dat)) / 8 + < (4 /* checksum */ + + 1 /* microsec */ + + 4 /* time */ + + 7) / 8) /* roundoff */ + return KRB4PROT_ERR_OVERRUN; + + KRB4_PUT32(p, checksum, le); + *p++ = time_usec; + KRB4_PUT32(p, time_sec, le); + + memset(p, 0, 7); /* nul-pad */ + pkt->length = (((p - pkt->dat) + 7) / 8) * 8; + return KRB4PROT_OK; +} + +/* + * decode_error + * + * Decodes an error reply from the KDC. + */ +int KRB5_CALLCONV +krb4prot_decode_error(KTEXT pkt, int *le, + char *pname, char *pinst, char *prealm, + unsigned long *time_ws, + unsigned long *err, char *err_string) +{ + unsigned char *p; + int msg_type, ret, errstrlen; + + p = pkt->dat; + if (pkt->length < 2) + return KRB4PROT_ERR_UNDERRUN; + if (*p++ != KRB_PROT_VERSION) + return KRB4PROT_ERR_PROT_VERS; + msg_type = *p++; + *le = msg_type & 1; + msg_type &= ~1; + if (msg_type != AUTH_MSG_ERR_REPLY) + return KRB4PROT_ERR_MSG_TYPE; + + ret = krb4prot_decode_naminstrlm(pkt, &p, pname, pinst, prealm); + if (ret) + return ret; + +#define PKT_REMAIN (pkt->length - (p - pkt->dat)) + if (PKT_REMAIN < (4 /* time */ + + 4)) /* err code */ + return KRB4PROT_ERR_UNDERRUN; + + if (time_ws != NULL) + KRB4_GET32(*time_ws, p, le); + else + p += 4; + if (err != NULL) + KRB4_GET32(*err, p, le); + else + p += 4; + + if (PKT_REMAIN <= 0) /* allow for missing error string */ + return KRB4PROT_OK; + + errstrlen = krb4int_strnlen((char *)p, PKT_REMAIN) + 1; + if (errstrlen <= 0) /* If it's there, it must be nul-terminated. */ + return KRB4PROT_ERR_OVERRUN; + if (err_string != NULL) + memcpy(err_string, p, (size_t)errstrlen); + + return KRB4PROT_OK; +#undef PKT_REMAIN +} diff --git a/src/lib/krb4/prot_common.c b/src/lib/krb4/prot_common.c index f1a1c147b..3e36de129 100644 --- a/src/lib/krb4/prot_common.c +++ b/src/lib/krb4/prot_common.c @@ -118,3 +118,19 @@ krb4prot_decode_naminstrlm(KTEXT pkt, /* buffer to decode from */ return KRB4PROT_OK; #undef PKT_REMAIN } + +int KRB5_CALLCONV +krb4prot_decode_header(KTEXT pkt, + int *pver, int *msgtype, int *le) +{ + unsigned char *p; + + p = pkt->dat; + if (pkt->length < 2) + return KRB4PROT_ERR_UNDERRUN; + *pver = *p++; + *msgtype = *p++; + *le = *msgtype & 1; + *msgtype &= ~1; + return KRB4PROT_OK; +} -- 2.26.2