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[] = "@(#)kerberos5.c 5.2 (Berkeley) 03/22/91"; 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 33 #ifdef KRB5 34 #include <arpa/telnet.h> 35 #include <stdio.h> 36 #include <krb5/krb5.h> 37 #include <krb5/crc-32.h> 38 #include <krb5/libos-proto.h> 39 #include <netdb.h> 40 #include <ctype.h> 41 42 #ifdef __STDC__ 43 #include <stdlib.h> 44 #endif 45 #ifdef NO_STRING_H 46 #include <strings.h> 47 #else 48 #include <string.h> 49 #endif 50 51 #include "encrypt.h" 52 #include "auth.h" 53 #include "misc.h" 54 55 extern auth_debug_mode; 56 57 char *malloc(); 58 59 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, 60 AUTHTYPE_KERBEROS_V5, }; 61 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 62 TELQUAL_NAME, }; 63 64 #define KRB_AUTH 0 /* Authentication data follows */ 65 #define KRB_REJECT 1 /* Rejected (reason might follow) */ 66 #define KRB_ACCEPT 2 /* Accepted */ 67 #define KRB_CHALLANGE 3 /* Challange for mutual auth. */ 68 #define KRB_RESPONSE 4 /* Response for mutual auth. */ 69 70 static krb5_data auth; 71 /* telnetd gets session key from here */ 72 static krb5_tkt_authent *authdat = NULL; 73 74 #if defined(ENCRYPT) 75 Block session_key; 76 #endif 77 static Schedule sched; 78 static Block challange; 79 80 static int 81 Data(ap, type, d, c) 82 Authenticator *ap; 83 int type; 84 void *d; 85 int c; 86 { 87 unsigned char *p = str_data + 4; 88 unsigned char *cd = (unsigned char *)d; 89 90 if (c == -1) 91 c = strlen((char *)cd); 92 93 if (auth_debug_mode) { 94 printf("%s:%d: [%d] (%d)", 95 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 96 str_data[3], 97 type, c); 98 printd(d, c); 99 printf("\r\n"); 100 } 101 *p++ = ap->type; 102 *p++ = ap->way; 103 *p++ = type; 104 while (c-- > 0) { 105 if ((*p++ = *cd++) == IAC) 106 *p++ = IAC; 107 } 108 *p++ = IAC; 109 *p++ = SE; 110 if (str_data[3] == TELQUAL_IS) 111 printsub('>', &str_data[2], p - &str_data[2]); 112 return(net_write(str_data, p - str_data)); 113 } 114 115 int 116 kerberos5_init(ap, server) 117 Authenticator *ap; 118 int server; 119 { 120 if (server) 121 str_data[3] = TELQUAL_REPLY; 122 else 123 str_data[3] = TELQUAL_IS; 124 krb5_init_ets(); 125 return(1); 126 } 127 128 int 129 kerberos5_send(ap) 130 Authenticator *ap; 131 { 132 char **realms; 133 char *name; 134 char *p1, *p2; 135 krb5_checksum ksum; 136 krb5_octet sum[CRC32_CKSUM_LENGTH]; 137 krb5_data *server[4]; 138 krb5_data srvdata[3]; 139 krb5_error_code r; 140 krb5_ccache ccache; 141 krb5_creds creds; /* telnet gets session key from here */ 142 extern krb5_flags krb5_kdc_default_options; 143 144 ksum.checksum_type = CKSUMTYPE_CRC32; 145 ksum.contents = sum; 146 ksum.length = sizeof(sum); 147 bzero((void *)sum, sizeof(sum)); 148 149 if (!UserNameRequested) { 150 if (auth_debug_mode) { 151 printf("Kerberos V5: no user name supplied\r\n"); 152 } 153 return(0); 154 } 155 156 if (r = krb5_cc_default(&ccache)) { 157 if (auth_debug_mode) { 158 printf("Kerberos V5: could not get default ccache\r\n"); 159 } 160 return(0); 161 } 162 163 if ((name = malloc(strlen(RemoteHostName)+1)) == NULL) { 164 if (auth_debug_mode) 165 printf("Out of memory for hostname in Kerberos V5\r\n"); 166 return(0); 167 } 168 169 if (r = krb5_get_host_realm(RemoteHostName, &realms)) { 170 if (auth_debug_mode) 171 printf("Kerberos V5: no realm for %s\r\n", RemoteHostName); 172 free(name); 173 return(0); 174 } 175 176 p1 = RemoteHostName; 177 p2 = name; 178 179 while (*p2 = *p1++) { 180 if (isupper(*p2)) 181 *p2 |= 040; 182 ++p2; 183 } 184 185 srvdata[0].data = realms[0]; 186 srvdata[0].length = strlen(realms[0]); 187 srvdata[1].data = "rcmd"; 188 srvdata[1].length = 4; 189 srvdata[2].data = name; 190 srvdata[2].length = p2 - name; 191 192 server[0] = &srvdata[0]; 193 server[1] = &srvdata[1]; 194 server[2] = &srvdata[2]; 195 server[3] = 0; 196 197 bzero((char *)&creds, sizeof(creds)); 198 creds.server = (krb5_principal)server; 199 200 if (r = krb5_cc_get_principal(ccache, &creds.client)) { 201 if (auth_debug_mode) { 202 printf("Keberos V5: failure on principal (%d)\r\n", 203 error_message(r)); 204 } 205 free(name); 206 krb5_free_host_realm(realms); 207 return(0); 208 } 209 210 if (r = krb5_get_credentials(krb5_kdc_default_options, ccache, &creds)) { 211 if (auth_debug_mode) { 212 printf("Keberos V5: failure on credentials(%d)\r\n",r); 213 } 214 free(name); 215 krb5_free_host_realm(realms); 216 return(0); 217 } 218 219 r = krb5_mk_req_extended(0, &ksum, &creds.times, 220 krb5_kdc_default_options, 221 ccache, &creds, 0, &auth); 222 223 free(name); 224 krb5_free_host_realm(realms); 225 if (r) { 226 if (auth_debug_mode) { 227 printf("Keberos V5: mk_req failed\r\n"); 228 } 229 return(0); 230 } 231 232 if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { 233 if (auth_debug_mode) 234 printf("Not enough room for user name\r\n"); 235 return(0); 236 } 237 if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 238 if (auth_debug_mode) 239 printf("Not enough room for authentication data\r\n"); 240 return(0); 241 } 242 /* 243 * If we are doing mutual authentication, get set up to send 244 * the challange, and verify it when the response comes back. 245 */ 246 if (((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 247 && (creds.keyblock.keytype == KEYTYPE_DES)) { 248 register int i; 249 250 des_key_sched(creds.keyblock.contents, sched); 251 des_set_random_generator_seed(creds.keyblock.contents); 252 des_new_random_key(challange); 253 des_ecb_encrypt(challange, session_key, sched, 1); 254 /* 255 * Increment the challange by 1, and encrypt it for 256 * later comparison. 257 */ 258 for (i = 7; i >= 0; --i) { 259 register int x; 260 x = (unsigned int)challange[i] + 1; 261 challange[i] = x; /* ignore overflow */ 262 if (x < 256) /* if no overflow, all done */ 263 break; 264 } 265 des_ecb_encrypt(challange, challange, sched, 1); 266 } 267 268 if (auth_debug_mode) { 269 printf("Sent Kerberos V5 credentials to server\r\n"); 270 } 271 return(1); 272 } 273 274 void 275 kerberos5_is(ap, data, cnt) 276 Authenticator *ap; 277 unsigned char *data; 278 int cnt; 279 { 280 int r; 281 struct hostent *hp; 282 char *p1, *p2; 283 static char *realm = NULL; 284 krb5_data *server[4]; 285 krb5_data srvdata[3]; 286 Session_Key skey; 287 char *name; 288 char *getenv(); 289 290 if (cnt-- < 1) 291 return; 292 switch (*data++) { 293 case KRB_AUTH: 294 auth.data = (char *)data; 295 auth.length = cnt; 296 297 if (!(hp = gethostbyname(LocalHostName))) { 298 if (auth_debug_mode) 299 printf("Cannot resolve local host name\r\n"); 300 Data(ap, KRB_REJECT, "Unknown local hostname.", -1); 301 auth_finished(ap, AUTH_REJECT); 302 return; 303 } 304 305 if (!realm && (krb5_get_default_realm(&realm))) { 306 if (auth_debug_mode) 307 printf("Could not get defualt realm\r\n"); 308 Data(ap, KRB_REJECT, "Could not get default realm.", -1); 309 auth_finished(ap, AUTH_REJECT); 310 return; 311 } 312 313 if ((name = malloc(strlen(hp->h_name)+1)) == NULL) { 314 if (auth_debug_mode) 315 printf("Out of memory for hostname in Kerberos V5\r\n"); 316 Data(ap, KRB_REJECT, "Out of memory.", -1); 317 auth_finished(ap, AUTH_REJECT); 318 return; 319 } 320 321 p1 = hp->h_name; 322 p2 = name; 323 324 while (*p2 = *p1++) { 325 if (isupper(*p2)) 326 *p2 |= 040; 327 ++p2; 328 } 329 330 srvdata[0].data = realm; 331 srvdata[0].length = strlen(realm); 332 srvdata[1].data = "rcmd"; 333 srvdata[1].length = 4; 334 srvdata[2].data = name; 335 srvdata[2].length = p2 - name; 336 337 server[0] = &srvdata[0]; 338 server[1] = &srvdata[1]; 339 server[2] = &srvdata[2]; 340 server[3] = 0; 341 342 if (authdat) 343 krb5_free_tkt_authent(authdat); 344 if (r = krb5_rd_req_simple(&auth, server, 0, &authdat)) { 345 char errbuf[128]; 346 347 authdat = 0; 348 (void) strcpy(errbuf, "Read req failed: "); 349 (void) strcat(errbuf, error_message(r)); 350 Data(ap, KRB_REJECT, errbuf, -1); 351 if (auth_debug_mode) 352 printf("%s\r\n", errbuf); 353 return; 354 } 355 free(name); 356 if (krb5_unparse_name(authdat->ticket->enc_part2 ->client, 357 &name)) 358 name = 0; 359 Data(ap, KRB_ACCEPT, name, name ? -1 : 0); 360 if (auth_debug_mode) { 361 printf("Kerberos5 accepting him as ``%s''\r\n", 362 name ? name : ""); 363 } 364 auth_finished(ap, AUTH_USER); 365 if (authdat->ticket->enc_part2->session->keytype != KEYTYPE_DES) 366 break; 367 bcopy((void *)authdat->ticket->enc_part2->session->contents, 368 (void *)session_key, sizeof(Block)); 369 break; 370 371 case KRB_CHALLANGE: 372 if (!VALIDKEY(session_key)) { 373 /* 374 * We don't have a valid session key, so just 375 * send back a response with an empty session 376 * key. 377 */ 378 Data(ap, KRB_RESPONSE, (void *)0, 0); 379 break; 380 } 381 382 des_key_sched(session_key, sched); 383 bcopy((void *)data, (void *)datablock, sizeof(Block)); 384 /* 385 * Take the received encrypted challange, and encrypt 386 * it again to get a unique session_key for the 387 * ENCRYPT option. 388 */ 389 des_ecb_encrypt(datablock, session_key, sched, 1); 390 skey.type = SK_DES; 391 skey.length = 8; 392 skey.data = session_key; 393 encrypt_session_key(&skey, 1); 394 /* 395 * Now decrypt the received encrypted challange, 396 * increment by one, re-encrypt it and send it back. 397 */ 398 des_ecb_encrypt(datablock, challange, sched, 0); 399 for (r = 7; r >= 0; r++) { 400 register int t; 401 t = (unsigned int)challange[r] + 1; 402 challange[r] = t; /* ignore overflow */ 403 if (t < 256) /* if no overflow, all done */ 404 break; 405 } 406 des_ecb_encrypt(challange, challange, sched, 1); 407 Data(ap, KRB_RESPONSE, (void *)challange, sizeof(challange)); 408 break; 409 410 default: 411 if (auth_debug_mode) 412 printf("Unknown Kerberos option %d\r\n", data[-1]); 413 Data(ap, KRB_REJECT, 0, 0); 414 break; 415 } 416 } 417 418 void 419 kerberos5_reply(ap, data, cnt) 420 Authenticator *ap; 421 unsigned char *data; 422 int cnt; 423 { 424 Session_Key skey; 425 426 if (cnt-- < 1) 427 return; 428 switch (*data++) { 429 case KRB_REJECT: 430 if (cnt > 0) { 431 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 432 cnt, data); 433 } else 434 printf("[ Kerberos V5 refuses authentication ]\r\n"); 435 auth_send_retry(); 436 return; 437 case KRB_ACCEPT: 438 printf("[ Kerberos V5 accepts you ]\n", cnt, data); 439 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 440 /* 441 * Send over the encrypted challange. 442 */ 443 Data(ap, KRB_CHALLANGE, (void *)session_key, 444 sizeof(session_key)); 445 #if defined(ENCRYPT) 446 des_ecb_encrypt(session_key, session_key, sched, 1); 447 skey.type = SK_DES; 448 skey.length = 8; 449 skey.data = session_key; 450 encrypt_session_key(&skey, 0); 451 #endif 452 return; 453 } 454 auth_finished(ap, AUTH_USER); 455 return; 456 case KRB_RESPONSE: 457 /* 458 * Verify that the response to the challange is correct. 459 */ 460 if ((cnt != sizeof(Block)) || 461 (0 != memcmp((void *)data, (void *)challange, 462 sizeof(challange)))) 463 { 464 printf("[ Kerberos V5 challange failed!!! ]\r\n"); 465 auth_send_retry(); 466 return; 467 } 468 printf("[ Kerberos V5 challange successful ]\r\n"); 469 auth_finished(ap, AUTH_USER); 470 break; 471 default: 472 if (auth_debug_mode) 473 printf("Unknown Kerberos option %d\r\n", data[-1]); 474 return; 475 } 476 } 477 478 int 479 kerberos5_status(ap, name, level) 480 Authenticator *ap; 481 char *name; 482 int level; 483 { 484 if (level < AUTH_USER) 485 return(level); 486 487 if (UserNameRequested && 488 krb5_kuserok(authdat->ticket->enc_part2->client, UserNameRequested)) 489 { 490 strcpy(name, UserNameRequested); 491 return(AUTH_VALID); 492 } else 493 return(AUTH_USER); 494 } 495 496 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 497 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len));} 498 499 void 500 kerberos5_printsub(data, cnt, buf, buflen) 501 unsigned char *data, *buf; 502 int cnt, buflen; 503 { 504 char lbuf[32]; 505 register int i; 506 507 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 508 buflen -= 1; 509 510 switch(data[3]) { 511 case KRB_REJECT: /* Rejected (reason might follow) */ 512 strncpy((char *)buf, " REJECT ", buflen); 513 goto common; 514 515 case KRB_ACCEPT: /* Accepted (name might follow) */ 516 strncpy((char *)buf, " ACCEPT ", buflen); 517 common: 518 BUMP(buf, buflen); 519 if (cnt <= 4) 520 break; 521 ADDC(buf, buflen, '"'); 522 for (i = 4; i < cnt; i++) 523 ADDC(buf, buflen, data[i]); 524 ADDC(buf, buflen, '"'); 525 ADDC(buf, buflen, '\0'); 526 break; 527 528 case KRB_AUTH: /* Authentication data follows */ 529 strncpy((char *)buf, " AUTH", buflen); 530 goto common2; 531 532 case KRB_CHALLANGE: 533 strncpy((char *)buf, " CHALLANGE", buflen); 534 goto common2; 535 536 case KRB_RESPONSE: 537 strncpy((char *)buf, " RESPONSE", buflen); 538 goto common2; 539 540 default: 541 sprintf(lbuf, " %d (unknown)", data[3]); 542 strncpy((char *)buf, lbuf, buflen); 543 common2: 544 BUMP(buf, buflen); 545 for (i = 4; i < cnt; i++) { 546 sprintf(lbuf, " %d", data[i]); 547 strncpy((char *)buf, lbuf, buflen); 548 BUMP(buf, buflen); 549 } 550 break; 551 } 552 } 553 #endif 554