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.1 (Berkeley) 02/28/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 62 #define KRB_AUTH 0 /* Authentication data follows */ 63 #define KRB_REJECT 1 /* Rejected (reason might follow) */ 64 #define KRB_ACCEPT 2 /* Accepted (name might follow) */ 65 #define KRB_NEWKEY 3 /* New key to use */ 66 #define KRB_NAME 4 /* Name to authenticate for */ 67 68 static krb5_data auth; 69 /* telnetd gets session key from here */ 70 static krb5_tkt_authent *authdat = NULL; 71 72 #if defined(ENCRYPT) 73 Block session_key; 74 #endif 75 76 static int 77 Data(type, d, c) 78 int type; 79 void *d; 80 int c; 81 { 82 unsigned char *p = str_data + 6; 83 unsigned char *cd = (unsigned char *)d; 84 85 if (c == -1) 86 c = strlen(d); 87 88 if (auth_debug_mode) { 89 printf("%s:%d: [%d] (%d)", 90 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 91 str_data[3], 92 type, c); 93 printd(d, c); 94 printf("\r\n"); 95 } 96 *p++ = type; 97 while (c-- > 0) { 98 if ((*p++ = *cd++) == IAC) 99 *p++ = IAC; 100 } 101 *p++ = IAC; 102 *p++ = SE; 103 if (str_data[3] == TELQUAL_IS) 104 printsub('>', &str_data[2], p - &str_data[2]); 105 return(net_write(str_data, p - str_data)); 106 } 107 108 int 109 kerberos5_init(ap, server) 110 Authenticator *ap; 111 int server; 112 { 113 if (server) 114 str_data[3] = TELQUAL_REPLY; 115 else 116 str_data[3] = TELQUAL_IS; 117 str_data[4] = ap->type; 118 str_data[5] = ap->way; 119 krb5_init_ets(); 120 return(1); 121 } 122 123 int 124 kerberos5_send(ap) 125 Authenticator *ap; 126 { 127 char **realms; 128 char *name; 129 char *p1, *p2; 130 krb5_checksum ksum; 131 krb5_octet sum[CRC32_CKSUM_LENGTH]; 132 krb5_data *server[4]; 133 krb5_data srvdata[3]; 134 krb5_error_code r; 135 krb5_ccache ccache; 136 krb5_creds creds; /* telnet gets session key from here */ 137 extern krb5_flags krb5_kdc_default_options; 138 139 ksum.checksum_type = CKSUMTYPE_CRC32; 140 ksum.contents = sum; 141 ksum.length = sizeof(sum); 142 bzero((void *)sum, sizeof(sum)); 143 144 if (!UserNameRequested) { 145 if (auth_debug_mode) { 146 printf("Kerberos V5: no user name supplied\r\n"); 147 } 148 return(0); 149 } 150 151 if (r = krb5_cc_default(&ccache)) { 152 if (auth_debug_mode) { 153 printf("Kerberos V5: could not get default ccache\r\n"); 154 } 155 return(0); 156 } 157 158 if ((name = malloc(strlen(RemoteHostName)+1)) == NULL) { 159 if (auth_debug_mode) 160 printf("Out of memory for hostname in Kerberos V5\r\n"); 161 return(0); 162 } 163 164 if (r = krb5_get_host_realm(RemoteHostName, &realms)) { 165 if (auth_debug_mode) 166 printf("Kerberos V5: no realm for %s\r\n", RemoteHostName); 167 free(name); 168 return(0); 169 } 170 171 p1 = RemoteHostName; 172 p2 = name; 173 174 while (*p2 = *p1++) { 175 if (isupper(*p2)) 176 *p2 |= 040; 177 ++p2; 178 } 179 180 srvdata[0].data = realms[0]; 181 srvdata[0].length = strlen(realms[0]); 182 srvdata[1].data = "rcmd"; 183 srvdata[1].length = 4; 184 srvdata[2].data = name; 185 srvdata[2].length = p2 - name; 186 187 server[0] = &srvdata[0]; 188 server[1] = &srvdata[1]; 189 server[2] = &srvdata[2]; 190 server[3] = 0; 191 192 bzero((char *)&creds, sizeof(creds)); 193 creds.server = (krb5_principal)server; 194 195 if (r = krb5_cc_get_principal(ccache, &creds.client)) { 196 if (auth_debug_mode) { 197 printf("Keberos V5: failure on principal (%d)\r\n", 198 error_message(r)); 199 } 200 free(name); 201 krb5_free_host_realm(realms); 202 return(0); 203 } 204 205 if (r = krb5_get_credentials(krb5_kdc_default_options, ccache, &creds)) { 206 if (auth_debug_mode) { 207 printf("Keberos V5: failure on credentials(%d)\r\n",r); 208 } 209 free(name); 210 krb5_free_host_realm(realms); 211 return(0); 212 } 213 214 r = krb5_mk_req_extended(0, &ksum, &creds.times, 215 krb5_kdc_default_options, 216 ccache, &creds, 0, &auth); 217 218 free(name); 219 krb5_free_host_realm(realms); 220 if (r) { 221 if (auth_debug_mode) { 222 printf("Keberos V5: mk_req failed\r\n"); 223 } 224 return(0); 225 } 226 227 if (!Data(KRB_NAME, (void *)UserNameRequested, -1)) { 228 if (auth_debug_mode) 229 printf("Not enough room for user name\r\n"); 230 return(0); 231 } 232 if (!Data(KRB_AUTH, auth.data, auth.length)) { 233 if (auth_debug_mode) 234 printf("Not enough room for authentication data\r\n"); 235 return(0); 236 } 237 #if defined(ENCRYPT) 238 if (creds.keyblock.keytype == KEYTYPE_DES) { 239 Schedule krb_sched; 240 Block enckey; 241 242 des_key_sched(creds.keyblock.contents, krb_sched); 243 des_set_random_generator_seed(creds.keyblock.contents); 244 des_new_random_key(session_key); 245 des_ecb_encrypt(session_key, enckey, krb_sched, 1); 246 Data(KRB_NEWKEY, (void *)enckey, sizeof(enckey)); 247 } 248 #endif 249 if (auth_debug_mode) { 250 printf("Sent Kerberos V5 credentials to server\r\n"); 251 } 252 return(1); 253 } 254 255 void 256 kerberos5_is(ap, data, cnt) 257 Authenticator *ap; 258 unsigned char *data; 259 int cnt; 260 { 261 int r; 262 struct hostent *hp; 263 char *p1, *p2; 264 static char *realm = NULL; 265 krb5_data *server[4]; 266 krb5_data srvdata[3]; 267 Schedule sched; 268 Session_Key skey; 269 char *name; 270 char *getenv(); 271 272 if (cnt-- < 1) 273 return; 274 switch (*data++) { 275 case KRB_NAME: { 276 char user[256]; 277 278 if (cnt > 255) 279 cnt = 255; 280 strncpy(user, data, cnt); 281 user[cnt] = 0; 282 auth_encrypt_user(user); 283 return; 284 } 285 case KRB_AUTH: 286 auth.data = (char *)data; 287 auth.length = cnt; 288 289 if (!(hp = gethostbyname(LocalHostName))) { 290 if (auth_debug_mode) 291 printf("Cannot resolve local host name\r\n"); 292 Data(KRB_REJECT, "Unknown local hostname.", -1); 293 auth_finished(ap, AUTH_REJECT); 294 return; 295 } 296 297 if (!realm && (krb5_get_default_realm(&realm))) { 298 if (auth_debug_mode) 299 printf("Could not get defualt realm\r\n"); 300 Data(KRB_REJECT, "Could not get default realm.", -1); 301 auth_finished(ap, AUTH_REJECT); 302 return; 303 } 304 305 if ((name = malloc(strlen(hp->h_name)+1)) == NULL) { 306 if (auth_debug_mode) 307 printf("Out of memory for hostname in Kerberos V5\r\n"); 308 Data(KRB_REJECT, "Out of memory.", -1); 309 auth_finished(ap, AUTH_REJECT); 310 return; 311 } 312 313 p1 = hp->h_name; 314 p2 = name; 315 316 while (*p2 = *p1++) { 317 if (isupper(*p2)) 318 *p2 |= 040; 319 ++p2; 320 } 321 322 srvdata[0].data = realm; 323 srvdata[0].length = strlen(realm); 324 srvdata[1].data = "rcmd"; 325 srvdata[1].length = 4; 326 srvdata[2].data = name; 327 srvdata[2].length = p2 - name; 328 329 server[0] = &srvdata[0]; 330 server[1] = &srvdata[1]; 331 server[2] = &srvdata[2]; 332 server[3] = 0; 333 334 if (authdat) 335 krb5_free_tkt_authent(authdat); 336 if (r = krb5_rd_req_simple(&auth, server, 0, &authdat)) { 337 char errbuf[128]; 338 339 authdat = 0; 340 (void) strcpy(errbuf, "Read req failed: "); 341 (void) strcat(errbuf, error_message(r)); 342 Data(KRB_REJECT, errbuf, -1); 343 if (auth_debug_mode) 344 printf("%s\r\n", errbuf); 345 return; 346 } 347 free(name); 348 if (krb5_unparse_name(authdat->ticket->enc_part2 ->client, 349 &name)) 350 name = 0; 351 Data(KRB_ACCEPT, name, name ? -1 : 0); 352 if (auth_debug_mode) { 353 printf("Kerberos5 accepting him as ``%s''\r\n", 354 name ? name : ""); 355 } 356 auth_finished(ap, AUTH_USER); 357 return; 358 case KRB_NEWKEY: 359 #if defined(ENCRYPT) 360 if (authdat && authdat->ticket->enc_part2->session->keytype 361 == KEYTYPE_DES) 362 { 363 des_key_sched(authdat->ticket->enc_part2->session 364 ->contents, sched); 365 des_ecb_encrypt(data, session_key, sched, 0); 366 skey.type = SK_DES; 367 skey.length = 8; 368 skey.data = session_key; 369 encrypt_session_key(&skey, 1); 370 } 371 #endif 372 return; 373 default: 374 if (auth_debug_mode) 375 printf("Unknown Kerberos option %d\r\n", data[-1]); 376 Data(KRB_REJECT, 0, 0); 377 return; 378 } 379 } 380 381 void 382 kerberos5_reply(ap, data, cnt) 383 Authenticator *ap; 384 unsigned char *data; 385 int cnt; 386 { 387 Session_Key skey; 388 389 if (cnt-- < 1) 390 return; 391 switch (*data++) { 392 case KRB_REJECT: 393 if (cnt > 0) { 394 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 395 cnt, data); 396 } else 397 printf("[ Kerberos V5 refuses authentication ]\r\n"); 398 auth_send_retry(); 399 return; 400 case KRB_ACCEPT: 401 if (cnt > 0) { 402 printf("[ Kerberos V5 accepts you as %.*s ]\n", cnt, data); 403 } else 404 printf("[ Kerberos V5 accepts you ]\n", cnt, data); 405 #if defined(ENCRYPT) 406 skey.type = SK_DES; 407 skey.length = 8; 408 skey.data = session_key; 409 encrypt_session_key(&skey, 0); 410 #endif 411 auth_finished(ap, AUTH_USER); 412 return; 413 default: 414 if (auth_debug_mode) 415 printf("Unknown Kerberos option %d\r\n", data[-1]); 416 return; 417 } 418 } 419 420 int 421 kerberos5_status(ap, name, level) 422 Authenticator *ap; 423 char *name; 424 int level; 425 { 426 if (level < AUTH_USER) 427 return(level); 428 429 if (UserNameRequested && 430 krb5_kuserok(authdat->ticket->enc_part2->client, UserNameRequested)) 431 { 432 strcpy(name, UserNameRequested); 433 return(AUTH_VALID); 434 } else 435 return(AUTH_USER); 436 } 437 438 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 439 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len));} 440 441 void 442 kerberos5_printsub(data, cnt, buf, buflen) 443 unsigned char *data, *buf; 444 int cnt, buflen; 445 { 446 char lbuf[32]; 447 register int i; 448 449 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 450 buflen -= 1; 451 452 switch(data[3]) { 453 case KRB_NAME: /* Name to authenticate for */ 454 strncpy(buf, " NAME ", buflen); 455 goto common; 456 457 case KRB_REJECT: /* Rejected (reason might follow) */ 458 strncpy(buf, " REJECT ", buflen); 459 goto common; 460 461 case KRB_ACCEPT: /* Accepted (name might follow) */ 462 strncpy(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(buf, " AUTH", buflen); 476 goto common2; 477 478 case KRB_NEWKEY: /* A new session key follows */ 479 strncpy(buf, " NEWKEY", buflen); 480 goto common2; 481 482 default: 483 sprintf(lbuf, " %d (unknown)", data[3]); 484 strncpy(buf, lbuf, buflen); 485 common2: 486 BUMP(buf, buflen); 487 for (i = 4; i < cnt; i++) { 488 sprintf(lbuf, " %d", data[i]); 489 strncpy(buf, lbuf, buflen); 490 BUMP(buf, buflen); 491 } 492 break; 493 } 494 } 495 #endif 496