#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <krb5.h>
#include <kadm5/admin.h>
#include <com_err.h>
#include <kerberosIV/krb.h>
#include <kerberosIV/des.h>
#ifndef LINT
static char rcsid[]=
"$Id: fakeka.c 18009 2006-05-16 01:45:00Z raeburn $";
#endif
#define PAD_TO(x, a) (((u_long)(x) + (a) - 1) & ~((a) - 1))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define MAXFORWARDERS 10
#define HEADER_LEN 8
#define KADATABASEINCONSISTENT (180480L)
#define KANOENT (180484L)
#define KABADREQUEST (180490L)
#define KABADTICKET (180504L)
#define KABADSERVER (180507L)
#define KABADUSER (180508L)
#define KACLOCKSKEW (180514L)
#define KAINTERNALERROR (180518L)
typedef struct packet {
char *base;
int len;
char data[1024];
} *packet_t;
typedef struct rx_header {
u_int rx_epoch;
u_int rx_cid;
u_int rx_callnum;
u_int rx_seq;
u_int rx_serial;
u_char rx_type;
u_char rx_flags;
u_char rx_userstatus;
u_char rx_securityindex;
u_short rx_spare;
u_short rx_service;
u_int rx_request;
} *rx_t;
char *progname = "fakeka";
char *localrealm = NULL;
char *localcell = NULL;
krb5_timestamp req_time;
kadm5_config_params realm_params;
int debug = 0;
#define MAX_TICKET_LIFETIME 2592000
static long cmu_seconds[] =
{
38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318,
65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684,
111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720,
191077, 204289, 218415, 233517, 249663, 266926, 285383, 305116,
326213, 348769, 372885, 398668, 426233, 455705, 487215, 520903,
556921, 595430, 636600, 680618, 727679, 777995, 831789, 889303,
950794, 1016536, 1086825, 1161973, 1242317, 1328217, 1420057, 1518246,
1623225, 1735463, 1855462, 1983757, 2120924, 2267575, 2424366, 2591999,
0
};
#if __STDC__
void perrorexit(char *);
void pexit(char *);
char *kaerror(int);
int get_princ_key(krb5_context, void *, kadm5_principal_ent_t, des_cblock,
des_key_schedule);
int check_princ(krb5_context, void *, char *, char *, kadm5_principal_ent_t);
int make_reply_packet(krb5_context, void *, packet_t, int, int, int,
char *, char *, char *, char *,
des_cblock, des_key_schedule, char *);
int Authenticate(krb5_context, void *, char *, packet_t, packet_t);
int GetTicket(krb5_context, void *, char *, packet_t, packet_t);
void process(krb5_context, void *, char *, packet_t, packet_t);
#endif
void perrorexit(str)
char *str;
{
perror(str);
exit(1);
}
void pexit(str)
char *str;
{
printf("%s\n", str);
exit(1);
}
char *kaerror(e)
int e;
{
static char buf[1024];
switch (e) {
case KADATABASEINCONSISTENT:
return "database is inconsistent";
case KANOENT:
return "principal does not exist";
case KABADREQUEST:
return "request was malformed (bad password)";
case KABADTICKET:
return "ticket was malformed, invalid, or expired";
case KABADSERVER:
return "cannot issue tickets for this service";
case KABADUSER:
return "principal expired";
case KACLOCKSKEW:
return "client time is too far skewed";
case KAINTERNALERROR:
return "internal error in fakeka, help!";
default:
sprintf(buf, "impossible error code %d, help!", e);
return buf;
}
}
typedef struct {
int num;
char *string;
} facility_mapping;
static facility_mapping mappings[] = {
#ifdef LOG_KERN
{ LOG_KERN, "KERN" },
#endif
#ifdef LOG_USER
{ LOG_USER, "USER" },
#endif
#ifdef LOG_MAIL
{ LOG_MAIL, "MAIL" },
#endif
#ifdef LOG_DAEMON
{ LOG_DAEMON, "DAEMON" },
#endif
#ifdef LOG_AUTH
{ LOG_AUTH, "AUTH" },
#endif
#ifdef LOG_LPR
{ LOG_LPR, "LPR" },
#endif
#ifdef LOG_NEWS
{ LOG_NEWS, "NEWS" },
#endif
#ifdef LOG_UUCP
{ LOG_UUCP, "UUCP" },
#endif
#ifdef LOG_CRON
{ LOG_CRON, "CRON" },
#endif
#ifdef LOG_LOCAL0
{ LOG_LOCAL0, "LOCAL0" },
#endif
#ifdef LOG_LOCAL1
{ LOG_LOCAL1, "LOCAL1" },
#endif
#ifdef LOG_LOCAL2
{ LOG_LOCAL2, "LOCAL2" },
#endif
#ifdef LOG_LOCAL3
{ LOG_LOCAL3, "LOCAL3" },
#endif
#ifdef LOG_LOCAL4
{ LOG_LOCAL4, "LOCAL4" },
#endif
#ifdef LOG_LOCAL5
{ LOG_LOCAL5, "LOCAL5" },
#endif
#ifdef LOG_LOCAL6
{ LOG_LOCAL6, "LOCAL6" },
#endif
#ifdef LOG_LOCAL7
{ LOG_LOCAL7, "LOCAL7" },
#endif
{ 0, NULL }
};
int get_princ_key(context, handle, p, k, s)
krb5_context context;
void *handle;
kadm5_principal_ent_t p;
des_cblock k;
des_key_schedule s;
{
int rv;
krb5_keyblock kb;
kadm5_ret_t retval;
if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
KRB5_KDB_SALTTYPE_AFS3, 0, &kb,
NULL, NULL)))
if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
KRB5_KDB_SALTTYPE_V4, 0, &kb,
NULL, NULL)))
if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
-1, 0, &kb, NULL, NULL))) {
syslog(LOG_ERR, "Couldn't find any matching key: %s",
error_message(retval));
return KAINTERNALERROR;
}
if (kb.length != sizeof(des_cblock)) {
krb5_free_keyblock_contents(context, &kb);
syslog(LOG_ERR, "Principal key size of %d didn't match C_Block size"
" %d", kb.length, sizeof(des_cblock));
return KAINTERNALERROR;
}
memcpy((char *) k, (char *) kb.contents, sizeof(des_cblock));
krb5_free_keyblock_contents(context, &kb);
rv = des_key_sched(k, s);
if (rv) {
memset((void *) k, 0, sizeof(k));
memset((void *)s, 0, sizeof(s));
return KAINTERNALERROR;
}
return 0;
}
int check_princ(context, handle, name, inst, p)
krb5_context context;
void *handle;
char *name, *inst;
kadm5_principal_ent_t p;
{
krb5_principal princ;
krb5_error_code code;
kadm5_ret_t retcode;
if (!name || (name[0] == '\0')) {
syslog(LOG_ERR, "screening out null principal");
return KANOENT;
}
if ((code = krb5_build_principal_ext(context, &princ, strlen(localrealm),
localrealm, strlen(name), name,
strlen(inst), inst, 0))) {
syslog(LOG_ERR, "could not build principal: %s", error_message(code));
return KAINTERNALERROR;
}
if ((retcode = kadm5_get_principal(handle, princ, p,
KADM5_PRINCIPAL_NORMAL_MASK |
KADM5_KEY_DATA))) {
if (retcode == KADM5_UNK_PRINC) {
krb5_free_principal(context, princ);
syslog(LOG_INFO, "principal %s.%s does not exist", name, inst);
return KANOENT;
} else {
krb5_free_principal(context, princ);
syslog(LOG_ERR, "kadm5_get_principal failed: %s",
error_message(retcode));
return KAINTERNALERROR;
}
}
krb5_free_principal(context, princ);
if (p->princ_expire_time && p->princ_expire_time < req_time) {
kadm5_free_principal_ent(handle, p);
return KABADUSER;
}
if ((p->pw_expiration && p->pw_expiration < req_time) ||
(p->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
kadm5_free_principal_ent(handle, p);
return KABADUSER;
}
if (p->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
kadm5_free_principal_ent(handle, p);
return KABADUSER;
}
if (p->attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
kadm5_free_principal_ent(handle, p);
return KABADUSER;
}
return 0;
}
int make_reply_packet(context, handle, reply, challenge_response, start_time,
end_time, cname, cinst, sname, sinst, key, sched, label)
krb5_context context;
void *handle;
packet_t reply;
int challenge_response, start_time, end_time;
char *cname, *cinst, *sname, *sinst;
des_cblock key;
des_key_schedule sched;
char *label;
{
int rv, n, maxn, v4life, *enclenp, *ticklenp;
u_char *p, *enc, *ticket;
kadm5_principal_ent_rec cprinc, sprinc;
des_cblock skey, new_session_key;
des_key_schedule ssched;
krb5_deltat lifetime;
rv = 0;
rv = check_princ(context, handle, cname, cinst, &cprinc);
if (rv)
return rv;
rv = check_princ(context, handle, sname, sinst, &sprinc);
if (rv) {
kadm5_free_principal_ent(handle, &cprinc);
return rv;
}
lifetime = end_time - start_time;
lifetime = min(lifetime, cprinc.max_life);
lifetime = min(lifetime, sprinc.max_life);
lifetime = min(lifetime, realm_params.max_life);
end_time = start_time + lifetime;
v4life = lifetime / 300;
if (v4life > 127) {
long *clist = cmu_seconds;
while (*clist && *clist < lifetime) clist++;
v4life = 128 + (clist - cmu_seconds);
}
if (!strcmp(sname, "afs") && (strcasecmp(sinst, localcell) == 0))
sinst[0] = '\0';
p = (unsigned char *) reply->base;
maxn = reply->len;
n = 0;
#define ERR(x) do { rv = x ; goto error; } while (0)
#define ADVANCE(x) { if ((n += x) > maxn) ERR(KAINTERNALERROR); else p += x;}
#define PUT_CHAR(x) { *p = (x); ADVANCE(1); }
#define PUT_INT(x) { int q = ntohl(x); memcpy(p, (char *)&q, 4); ADVANCE(4); }
#define PUT_STR(x) { strcpy((char *) p, x); ADVANCE(strlen(x) + 1); }
ADVANCE(28);
PUT_INT(0x2bc);
enclenp = (int *)p;
PUT_INT(0);
enc = p;
PUT_INT(0);
PUT_INT(challenge_response);
des_new_random_key(new_session_key);
memcpy(p, new_session_key, 8);
ADVANCE(8);
PUT_INT(start_time);
PUT_INT(end_time);
PUT_INT(sprinc.kvno);
ticklenp = (int *)p;
PUT_INT(0);
PUT_STR(cname);
PUT_STR(cinst);
PUT_STR("");
PUT_STR(sname);
PUT_STR(sinst);
ticket = p;
PUT_CHAR(0);
PUT_STR(cname);
PUT_STR(cinst);
PUT_STR("");
PUT_INT(0);
memcpy(p, new_session_key, 8);
ADVANCE(8);
PUT_CHAR(v4life);
PUT_INT(start_time);
PUT_STR(sname);
PUT_STR(sinst);
ADVANCE(PAD_TO(p - ticket, 8) - (p - ticket));
*ticklenp = ntohl(p - ticket);
rv = get_princ_key(context, handle, &sprinc, skey, ssched);
if (rv)
return rv;
des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, p - ticket,
ssched, (C_Block *) skey, ENCRYPT);
memset(skey, 0, sizeof(skey));
memset(ssched, 0, sizeof(ssched));
PUT_STR(label);
ADVANCE(-1);
ADVANCE(PAD_TO(p - enc, 8) - (p - enc));
#undef ERR
#undef ADVANCE
#undef PUT_CHAR
#undef PUT_INT
#undef PUT_STR
*enclenp = ntohl(p - enc);
des_pcbc_encrypt((C_Block *) enc, (C_Block *) enc, p - enc, sched,
(C_Block *) key, ENCRYPT);
reply->len = n;
error:
memset(new_session_key, 0, sizeof(new_session_key));
kadm5_free_principal_ent(handle, &cprinc);
kadm5_free_principal_ent(handle, &sprinc);
return rv;
}
#define ERR(x) do { rv = x; goto error; } while (0)
#define ADVANCE(x) { if ((n += x) > maxn) ERR(KABADREQUEST); else p += x; }
#define GET_INT(x) { int q; memcpy((char *)&q, p, 4); x = ntohl(q); ADVANCE(4); }
#define GET_CHAR(x) { x = *p; ADVANCE(1); }
#define GET_PSTR(x) \
{ \
GET_INT(len); \
if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
memcpy(x, p, len); \
x[len] = 0; \
ADVANCE(PAD_TO(len, 4)); \
}
#define GET_STR(x) \
{ \
len = strlen(p); \
if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
strcpy(x, p); \
ADVANCE(len + 1); \
}
int Authenticate(context, handle, from, req, reply)
krb5_context context;
void *handle;
char *from;
packet_t req, reply;
{
int rv, n, maxn;
int len, start_time, end_time, challenge;
char name[ANAME_SZ+1], inst[INST_SZ+1], *p;
kadm5_principal_ent_rec cprinc;
des_cblock ckey;
des_key_schedule csched;
int free_princ_ent = 0;
rv = 0;
p = req->base;
maxn = req->len;
n = 0;
ADVANCE(32);
GET_PSTR(name);
GET_PSTR(inst);
if (debug)
fprintf(stderr, "Authenticating %s.%s\n", name, inst);
rv = check_princ(context, handle, name, inst, &cprinc);
if (rv)
ERR(rv);
free_princ_ent = 1;
GET_INT(start_time);
GET_INT(end_time);
GET_INT(len);
if (len != 8)
ERR(KABADREQUEST);
rv = get_princ_key(context, handle, &cprinc, ckey, csched);
if (rv)
ERR(rv);
des_pcbc_encrypt((C_Block *) p, (C_Block *) p, 8, csched,
(C_Block *) ckey, DECRYPT);
GET_INT(challenge);
rv = memcmp(p, "gTGS", 4);
if (rv)
ERR(KABADREQUEST);
ADVANCE(4);
ADVANCE(8);
rv = make_reply_packet(context, handle, reply, challenge + 1, start_time,
end_time, name, inst, "krbtgt", localcell,
ckey, csched, "tgsT");
error:
memset(ckey, 0, sizeof(ckey));
memset(csched, 0, sizeof(csched));
syslog(LOG_INFO, "authenticate: %s.%s from %s", name, inst, from);
if (rv) {
syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
}
if (free_princ_ent)
kadm5_free_principal_ent(handle, &cprinc);
return rv;
}
int GetTicket(context, handle, from, req, reply)
krb5_context context;
void *handle;
char *from;
packet_t req, reply;
{
int rv, n, maxn, len, ticketlen;
char *p;
u_int kvno, start_time, end_time, times[2], flags, ipaddr;
u_int tgt_start_time, tgt_end_time, lifetime;
char rname[ANAME_SZ+1], rinst[INST_SZ+1];
char sname[ANAME_SZ+1], sinst[INST_SZ+1];
char cname[ANAME_SZ+1], cinst[INST_SZ+1];
char cell[REALM_SZ+1], realm[REALM_SZ+1];
char enctimes[8 + 1], ticket[1024];
u_char tgt_lifetime;
kadm5_principal_ent_rec cprinc;
des_cblock ckey, session_key;
des_key_schedule csched, session_sched;
int free_princ_ent = 0;
rv = 0;
strcpy(rname, "Unknown");
strcpy(rinst, "Unknown");
strcpy(sname, "Unknown");
strcpy(sinst, "Unknown");
strcpy(cname, "Unknown");
strcpy(cinst, "Unknown");
strcpy(cell, "Unknown");
strcpy(realm, "Unknown");
p = req->base;
maxn = req->len;
n = 0;
ADVANCE(32);
GET_INT(kvno);
GET_PSTR(cell);
if (!cell[0])
strcpy(cell, localcell);
if (debug)
fprintf(stderr, "Cell is %s\n", cell);
memset(ticket, 0, sizeof(ticket));
GET_PSTR(ticket);
ticketlen = len;
GET_PSTR(rname);
GET_PSTR(rinst);
if (debug)
fprintf(stderr, "Request for %s/%s\n", rname, rinst);
GET_PSTR(enctimes);
if (len != 8)
ERR(KABADREQUEST);
ADVANCE(8);
rv = check_princ(context, handle, "krbtgt", cell, &cprinc);
if (rv)
ERR(rv);
free_princ_ent = 1;
rv = get_princ_key(context, handle, &cprinc, ckey, csched);
if (rv)
ERR(rv);
des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, ticketlen, csched,
(C_Block *) ckey, DECRYPT);
memset(ckey, 0, sizeof(ckey));
memset(csched, 0, sizeof(csched));
p = ticket;
maxn = ticketlen;
n = 0;
GET_CHAR(flags);
GET_STR(cname);
GET_STR(cinst);
GET_STR(realm);
GET_INT(ipaddr);
memcpy(session_key, p, 8);
ADVANCE(8);
GET_CHAR(tgt_lifetime);
GET_INT(tgt_start_time);
GET_STR(sname);
GET_STR(sinst);
if (debug)
fprintf(stderr,
"ticket: %s.%s@%s for %s.%s\n",
cname, cinst, realm, sname, sinst);
rv = des_key_sched(session_key, session_sched);
if (rv)
ERR(KABADTICKET);
des_ecb_encrypt((C_Block *) enctimes, (C_Block *) times, session_sched,
DECRYPT);
start_time = ntohl(times[0]);
end_time = ntohl(times[1]);
if (flags || ipaddr) {
if (debug)
fprintf(stderr, "ERROR: flags or ipaddr field non-zero\n");
ERR(KABADTICKET);
}
if (strcmp(sname, "krbtgt")) {
if (debug)
fprintf(stderr, "ERROR: not for krbtgt service\n");
ERR(KABADTICKET);
}
if (strcasecmp(sinst, localcell)) {
if (debug)
fprintf(stderr,
"ERROR: Service instance (%s) differs from local cell\n",
sinst);
ERR(KABADTICKET);
}
if (strcasecmp(cell, localcell)) {
if (debug)
fprintf(stderr, "ERROR: Cell %s != local cell", cell);
ERR(KABADTICKET);
}
if (*realm && strcasecmp(realm, cell)) {
if (debug)
fprintf(stderr, "ERROR: Realm %s != cell %s\n", realm, cell);
ERR(KABADTICKET);
}
if (! ((strcmp(rname, "afs") == 0 && ! *rinst) ||
(strcmp(rname, "emt") == 0 && strcmp(rinst, "admin") == 0) ||
(strcmp(rname, "adm") == 0 && strcmp(rinst, "admin") == 0)))
ERR(KABADSERVER);
if ((strcmp(rname, "afs") == 0) && !*rinst &&
strcmp(localrealm, localcell) &&
(strcasecmp(cell, localcell) == 0)) {
char *c;
strcpy(rinst, localcell);
for (c = rinst; *c != NULL; c++)
*c = (char) tolower( (int) *c);
if (debug)
fprintf(stderr, "Getting ticket for afs/%s\n", localcell);
}
if (!strcmp(rname, "changepw") || !strcmp(rname, "krbtgt"))
ERR(KABADSERVER);
if (req_time < tgt_start_time - CLOCK_SKEW) {
if (debug)
fprintf(stderr, "ERROR: Ticket not yet valid\n");
ERR(KABADTICKET);
}
if (tgt_lifetime < 128)
tgt_end_time = tgt_start_time + tgt_lifetime * 300;
else if (tgt_lifetime < 192)
tgt_end_time = tgt_start_time + cmu_seconds[tgt_lifetime - 128];
else
tgt_end_time = tgt_start_time + MAX_TICKET_LIFETIME;
if (tgt_end_time < req_time) {
if (debug)
fprintf(stderr, "ERROR: Ticket expired\n");
ERR(KABADTICKET);
}
if (abs(req_time - start_time) > CLOCK_SKEW)
ERR(KACLOCKSKEW);
lifetime = tgt_end_time - req_time;
lifetime = min(lifetime, end_time - start_time);
end_time = req_time + lifetime;
rv = make_reply_packet(context, handle, reply, 0, start_time, end_time,
cname, cinst, rname, rinst,
session_key, session_sched, "gtkt");
error:
memset(ticket, 0, sizeof(ticket));
memset(session_key, 0, sizeof(session_key));
memset(session_sched, 0, sizeof(session_sched));
if (free_princ_ent)
kadm5_free_principal_ent(handle, &cprinc);
syslog(LOG_INFO, "getticket: %s.%s from %s for %s.%s",
cname, cinst, from, rname, rinst);
if (rv) {
syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
}
return rv;
}
#undef ERR
#undef ADVANCE
#undef GET_INT
#undef GET_PSTR
#undef GET_STR
void process(context, handle, from, req, reply)
krb5_context context;
void *handle;
char *from;
packet_t req, reply;
{
int rv;
rx_t req_rx = (rx_t)req->base;
rx_t reply_rx = (rx_t)reply->base;
int service, request;
service = ntohs(req_rx->rx_service);
request = ntohl(req_rx->rx_request);
if (req_rx->rx_type != 1) {
reply->len = 0;
return;
}
*reply_rx = *req_rx;
reply_rx->rx_flags = 4;
rv = -1;
if (service == 0x2db && (request == 0x15 || request == 0x16)) {
if (debug)
fprintf(stderr, "Handling Authenticate request\n");
rv = Authenticate(context, handle, from, req, reply);
}
if (service == 0x2dc && request == 0x17) {
if (debug)
fprintf(stderr, "Handling GetTicket request\n");
rv = GetTicket(context, handle, from, req, reply);
}
if (rv == -1) {
syslog(LOG_INFO, "bogus request %d/%d", service, request);
rv = KABADREQUEST;
}
if (rv) {
reply->len = sizeof (*reply_rx);
reply_rx->rx_type = 4;
reply_rx->rx_flags = 0;
reply_rx->rx_request = ntohl(rv);
}
}
int main(argc, argv)
int argc;
char **argv;
{
int s, rv, ch, mflag = 0;
u_short port;
struct sockaddr_in sin;
int forwarders[MAXFORWARDERS], num_forwarders;
krb5_context context;
krb5_error_code code;
krb5_keyblock mkey;
krb5_principal master_princ;
kadm5_principal_ent_rec master_princ_rec;
void *handle;
facility_mapping *mapping;
int facility = LOG_DAEMON;
extern char *optarg;
port = 7004;
num_forwarders = 0;
while ((ch = getopt(argc, argv, "c:df:l:mp:r:")) != -1) {
switch (ch) {
case 'c':
localcell = optarg;
break;
case 'd':
debug++;
break;
case 'f': {
struct hostent *hp;
if (num_forwarders++ >= MAXFORWARDERS)
pexit("too many forwarders\n");
hp = gethostbyname(optarg);
if (!hp) {
printf("unknown host %s\n", optarg);
exit(1);
}
forwarders[num_forwarders - 1] = *(int *)hp->h_addr;
break;
}
case 'l':
for (mapping = mappings; mapping->string != NULL; mapping++)
if (strcmp(mapping->string, optarg) == 0)
break;
if (mapping->string == NULL) {
printf("Unknown facility \"%s\"\n", optarg);
exit(1);
}
facility = mapping->num;
break;
case 'm':
mflag = 1;
break;
case 'p':
if (isdigit(*optarg)) {
port = atoi(optarg);
}
else {
struct servent *sp;
sp = getservbyname(optarg, "udp");
if (!sp) {
printf("unknown service %s\n", optarg);
exit(1);
}
port = sp->s_port;
}
break;
case 'r':
localrealm = optarg;
break;
default:
printf("usage: %s [-c cell] [-d] [-f forwarder-host] [-l facility ] [-p port] [-r realm]\n",
argv[0]);
exit(1);
}
}
openlog("fakeka", LOG_PID, facility);
port = htons(port);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
perrorexit("Couldn't create socket");
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = port;
rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
if (rv < 0)
perrorexit("Couldn't bind socket");
if ((code = krb5int_init_context_kdc(&context))) {
com_err(argv[0], code, "while initializing Kerberos");
exit(1);
}
if (!localrealm && (code = krb5_get_default_realm(context, &localrealm))) {
com_err(argv[0], code, "while getting local realm");
exit(1);
}
if (!localcell)
localcell = localrealm;
if ((code = kadm5_init_with_password(progname, NULL, KADM5_ADMIN_SERVICE,
NULL, KADM5_STRUCT_VERSION,
KADM5_API_VERSION_2,
(char **) NULL,
&handle))) {
com_err(argv[0], code, "while initializing Kadm5");
exit(1);
}
if ((code = kadm5_get_config_params(context, 1, NULL,
&realm_params))) {
com_err(argv[0], code, "while getting realm parameters");
exit(1);
}
if (! (realm_params.mask & KADM5_CONFIG_MAX_LIFE)) {
fprintf(stderr, "Cannot determine maximum ticket lifetime\n");
exit(1);
}
if ((code = krb5_parse_name(context, realm_params.mask &
KADM5_CONFIG_MKEY_NAME ?
realm_params.mkey_name : "K/M",
&master_princ))) {
com_err(argv[0], code, "while parsing master key name");
exit(1);
}
if ((code = kadm5_get_principal(handle, master_princ, &master_princ_rec,
KADM5_KEY_DATA))) {
com_err(argv[0], code, "while getting master key data");
exit(1);
}
if ((code = kadm5_decrypt_key(handle, &master_princ_rec,
ENCTYPE_DES_CBC_CRC, -1, 0, &mkey, NULL,
NULL))) {
com_err(argv[0], code, "while decrypting the master key");
exit(1);
}
des_init_random_number_generator(mkey.contents);
krb5_free_keyblock_contents(context, &mkey);
kadm5_free_principal_ent(handle, &master_princ_rec);
krb5_free_principal(context, master_princ);
if (!debug && mflag && daemon(0, 0)) {
com_err(argv[0], errno, "while detaching from tty");
}
for (;;) {
struct packet req, reply;
int sinlen, packetlen, i, forwarded;
char *from;
sinlen = sizeof(sin);
forwarded = 0;
memset(req.data, 0, sizeof(req.data));
rv = recvfrom(s, req.data, sizeof(req.data),
0, (struct sockaddr *)&sin, &sinlen);
if (rv < 0) {
syslog(LOG_ERR, "recvfrom failed: %m");
sleep(1);
continue;
}
packetlen = rv;
for (i = 0; i < num_forwarders; i++) {
if (sin.sin_addr.s_addr == forwarders[i]) {
forwarded = 1;
break;
}
}
if ((code = krb5_timeofday(context, &req_time))) {
syslog(LOG_ERR, "krb5_timeofday failed: %s",
error_message(code));
continue;
}
memset(reply.data, 0, sizeof(reply.data));
req.len = packetlen;
req.base = req.data;
reply.base = reply.data;
reply.len = sizeof(reply.data);
if (forwarded) {
struct in_addr ia;
memcpy(&ia.s_addr, req.data, 4);
from = inet_ntoa(ia);
memcpy(reply.data, req.data, HEADER_LEN);
req.base += HEADER_LEN;
req.len -= HEADER_LEN;
reply.base += HEADER_LEN;
reply.len -= HEADER_LEN;
}
else {
from = inet_ntoa(sin.sin_addr);
}
process(context, handle, from, &req, &reply);
if (reply.len == 0)
continue;
if (forwarded) {
reply.len += HEADER_LEN;
}
rv = sendto(s, reply.data, reply.len,
0, (struct sockaddr *)&sin, sinlen);
if (rv < 0) {
syslog(LOG_ERR, "sendto failed: %m");
sleep(1);
}
}
}