3
* Copyright (c) 1994 Carnegie Mellon University
6
* Permission to use, copy, modify and distribute this software and its
7
* documentation is hereby granted, provided that both the copyright
8
* notice and this permission notice appear in all copies of the
9
* software, derivative works or modified versions, and any portions
10
* thereof, and that both notices appear in supporting documentation.
12
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16
* Carnegie Mellon requests users of this software to return to
18
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
19
* School of Computer Science
20
* Carnegie Mellon University
21
* Pittsburgh PA 15213-3890
23
* any improvements or extensions that they make and grant Carnegie Mellon
24
* the rights to redistribute these changes.
26
* Converted to Kerberos 5 by Ken Hornstein <kenh@cmf.nrl.navy.mil>
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <netinet/in.h>
32
#include <arpa/inet.h>
50
#include <kadm5/admin.h>
52
#include <kerberosIV/krb.h>
53
#include <kerberosIV/des.h>
57
"$Id: fakeka.c 18009 2006-05-16 01:45:00Z raeburn $";
64
#define PAD_TO(x, a) (((u_long)(x) + (a) - 1) & ~((a) - 1))
65
#define min(a, b) ((a) < (b) ? (a) : (b))
66
#define MAXFORWARDERS 10
70
* Error values from kautils.h
72
* The security errors are:
73
* KABADTICKET, KABADSERVER, KABADUSER, and KACLOCKSKEW
76
#define KADATABASEINCONSISTENT (180480L)
77
#define KANOENT (180484L)
78
#define KABADREQUEST (180490L)
79
#define KABADTICKET (180504L)
80
#define KABADSERVER (180507L)
81
#define KABADUSER (180508L)
82
#define KACLOCKSKEW (180514L)
83
#define KAINTERNALERROR (180518L)
90
typedef struct packet {
96
typedef struct rx_header {
104
u_char rx_userstatus;
105
u_char rx_securityindex;
116
char *progname = "fakeka"; /* needed by libkdb.a */
117
char *localrealm = NULL;
118
char *localcell = NULL;
119
krb5_timestamp req_time;
120
kadm5_config_params realm_params;
125
* This is a table for the "infamous" CMU ticket lifetime conversion. If
126
* the lifetime is greater than 128, use this table
128
#define MAX_TICKET_LIFETIME 2592000
129
static long cmu_seconds[] =
131
38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318,
132
65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684,
133
111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720,
134
191077, 204289, 218415, 233517, 249663, 266926, 285383, 305116,
135
326213, 348769, 372885, 398668, 426233, 455705, 487215, 520903,
136
556921, 595430, 636600, 680618, 727679, 777995, 831789, 889303,
137
950794, 1016536, 1086825, 1161973, 1242317, 1328217, 1420057, 1518246,
138
1623225, 1735463, 1855462, 1983757, 2120924, 2267575, 2424366, 2591999,
144
* Prototypes for all the functions we define
147
void perrorexit(char *);
150
int get_princ_key(krb5_context, void *, kadm5_principal_ent_t, des_cblock,
152
int check_princ(krb5_context, void *, char *, char *, kadm5_principal_ent_t);
154
int make_reply_packet(krb5_context, void *, packet_t, int, int, int,
155
char *, char *, char *, char *,
156
des_cblock, des_key_schedule, char *);
158
int Authenticate(krb5_context, void *, char *, packet_t, packet_t);
159
int GetTicket(krb5_context, void *, char *, packet_t, packet_t);
160
void process(krb5_context, void *, char *, packet_t, packet_t);
165
* Helpers for exiting with errors
184
* Translate error codes into strings.
190
static char buf[1024];
193
case KADATABASEINCONSISTENT:
194
return "database is inconsistent";
196
return "principal does not exist";
198
return "request was malformed (bad password)";
200
return "ticket was malformed, invalid, or expired";
202
return "cannot issue tickets for this service";
204
return "principal expired";
206
return "client time is too far skewed";
207
case KAINTERNALERROR:
208
return "internal error in fakeka, help!";
210
sprintf(buf, "impossible error code %d, help!", e);
224
static facility_mapping mappings[] = {
226
{ LOG_KERN, "KERN" },
229
{ LOG_USER, "USER" },
232
{ LOG_MAIL, "MAIL" },
235
{ LOG_DAEMON, "DAEMON" },
238
{ LOG_AUTH, "AUTH" },
244
{ LOG_NEWS, "NEWS" },
247
{ LOG_UUCP, "UUCP" },
250
{ LOG_CRON, "CRON" },
253
{ LOG_LOCAL0, "LOCAL0" },
256
{ LOG_LOCAL1, "LOCAL1" },
259
{ LOG_LOCAL2, "LOCAL2" },
262
{ LOG_LOCAL3, "LOCAL3" },
265
{ LOG_LOCAL4, "LOCAL4" },
268
{ LOG_LOCAL5, "LOCAL5" },
271
{ LOG_LOCAL6, "LOCAL6" },
274
{ LOG_LOCAL7, "LOCAL7" },
281
* Get the principal's key and key schedule from the db record.
283
* Life is more complicated in the V5 world. Since we can have different
284
* encryption types, we have to make sure that we get back a DES key.
285
* Also, we have to try to get back a AFS3 or V4 salted key, since AFS
286
* doesn't know about a V5 style salt.
289
int get_princ_key(context, handle, p, k, s)
290
krb5_context context;
292
kadm5_principal_ent_t p;
301
* We need to call kadm5_decrypt_key to decrypt the key data
302
* from the principal record. We _must_ have a encryption type
303
* of DES_CBC_CRC, and we prefer having a salt type of AFS 3 (but
304
* a V4 salt will work as well). If that fails, then return any
305
* type of key we can find.
307
* Note that since this uses kadm5_decrypt_key, it means it has to
308
* be compiled with the kadm5srv library.
311
if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
312
KRB5_KDB_SALTTYPE_AFS3, 0, &kb,
314
if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
315
KRB5_KDB_SALTTYPE_V4, 0, &kb,
317
if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
318
-1, 0, &kb, NULL, NULL))) {
319
syslog(LOG_ERR, "Couldn't find any matching key: %s",
320
error_message(retval));
321
return KAINTERNALERROR;
325
* Copy the data from our krb5_keyblock to the des_cblock. Make sure
326
* the size of our key matches the V4/AFS des_cblock.
329
if (kb.length != sizeof(des_cblock)) {
330
krb5_free_keyblock_contents(context, &kb);
331
syslog(LOG_ERR, "Principal key size of %d didn't match C_Block size"
332
" %d", kb.length, sizeof(des_cblock));
333
return KAINTERNALERROR;
336
memcpy((char *) k, (char *) kb.contents, sizeof(des_cblock));
338
krb5_free_keyblock_contents(context, &kb);
341
* Calculate the des key schedule
344
rv = des_key_sched(k, s);
346
memset((void *) k, 0, sizeof(k));
347
memset((void *)s, 0, sizeof(s));
348
return KAINTERNALERROR;
355
* Fetch principal from db and validate it.
357
* Note that this always fetches the key data from the principal (but it
358
* doesn't decrypt it).
361
int check_princ(context, handle, name, inst, p)
362
krb5_context context;
365
kadm5_principal_ent_t p;
367
krb5_principal princ;
368
krb5_error_code code;
372
* Screen out null principals. They are causing crashes here
373
* under HPUX-10.20. - vwelch@ncsa.uiuc.edu 1/6/98
375
if (!name || (name[0] == '\0')) {
376
syslog(LOG_ERR, "screening out null principal");
381
* Build a principal from the name and instance (the realm is always
385
if ((code = krb5_build_principal_ext(context, &princ, strlen(localrealm),
386
localrealm, strlen(name), name,
387
strlen(inst), inst, 0))) {
388
syslog(LOG_ERR, "could not build principal: %s", error_message(code));
389
return KAINTERNALERROR;
393
* Fetch the principal from the database -- also fetch the key data.
394
* Note that since this retrieves the key data, it has to be linked with
395
* the kadm5srv library.
398
if ((retcode = kadm5_get_principal(handle, princ, p,
399
KADM5_PRINCIPAL_NORMAL_MASK |
401
if (retcode == KADM5_UNK_PRINC) {
402
krb5_free_principal(context, princ);
403
syslog(LOG_INFO, "principal %s.%s does not exist", name, inst);
406
krb5_free_principal(context, princ);
407
syslog(LOG_ERR, "kadm5_get_principal failed: %s",
408
error_message(retcode));
409
return KAINTERNALERROR;
413
krb5_free_principal(context, princ);
416
* Check various things - taken from the KDC code.
418
* Since we're essentially bypassing the KDC, we need to make sure
419
* that we don't give out a ticket that we shouldn't.
423
* Has the principal expired?
426
if (p->princ_expire_time && p->princ_expire_time < req_time) {
427
kadm5_free_principal_ent(handle, p);
432
* Has the principal's password expired? Note that we don't
433
* check for the PWCHANGE_SERVICE flag here, since we don't
434
* support password changing. We do support the REQUIRES_PWCHANGE
438
if ((p->pw_expiration && p->pw_expiration < req_time) ||
439
(p->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
440
kadm5_free_principal_ent(handle, p);
445
* See if the principal is locked out
448
if (p->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
449
kadm5_free_principal_ent(handle, p);
454
* There's no way we can handle hardware preauth, so
455
* disallow tickets with this flag set.
458
if (p->attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
459
kadm5_free_principal_ent(handle, p);
472
* Create an rx reply packet in "packet" using the provided data.
473
* The caller is responsible for zeroing key and sched.
476
int make_reply_packet(context, handle, reply, challenge_response, start_time,
477
end_time, cname, cinst, sname, sinst, key, sched, label)
478
krb5_context context;
481
int challenge_response, start_time, end_time;
482
char *cname, *cinst, *sname, *sinst;
484
des_key_schedule sched;
487
int rv, n, maxn, v4life, *enclenp, *ticklenp;
488
u_char *p, *enc, *ticket;
489
kadm5_principal_ent_rec cprinc, sprinc;
490
des_cblock skey, new_session_key;
491
des_key_schedule ssched;
492
krb5_deltat lifetime;
496
rv = check_princ(context, handle, cname, cinst, &cprinc);
500
rv = check_princ(context, handle, sname, sinst, &sprinc);
502
kadm5_free_principal_ent(handle, &cprinc);
507
* Bound ticket lifetime by max lifetimes of user and service.
509
* Since V5 already stores everything in Unix epoch timestamps like
510
* AFS, these calculations are much simpler.
513
lifetime = end_time - start_time;
514
lifetime = min(lifetime, cprinc.max_life);
515
lifetime = min(lifetime, sprinc.max_life);
516
lifetime = min(lifetime, realm_params.max_life);
518
end_time = start_time + lifetime;
521
* But we have to convert back to V4-style lifetimes
524
v4life = lifetime / 300;
527
* Use the CMU algorithm instead
529
long *clist = cmu_seconds;
530
while (*clist && *clist < lifetime) clist++;
531
v4life = 128 + (clist - cmu_seconds);
535
* If this is for afs and the instance is the local cell name
536
* then we assume we added the instance in GetTickets to
537
* identify the afs key in the kerberos database. This is for
538
* cases where the afs cell name is different from the kerberos
539
* realm name. We now want to remove the instance so it doesn't
540
* cause klog to barf.
542
if (!strcmp(sname, "afs") && (strcasecmp(sinst, localcell) == 0))
546
* All the data needed to construct the ticket is ready, so do it.
549
p = (unsigned char *) reply->base;
553
#define ERR(x) do { rv = x ; goto error; } while (0)
554
#define ADVANCE(x) { if ((n += x) > maxn) ERR(KAINTERNALERROR); else p += x;}
555
#define PUT_CHAR(x) { *p = (x); ADVANCE(1); }
556
#define PUT_INT(x) { int q = ntohl(x); memcpy(p, (char *)&q, 4); ADVANCE(4); }
557
#define PUT_STR(x) { strcpy((char *) p, x); ADVANCE(strlen(x) + 1); }
563
PUT_INT(0); /* filled in later */
567
PUT_INT(challenge_response);
570
* new_session_key is created here, and remains in the clear
571
* until just before we return.
573
des_new_random_key(new_session_key);
574
memcpy(p, new_session_key, 8);
579
PUT_INT(sprinc.kvno);
582
PUT_INT(0); /* filled in later */
591
PUT_CHAR(0); /* flags, always 0 */
595
PUT_INT(0); /* would be ip address */
597
memcpy(p, new_session_key, 8);
606
ADVANCE(PAD_TO(p - ticket, 8) - (p - ticket));
608
*ticklenp = ntohl(p - ticket);
610
rv = get_princ_key(context, handle, &sprinc, skey, ssched);
613
des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, p - ticket,
614
ssched, (C_Block *) skey, ENCRYPT);
615
memset(skey, 0, sizeof(skey));
616
memset(ssched, 0, sizeof(ssched));
618
PUT_STR(label); /* "tgsT" or "gtkt" */
619
ADVANCE(-1); /* back up over string terminator */
621
ADVANCE(PAD_TO(p - enc, 8) - (p - enc));
628
*enclenp = ntohl(p - enc);
629
des_pcbc_encrypt((C_Block *) enc, (C_Block *) enc, p - enc, sched,
630
(C_Block *) key, ENCRYPT);
634
memset(new_session_key, 0, sizeof(new_session_key));
635
kadm5_free_principal_ent(handle, &cprinc);
636
kadm5_free_principal_ent(handle, &sprinc);
641
#define ERR(x) do { rv = x; goto error; } while (0)
642
#define ADVANCE(x) { if ((n += x) > maxn) ERR(KABADREQUEST); else p += x; }
643
#define GET_INT(x) { int q; memcpy((char *)&q, p, 4); x = ntohl(q); ADVANCE(4); }
644
#define GET_CHAR(x) { x = *p; ADVANCE(1); }
645
#define GET_PSTR(x) \
648
if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
651
ADVANCE(PAD_TO(len, 4)); \
657
if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
664
* Process an Authenticate request.
667
int Authenticate(context, handle, from, req, reply)
668
krb5_context context;
674
int len, start_time, end_time, challenge;
675
char name[ANAME_SZ+1], inst[INST_SZ+1], *p;
676
kadm5_principal_ent_rec cprinc;
678
des_key_schedule csched;
679
int free_princ_ent = 0;
693
fprintf(stderr, "Authenticating %s.%s\n", name, inst);
695
rv = check_princ(context, handle, name, inst, &cprinc);
709
* ckey and csched are set here and remain in the clear
710
* until just before we return.
713
rv = get_princ_key(context, handle, &cprinc, ckey, csched);
716
des_pcbc_encrypt((C_Block *) p, (C_Block *) p, 8, csched,
717
(C_Block *) ckey, DECRYPT);
721
rv = memcmp(p, "gTGS", 4);
726
/* ignore the rest */
730
* We have all the data from the request, now generate the reply.
733
rv = make_reply_packet(context, handle, reply, challenge + 1, start_time,
734
end_time, name, inst, "krbtgt", localcell,
735
ckey, csched, "tgsT");
737
memset(ckey, 0, sizeof(ckey));
738
memset(csched, 0, sizeof(csched));
740
syslog(LOG_INFO, "authenticate: %s.%s from %s", name, inst, from);
742
syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
745
kadm5_free_principal_ent(handle, &cprinc);
751
* Process a GetTicket rpc.
754
int GetTicket(context, handle, from, req, reply)
755
krb5_context context;
760
int rv, n, maxn, len, ticketlen;
762
u_int kvno, start_time, end_time, times[2], flags, ipaddr;
763
u_int tgt_start_time, tgt_end_time, lifetime;
764
char rname[ANAME_SZ+1], rinst[INST_SZ+1]; /* requested principal */
765
char sname[ANAME_SZ+1], sinst[INST_SZ+1]; /* service principal (TGT) */
766
char cname[ANAME_SZ+1], cinst[INST_SZ+1]; /* client principal */
767
char cell[REALM_SZ+1], realm[REALM_SZ+1];
768
char enctimes[8 + 1], ticket[1024];
770
kadm5_principal_ent_rec cprinc;
771
des_cblock ckey, session_key;
772
des_key_schedule csched, session_sched;
773
int free_princ_ent = 0;
778
* Initialize these so we don't crash trying to print them in
779
* case they don't get filled in.
781
strcpy(rname, "Unknown");
782
strcpy(rinst, "Unknown");
783
strcpy(sname, "Unknown");
784
strcpy(sinst, "Unknown");
785
strcpy(cname, "Unknown");
786
strcpy(cinst, "Unknown");
787
strcpy(cell, "Unknown");
788
strcpy(realm, "Unknown");
800
strcpy(cell, localcell);
803
fprintf(stderr, "Cell is %s\n", cell);
805
memset(ticket, 0, sizeof(ticket));
807
ticketlen = len; /* hacky hack hack */
812
fprintf(stderr, "Request for %s/%s\n", rname, rinst);
814
GET_PSTR(enctimes); /* still encrypted */
815
if (len != 8) /* hack and hack again */
818
/* ignore the rest */
822
* That's it for the packet, now decode the embedded ticket.
825
rv = check_princ(context, handle, "krbtgt", cell, &cprinc);
831
rv = get_princ_key(context, handle, &cprinc, ckey, csched);
834
des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, ticketlen, csched,
835
(C_Block *) ckey, DECRYPT);
836
memset(ckey, 0, sizeof(ckey));
837
memset(csched, 0, sizeof(csched));
840
* The ticket's session key is now in the clear in the ticket buffer.
841
* We zero it just before returning.
853
memcpy(session_key, p, 8);
856
GET_CHAR(tgt_lifetime);
857
GET_INT(tgt_start_time);
863
"ticket: %s.%s@%s for %s.%s\n",
864
cname, cinst, realm, sname, sinst);
867
* ok, we've got the ticket unpacked.
868
* now decrypt the start and end times.
871
rv = des_key_sched(session_key, session_sched);
875
des_ecb_encrypt((C_Block *) enctimes, (C_Block *) times, session_sched,
877
start_time = ntohl(times[0]);
878
end_time = ntohl(times[1]);
881
* All the info we need is now available.
882
* Now validate the request.
886
* This translator requires that the flags and IP address
887
* in the ticket be zero, because we always set them that way,
888
* and we want to accept only tickets that we generated.
890
* Are the flags and IP address fields 0?
892
if (flags || ipaddr) {
894
fprintf(stderr, "ERROR: flags or ipaddr field non-zero\n");
898
* Is the supplied ticket a tgt?
900
if (strcmp(sname, "krbtgt")) {
902
fprintf(stderr, "ERROR: not for krbtgt service\n");
907
* This translator does not allow MIT-style cross-realm access.
908
* Is this a cross-realm ticket?
910
if (strcasecmp(sinst, localcell)) {
913
"ERROR: Service instance (%s) differs from local cell\n",
919
* This translator does not issue cross-realm tickets,
920
* since klog doesn't use this feature.
921
* Is the request for a cross-realm ticket?
923
if (strcasecmp(cell, localcell)) {
925
fprintf(stderr, "ERROR: Cell %s != local cell", cell);
930
* Even if we later decide to issue cross-realm tickets,
931
* we should not permit "realm hopping".
932
* This means that the client's realm should match
933
* the realm of the tgt with whose key we are supposed
934
* to decrypt the ticket. I think.
936
if (*realm && strcasecmp(realm, cell)) {
938
fprintf(stderr, "ERROR: Realm %s != cell %s\n", realm, cell);
943
* This translator issues service tickets only for afs,
944
* since klog is the only client that should be using it.
945
* Is the requested service afs?
947
* Note: to make EMT work, we're allowing tickets for emt/admin and
950
if (! ((strcmp(rname, "afs") == 0 && ! *rinst) ||
951
(strcmp(rname, "emt") == 0 && strcmp(rinst, "admin") == 0) ||
952
(strcmp(rname, "adm") == 0 && strcmp(rinst, "admin") == 0)))
956
* If the local realm name and cell name differ and the user
957
* is in the local cell and has requested a ticket of afs. (no
958
* instance, then we actually want to get a ticket for
959
* afs/<cell name>@<realm name>
961
if ((strcmp(rname, "afs") == 0) && !*rinst &&
962
strcmp(localrealm, localcell) &&
963
(strcasecmp(cell, localcell) == 0)) {
966
strcpy(rinst, localcell);
968
for (c = rinst; *c != NULL; c++)
969
*c = (char) tolower( (int) *c);
972
fprintf(stderr, "Getting ticket for afs/%s\n", localcell);
976
* Even if we later decide to issue service tickets for
977
* services other than afs, we should still disallow
978
* the "changepw" and "krbtgt" services.
980
if (!strcmp(rname, "changepw") || !strcmp(rname, "krbtgt"))
984
* Is the tgt valid yet? (ie. is the start time in the future)
986
if (req_time < tgt_start_time - CLOCK_SKEW) {
988
fprintf(stderr, "ERROR: Ticket not yet valid\n");
993
* Has the tgt expired? (ie. is the end time in the past)
995
* Sigh, convert from V4 lifetimes back to Unix epoch times.
998
if (tgt_lifetime < 128)
999
tgt_end_time = tgt_start_time + tgt_lifetime * 300;
1000
else if (tgt_lifetime < 192)
1001
tgt_end_time = tgt_start_time + cmu_seconds[tgt_lifetime - 128];
1003
tgt_end_time = tgt_start_time + MAX_TICKET_LIFETIME;
1005
if (tgt_end_time < req_time) {
1007
fprintf(stderr, "ERROR: Ticket expired\n");
1012
* This translator uses the requested start time as a cheesy
1013
* authenticator, since the KA protocol does not have an
1014
* explicit authenticator. We can do this since klog always
1015
* requests a start time equal to the current time.
1017
* Is the requested start time approximately now?
1019
if (abs(req_time - start_time) > CLOCK_SKEW)
1023
* The new ticket's lifetime is the minimum of:
1024
* 1. remainder of tgt's lifetime
1025
* 2. requested lifetime
1027
* This is further limited by the client and service's max lifetime
1028
* in make_reply_packet().
1031
lifetime = tgt_end_time - req_time;
1032
lifetime = min(lifetime, end_time - start_time);
1033
end_time = req_time + lifetime;
1036
* We have all the data from the request, now generate the reply.
1039
rv = make_reply_packet(context, handle, reply, 0, start_time, end_time,
1040
cname, cinst, rname, rinst,
1041
session_key, session_sched, "gtkt");
1043
memset(ticket, 0, sizeof(ticket));
1044
memset(session_key, 0, sizeof(session_key));
1045
memset(session_sched, 0, sizeof(session_sched));
1048
kadm5_free_principal_ent(handle, &cprinc);
1050
syslog(LOG_INFO, "getticket: %s.%s from %s for %s.%s",
1051
cname, cinst, from, rname, rinst);
1053
syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
1066
* Convert the request into a reply.
1067
* Returns 0 on success.
1070
void process(context, handle, from, req, reply)
1071
krb5_context context;
1074
packet_t req, reply;
1077
rx_t req_rx = (rx_t)req->base;
1078
rx_t reply_rx = (rx_t)reply->base;
1079
int service, request;
1081
service = ntohs(req_rx->rx_service);
1082
request = ntohl(req_rx->rx_request);
1084
/* ignore everything but type 1 */
1085
if (req_rx->rx_type != 1) {
1090
/* copy the rx header and change the flags */
1091
*reply_rx = *req_rx;
1092
reply_rx->rx_flags = 4;
1096
if (service == 0x2db && (request == 0x15 || request == 0x16)) {
1098
fprintf(stderr, "Handling Authenticate request\n");
1099
rv = Authenticate(context, handle, from, req, reply);
1101
if (service == 0x2dc && request == 0x17) {
1103
fprintf(stderr, "Handling GetTicket request\n");
1104
rv = GetTicket(context, handle, from, req, reply);
1107
if (service == 0x2db && request == 0x1) {
1108
rv = Authenticate_old(from, req, reply);
1110
if (service == 0x2dc && request == 0x3) {
1111
rv = GetTicket_old(from, req, reply);
1115
syslog(LOG_INFO, "bogus request %d/%d", service, request);
1120
/* send the error back to rx */
1121
reply->len = sizeof (*reply_rx);
1123
reply_rx->rx_type = 4;
1124
reply_rx->rx_flags = 0;
1125
reply_rx->rx_request = ntohl(rv);
1130
int main(argc, argv)
1134
int s, rv, ch, mflag = 0;
1136
struct sockaddr_in sin;
1137
int forwarders[MAXFORWARDERS], num_forwarders;
1138
krb5_context context;
1139
krb5_error_code code;
1141
krb5_principal master_princ;
1142
kadm5_principal_ent_rec master_princ_rec;
1144
facility_mapping *mapping;
1145
int facility = LOG_DAEMON;
1147
extern char *optarg;
1155
while ((ch = getopt(argc, argv, "c:df:l:mp:r:")) != -1) {
1166
if (num_forwarders++ >= MAXFORWARDERS)
1167
pexit("too many forwarders\n");
1169
hp = gethostbyname(optarg);
1171
printf("unknown host %s\n", optarg);
1174
forwarders[num_forwarders - 1] = *(int *)hp->h_addr;
1179
for (mapping = mappings; mapping->string != NULL; mapping++)
1180
if (strcmp(mapping->string, optarg) == 0)
1183
if (mapping->string == NULL) {
1184
printf("Unknown facility \"%s\"\n", optarg);
1188
facility = mapping->num;
1194
if (isdigit(*optarg)) {
1195
port = atoi(optarg);
1200
sp = getservbyname(optarg, "udp");
1202
printf("unknown service %s\n", optarg);
1209
localrealm = optarg;
1212
printf("usage: %s [-c cell] [-d] [-f forwarder-host] [-l facility ] [-p port] [-r realm]\n",
1218
openlog("fakeka", LOG_PID, facility);
1223
* Set up the socket.
1226
s = socket(AF_INET, SOCK_DGRAM, 0);
1228
perrorexit("Couldn't create socket");
1230
sin.sin_family = AF_INET;
1231
sin.sin_addr.s_addr = 0;
1232
sin.sin_port = port;
1234
rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
1236
perrorexit("Couldn't bind socket");
1239
* Initialize kerberos stuff and kadm5 stuff.
1242
if ((code = krb5int_init_context_kdc(&context))) {
1243
com_err(argv[0], code, "while initializing Kerberos");
1247
if (!localrealm && (code = krb5_get_default_realm(context, &localrealm))) {
1248
com_err(argv[0], code, "while getting local realm");
1253
localcell = localrealm;
1255
if ((code = kadm5_init_with_password(progname, NULL, KADM5_ADMIN_SERVICE,
1256
NULL, KADM5_STRUCT_VERSION,
1257
KADM5_API_VERSION_2,
1258
(char **) NULL, /* db_args */
1260
com_err(argv[0], code, "while initializing Kadm5");
1264
if ((code = kadm5_get_config_params(context, 1, NULL,
1266
com_err(argv[0], code, "while getting realm parameters");
1270
if (! (realm_params.mask & KADM5_CONFIG_MAX_LIFE)) {
1271
fprintf(stderr, "Cannot determine maximum ticket lifetime\n");
1276
* We need to initialize the random number generator for DES. Use
1277
* the master key to do this.
1280
if ((code = krb5_parse_name(context, realm_params.mask &
1281
KADM5_CONFIG_MKEY_NAME ?
1282
realm_params.mkey_name : "K/M",
1284
com_err(argv[0], code, "while parsing master key name");
1288
if ((code = kadm5_get_principal(handle, master_princ, &master_princ_rec,
1290
com_err(argv[0], code, "while getting master key data");
1294
if ((code = kadm5_decrypt_key(handle, &master_princ_rec,
1295
ENCTYPE_DES_CBC_CRC, -1, 0, &mkey, NULL,
1297
com_err(argv[0], code, "while decrypting the master key");
1301
des_init_random_number_generator(mkey.contents);
1303
krb5_free_keyblock_contents(context, &mkey);
1305
kadm5_free_principal_ent(handle, &master_princ_rec);
1307
krb5_free_principal(context, master_princ);
1310
* Fork and go into the background, if requested
1313
if (!debug && mflag && daemon(0, 0)) {
1314
com_err(argv[0], errno, "while detaching from tty");
1322
struct packet req, reply;
1323
int sinlen, packetlen, i, forwarded;
1326
sinlen = sizeof(sin);
1329
memset(req.data, 0, sizeof(req.data));
1330
rv = recvfrom(s, req.data, sizeof(req.data),
1331
0, (struct sockaddr *)&sin, &sinlen);
1334
syslog(LOG_ERR, "recvfrom failed: %m");
1340
for (i = 0; i < num_forwarders; i++) {
1341
if (sin.sin_addr.s_addr == forwarders[i]) {
1347
if ((code = krb5_timeofday(context, &req_time))) {
1348
syslog(LOG_ERR, "krb5_timeofday failed: %s",
1349
error_message(code));
1353
memset(reply.data, 0, sizeof(reply.data));
1354
req.len = packetlen;
1355
req.base = req.data;
1356
reply.base = reply.data;
1357
reply.len = sizeof(reply.data);
1362
memcpy(&ia.s_addr, req.data, 4);
1363
from = inet_ntoa(ia);
1365
* copy the forwarder header and adjust the bases and lengths.
1367
memcpy(reply.data, req.data, HEADER_LEN);
1368
req.base += HEADER_LEN;
1369
req.len -= HEADER_LEN;
1370
reply.base += HEADER_LEN;
1371
reply.len -= HEADER_LEN;
1374
from = inet_ntoa(sin.sin_addr);
1377
process(context, handle, from, &req, &reply);
1383
/* re-adjust the length to account for the forwarder header */
1384
reply.len += HEADER_LEN;
1387
rv = sendto(s, reply.data, reply.len,
1388
0, (struct sockaddr *)&sin, sinlen);
1390
syslog(LOG_ERR, "sendto failed: %m");