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