1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)kerberos.c 8.2 (Berkeley) 02/16/95"; 10 #endif /* not lint */ 11 12 /* 13 * Copyright (C) 1990 by the Massachusetts Institute of Technology 14 * 15 * Export of this software from the United States of America is assumed 16 * to require a specific license from the United States Government. 17 * It is the responsibility of any person or organization contemplating 18 * export to obtain such a license before exporting. 19 * 20 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 21 * distribute this software and its documentation for any purpose and 22 * without fee is hereby granted, provided that the above copyright 23 * notice appear in all copies and that both that copyright notice and 24 * this permission notice appear in supporting documentation, and that 25 * the name of M.I.T. not be used in advertising or publicity pertaining 26 * to distribution of the software without specific, written prior 27 * permission. M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 */ 31 32 #ifdef KRB4 33 #include <sys/types.h> 34 #include <arpa/telnet.h> 35 #include <stdio.h> 36 #include <des.h> /* BSD wont include this in krb.h, so we do it here */ 37 #include <krb.h> 38 #ifdef __STDC__ 39 #include <stdlib.h> 40 #endif 41 #ifdef NO_STRING_H 42 #include <strings.h> 43 #else 44 #include <string.h> 45 #endif 46 47 #include "encrypt.h" 48 #include "auth.h" 49 #include "misc.h" 50 51 int kerberos4_cksum P((unsigned char *, int)); 52 int krb_mk_req P((KTEXT, char *, char *, char *, u_long)); 53 int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *)); 54 int krb_kntoln P((AUTH_DAT *, char *)); 55 int krb_get_cred P((char *, char *, char *, CREDENTIALS *)); 56 int krb_get_lrealm P((char *, int)); 57 int kuserok P((AUTH_DAT *, char *)); 58 59 extern auth_debug_mode; 60 61 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, 62 AUTHTYPE_KERBEROS_V4, }; 63 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 64 TELQUAL_NAME, }; 65 66 #define KRB_AUTH 0 /* Authentication data follows */ 67 #define KRB_REJECT 1 /* Rejected (reason might follow) */ 68 #define KRB_ACCEPT 2 /* Accepted */ 69 #define KRB_CHALLENGE 3 /* Challenge for mutual auth. */ 70 #define KRB_RESPONSE 4 /* Response for mutual auth. */ 71 72 #define KRB_SERVICE_NAME "rcmd" 73 74 static KTEXT_ST auth; 75 static char name[ANAME_SZ]; 76 static AUTH_DAT adat = { 0 }; 77 #ifdef ENCRYPTION 78 static Block session_key = { 0 }; 79 static Schedule sched; 80 static Block challenge = { 0 }; 81 #endif /* ENCRYPTION */ 82 83 static int 84 Data(ap, type, d, c) 85 Authenticator *ap; 86 int type; 87 void *d; 88 int c; 89 { 90 unsigned char *p = str_data + 4; 91 unsigned char *cd = (unsigned char *)d; 92 93 if (c == -1) 94 c = strlen((char *)cd); 95 96 if (auth_debug_mode) { 97 printf("%s:%d: [%d] (%d)", 98 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 99 str_data[3], 100 type, c); 101 printd(d, c); 102 printf("\r\n"); 103 } 104 *p++ = ap->type; 105 *p++ = ap->way; 106 *p++ = type; 107 while (c-- > 0) { 108 if ((*p++ = *cd++) == IAC) 109 *p++ = IAC; 110 } 111 *p++ = IAC; 112 *p++ = SE; 113 if (str_data[3] == TELQUAL_IS) 114 printsub('>', &str_data[2], p - (&str_data[2])); 115 return(net_write(str_data, p - str_data)); 116 } 117 118 int 119 kerberos4_init(ap, server) 120 Authenticator *ap; 121 int server; 122 { 123 FILE *fp; 124 125 if (server) { 126 str_data[3] = TELQUAL_REPLY; 127 if ((fp = fopen(KEYFILE, "r")) == NULL) 128 return(0); 129 fclose(fp); 130 } else { 131 str_data[3] = TELQUAL_IS; 132 } 133 return(1); 134 } 135 136 char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 137 int dst_realm_sz = REALM_SZ; 138 139 int 140 kerberos4_send(ap) 141 Authenticator *ap; 142 { 143 KTEXT_ST auth; 144 #ifdef ENCRYPTION 145 Block enckey; 146 #endif /* ENCRYPTION */ 147 char instance[INST_SZ]; 148 char *realm; 149 char *krb_realmofhost(); 150 char *krb_get_phost(); 151 CREDENTIALS cred; 152 int r; 153 154 printf("[ Trying KERBEROS4 ... ]\n"); 155 if (!UserNameRequested) { 156 if (auth_debug_mode) { 157 printf("Kerberos V4: no user name supplied\r\n"); 158 } 159 return(0); 160 } 161 162 bzero(instance, sizeof(instance)); 163 164 if (realm = krb_get_phost(RemoteHostName)) 165 strncpy(instance, realm, sizeof(instance)); 166 167 instance[sizeof(instance)-1] = '\0'; 168 169 realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName); 170 171 if (!realm) { 172 printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); 173 return(0); 174 } 175 if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) { 176 printf("mk_req failed: %s\r\n", krb_err_txt[r]); 177 return(0); 178 } 179 if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) { 180 printf("get_cred failed: %s\r\n", krb_err_txt[r]); 181 return(0); 182 } 183 if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { 184 if (auth_debug_mode) 185 printf("Not enough room for user name\r\n"); 186 return(0); 187 } 188 if (auth_debug_mode) 189 printf("Sent %d bytes of authentication data\r\n", auth.length); 190 if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) { 191 if (auth_debug_mode) 192 printf("Not enough room for authentication data\r\n"); 193 return(0); 194 } 195 #ifdef ENCRYPTION 196 /* 197 * If we are doing mutual authentication, get set up to send 198 * the challenge, and verify it when the response comes back. 199 */ 200 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 201 register int i; 202 203 des_key_sched(cred.session, sched); 204 des_init_random_number_generator(cred.session); 205 des_new_random_key(session_key); 206 des_ecb_encrypt(session_key, session_key, sched, 0); 207 des_ecb_encrypt(session_key, challenge, sched, 0); 208 /* 209 * Increment the challenge by 1, and encrypt it for 210 * later comparison. 211 */ 212 for (i = 7; i >= 0; --i) { 213 register int x; 214 x = (unsigned int)challenge[i] + 1; 215 challenge[i] = x; /* ignore overflow */ 216 if (x < 256) /* if no overflow, all done */ 217 break; 218 } 219 des_ecb_encrypt(challenge, challenge, sched, 1); 220 } 221 #endif /* ENCRYPTION */ 222 223 if (auth_debug_mode) { 224 printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); 225 printd(auth.dat, auth.length); 226 printf("\r\n"); 227 printf("Sent Kerberos V4 credentials to server\r\n"); 228 } 229 return(1); 230 } 231 232 void 233 kerberos4_is(ap, data, cnt) 234 Authenticator *ap; 235 unsigned char *data; 236 int cnt; 237 { 238 #ifdef ENCRYPTION 239 Session_Key skey; 240 Block datablock; 241 #endif /* ENCRYPTION */ 242 char realm[REALM_SZ]; 243 char instance[INST_SZ]; 244 int r; 245 246 if (cnt-- < 1) 247 return; 248 switch (*data++) { 249 case KRB_AUTH: 250 if (krb_get_lrealm(realm, 1) != KSUCCESS) { 251 Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1); 252 auth_finished(ap, AUTH_REJECT); 253 if (auth_debug_mode) 254 printf("No local realm\r\n"); 255 return; 256 } 257 bcopy((void *)data, (void *)auth.dat, auth.length = cnt); 258 if (auth_debug_mode) { 259 printf("Got %d bytes of authentication data\r\n", cnt); 260 printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); 261 printd(auth.dat, auth.length); 262 printf("\r\n"); 263 } 264 instance[0] = '*'; instance[1] = 0; 265 if (r = krb_rd_req(&auth, KRB_SERVICE_NAME, 266 instance, 0, &adat, "")) { 267 if (auth_debug_mode) 268 printf("Kerberos failed him as %s\r\n", name); 269 Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1); 270 auth_finished(ap, AUTH_REJECT); 271 return; 272 } 273 #ifdef ENCRYPTION 274 bcopy((void *)adat.session, (void *)session_key, sizeof(Block)); 275 #endif /* ENCRYPTION */ 276 krb_kntoln(&adat, name); 277 278 if (UserNameRequested && !kuserok(&adat, UserNameRequested)) 279 Data(ap, KRB_ACCEPT, (void *)0, 0); 280 else 281 Data(ap, KRB_REJECT, 282 (void *)"user is not authorized", -1); 283 auth_finished(ap, AUTH_USER); 284 break; 285 286 case KRB_CHALLENGE: 287 #ifndef ENCRYPTION 288 Data(ap, KRB_RESPONSE, (void *)0, 0); 289 #else /* ENCRYPTION */ 290 if (!VALIDKEY(session_key)) { 291 /* 292 * We don't have a valid session key, so just 293 * send back a response with an empty session 294 * key. 295 */ 296 Data(ap, KRB_RESPONSE, (void *)0, 0); 297 break; 298 } 299 300 /* 301 * Initialize the random number generator since it's 302 * used later on by the encryption routine. 303 */ 304 des_init_random_number_generator(session_key); 305 des_key_sched(session_key, sched); 306 bcopy((void *)data, (void *)datablock, sizeof(Block)); 307 /* 308 * Take the received encrypted challenge, and encrypt 309 * it again to get a unique session_key for the 310 * ENCRYPT option. 311 */ 312 des_ecb_encrypt(datablock, session_key, sched, 1); 313 skey.type = SK_DES; 314 skey.length = 8; 315 skey.data = session_key; 316 encrypt_session_key(&skey, 1); 317 /* 318 * Now decrypt the received encrypted challenge, 319 * increment by one, re-encrypt it and send it back. 320 */ 321 des_ecb_encrypt(datablock, challenge, sched, 0); 322 for (r = 7; r >= 0; r--) { 323 register int t; 324 t = (unsigned int)challenge[r] + 1; 325 challenge[r] = t; /* ignore overflow */ 326 if (t < 256) /* if no overflow, all done */ 327 break; 328 } 329 des_ecb_encrypt(challenge, challenge, sched, 1); 330 Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge)); 331 #endif /* ENCRYPTION */ 332 break; 333 334 default: 335 if (auth_debug_mode) 336 printf("Unknown Kerberos option %d\r\n", data[-1]); 337 Data(ap, KRB_REJECT, 0, 0); 338 break; 339 } 340 } 341 342 void 343 kerberos4_reply(ap, data, cnt) 344 Authenticator *ap; 345 unsigned char *data; 346 int cnt; 347 { 348 #ifdef ENCRYPTION 349 Session_Key skey; 350 #endif /* ENCRYPTION */ 351 352 if (cnt-- < 1) 353 return; 354 switch (*data++) { 355 case KRB_REJECT: 356 if (cnt > 0) { 357 printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n", 358 cnt, data); 359 } else 360 printf("[ Kerberos V4 refuses authentication ]\r\n"); 361 auth_send_retry(); 362 return; 363 case KRB_ACCEPT: 364 printf("[ Kerberos V4 accepts you ]\n"); 365 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 366 /* 367 * Send over the encrypted challenge. 368 */ 369 #ifndef ENCRYPTION 370 Data(ap, KRB_CHALLENGE, (void *)0, 0); 371 #else /* ENCRYPTION */ 372 Data(ap, KRB_CHALLENGE, (void *)session_key, 373 sizeof(session_key)); 374 des_ecb_encrypt(session_key, session_key, sched, 1); 375 skey.type = SK_DES; 376 skey.length = 8; 377 skey.data = session_key; 378 encrypt_session_key(&skey, 0); 379 #endif /* ENCRYPTION */ 380 return; 381 } 382 auth_finished(ap, AUTH_USER); 383 return; 384 case KRB_RESPONSE: 385 #ifdef ENCRYPTION 386 /* 387 * Verify that the response to the challenge is correct. 388 */ 389 if ((cnt != sizeof(Block)) || 390 (0 != memcmp((void *)data, (void *)challenge, 391 sizeof(challenge)))) 392 { 393 #endif /* ENCRYPTION */ 394 printf("[ Kerberos V4 challenge failed!!! ]\r\n"); 395 auth_send_retry(); 396 return; 397 #ifdef ENCRYPTION 398 } 399 printf("[ Kerberos V4 challenge successful ]\r\n"); 400 auth_finished(ap, AUTH_USER); 401 #endif /* ENCRYPTION */ 402 break; 403 default: 404 if (auth_debug_mode) 405 printf("Unknown Kerberos option %d\r\n", data[-1]); 406 return; 407 } 408 } 409 410 int 411 kerberos4_status(ap, name, level) 412 Authenticator *ap; 413 char *name; 414 int level; 415 { 416 if (level < AUTH_USER) 417 return(level); 418 419 if (UserNameRequested && !kuserok(&adat, UserNameRequested)) { 420 strcpy(name, UserNameRequested); 421 return(AUTH_VALID); 422 } else 423 return(AUTH_USER); 424 } 425 426 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 427 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 428 429 void 430 kerberos4_printsub(data, cnt, buf, buflen) 431 unsigned char *data, *buf; 432 int cnt, buflen; 433 { 434 char lbuf[32]; 435 register int i; 436 437 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 438 buflen -= 1; 439 440 switch(data[3]) { 441 case KRB_REJECT: /* Rejected (reason might follow) */ 442 strncpy((char *)buf, " REJECT ", buflen); 443 goto common; 444 445 case KRB_ACCEPT: /* Accepted (name might follow) */ 446 strncpy((char *)buf, " ACCEPT ", buflen); 447 common: 448 BUMP(buf, buflen); 449 if (cnt <= 4) 450 break; 451 ADDC(buf, buflen, '"'); 452 for (i = 4; i < cnt; i++) 453 ADDC(buf, buflen, data[i]); 454 ADDC(buf, buflen, '"'); 455 ADDC(buf, buflen, '\0'); 456 break; 457 458 case KRB_AUTH: /* Authentication data follows */ 459 strncpy((char *)buf, " AUTH", buflen); 460 goto common2; 461 462 case KRB_CHALLENGE: 463 strncpy((char *)buf, " CHALLENGE", buflen); 464 goto common2; 465 466 case KRB_RESPONSE: 467 strncpy((char *)buf, " RESPONSE", buflen); 468 goto common2; 469 470 default: 471 sprintf(lbuf, " %d (unknown)", data[3]); 472 strncpy((char *)buf, lbuf, buflen); 473 common2: 474 BUMP(buf, buflen); 475 for (i = 4; i < cnt; i++) { 476 sprintf(lbuf, " %d", data[i]); 477 strncpy((char *)buf, lbuf, buflen); 478 BUMP(buf, buflen); 479 } 480 break; 481 } 482 } 483 484 int 485 kerberos4_cksum(d, n) 486 unsigned char *d; 487 int n; 488 { 489 int ck = 0; 490 491 /* 492 * A comment is probably needed here for those not 493 * well versed in the "C" language. Yes, this is 494 * supposed to be a "switch" with the body of the 495 * "switch" being a "while" statement. The whole 496 * purpose of the switch is to allow us to jump into 497 * the middle of the while() loop, and then not have 498 * to do any more switch()s. 499 * 500 * Some compilers will spit out a warning message 501 * about the loop not being entered at the top. 502 */ 503 switch (n&03) 504 while (n > 0) { 505 case 0: 506 ck ^= (int)*d++ << 24; 507 --n; 508 case 3: 509 ck ^= (int)*d++ << 16; 510 --n; 511 case 2: 512 ck ^= (int)*d++ << 8; 513 --n; 514 case 1: 515 ck ^= (int)*d++; 516 --n; 517 } 518 return(ck); 519 } 520 #endif 521 522 #ifdef notdef 523 524 prkey(msg, key) 525 char *msg; 526 unsigned char *key; 527 { 528 register int i; 529 printf("%s:", msg); 530 for (i = 0; i < 8; i++) 531 printf(" %3d", key[i]); 532 printf("\r\n"); 533 } 534 #endif 535