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