#include "krb.h"
#include "des.h"
#include "krb4int.h"
#include "prot.h"
#include "port-sockets.h"
#include <string.h>
#ifndef KEY_PROC_TYPE_DEFINED
typedef int (*key_proc_type) (char *, char *, char *,
char *, C_Block);
#endif
#ifndef DECRYPT_TKT_TYPE_DEFINED
typedef int (*decrypt_tkt_type) (char *, char *, char *, char *,
key_proc_type, KTEXT *);
#endif
static int decrypt_tkt(char *, char *, char *, char *, key_proc_type, KTEXT *);
static int krb_mk_in_tkt_preauth(char *, char *, char *, char *, char *,
int, char *, int, KTEXT, int *, struct sockaddr_in *);
static int krb_parse_in_tkt_creds(char *, char *, char *, char *, char *,
int, KTEXT, int, CREDENTIALS *);
static int
decrypt_tkt(user, instance, realm, arg, key_proc, cipp)
char *user;
char *instance;
char *realm;
char *arg;
key_proc_type key_proc;
KTEXT *cipp;
{
KTEXT cip = *cipp;
C_Block key;
Key_schedule key_s;
register int rc;
#ifndef NOENCRYPTION
#endif
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, (C_Block *)key, 0);
#endif
memset(key, 0, sizeof(key));
memset(key_s, 0, sizeof(key_s));
return 0;
}
static int
krb_mk_in_tkt_preauth(user, instance, realm, service, sinstance, life,
preauth_p, preauth_len, cip, byteorder, local_addr)
char *user;
char *instance;
char *realm;
char *service;
char *sinstance;
int life;
char *preauth_p;
int preauth_len;
KTEXT cip;
int *byteorder;
struct sockaddr_in *local_addr;
{
KTEXT_ST pkt_st;
KTEXT pkt = &pkt_st;
KTEXT_ST rpkt_st;
KTEXT rpkt = &rpkt_st;
unsigned char *p;
size_t userlen, instlen, realmlen, servicelen, sinstlen;
unsigned KRB4_32 t_local;
int msg_byte_order;
int kerror;
socklen_t addrlen;
#if 0
unsigned long exp_date;
#endif
unsigned long rep_err_code;
unsigned long cip_len;
unsigned int t_switch;
int i, len;
p = pkt->dat;
userlen = strlen(user) + 1;
instlen = strlen(instance) + 1;
realmlen = strlen(realm) + 1;
servicelen = strlen(service) + 1;
sinstlen = strlen(sinstance) + 1;
if (sizeof(pkt->dat) < (1 + 1 + userlen + instlen + realmlen
+ 4 + 1 + servicelen + sinstlen
+ preauth_len)) {
pkt->length = 0;
return INTK_ERR;
}
*p++ = KRB_PROT_VERSION;
*p++ = AUTH_MSG_KDC_REQUEST;
memcpy(p, user, userlen);
p += userlen;
memcpy(p, instance, instlen);
p += instlen;
memcpy(p, realm, realmlen);
p += realmlen;
t_local = TIME_GMT_UNIXSEC;
KRB4_PUT32BE(p, t_local);
*p++ = life;
memcpy(p, service, servicelen);
p += servicelen;
memcpy(p, sinstance, sinstlen);
p += sinstlen;
if (preauth_len)
memcpy(p, preauth_p, (size_t)preauth_len);
p += preauth_len;
pkt->length = p - pkt->dat;
rpkt->length = 0;
addrlen = sizeof(struct sockaddr_in);
kerror = krb4int_send_to_kdc_addr(pkt, rpkt, realm,
(struct sockaddr *)local_addr,
&addrlen);
if (kerror)
return kerror;
p = rpkt->dat;
#define RPKT_REMAIN (rpkt->length - (p - rpkt->dat))
if (RPKT_REMAIN < 1 + 1)
return INTK_PROT;
if (*p++ != KRB_PROT_VERSION)
return INTK_PROT;
t_switch = *p++;
msg_byte_order = t_switch & 1;
t_switch &= ~1;
for (i = 0; i < 3; i++) {
len = krb4int_strnlen((char *)p, RPKT_REMAIN) + 1;
if (len <= 0)
return INTK_PROT;
p += len;
}
switch (t_switch) {
case AUTH_MSG_KDC_REPLY:
if (RPKT_REMAIN < 4 + 1 + 4 + 1)
return INTK_PROT;
p += 4 + 1 + 4 + 1;
break;
case AUTH_MSG_ERR_REPLY:
if (RPKT_REMAIN < 8)
return INTK_PROT;
p += 4;
KRB4_GET32(rep_err_code, p, msg_byte_order);
return rep_err_code;
default:
return INTK_PROT;
}
if (RPKT_REMAIN < 2)
return INTK_PROT;
KRB4_GET16(cip_len, p, msg_byte_order);
if (RPKT_REMAIN < cip_len)
return INTK_ERR;
cip->length = cip_len;
memcpy(cip->dat, p, (size_t)cip->length);
p += cip->length;
*byteorder = msg_byte_order;
return INTK_OK;
}
static int
krb_parse_in_tkt_creds(user, instance, realm, service, sinstance, life, cip,
byteorder, creds)
char *user;
char *instance;
char *realm;
char *service;
char *sinstance;
int life;
KTEXT cip;
int byteorder;
CREDENTIALS *creds;
{
unsigned char *ptr;
int len;
int kvno;
char s_name[SNAME_SZ];
char s_instance[INST_SZ];
char rlm[REALM_SZ];
KTEXT_ST tkt_st;
KTEXT tkt = &tkt_st;
unsigned long kdc_time;
unsigned KRB4_32 t_local;
KRB4_32 t_diff;
int lifetime;
ptr = cip->dat;
#define CIP_REMAIN (cip->length - (ptr - cip->dat))
if (CIP_REMAIN < 8)
return INTK_BADPW;
ptr += 8;
len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
if (len <= 0 || len > sizeof(s_name))
return INTK_BADPW;
memcpy(s_name, ptr, (size_t)len);
ptr += len;
len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
if (len <= 0 || len > sizeof(s_instance))
return INTK_BADPW;
memcpy(s_instance, ptr, (size_t)len);
ptr += len;
len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
if (len <= 0 || len > sizeof(rlm))
return INTK_BADPW;
memcpy(rlm, ptr, (size_t)len);
ptr += len;
if (CIP_REMAIN < 3)
return INTK_BADPW;
lifetime = *ptr++;
kvno = *ptr++;
tkt->length = *ptr++;
if (CIP_REMAIN < tkt->length)
return INTK_BADPW;
memcpy(tkt->dat, ptr, (size_t)tkt->length);
ptr += tkt->length;
if (strcmp(s_name, service) || strcmp(s_instance, sinstance)
|| strcmp(rlm, realm))
return INTK_ERR;
if (CIP_REMAIN < 4)
return INTK_BADPW;
KRB4_GET32(kdc_time, ptr, byteorder);
t_local = TIME_GMT_UNIXSEC;
t_diff = t_local - kdc_time;
if (t_diff < 0)
t_diff = -t_diff;
if (t_diff > CLOCK_SKEW) {
return RD_AP_TIME;
}
strncpy(creds->service, s_name, sizeof(creds->service));
strncpy(creds->instance, s_instance, sizeof(creds->instance));
strncpy(creds->realm, rlm, sizeof(creds->realm));
memmove(creds->session, cip->dat, sizeof(C_Block));
creds->lifetime = lifetime;
creds->kvno = kvno;
creds->ticket_st.length = tkt->length;
memmove(creds->ticket_st.dat, tkt->dat, (size_t)tkt->length);
creds->issue_date = t_local;
strncpy(creds->pname, user, sizeof(creds->pname));
strncpy(creds->pinst, instance, sizeof(creds->pinst));
return INTK_OK;
}
int
krb_get_in_tkt_preauth_creds(user, instance, realm, service, sinstance, life,
key_proc, decrypt_proc,
arg, preauth_p, preauth_len, creds, laddrp)
char *user;
char *instance;
char *realm;
char *service;
char *sinstance;
int life;
key_proc_type key_proc;
decrypt_tkt_type decrypt_proc;
char *arg;
char *preauth_p;
int preauth_len;
CREDENTIALS *creds;
KRB_UINT32 *laddrp;
{
int ok;
char key_string[BUFSIZ];
KTEXT_ST cip_st;
KTEXT cip = &cip_st;
int kerror;
int byteorder;
key_proc_type *keyprocs = krb_get_keyprocs (key_proc);
int i = 0;
struct sockaddr_in local_addr;
kerror = krb_mk_in_tkt_preauth(user, instance, realm,
service, sinstance,
life, preauth_p, preauth_len,
cip, &byteorder, &local_addr);
if (kerror)
return kerror;
#if !(defined(_WIN32) || defined(USE_LOGIN_LIBRARY))
if (arg == NULL) {
ok = des_read_pw_string(key_string, sizeof(key_string), "Password", 0);
if (ok != 0)
return ok;
arg = key_string;
}
#endif
do {
KTEXT_ST cip_copy_st;
memcpy(&cip_copy_st, &cip_st, sizeof(cip_st));
cip = &cip_copy_st;
if (decrypt_proc == NULL) {
decrypt_tkt (user, instance, realm, arg, keyprocs[i], &cip);
} else {
(*decrypt_proc)(user, instance, realm, arg, keyprocs[i], &cip);
}
kerror = krb_parse_in_tkt_creds(user, instance, realm,
service, sinstance, life, cip, byteorder, creds);
} while ((keyprocs [++i] != NULL) && (kerror == INTK_BADPW));
cip = &cip_st;
if (laddrp != NULL) {
*laddrp = local_addr.sin_addr.s_addr;
}
memset(key_string, 0, sizeof(key_string));
memset(cip->dat, 0, (size_t)cip->length);
return kerror;
}
int KRB5_CALLCONV
krb_get_in_tkt_creds(user, instance, realm, service, sinstance, life,
key_proc, decrypt_proc, arg, creds)
char *user;
char *instance;
char *realm;
char *service;
char *sinstance;
int life;
key_proc_type key_proc;
decrypt_tkt_type decrypt_proc;
char *arg;
CREDENTIALS *creds;
{
#if TARGET_OS_MAC
KRB_UINT32 *laddrp = &creds->address;
#else
KRB_UINT32 *laddrp = NULL;
#endif
return krb_get_in_tkt_preauth_creds(user, instance, realm,
service, sinstance, life,
key_proc, decrypt_proc, arg,
NULL, 0, creds, laddrp);
}
int KRB5_CALLCONV
krb_get_in_tkt_preauth(user, instance, realm, service, sinstance, life,
key_proc, decrypt_proc,
arg, preauth_p, preauth_len)
char *user;
char *instance;
char *realm;
char *service;
char *sinstance;
int life;
key_proc_type key_proc;
decrypt_tkt_type decrypt_proc;
char *arg;
char *preauth_p;
int preauth_len;
{
int retval;
KRB_UINT32 laddr;
CREDENTIALS creds;
do {
retval = krb_get_in_tkt_preauth_creds(user, instance, realm,
service, sinstance, life,
key_proc, decrypt_proc,
arg, preauth_p, preauth_len,
&creds, &laddr);
if (retval != KSUCCESS) break;
if (krb_in_tkt(user, instance, realm) != KSUCCESS) {
retval = INTK_ERR;
break;
}
retval = krb4int_save_credentials_addr(creds.service, creds.instance,
creds.realm, creds.session,
creds.lifetime, creds.kvno,
&creds.ticket_st,
creds.issue_date, laddr);
if (retval != KSUCCESS) break;
} while (0);
memset(&creds, 0, sizeof(creds));
return retval;
}
int KRB5_CALLCONV
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;
key_proc_type key_proc;
decrypt_tkt_type decrypt_proc;
char *arg;
{
return krb_get_in_tkt_preauth(user, instance, realm,
service, sinstance, life,
key_proc, decrypt_proc, arg,
NULL, 0);
}