1 /* $NetBSD: spx.c,v 1.7 2005/04/19 03:19:46 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)spx.c 8.2 (Berkeley) 5/30/95"; 37 #else 38 __RCSID("$NetBSD: spx.c,v 1.7 2005/04/19 03:19:46 christos Exp $"); 39 #endif 40 #endif /* not lint */ 41 42 #ifdef SPX 43 /* 44 * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION 45 * ALL RIGHTS RESERVED 46 * 47 * "Digital Equipment Corporation authorizes the reproduction, 48 * distribution and modification of this software subject to the following 49 * restrictions: 50 * 51 * 1. Any partial or whole copy of this software, or any modification 52 * thereof, must include this copyright notice in its entirety. 53 * 54 * 2. This software is supplied "as is" with no warranty of any kind, 55 * expressed or implied, for any purpose, including any warranty of fitness 56 * or merchantibility. DIGITAL assumes no responsibility for the use or 57 * reliability of this software, nor promises to provide any form of 58 * support for it on any basis. 59 * 60 * 3. Distribution of this software is authorized only if no profit or 61 * remuneration of any kind is received in exchange for such distribution. 62 * 63 * 4. This software produces public key authentication certificates 64 * bearing an expiration date established by DIGITAL and RSA Data 65 * Security, Inc. It may cease to generate certificates after the expiration 66 * date. Any modification of this software that changes or defeats 67 * the expiration date or its effect is unauthorized. 68 * 69 * 5. Software that will renew or extend the expiration date of 70 * authentication certificates produced by this software may be obtained 71 * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA 72 * 94065, (415)595-8782, or from DIGITAL" 73 * 74 */ 75 76 #include <sys/types.h> 77 #include <arpa/telnet.h> 78 #include <stdio.h> 79 #include "gssapi_defs.h" 80 #include <stdlib.h> 81 #ifdef NO_STRING_H 82 #include <strings.h> 83 #else 84 #include <string.h> 85 #endif 86 87 #include <pwd.h> 88 #include "encrypt.h" 89 #include "auth.h" 90 #include "misc.h" 91 92 extern auth_debug_mode; 93 94 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, 95 AUTHTYPE_SPX, }; 96 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 97 TELQUAL_NAME, }; 98 99 #define SPX_AUTH 0 /* Authentication data follows */ 100 #define SPX_REJECT 1 /* Rejected (reason might follow) */ 101 #define SPX_ACCEPT 2 /* Accepted */ 102 103 #ifdef ENCRYPTION 104 static Block session_key = { 0 }; 105 #endif /* ENCRYPTION */ 106 static Schedule sched; 107 static Block challenge = { 0 }; 108 109 110 /*******************************************************************/ 111 112 gss_OID_set actual_mechs; 113 gss_OID actual_mech_type, output_name_type; 114 int major_status, status, msg_ctx = 0, new_status; 115 int req_flags = 0, ret_flags, lifetime_rec; 116 gss_cred_id_t gss_cred_handle; 117 gss_ctx_id_t actual_ctxhandle, context_handle; 118 gss_buffer_desc output_token, input_token, input_name_buffer; 119 gss_buffer_desc status_string; 120 gss_name_t desired_targname, src_name; 121 gss_channel_bindings input_chan_bindings; 122 char lhostname[GSS_C_MAX_PRINTABLE_NAME]; 123 char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; 124 int to_addr=0, from_addr=0; 125 char *address; 126 gss_buffer_desc fullname_buffer; 127 gss_OID fullname_type; 128 gss_cred_id_t gss_delegated_cred_handle; 129 130 /*******************************************************************/ 131 132 133 134 static int 135 Data(ap, type, d, c) 136 Authenticator *ap; 137 int type; 138 void *d; 139 int c; 140 { 141 unsigned char *p = str_data + 4; 142 unsigned char *cd = (unsigned char *)d; 143 144 if (c == -1) 145 c = strlen((char *)cd); 146 147 if (0) { 148 printf("%s:%d: [%d] (%d)", 149 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 150 str_data[3], 151 type, c); 152 printd(d, c); 153 printf("\r\n"); 154 } 155 *p++ = ap->type; 156 *p++ = ap->way; 157 *p++ = type; 158 while (c-- > 0) { 159 if ((*p++ = *cd++) == IAC) 160 *p++ = IAC; 161 } 162 *p++ = IAC; 163 *p++ = SE; 164 if (str_data[3] == TELQUAL_IS) 165 printsub('>', &str_data[2], p - (&str_data[2])); 166 return(telnet_net_write(str_data, p - str_data)); 167 } 168 169 int 170 spx_init(ap, server) 171 Authenticator *ap; 172 int server; 173 { 174 gss_cred_id_t tmp_cred_handle; 175 176 if (server) { 177 str_data[3] = TELQUAL_REPLY; 178 gethostname(lhostname, sizeof(lhostname)); 179 strlcpy(targ_printable, "SERVICE:rcmd@", 180 sizeof(targ_printable)); 181 strlcat(targ_printable, lhostname, sizeof(targ_printable)); 182 input_name_buffer.length = strlen(targ_printable); 183 input_name_buffer.value = targ_printable; 184 major_status = gss_import_name(&status, 185 &input_name_buffer, 186 GSS_C_NULL_OID, 187 &desired_targname); 188 major_status = gss_acquire_cred(&status, 189 desired_targname, 190 0, 191 GSS_C_NULL_OID_SET, 192 GSS_C_ACCEPT, 193 &tmp_cred_handle, 194 &actual_mechs, 195 &lifetime_rec); 196 if (major_status != GSS_S_COMPLETE) return(0); 197 } else { 198 str_data[3] = TELQUAL_IS; 199 } 200 return(1); 201 } 202 203 int 204 spx_send(ap) 205 Authenticator *ap; 206 { 207 Block enckey; 208 int r; 209 210 gss_OID actual_mech_type, output_name_type; 211 int msg_ctx = 0, new_status, status; 212 int req_flags = 0, ret_flags, lifetime_rec, major_status; 213 gss_buffer_desc output_token, input_token, input_name_buffer; 214 gss_buffer_desc output_name_buffer, status_string; 215 gss_name_t desired_targname; 216 gss_channel_bindings input_chan_bindings; 217 char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; 218 int from_addr=0, to_addr=0, myhostlen, j; 219 int deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0; 220 char *address; 221 222 printf("[ Trying SPX ... ]\n"); 223 strlcpy(targ_printable, "SERVICE:rcmd@", sizeof(targ_printable)); 224 strlcat(targ_printable, RemoteHostName, sizeof(targ_printable)); 225 226 input_name_buffer.length = strlen(targ_printable); 227 input_name_buffer.value = targ_printable; 228 229 if (!UserNameRequested) { 230 return(0); 231 } 232 233 major_status = gss_import_name(&status, 234 &input_name_buffer, 235 GSS_C_NULL_OID, 236 &desired_targname); 237 238 239 major_status = gss_display_name(&status, 240 desired_targname, 241 &output_name_buffer, 242 &output_name_type); 243 244 printf("target is '%s'\n", output_name_buffer.value); fflush(stdout); 245 246 major_status = gss_release_buffer(&status, &output_name_buffer); 247 248 input_chan_bindings = (gss_channel_bindings) 249 malloc(sizeof(gss_channel_bindings_desc)); 250 251 input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; 252 input_chan_bindings->initiator_address.length = 4; 253 address = (char *) malloc(4); 254 input_chan_bindings->initiator_address.value = (char *) address; 255 address[0] = ((from_addr & 0xff000000) >> 24); 256 address[1] = ((from_addr & 0xff0000) >> 16); 257 address[2] = ((from_addr & 0xff00) >> 8); 258 address[3] = (from_addr & 0xff); 259 input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; 260 input_chan_bindings->acceptor_address.length = 4; 261 address = (char *) malloc(4); 262 input_chan_bindings->acceptor_address.value = (char *) address; 263 address[0] = ((to_addr & 0xff000000) >> 24); 264 address[1] = ((to_addr & 0xff0000) >> 16); 265 address[2] = ((to_addr & 0xff00) >> 8); 266 address[3] = (to_addr & 0xff); 267 input_chan_bindings->application_data.length = 0; 268 269 req_flags = 0; 270 if (deleg_flag) req_flags = req_flags | 1; 271 if (mutual_flag) req_flags = req_flags | 2; 272 if (replay_flag) req_flags = req_flags | 4; 273 if (seq_flag) req_flags = req_flags | 8; 274 275 major_status = gss_init_sec_context(&status, /* minor status */ 276 GSS_C_NO_CREDENTIAL, /* cred handle */ 277 &actual_ctxhandle, /* ctx handle */ 278 desired_targname, /* target name */ 279 GSS_C_NULL_OID, /* mech type */ 280 req_flags, /* req flags */ 281 0, /* time req */ 282 input_chan_bindings, /* chan binding */ 283 GSS_C_NO_BUFFER, /* input token */ 284 &actual_mech_type, /* actual mech */ 285 &output_token, /* output token */ 286 &ret_flags, /* ret flags */ 287 &lifetime_rec); /* time rec */ 288 289 if ((major_status != GSS_S_COMPLETE) && 290 (major_status != GSS_S_CONTINUE_NEEDED)) { 291 gss_display_status(&new_status, 292 status, 293 GSS_C_MECH_CODE, 294 GSS_C_NULL_OID, 295 &msg_ctx, 296 &status_string); 297 printf("%s\n", status_string.value); 298 return(0); 299 } 300 301 if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { 302 return(0); 303 } 304 305 if (!Data(ap, SPX_AUTH, (void *)output_token.value, output_token.length)) { 306 return(0); 307 } 308 309 return(1); 310 } 311 312 void 313 spx_is(ap, data, cnt) 314 Authenticator *ap; 315 unsigned char *data; 316 int cnt; 317 { 318 Session_Key skey; 319 Block datablock; 320 int r; 321 322 if (cnt-- < 1) 323 return; 324 switch (*data++) { 325 case SPX_AUTH: 326 input_token.length = cnt; 327 input_token.value = (char *) data; 328 329 gethostname(lhostname, sizeof(lhostname)); 330 331 strlcpy(targ_printable, "SERVICE:rcmd@", 332 sizeof(targ_printable)); 333 strlcat(targ_printable, lhostname, sizeof(targ_printable)); 334 335 input_name_buffer.length = strlen(targ_printable); 336 input_name_buffer.value = targ_printable; 337 338 major_status = gss_import_name(&status, 339 &input_name_buffer, 340 GSS_C_NULL_OID, 341 &desired_targname); 342 343 major_status = gss_acquire_cred(&status, 344 desired_targname, 345 0, 346 GSS_C_NULL_OID_SET, 347 GSS_C_ACCEPT, 348 &gss_cred_handle, 349 &actual_mechs, 350 &lifetime_rec); 351 352 major_status = gss_release_name(&status, desired_targname); 353 354 input_chan_bindings = (gss_channel_bindings) 355 malloc(sizeof(gss_channel_bindings_desc)); 356 357 input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; 358 input_chan_bindings->initiator_address.length = 4; 359 address = (char *) malloc(4); 360 input_chan_bindings->initiator_address.value = (char *) address; 361 address[0] = ((from_addr & 0xff000000) >> 24); 362 address[1] = ((from_addr & 0xff0000) >> 16); 363 address[2] = ((from_addr & 0xff00) >> 8); 364 address[3] = (from_addr & 0xff); 365 input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; 366 input_chan_bindings->acceptor_address.length = 4; 367 address = (char *) malloc(4); 368 input_chan_bindings->acceptor_address.value = (char *) address; 369 address[0] = ((to_addr & 0xff000000) >> 24); 370 address[1] = ((to_addr & 0xff0000) >> 16); 371 address[2] = ((to_addr & 0xff00) >> 8); 372 address[3] = (to_addr & 0xff); 373 input_chan_bindings->application_data.length = 0; 374 375 major_status = gss_accept_sec_context(&status, 376 &context_handle, 377 gss_cred_handle, 378 &input_token, 379 input_chan_bindings, 380 &src_name, 381 &actual_mech_type, 382 &output_token, 383 &ret_flags, 384 &lifetime_rec, 385 &gss_delegated_cred_handle); 386 387 388 if (major_status != GSS_S_COMPLETE) { 389 390 major_status = gss_display_name(&status, 391 src_name, 392 &fullname_buffer, 393 &fullname_type); 394 Data(ap, SPX_REJECT, (void *)"auth failed", -1); 395 auth_finished(ap, AUTH_REJECT); 396 return; 397 } 398 399 major_status = gss_display_name(&status, 400 src_name, 401 &fullname_buffer, 402 &fullname_type); 403 404 405 Data(ap, SPX_ACCEPT, (void *)output_token.value, output_token.length); 406 auth_finished(ap, AUTH_USER); 407 break; 408 409 default: 410 Data(ap, SPX_REJECT, 0, 0); 411 break; 412 } 413 } 414 415 416 void 417 spx_reply(ap, data, cnt) 418 Authenticator *ap; 419 unsigned char *data; 420 int cnt; 421 { 422 Session_Key skey; 423 424 if (cnt-- < 1) 425 return; 426 switch (*data++) { 427 case SPX_REJECT: 428 if (cnt > 0) { 429 printf("[ SPX refuses authentication because %.*s ]\r\n", 430 cnt, data); 431 } else 432 printf("[ SPX refuses authentication ]\r\n"); 433 auth_send_retry(); 434 return; 435 case SPX_ACCEPT: 436 printf("[ SPX accepts you ]\n"); 437 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 438 /* 439 * Send over the encrypted challenge. 440 */ 441 input_token.value = (char *) data; 442 input_token.length = cnt; 443 444 major_status = gss_init_sec_context(&status, /* minor stat */ 445 GSS_C_NO_CREDENTIAL, /* cred handle */ 446 &actual_ctxhandle, /* ctx handle */ 447 desired_targname, /* target name */ 448 GSS_C_NULL_OID, /* mech type */ 449 req_flags, /* req flags */ 450 0, /* time req */ 451 input_chan_bindings, /* chan binding */ 452 &input_token, /* input token */ 453 &actual_mech_type, /* actual mech */ 454 &output_token, /* output token */ 455 &ret_flags, /* ret flags */ 456 &lifetime_rec); /* time rec */ 457 458 if (major_status != GSS_S_COMPLETE) { 459 gss_display_status(&new_status, 460 status, 461 GSS_C_MECH_CODE, 462 GSS_C_NULL_OID, 463 &msg_ctx, 464 &status_string); 465 printf("[ SPX mutual response fails ... '%s' ]\r\n", 466 status_string.value); 467 auth_send_retry(); 468 return; 469 } 470 } 471 auth_finished(ap, AUTH_USER); 472 return; 473 474 default: 475 return; 476 } 477 } 478 479 int 480 spx_status(ap, name, l, level) 481 Authenticator *ap; 482 char *name; 483 size_t l; 484 int level; 485 { 486 487 gss_buffer_desc fullname_buffer, acl_file_buffer; 488 gss_OID fullname_type; 489 char acl_file[160], fullname[160]; 490 int major_status, status = 0; 491 struct passwd pws, *pwd; 492 char pwbuf[1024]; 493 494 /* 495 * hard code fullname to 496 * "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan" 497 * and acl_file to "~kannan/.sphinx" 498 */ 499 500 if (getpwnam_r(UserNameRequested, &pws, pwbuf, sizeof(pwbuf), &pwd) 501 != 0 || pwd == NULL) { 502 return(AUTH_USER); /* not authenticated */ 503 } 504 505 strlcpy(acl_file, pwd->pw_dir, sizeof(acl_file)); 506 strlcat(acl_file, "/.sphinx", sizeof(acl_file)); 507 acl_file_buffer.value = acl_file; 508 acl_file_buffer.length = strlen(acl_file); 509 510 major_status = gss_display_name(&status, 511 src_name, 512 &fullname_buffer, 513 &fullname_type); 514 515 if (level < AUTH_USER) 516 return(level); 517 518 major_status = gss__check_acl(&status, &fullname_buffer, 519 &acl_file_buffer); 520 521 if (major_status == GSS_S_COMPLETE) { 522 strlcpy(name, UserNameRequested, l); 523 return(AUTH_VALID); 524 } else { 525 return(AUTH_USER); 526 } 527 528 } 529 530 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 531 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 532 533 void 534 spx_printsub(data, cnt, buf, buflen) 535 unsigned char *data, *buf; 536 int cnt, buflen; 537 { 538 char lbuf[32]; 539 register int i; 540 541 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 542 buflen -= 1; 543 544 switch(data[3]) { 545 case SPX_REJECT: /* Rejected (reason might follow) */ 546 strncpy((char *)buf, " REJECT ", buflen); 547 goto common; 548 549 case SPX_ACCEPT: /* Accepted (name might follow) */ 550 strncpy((char *)buf, " ACCEPT ", buflen); 551 common: 552 BUMP(buf, buflen); 553 if (cnt <= 4) 554 break; 555 ADDC(buf, buflen, '"'); 556 for (i = 4; i < cnt; i++) 557 ADDC(buf, buflen, data[i]); 558 ADDC(buf, buflen, '"'); 559 ADDC(buf, buflen, '\0'); 560 break; 561 562 case SPX_AUTH: /* Authentication data follows */ 563 strncpy((char *)buf, " AUTH", buflen); 564 goto common2; 565 566 default: 567 snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[3]); 568 strncpy((char *)buf, lbuf, buflen); 569 common2: 570 BUMP(buf, buflen); 571 for (i = 4; i < cnt; i++) { 572 snprintf(lbuf, sizeof(lbuf), " %d", data[i]); 573 strncpy((char *)buf, lbuf, buflen); 574 BUMP(buf, buflen); 575 } 576 break; 577 } 578 } 579 580 #endif 581 582 #ifdef notdef 583 584 prkey(msg, key) 585 char *msg; 586 unsigned char *key; 587 { 588 register int i; 589 printf("%s:", msg); 590 for (i = 0; i < 8; i++) 591 printf(" %3d", key[i]); 592 printf("\r\n"); 593 } 594 #endif 595