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.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 #ifdef KRB4 33 #include <sys/types.h> 34 #include <arpa/telnet.h> 35 #include <stdio.h> 36 #if defined(ENCRYPT) 37 #define __NEED_ENCRYPT__ 38 #undef ENCRYPT 39 #endif 40 #include <des.h> /* BSD wont include this in krb.h, so we do it here */ 41 #include <krb.h> 42 #if defined(__NEED_ENCRYPT__) && !defined(ENCRYPT) 43 #define ENCRYPT 44 #undef __NEED_ENCRYPT__ 45 #endif 46 #ifdef __STDC__ 47 #include <stdlib.h> 48 #endif 49 #ifdef NO_STRING_H 50 #include <strings.h> 51 #else 52 #include <string.h> 53 #endif 54 55 #include "encrypt.h" 56 #include "auth.h" 57 #include "misc.h" 58 59 int cksum P((unsigned char *, int)); 60 int krb_mk_req P((KTEXT, char *, char *, char *, u_long)); 61 int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *)); 62 int krb_kntoln P((AUTH_DAT *, char *)); 63 int krb_get_cred P((char *, char *, char *, CREDENTIALS *)); 64 int krb_get_lrealm P((char *, int)); 65 int kuserok P((AUTH_DAT *, char *)); 66 67 extern auth_debug_mode; 68 69 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, 70 AUTHTYPE_KERBEROS_V4, }; 71 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 72 TELQUAL_NAME, }; 73 74 #define KRB_AUTH 0 /* Authentication data follows */ 75 #define KRB_REJECT 1 /* Rejected (reason might follow) */ 76 #define KRB_ACCEPT 2 /* Accepted */ 77 #define KRB_CHALLANGE 3 /* Challange for mutual auth. */ 78 #define KRB_RESPONSE 4 /* Response for mutual auth. */ 79 80 static KTEXT_ST auth; 81 static char name[ANAME_SZ]; 82 static AUTH_DAT adat = { 0 }; 83 #if defined(ENCRYPT) 84 static Block session_key = { 0 }; 85 #endif 86 static Schedule sched; 87 static Block challange = { 0 }; 88 89 static int 90 Data(ap, type, d, c) 91 Authenticator *ap; 92 int type; 93 void *d; 94 int c; 95 { 96 unsigned char *p = str_data + 4; 97 unsigned char *cd = (unsigned char *)d; 98 99 if (c == -1) 100 c = strlen((char *)cd); 101 102 if (auth_debug_mode) { 103 printf("%s:%d: [%d] (%d)", 104 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 105 str_data[3], 106 type, c); 107 printd(d, c); 108 printf("\r\n"); 109 } 110 *p++ = ap->type; 111 *p++ = ap->way; 112 *p++ = type; 113 while (c-- > 0) { 114 if ((*p++ = *cd++) == IAC) 115 *p++ = IAC; 116 } 117 *p++ = IAC; 118 *p++ = SE; 119 if (str_data[3] == TELQUAL_IS) 120 printsub('>', &str_data[2], p - (&str_data[2])); 121 return(net_write(str_data, p - str_data)); 122 } 123 124 int 125 kerberos4_init(ap, server) 126 Authenticator *ap; 127 int server; 128 { 129 if (server) 130 str_data[3] = TELQUAL_REPLY; 131 else 132 str_data[3] = TELQUAL_IS; 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 if (!UserNameRequested) { 153 if (auth_debug_mode) { 154 printf("Kerberos V4: no user name supplied\r\n"); 155 } 156 return(0); 157 } 158 159 bzero(instance, sizeof(instance)); 160 if (realm = krb_get_phost(RemoteHostName)) 161 strncpy(instance, realm, sizeof(instance)); 162 instance[sizeof(instance)-1] = '\0'; 163 164 realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName); 165 if (!realm) { 166 if (auth_debug_mode) { 167 printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); 168 } 169 return(0); 170 } 171 if (r = krb_mk_req(&auth, "rcmd", instance, realm, 0L)) { 172 if (auth_debug_mode) { 173 printf("mk_req failed: %s\r\n", krb_err_txt[r]); 174 } 175 return(0); 176 } 177 if (r = krb_get_cred("rcmd", instance, realm, &cred)) { 178 if (auth_debug_mode) { 179 printf("get_cred failed: %s\r\n", krb_err_txt[r]); 180 } 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 /* 196 * If we are doing mutual authentication, get set up to send 197 * the challange, and verify it when the response comes back. 198 */ 199 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 200 register int i; 201 202 des_key_sched(cred.session, sched); 203 des_set_random_generator_seed(cred.session); 204 des_new_random_key(challange); 205 des_ecb_encrypt(challange, session_key, sched, 1); 206 /* 207 * Increment the challange by 1, and encrypt it for 208 * later comparison. 209 */ 210 for (i = 7; i >= 0; --i) { 211 register int x; 212 x = (unsigned int)challange[i] + 1; 213 challange[i] = x; /* ignore overflow */ 214 if (x < 256) /* if no overflow, all done */ 215 break; 216 } 217 des_ecb_encrypt(challange, challange, sched, 1); 218 } 219 220 if (auth_debug_mode) { 221 printf("CK: %d:", 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:", 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, "rcmd", instance, 0, &adat, "")) { 261 if (auth_debug_mode) 262 printf("Kerberos failed him as %s\r\n", name); 263 Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1); 264 auth_finished(ap, AUTH_REJECT); 265 return; 266 } 267 bcopy((void *)adat.session, (void *)session_key, sizeof(Block)); 268 krb_kntoln(&adat, name); 269 Data(ap, KRB_ACCEPT, (void *)0, 0); 270 auth_finished(ap, AUTH_USER); 271 if (auth_debug_mode) { 272 printf("Kerberos accepting him as %s\r\n", name); 273 } 274 break; 275 276 case KRB_CHALLANGE: 277 if (!VALIDKEY(session_key)) { 278 /* 279 * We don't have a valid session key, so just 280 * send back a response with an empty session 281 * key. 282 */ 283 Data(ap, KRB_RESPONSE, (void *)0, 0); 284 break; 285 } 286 287 des_key_sched(session_key, sched); 288 bcopy((void *)data, (void *)datablock, sizeof(Block)); 289 /* 290 * Take the received encrypted challange, and encrypt 291 * it again to get a unique session_key for the 292 * ENCRYPT option. 293 */ 294 des_ecb_encrypt(datablock, session_key, sched, 1); 295 skey.type = SK_DES; 296 skey.length = 8; 297 skey.data = session_key; 298 encrypt_session_key(&skey, 1); 299 /* 300 * Now decrypt the received encrypted challange, 301 * increment by one, re-encrypt it and send it back. 302 */ 303 des_ecb_encrypt(datablock, challange, sched, 0); 304 for (r = 7; r >= 0; r++) { 305 register int t; 306 t = (unsigned int)challange[r] + 1; 307 challange[r] = t; /* ignore overflow */ 308 if (t < 256) /* if no overflow, all done */ 309 break; 310 } 311 des_ecb_encrypt(challange, challange, sched, 1); 312 Data(ap, KRB_RESPONSE, (void *)challange, sizeof(challange)); 313 break; 314 315 default: 316 if (auth_debug_mode) 317 printf("Unknown Kerberos option %d\r\n", data[-1]); 318 Data(ap, KRB_REJECT, 0, 0); 319 break; 320 } 321 } 322 323 void 324 kerberos4_reply(ap, data, cnt) 325 Authenticator *ap; 326 unsigned char *data; 327 int cnt; 328 { 329 Session_Key skey; 330 331 if (cnt-- < 1) 332 return; 333 switch (*data++) { 334 case KRB_REJECT: 335 if (cnt > 0) { 336 printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n", 337 cnt, data); 338 } else 339 printf("[ Kerberos V4 refuses authentication ]\r\n"); 340 auth_send_retry(); 341 return; 342 case KRB_ACCEPT: 343 printf("[ Kerberos V4 accepts you ]\n"); 344 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 345 /* 346 * Send over the encrypted challange. 347 */ 348 Data(ap, KRB_CHALLANGE, (void *)session_key, 349 sizeof(session_key)); 350 #if defined(ENCRYPT) 351 des_ecb_encrypt(session_key, session_key, sched, 1); 352 skey.type = SK_DES; 353 skey.length = 8; 354 skey.data = session_key; 355 encrypt_session_key(&skey, 0); 356 #endif 357 return; 358 } 359 auth_finished(ap, AUTH_USER); 360 return; 361 case KRB_RESPONSE: 362 /* 363 * Verify that the response to the challange is correct. 364 */ 365 if ((cnt != sizeof(Block)) || 366 (0 != memcmp((void *)data, (void *)challange, 367 sizeof(challange)))) 368 { 369 printf("[ Kerberos V4 challange failed!!! ]\r\n"); 370 auth_send_retry(); 371 return; 372 } 373 printf("[ Kerberos V4 challange successful ]\r\n"); 374 auth_finished(ap, AUTH_USER); 375 break; 376 default: 377 if (auth_debug_mode) 378 printf("Unknown Kerberos option %d\r\n", data[-1]); 379 return; 380 } 381 } 382 383 int 384 kerberos4_status(ap, name, level) 385 Authenticator *ap; 386 char *name; 387 int level; 388 { 389 if (level < AUTH_USER) 390 return(level); 391 392 if (UserNameRequested && !kuserok(&adat, UserNameRequested)) { 393 strcpy(name, UserNameRequested); 394 return(AUTH_VALID); 395 } else 396 return(AUTH_USER); 397 } 398 399 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 400 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 401 402 void 403 kerberos4_printsub(data, cnt, buf, buflen) 404 unsigned char *data, *buf; 405 int cnt, buflen; 406 { 407 char lbuf[32]; 408 register int i; 409 410 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 411 buflen -= 1; 412 413 switch(data[3]) { 414 case KRB_REJECT: /* Rejected (reason might follow) */ 415 strncpy((char *)buf, " REJECT ", buflen); 416 goto common; 417 418 case KRB_ACCEPT: /* Accepted (name might follow) */ 419 strncpy((char *)buf, " ACCEPT ", buflen); 420 common: 421 BUMP(buf, buflen); 422 if (cnt <= 4) 423 break; 424 ADDC(buf, buflen, '"'); 425 for (i = 4; i < cnt; i++) 426 ADDC(buf, buflen, data[i]); 427 ADDC(buf, buflen, '"'); 428 ADDC(buf, buflen, '\0'); 429 break; 430 431 case KRB_AUTH: /* Authentication data follows */ 432 strncpy((char *)buf, " AUTH", buflen); 433 goto common2; 434 435 case KRB_CHALLANGE: 436 strncpy((char *)buf, " CHALLANGE", buflen); 437 goto common2; 438 439 case KRB_RESPONSE: 440 strncpy((char *)buf, " RESPONSE", buflen); 441 goto common2; 442 443 default: 444 sprintf(lbuf, " %d (unknown)", data[3]); 445 strncpy((char *)buf, lbuf, buflen); 446 common2: 447 BUMP(buf, buflen); 448 for (i = 4; i < cnt; i++) { 449 sprintf(lbuf, " %d", data[i]); 450 strncpy((char *)buf, lbuf, buflen); 451 BUMP(buf, buflen); 452 } 453 break; 454 } 455 } 456 457 int 458 cksum(d, n) 459 unsigned char *d; 460 int n; 461 { 462 int ck = 0; 463 464 switch (n&03) 465 while (n > 0) { 466 case 0: 467 ck ^= *d++ << 24; 468 --n; 469 case 3: 470 ck ^= *d++ << 16; 471 --n; 472 case 2: 473 ck ^= *d++ << 8; 474 --n; 475 case 1: 476 ck ^= *d++; 477 --n; 478 } 479 return(ck); 480 } 481 #endif 482 483 #ifdef notdef 484 485 prkey(msg, key) 486 char *msg; 487 unsigned char *key; 488 { 489 register int i; 490 printf("%s:", msg); 491 for (i = 0; i < 8; i++) 492 printf(" %3d", key[i]); 493 printf("\r\n"); 494 } 495 #endif 496