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.1 (Berkeley) 06/04/93"; 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_set_random_generator_seed(cred.session); 205 des_new_random_key(challenge); 206 des_ecb_encrypt(challenge, session_key, sched, 1); 207 /* 208 * Increment the challenge by 1, and encrypt it for 209 * later comparison. 210 */ 211 for (i = 7; i >= 0; --i) { 212 register int x; 213 x = (unsigned int)challenge[i] + 1; 214 challenge[i] = x; /* ignore overflow */ 215 if (x < 256) /* if no overflow, all done */ 216 break; 217 } 218 des_ecb_encrypt(challenge, challenge, sched, 1); 219 } 220 #endif /* ENCRYPTION */ 221 222 if (auth_debug_mode) { 223 printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); 224 printd(auth.dat, auth.length); 225 printf("\r\n"); 226 printf("Sent Kerberos V4 credentials to server\r\n"); 227 } 228 return(1); 229 } 230 231 void 232 kerberos4_is(ap, data, cnt) 233 Authenticator *ap; 234 unsigned char *data; 235 int cnt; 236 { 237 #ifdef ENCRYPTION 238 Session_Key skey; 239 Block datablock; 240 #endif /* ENCRYPTION */ 241 char realm[REALM_SZ]; 242 char instance[INST_SZ]; 243 int r; 244 245 if (cnt-- < 1) 246 return; 247 switch (*data++) { 248 case KRB_AUTH: 249 if (krb_get_lrealm(realm, 1) != KSUCCESS) { 250 Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1); 251 auth_finished(ap, AUTH_REJECT); 252 if (auth_debug_mode) 253 printf("No local realm\r\n"); 254 return; 255 } 256 bcopy((void *)data, (void *)auth.dat, auth.length = cnt); 257 if (auth_debug_mode) { 258 printf("Got %d bytes of authentication data\r\n", cnt); 259 printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); 260 printd(auth.dat, auth.length); 261 printf("\r\n"); 262 } 263 instance[0] = '*'; instance[1] = 0; 264 if (r = krb_rd_req(&auth, KRB_SERVICE_NAME, 265 instance, 0, &adat, "")) { 266 if (auth_debug_mode) 267 printf("Kerberos failed him as %s\r\n", name); 268 Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1); 269 auth_finished(ap, AUTH_REJECT); 270 return; 271 } 272 #ifdef ENCRYPTION 273 bcopy((void *)adat.session, (void *)session_key, sizeof(Block)); 274 #endif /* ENCRYPTION */ 275 krb_kntoln(&adat, name); 276 277 if (UserNameRequested && !kuserok(&adat, UserNameRequested)) 278 Data(ap, KRB_ACCEPT, (void *)0, 0); 279 else 280 Data(ap, KRB_REJECT, 281 (void *)"user is not authorized", -1); 282 auth_finished(ap, AUTH_USER); 283 break; 284 285 case KRB_CHALLENGE: 286 #ifndef ENCRYPTION 287 Data(ap, KRB_RESPONSE, (void *)0, 0); 288 #else /* ENCRYPTION */ 289 if (!VALIDKEY(session_key)) { 290 /* 291 * We don't have a valid session key, so just 292 * send back a response with an empty session 293 * key. 294 */ 295 Data(ap, KRB_RESPONSE, (void *)0, 0); 296 break; 297 } 298 299 des_key_sched(session_key, sched); 300 bcopy((void *)data, (void *)datablock, sizeof(Block)); 301 /* 302 * Take the received encrypted challenge, and encrypt 303 * it again to get a unique session_key for the 304 * ENCRYPT option. 305 */ 306 des_ecb_encrypt(datablock, session_key, sched, 1); 307 skey.type = SK_DES; 308 skey.length = 8; 309 skey.data = session_key; 310 encrypt_session_key(&skey, 1); 311 /* 312 * Now decrypt the received encrypted challenge, 313 * increment by one, re-encrypt it and send it back. 314 */ 315 des_ecb_encrypt(datablock, challenge, sched, 0); 316 for (r = 7; r >= 0; r++) { 317 register int t; 318 t = (unsigned int)challenge[r] + 1; 319 challenge[r] = t; /* ignore overflow */ 320 if (t < 256) /* if no overflow, all done */ 321 break; 322 } 323 des_ecb_encrypt(challenge, challenge, sched, 1); 324 Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge)); 325 #endif /* ENCRYPTION */ 326 break; 327 328 default: 329 if (auth_debug_mode) 330 printf("Unknown Kerberos option %d\r\n", data[-1]); 331 Data(ap, KRB_REJECT, 0, 0); 332 break; 333 } 334 } 335 336 void 337 kerberos4_reply(ap, data, cnt) 338 Authenticator *ap; 339 unsigned char *data; 340 int cnt; 341 { 342 #ifdef ENCRYPTION 343 Session_Key skey; 344 #endif /* ENCRYPTION */ 345 346 if (cnt-- < 1) 347 return; 348 switch (*data++) { 349 case KRB_REJECT: 350 if (cnt > 0) { 351 printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n", 352 cnt, data); 353 } else 354 printf("[ Kerberos V4 refuses authentication ]\r\n"); 355 auth_send_retry(); 356 return; 357 case KRB_ACCEPT: 358 printf("[ Kerberos V4 accepts you ]\n"); 359 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 360 /* 361 * Send over the encrypted challenge. 362 */ 363 #ifndef ENCRYPTION 364 Data(ap, KRB_CHALLENGE, (void *)0, 0); 365 #else /* ENCRYPTION */ 366 Data(ap, KRB_CHALLENGE, (void *)session_key, 367 sizeof(session_key)); 368 des_ecb_encrypt(session_key, session_key, sched, 1); 369 skey.type = SK_DES; 370 skey.length = 8; 371 skey.data = session_key; 372 encrypt_session_key(&skey, 0); 373 #endif /* ENCRYPTION */ 374 return; 375 } 376 auth_finished(ap, AUTH_USER); 377 return; 378 case KRB_RESPONSE: 379 #ifdef ENCRYPTION 380 /* 381 * Verify that the response to the challenge is correct. 382 */ 383 if ((cnt != sizeof(Block)) || 384 (0 != memcmp((void *)data, (void *)challenge, 385 sizeof(challenge)))) 386 { 387 #endif /* ENCRYPTION */ 388 printf("[ Kerberos V4 challenge failed!!! ]\r\n"); 389 auth_send_retry(); 390 return; 391 #ifdef ENCRYPTION 392 } 393 printf("[ Kerberos V4 challenge successful ]\r\n"); 394 auth_finished(ap, AUTH_USER); 395 #endif /* ENCRYPTION */ 396 break; 397 default: 398 if (auth_debug_mode) 399 printf("Unknown Kerberos option %d\r\n", data[-1]); 400 return; 401 } 402 } 403 404 int 405 kerberos4_status(ap, name, level) 406 Authenticator *ap; 407 char *name; 408 int level; 409 { 410 if (level < AUTH_USER) 411 return(level); 412 413 if (UserNameRequested && !kuserok(&adat, UserNameRequested)) { 414 strcpy(name, UserNameRequested); 415 return(AUTH_VALID); 416 } else 417 return(AUTH_USER); 418 } 419 420 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 421 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 422 423 void 424 kerberos4_printsub(data, cnt, buf, buflen) 425 unsigned char *data, *buf; 426 int cnt, buflen; 427 { 428 char lbuf[32]; 429 register int i; 430 431 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 432 buflen -= 1; 433 434 switch(data[3]) { 435 case KRB_REJECT: /* Rejected (reason might follow) */ 436 strncpy((char *)buf, " REJECT ", buflen); 437 goto common; 438 439 case KRB_ACCEPT: /* Accepted (name might follow) */ 440 strncpy((char *)buf, " ACCEPT ", buflen); 441 common: 442 BUMP(buf, buflen); 443 if (cnt <= 4) 444 break; 445 ADDC(buf, buflen, '"'); 446 for (i = 4; i < cnt; i++) 447 ADDC(buf, buflen, data[i]); 448 ADDC(buf, buflen, '"'); 449 ADDC(buf, buflen, '\0'); 450 break; 451 452 case KRB_AUTH: /* Authentication data follows */ 453 strncpy((char *)buf, " AUTH", buflen); 454 goto common2; 455 456 case KRB_CHALLENGE: 457 strncpy((char *)buf, " CHALLENGE", buflen); 458 goto common2; 459 460 case KRB_RESPONSE: 461 strncpy((char *)buf, " RESPONSE", buflen); 462 goto common2; 463 464 default: 465 sprintf(lbuf, " %d (unknown)", data[3]); 466 strncpy((char *)buf, lbuf, buflen); 467 common2: 468 BUMP(buf, buflen); 469 for (i = 4; i < cnt; i++) { 470 sprintf(lbuf, " %d", data[i]); 471 strncpy((char *)buf, lbuf, buflen); 472 BUMP(buf, buflen); 473 } 474 break; 475 } 476 } 477 478 int 479 kerberos4_cksum(d, n) 480 unsigned char *d; 481 int n; 482 { 483 int ck = 0; 484 485 /* 486 * A comment is probably needed here for those not 487 * well versed in the "C" language. Yes, this is 488 * supposed to be a "switch" with the body of the 489 * "switch" being a "while" statement. The whole 490 * purpose of the switch is to allow us to jump into 491 * the middle of the while() loop, and then not have 492 * to do any more switch()s. 493 * 494 * Some compilers will spit out a warning message 495 * about the loop not being entered at the top. 496 */ 497 switch (n&03) 498 while (n > 0) { 499 case 0: 500 ck ^= (int)*d++ << 24; 501 --n; 502 case 3: 503 ck ^= (int)*d++ << 16; 504 --n; 505 case 2: 506 ck ^= (int)*d++ << 8; 507 --n; 508 case 1: 509 ck ^= (int)*d++; 510 --n; 511 } 512 return(ck); 513 } 514 #endif 515 516 #ifdef notdef 517 518 prkey(msg, key) 519 char *msg; 520 unsigned char *key; 521 { 522 register int i; 523 printf("%s:", msg); 524 for (i = 0; i < 8; i++) 525 printf(" %3d", key[i]); 526 printf("\r\n"); 527 } 528 #endif 529