diff options
| author | Greg Hudson <ghudson@mit.edu> | 2008-12-15 18:32:44 +0000 |
|---|---|---|
| committer | Greg Hudson <ghudson@mit.edu> | 2008-12-15 18:32:44 +0000 |
| commit | b03dd7a3955864c7f84742ac37a97cf00bcd786e (patch) | |
| tree | 7b4df956ba4ee910d7bd733f5db54bf14067732e /src/kdc/fakeka.c | |
| parent | 54b5e5b06d03a102874857935ed92dd30b726bc8 (diff) | |
| download | krb5-b03dd7a3955864c7f84742ac37a97cf00bcd786e.tar.gz krb5-b03dd7a3955864c7f84742ac37a97cf00bcd786e.tar.xz krb5-b03dd7a3955864c7f84742ac37a97cf00bcd786e.zip | |
In the KDC, remove krb4 request handling support and fakeka code
ticket: 6303
status: open
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21448 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kdc/fakeka.c')
| -rw-r--r-- | src/kdc/fakeka.c | 1397 |
1 files changed, 0 insertions, 1397 deletions
diff --git a/src/kdc/fakeka.c b/src/kdc/fakeka.c deleted file mode 100644 index 39916647c..000000000 --- a/src/kdc/fakeka.c +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * COPYRIGHT NOTICE - * Copyright (c) 1994 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - * - * Converted to Kerberos 5 by Ken Hornstein <kenh@cmf.nrl.navy.mil> - */ - -#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> -#include <k5-platform.h> - -#ifndef LINT -static char rcsid[]= - "$Id$"; -#endif - -/* - * Misc macros - */ - -#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 - -/* - * Error values from kautils.h - * - * The security errors are: - * KABADTICKET, KABADSERVER, KABADUSER, and KACLOCKSKEW - */ - -#define KADATABASEINCONSISTENT (180480L) -#define KANOENT (180484L) -#define KABADREQUEST (180490L) -#define KABADTICKET (180504L) -#define KABADSERVER (180507L) -#define KABADUSER (180508L) -#define KACLOCKSKEW (180514L) -#define KAINTERNALERROR (180518L) - - -/* - * Type definitions - */ - -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; - - -/* - * Global vars - */ - -char *progname = "fakeka"; /* needed by libkdb.a */ -char *localrealm = NULL; -char *localcell = NULL; -krb5_timestamp req_time; -kadm5_config_params realm_params; -int debug = 0; - - -/* - * This is a table for the "infamous" CMU ticket lifetime conversion. If - * the lifetime is greater than 128, use this table - */ -#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__ -/* - * Prototypes for all the functions we define - */ - -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 - - -/* - * Helpers for exiting with errors - */ - -void perrorexit(str) -char *str; -{ - perror(str); - exit(1); -} - -void pexit(str) -char *str; -{ - printf("%s\n", str); - exit(1); -} - - -/* - * Translate error codes into strings. - */ - -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: - snprintf(buf, sizeof(buf), "impossible error code %d, help!", e); - return buf; - } - /*NOTREACHED*/ -} - -/* - * Syslog facilities - */ -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 } -}; - - -/* - * Get the principal's key and key schedule from the db record. - * - * Life is more complicated in the V5 world. Since we can have different - * encryption types, we have to make sure that we get back a DES key. - * Also, we have to try to get back a AFS3 or V4 salted key, since AFS - * doesn't know about a V5 style salt. - */ - -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; - - /* - * We need to call kadm5_decrypt_key to decrypt the key data - * from the principal record. We _must_ have a encryption type - * of DES_CBC_CRC, and we prefer having a salt type of AFS 3 (but - * a V4 salt will work as well). If that fails, then return any - * type of key we can find. - * - * Note that since this uses kadm5_decrypt_key, it means it has to - * be compiled with the kadm5srv library. - */ - - 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; - } - - /* - * Copy the data from our krb5_keyblock to the des_cblock. Make sure - * the size of our key matches the V4/AFS des_cblock. - */ - - 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); - - /* - * Calculate the des key schedule - */ - - rv = des_key_sched(k, s); - if (rv) { - memset((void *) k, 0, sizeof(k)); - memset((void *)s, 0, sizeof(s)); - return KAINTERNALERROR; - } - return 0; -} - - -/* - * Fetch principal from db and validate it. - * - * Note that this always fetches the key data from the principal (but it - * doesn't decrypt it). - */ - -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; - - /* - * Screen out null principals. They are causing crashes here - * under HPUX-10.20. - vwelch@ncsa.uiuc.edu 1/6/98 - */ - if (!name || (name[0] == '\0')) { - syslog(LOG_ERR, "screening out null principal"); - return KANOENT; - } - - /* - * Build a principal from the name and instance (the realm is always - * the same). - */ - - 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; - } - - /* - * Fetch the principal from the database -- also fetch the key data. - * Note that since this retrieves the key data, it has to be linked with - * the kadm5srv library. - */ - - 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); - - /* - * Check various things - taken from the KDC code. - * - * Since we're essentially bypassing the KDC, we need to make sure - * that we don't give out a ticket that we shouldn't. - */ - - /* - * Has the principal expired? - */ - - if (p->princ_expire_time && p->princ_expire_time < req_time) { - kadm5_free_principal_ent(handle, p); - return KABADUSER; - } - - /* - * Has the principal's password expired? Note that we don't - * check for the PWCHANGE_SERVICE flag here, since we don't - * support password changing. We do support the REQUIRES_PWCHANGE - * flag, though. - */ - - if ((p->pw_expiration && p->pw_expiration < req_time) || - (p->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { - kadm5_free_principal_ent(handle, p); - return KABADUSER; - } - - /* - * See if the principal is locked out - */ - - if (p->attributes & KRB5_KDB_DISALLOW_ALL_TIX) { - kadm5_free_principal_ent(handle, p); - return KABADUSER; - } - - /* - * There's no way we can handle hardware preauth, so - * disallow tickets with this flag set. - */ - - if (p->attributes & KRB5_KDB_REQUIRES_HW_AUTH) { - kadm5_free_principal_ent(handle, p); - return KABADUSER; - } - - /* - * Must be okay, then - */ - - return 0; -} - - -/* - * Create an rx reply packet in "packet" using the provided data. - * The caller is responsible for zeroing key and sched. - */ - -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; - } - - /* - * Bound ticket lifetime by max lifetimes of user and service. - * - * Since V5 already stores everything in Unix epoch timestamps like - * AFS, these calculations are much simpler. - */ - - 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; - - /* - * But we have to convert back to V4-style lifetimes - */ - - v4life = lifetime / 300; - if (v4life > 127) { - /* - * Use the CMU algorithm instead - */ - long *clist = cmu_seconds; - while (*clist && *clist < lifetime) clist++; - v4life = 128 + (clist - cmu_seconds); - } - - /* - * If this is for afs and the instance is the local cell name - * then we assume we added the instance in GetTickets to - * identify the afs key in the kerberos database. This is for - * cases where the afs cell name is different from the kerberos - * realm name. We now want to remove the instance so it doesn't - * cause klog to barf. - */ - if (!strcmp(sname, "afs") && (strcasecmp(sinst, localcell) == 0)) - sinst[0] = '\0'; - - /* - * All the data needed to construct the ticket is ready, so do it. - */ - - 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); /* filled in later */ - - enc = p; - PUT_INT(0); - PUT_INT(challenge_response); - - /* - * new_session_key is created here, and remains in the clear - * until just before we return. - */ - 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); /* filled in later */ - - PUT_STR(cname); - PUT_STR(cinst); - PUT_STR(""); - PUT_STR(sname); - PUT_STR(sinst); - - ticket = p; - PUT_CHAR(0); /* flags, always 0 */ - PUT_STR(cname); - PUT_STR(cinst); - PUT_STR(""); - PUT_INT(0); /* would be ip address */ - - 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); /* "tgsT" or "gtkt" */ - ADVANCE(-1); /* back up over string terminator */ - - 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); \ - } - - -/* - * Process an Authenticate request. - */ - -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); - - /* - * ckey and csched are set here and remain in the clear - * until just before we return. - */ - - 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); - - /* ignore the rest */ - ADVANCE(8); - - /* - * We have all the data from the request, now generate the reply. - */ - - 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; -} - - -/* - * Process a GetTicket rpc. - */ - -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]; /* requested principal */ - char sname[ANAME_SZ+1], sinst[INST_SZ+1]; /* service principal (TGT) */ - char cname[ANAME_SZ+1], cinst[INST_SZ+1]; /* client principal */ - 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; - - /* - * Initialize these so we don't crash trying to print them in - * case they don't get filled in. - */ - strlcpy(rname, "Unknown", sizeof(rname)); - strlcpy(rinst, "Unknown", sizeof(rinst)); - strlcpy(sname, "Unknown", sizeof(sname)); - strlcpy(sinst, "Unknown", sizeof(sinst)); - strlcpy(cname, "Unknown", sizeof(cname)); - strlcpy(cinst, "Unknown", sizeof(cinst)); - strlcpy(cell, "Unknown", sizeof(cell)); - strlcpy(realm, "Unknown", sizeof(realm)); - - p = req->base; - maxn = req->len; - n = 0; - - ADVANCE(32); - - GET_INT(kvno); - - GET_PSTR(cell); - if (!cell[0]) - strlcpy(cell, localcell, sizeof(cell)); - - if (debug) - fprintf(stderr, "Cell is %s\n", cell); - - memset(ticket, 0, sizeof(ticket)); - GET_PSTR(ticket); - ticketlen = len; /* hacky hack hack */ - GET_PSTR(rname); - GET_PSTR(rinst); - - if (debug) - fprintf(stderr, "Request for %s/%s\n", rname, rinst); - - GET_PSTR(enctimes); /* still encrypted */ - if (len != 8) /* hack and hack again */ - ERR(KABADREQUEST); - - /* ignore the rest */ - ADVANCE(8); - - /* - * That's it for the packet, now decode the embedded ticket. - */ - - 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)); - - /* - * The ticket's session key is now in the clear in the ticket buffer. - * We zero it just before returning. - */ - - 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); - - /* - * ok, we've got the ticket unpacked. - * now decrypt the start and end times. - */ - - 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]); - - /* - * All the info we need is now available. - * Now validate the request. - */ - - /* - * This translator requires that the flags and IP address - * in the ticket be zero, because we always set them that way, - * and we want to accept only tickets that we generated. - * - * Are the flags and IP address fields 0? - */ - if (flags || ipaddr) { - if (debug) - fprintf(stderr, "ERROR: flags or ipaddr field non-zero\n"); - ERR(KABADTICKET); - } - /* - * Is the supplied ticket a tgt? - */ - if (strcmp(sname, "krbtgt")) { - if (debug) - fprintf(stderr, "ERROR: not for krbtgt service\n"); - ERR(KABADTICKET); - } - - /* - * This translator does not allow MIT-style cross-realm access. - * Is this a cross-realm ticket? - */ - if (strcasecmp(sinst, localcell)) { - if (debug) - fprintf(stderr, - "ERROR: Service instance (%s) differs from local cell\n", - sinst); - ERR(KABADTICKET); - } - - /* - * This translator does not issue cross-realm tickets, - * since klog doesn't use this feature. - * Is the request for a cross-realm ticket? - */ - if (strcasecmp(cell, localcell)) { - if (debug) - fprintf(stderr, "ERROR: Cell %s != local cell", cell); - ERR(KABADTICKET); - } - - /* - * Even if we later decide to issue cross-realm tickets, - * we should not permit "realm hopping". - * This means that the client's realm should match - * the realm of the tgt with whose key we are supposed - * to decrypt the ticket. I think. - */ - if (*realm && strcasecmp(realm, cell)) { - if (debug) - fprintf(stderr, "ERROR: Realm %s != cell %s\n", realm, cell); - ERR(KABADTICKET); - } - - /* - * This translator issues service tickets only for afs, - * since klog is the only client that should be using it. - * Is the requested service afs? - * - * Note: to make EMT work, we're allowing tickets for emt/admin and - * adm/admin. - */ - 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 the local realm name and cell name differ and the user - * is in the local cell and has requested a ticket of afs. (no - * instance, then we actually want to get a ticket for - * afs/<cell name>@<realm name> - */ - if ((strcmp(rname, "afs") == 0) && !*rinst && - strcmp(localrealm, localcell) && - (strcasecmp(cell, localcell) == 0)) { - char *c; - - strlcpy(rinst, localcell, sizeof(rinst)); - - for (c = rinst; *c != NULL; c++) - *c = (char) tolower( (int) *c); - - if (debug) - fprintf(stderr, "Getting ticket for afs/%s\n", localcell); - } - - /* - * Even if we later decide to issue service tickets for - * services other than afs, we should still disallow - * the "changepw" and "krbtgt" services. - */ - if (!strcmp(rname, "changepw") || !strcmp(rname, "krbtgt")) - ERR(KABADSERVER); - - /* - * Is the tgt valid yet? (ie. is the start time in the future) - */ - if (req_time < tgt_start_time - CLOCK_SKEW) { - if (debug) - fprintf(stderr, "ERROR: Ticket not yet valid\n"); - ERR(KABADTICKET); - } - - /* - * Has the tgt expired? (ie. is the end time in the past) - * - * Sigh, convert from V4 lifetimes back to Unix epoch times. - */ - - 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); - } - - /* - * This translator uses the requested start time as a cheesy - * authenticator, since the KA protocol does not have an - * explicit authenticator. We can do this since klog always - * requests a start time equal to the current time. - * - * Is the requested start time approximately now? - */ - if (abs(req_time - start_time) > CLOCK_SKEW) - ERR(KACLOCKSKEW); - - /* - * The new ticket's lifetime is the minimum of: - * 1. remainder of tgt's lifetime - * 2. requested lifetime - * - * This is further limited by the client and service's max lifetime - * in make_reply_packet(). - */ - - lifetime = tgt_end_time - req_time; - lifetime = min(lifetime, end_time - start_time); - end_time = req_time + lifetime; - - /* - * We have all the data from the request, now generate the reply. - */ - - 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 - -/* - * Convert the request into a reply. - * Returns 0 on success. - */ - -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); - - /* ignore everything but type 1 */ - if (req_rx->rx_type != 1) { - reply->len = 0; - return; - } - - /* copy the rx header and change the flags */ - *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 (service == 0x2db && request == 0x1) { - rv = Authenticate_old(from, req, reply); - } - if (service == 0x2dc && request == 0x3) { - rv = GetTicket_old(from, req, reply); - } - */ - if (rv == -1) { - syslog(LOG_INFO, "bogus request %d/%d", service, request); - rv = KABADREQUEST; - } - - if (rv) { - /* send the error back to rx */ - 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; - - /* - * Parse args. - */ - 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); - - /* - * Set up the socket. - */ - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - perrorexit("Couldn't create socket"); - set_cloexec_fd(s); - - 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"); - - /* - * Initialize kerberos stuff and kadm5 stuff. - */ - - 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, /* db_args */ - &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); - } - - /* - * We need to initialize the random number generator for DES. Use - * the master key to do this. - */ - - 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); - - /* - * Fork and go into the background, if requested - */ - - if (!debug && mflag && daemon(0, 0)) { - com_err(argv[0], errno, "while detaching from tty"); - } - - /* - * rpc server loop. - */ - - 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); - /* - * copy the forwarder header and adjust the bases and lengths. - */ - 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) { - /* re-adjust the length to account for the forwarder header */ - 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); - } - } - /*NOTREACHED*/ -} |
