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