1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* GSSAPI SASL plugin 7 * Leif Johansson 8 * Rob Siemborski (SASL v2 Conversion) 9 * $Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $ 10 */ 11 /* 12 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in 23 * the documentation and/or other materials provided with the 24 * distribution. 25 * 26 * 3. The name "Carnegie Mellon University" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For permission or any other legal 29 * details, please contact 30 * Office of Technology Transfer 31 * Carnegie Mellon University 32 * 5000 Forbes Avenue 33 * Pittsburgh, PA 15213-3890 34 * (412) 268-4387, fax: (412) 268-7395 35 * tech-transfer@andrew.cmu.edu 36 * 37 * 4. Redistributions of any form whatsoever must retain the following 38 * acknowledgment: 39 * "This product includes software developed by Computing Services 40 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 41 * 42 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 43 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 44 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 45 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 47 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 48 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 */ 50 51 #include <config.h> 52 53 #ifdef HAVE_GSSAPI_H 54 #include <gssapi.h> 55 #else 56 #include <gssapi/gssapi.h> 57 #endif 58 59 #ifdef WIN32 60 # include <winsock.h> 61 62 # ifndef R_OK 63 # define R_OK 04 64 # endif 65 /* we also need io.h for access() prototype */ 66 # include <io.h> 67 #else 68 # include <sys/param.h> 69 # include <sys/socket.h> 70 # include <netinet/in.h> 71 # include <arpa/inet.h> 72 # include <netdb.h> 73 #endif /* WIN32 */ 74 #include <fcntl.h> 75 #include <stdio.h> 76 #include <sasl.h> 77 #include <saslutil.h> 78 #include <saslplug.h> 79 80 #include "plugin_common.h" 81 82 #ifdef HAVE_UNISTD_H 83 #include <unistd.h> 84 #endif 85 86 #include <errno.h> 87 88 #ifdef WIN32 89 /* This must be after sasl.h */ 90 # include "saslgssapi.h" 91 #endif /* WIN32 */ 92 93 /***************************** Common Section *****************************/ 94 95 #ifndef _SUN_SDK_ 96 static const char plugin_id[] = "$Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $"; 97 #endif /* !_SUN_SDK_ */ 98 99 static const char * GSSAPI_BLANK_STRING = ""; 100 101 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE 102 extern gss_OID gss_nt_service_name; 103 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name 104 #endif 105 106 #ifdef _SUN_SDK_ 107 static int 108 get_oid(const sasl_utils_t *utils, gss_OID *oid); 109 #ifdef GSSAPI_PROTECT 110 DEFINE_STATIC_MUTEX(global_mutex); 111 #endif /* GSSAPI_PROTECT */ 112 #endif /* _SUN_SDK_ */ 113 114 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se> 115 * inspired by the kerberos mechanism and the gssapi_server and 116 * gssapi_client from the heimdal distribution by Assar Westerlund 117 * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>. 118 * See the configure.in file for details on dependencies. 119 * Heimdal can be obtained from http://www.pdc.kth.se/heimdal 120 * 121 * Important contributions from Sam Hartman <hartmans@fundsxpress.com>. 122 */ 123 124 typedef struct context { 125 int state; 126 127 gss_ctx_id_t gss_ctx; 128 gss_name_t client_name; 129 gss_name_t server_name; 130 gss_cred_id_t server_creds; 131 sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the 132 server */ 133 #ifdef _SUN_SDK_ 134 gss_cred_id_t client_creds; 135 gss_OID mech_oid; 136 int use_authid; 137 #endif /* _SUN_SDK_ */ 138 const sasl_utils_t *utils; 139 140 /* layers buffering */ 141 char *buffer; 142 #ifdef _SUN_SDK_ 143 unsigned bufsize; 144 #else 145 int bufsize; 146 #endif /* _SUN_SDK_ */ 147 char sizebuf[4]; 148 #ifdef _SUN_SDK_ 149 unsigned cursize; 150 unsigned size; 151 #else 152 int cursize; 153 int size; 154 #endif /* _SUN_SDK_ */ 155 unsigned needsize; 156 157 char *encode_buf; /* For encoding/decoding mem management */ 158 char *decode_buf; 159 char *decode_once_buf; 160 unsigned encode_buf_len; 161 unsigned decode_buf_len; 162 unsigned decode_once_buf_len; 163 buffer_info_t *enc_in_buf; 164 165 char *out_buf; /* per-step mem management */ 166 unsigned out_buf_len; 167 168 char *authid; /* hold the authid between steps - server */ 169 const char *user; /* hold the userid between steps - client */ 170 #ifdef _SUN_SDK_ 171 const char *client_authid; 172 #endif /* _SUN_SDK_ */ 173 #ifdef _INTEGRATED_SOLARIS_ 174 void *h; 175 #endif /* _INTEGRATED_SOLARIS_ */ 176 } context_t; 177 178 enum { 179 SASL_GSSAPI_STATE_AUTHNEG = 1, 180 SASL_GSSAPI_STATE_SSFCAP = 2, 181 SASL_GSSAPI_STATE_SSFREQ = 3, 182 SASL_GSSAPI_STATE_AUTHENTICATED = 4 183 }; 184 185 #ifdef _SUN_SDK_ 186 /* sasl_gss_log only logs gss_display_status() error string */ 187 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(text,y,z,1) 188 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(text,y,z,0) 189 static void 190 sasl_gss_seterror_(const context_t *text, OM_uint32 maj, OM_uint32 min, 191 int logonly) 192 #else 193 static void 194 sasl_gss_seterror(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min) 195 #endif /* _SUN_SDK_ */ 196 { 197 OM_uint32 maj_stat, min_stat; 198 gss_buffer_desc msg; 199 OM_uint32 msg_ctx; 200 int ret; 201 char *out = NULL; 202 #ifdef _SUN_SDK_ 203 unsigned len, curlen = 0; 204 const sasl_utils_t *utils = text->utils; 205 char *prefix = dgettext(TEXT_DOMAIN, "GSSAPI Error: "); 206 #else 207 size_t len, curlen = 0; 208 const char prefix[] = "GSSAPI Error: "; 209 #endif /* _SUN_SDK_ */ 210 211 if(!utils) return; 212 213 len = sizeof(prefix); 214 ret = _plug_buf_alloc(utils, &out, &curlen, 256); 215 if(ret != SASL_OK) return; 216 217 strcpy(out, prefix); 218 219 msg_ctx = 0; 220 while (1) { 221 maj_stat = gss_display_status(&min_stat, maj, 222 #ifdef _SUN_SDK_ 223 GSS_C_GSS_CODE, text->mech_oid, 224 #else 225 GSS_C_GSS_CODE, GSS_C_NULL_OID, 226 #endif /* _SUN_SDK_ */ 227 &msg_ctx, &msg); 228 if(GSS_ERROR(maj_stat)) { 229 #ifdef _SUN_SDK_ 230 if (logonly) { 231 utils->log(text->utils->conn, SASL_LOG_FAIL, 232 "GSSAPI Failure: (could not get major error message)"); 233 } else { 234 #endif /* _SUN_SDK_ */ 235 #ifdef _INTEGRATED_SOLARIS_ 236 utils->seterror(utils->conn, 0, 237 gettext("GSSAPI Failure " 238 "(could not get major error message)")); 239 #ifdef _SUN_SDK_ 240 } 241 #endif /* _SUN_SDK_ */ 242 #else 243 utils->seterror(utils->conn, 0, 244 "GSSAPI Failure " 245 "(could not get major error message)"); 246 #ifdef _SUN_SDK_ 247 } 248 #endif /* _SUN_SDK_ */ 249 #endif /* _INTEGRATED_SOLARIS_ */ 250 utils->free(out); 251 return; 252 } 253 254 len += len + msg.length; 255 ret = _plug_buf_alloc(utils, &out, &curlen, len); 256 257 if(ret != SASL_OK) { 258 utils->free(out); 259 return; 260 } 261 262 strcat(out, msg.value); 263 264 gss_release_buffer(&min_stat, &msg); 265 266 if (!msg_ctx) 267 break; 268 } 269 270 /* Now get the minor status */ 271 272 len += 2; 273 ret = _plug_buf_alloc(utils, &out, &curlen, len); 274 if(ret != SASL_OK) { 275 utils->free(out); 276 return; 277 } 278 279 strcat(out, " ("); 280 281 msg_ctx = 0; 282 while (1) { 283 maj_stat = gss_display_status(&min_stat, min, 284 #ifdef _SUN_SDK_ 285 GSS_C_MECH_CODE, text->mech_oid, 286 #else 287 GSS_C_MECH_CODE, GSS_C_NULL_OID, 288 #endif /* _SUN_SDK_ */ 289 &msg_ctx, &msg); 290 if(GSS_ERROR(maj_stat)) { 291 #ifdef _SUN_SDK_ 292 if (logonly) { 293 utils->log(text->utils->conn, SASL_LOG_FAIL, 294 "GSSAPI Failure: (could not get minor error message)"); 295 } else { 296 #endif /* _SUN_SDK_ */ 297 #ifdef _INTEGRATED_SOLARIS_ 298 utils->seterror(utils->conn, 0, 299 gettext("GSSAPI Failure " 300 "(could not get minor error message)")); 301 #ifdef _SUN_SDK_ 302 } 303 #endif /* _SUN_SDK_ */ 304 #else 305 utils->seterror(utils->conn, 0, 306 "GSSAPI Failure " 307 "(could not get minor error message)"); 308 #ifdef _SUN_SDK_ 309 } 310 #endif /* _SUN_SDK_ */ 311 #endif /* _INTEGRATED_SOLARIS_ */ 312 utils->free(out); 313 return; 314 } 315 316 len += len + msg.length; 317 ret = _plug_buf_alloc(utils, &out, &curlen, len); 318 319 if(ret != SASL_OK) { 320 utils->free(out); 321 return; 322 } 323 324 strcat(out, msg.value); 325 326 gss_release_buffer(&min_stat, &msg); 327 328 if (!msg_ctx) 329 break; 330 } 331 332 len += 1; 333 ret = _plug_buf_alloc(utils, &out, &curlen, len); 334 if(ret != SASL_OK) { 335 utils->free(out); 336 return; 337 } 338 339 strcat(out, ")"); 340 341 #ifdef _SUN_SDK_ 342 if (logonly) { 343 utils->log(text->utils->conn, SASL_LOG_FAIL, out); 344 } else { 345 utils->seterror(utils->conn, 0, out); 346 } 347 #else 348 utils->seterror(utils->conn, 0, out); 349 #endif /* _SUN_SDK_ */ 350 utils->free(out); 351 } 352 353 static int 354 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov, 355 const char **output, unsigned *outputlen, int privacy) 356 { 357 context_t *text = (context_t *)context; 358 OM_uint32 maj_stat, min_stat; 359 gss_buffer_t input_token, output_token; 360 gss_buffer_desc real_input_token, real_output_token; 361 int ret; 362 struct buffer_info *inblob, bufinfo; 363 364 if(!output) return SASL_BADPARAM; 365 366 if(numiov > 1) { 367 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf); 368 if(ret != SASL_OK) return ret; 369 inblob = text->enc_in_buf; 370 } else { 371 bufinfo.data = invec[0].iov_base; 372 bufinfo.curlen = invec[0].iov_len; 373 inblob = &bufinfo; 374 } 375 376 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE; 377 378 input_token = &real_input_token; 379 380 real_input_token.value = inblob->data; 381 real_input_token.length = inblob->curlen; 382 383 output_token = &real_output_token; 384 output_token->value = NULL; 385 output_token->length = 0; 386 387 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 388 if (LOCK_MUTEX(&global_mutex) < 0) 389 return (SASL_FAIL); 390 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 391 maj_stat = gss_wrap (&min_stat, 392 text->gss_ctx, 393 privacy, 394 GSS_C_QOP_DEFAULT, 395 input_token, 396 NULL, 397 output_token); 398 399 if (GSS_ERROR(maj_stat)) 400 { 401 sasl_gss_seterror(text->utils, maj_stat, min_stat); 402 if (output_token->value) 403 gss_release_buffer(&min_stat, output_token); 404 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 405 UNLOCK_MUTEX(&global_mutex); 406 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 407 return SASL_FAIL; 408 } 409 410 if (output_token->value && output) { 411 int len; 412 413 ret = _plug_buf_alloc(text->utils, &(text->encode_buf), 414 &(text->encode_buf_len), output_token->length + 4); 415 416 if (ret != SASL_OK) { 417 gss_release_buffer(&min_stat, output_token); 418 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 419 UNLOCK_MUTEX(&global_mutex); 420 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 421 return ret; 422 } 423 424 len = htonl(output_token->length); 425 memcpy(text->encode_buf, &len, 4); 426 memcpy(text->encode_buf + 4, output_token->value, output_token->length); 427 } 428 429 if (outputlen) { 430 *outputlen = output_token->length + 4; 431 } 432 433 *output = text->encode_buf; 434 435 if (output_token->value) 436 gss_release_buffer(&min_stat, output_token); 437 438 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 439 UNLOCK_MUTEX(&global_mutex); 440 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 441 442 return SASL_OK; 443 } 444 445 static int gssapi_privacy_encode(void *context, const struct iovec *invec, 446 unsigned numiov, const char **output, 447 unsigned *outputlen) 448 { 449 return sasl_gss_encode(context,invec,numiov,output,outputlen,1); 450 } 451 452 static int gssapi_integrity_encode(void *context, const struct iovec *invec, 453 unsigned numiov, const char **output, 454 unsigned *outputlen) 455 { 456 return sasl_gss_encode(context,invec,numiov,output,outputlen,0); 457 } 458 459 #define myMIN(a,b) (((a) < (b)) ? (a) : (b)) 460 461 static int gssapi_decode_once(void *context, 462 const char **input, unsigned *inputlen, 463 char **output, unsigned *outputlen) 464 { 465 context_t *text = (context_t *) context; 466 OM_uint32 maj_stat, min_stat; 467 gss_buffer_t input_token, output_token; 468 gss_buffer_desc real_input_token, real_output_token; 469 int result; 470 unsigned diff; 471 472 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) { 473 #ifdef _INTEGRATED_SOLARIS_ 474 SETERROR(text->utils, gettext("GSSAPI Failure")); 475 #else 476 SETERROR(text->utils, "GSSAPI Failure"); 477 #endif /* _INTEGRATED_SOLARIS_ */ 478 return SASL_NOTDONE; 479 } 480 481 /* first we need to extract a packet */ 482 if (text->needsize > 0) { 483 /* how long is it? */ 484 int tocopy = myMIN(text->needsize, *inputlen); 485 486 memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy); 487 text->needsize -= tocopy; 488 *input += tocopy; 489 *inputlen -= tocopy; 490 491 if (text->needsize == 0) { 492 /* got the entire size */ 493 memcpy(&text->size, text->sizebuf, 4); 494 text->size = ntohl(text->size); 495 text->cursize = 0; 496 497 #ifdef _SUN_SDK_ 498 if (text->size > 0xFFFFFF) { 499 text->utils->log(text->utils->conn, SASL_LOG_ERR, 500 "Illegal size in sasl_gss_decode_once"); 501 #else 502 if (text->size > 0xFFFFFF || text->size <= 0) { 503 SETERROR(text->utils, "Illegal size in sasl_gss_decode_once"); 504 #endif /* _SUN_SDK_ */ 505 return SASL_FAIL; 506 } 507 508 if (text->bufsize < text->size + 5) { 509 result = _plug_buf_alloc(text->utils, &text->buffer, 510 &(text->bufsize), text->size+5); 511 if(result != SASL_OK) return result; 512 } 513 } 514 if (*inputlen == 0) { 515 /* need more data ! */ 516 *outputlen = 0; 517 *output = NULL; 518 519 return SASL_OK; 520 } 521 } 522 523 diff = text->size - text->cursize; 524 525 if (*inputlen < diff) { 526 /* ok, let's queue it up; not enough data */ 527 memcpy(text->buffer + text->cursize, *input, *inputlen); 528 text->cursize += *inputlen; 529 *inputlen = 0; 530 *outputlen = 0; 531 *output = NULL; 532 return SASL_OK; 533 } else { 534 memcpy(text->buffer + text->cursize, *input, diff); 535 *input += diff; 536 *inputlen -= diff; 537 } 538 539 input_token = &real_input_token; 540 real_input_token.value = text->buffer; 541 real_input_token.length = text->size; 542 543 output_token = &real_output_token; 544 output_token->value = NULL; 545 output_token->length = 0; 546 547 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 548 if (LOCK_MUTEX(&global_mutex) < 0) 549 return (SASL_FAIL); 550 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 551 552 maj_stat = gss_unwrap (&min_stat, 553 text->gss_ctx, 554 input_token, 555 output_token, 556 NULL, 557 NULL); 558 559 if (GSS_ERROR(maj_stat)) 560 { 561 sasl_gss_seterror(text->utils, maj_stat, min_stat); 562 if (output_token->value) 563 gss_release_buffer(&min_stat, output_token); 564 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 565 UNLOCK_MUTEX(&global_mutex); 566 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 567 return SASL_FAIL; 568 } 569 570 if (outputlen) 571 *outputlen = output_token->length; 572 573 if (output_token->value) { 574 if (output) { 575 result = _plug_buf_alloc(text->utils, &text->decode_once_buf, 576 &text->decode_once_buf_len, 577 *outputlen); 578 if(result != SASL_OK) { 579 gss_release_buffer(&min_stat, output_token); 580 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 581 UNLOCK_MUTEX(&global_mutex); 582 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 583 return result; 584 } 585 *output = text->decode_once_buf; 586 memcpy(*output, output_token->value, *outputlen); 587 } 588 gss_release_buffer(&min_stat, output_token); 589 } 590 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 591 UNLOCK_MUTEX(&global_mutex); 592 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 593 594 /* reset for the next packet */ 595 #ifndef _SUN_SDK_ 596 text->size = -1; 597 #endif /* !_SUN_SDK_ */ 598 text->needsize = 4; 599 600 return SASL_OK; 601 } 602 603 static int gssapi_decode(void *context, 604 const char *input, unsigned inputlen, 605 const char **output, unsigned *outputlen) 606 { 607 context_t *text = (context_t *) context; 608 int ret; 609 610 ret = _plug_decode(text->utils, context, input, inputlen, 611 &text->decode_buf, &text->decode_buf_len, outputlen, 612 gssapi_decode_once); 613 614 *output = text->decode_buf; 615 616 return ret; 617 } 618 619 static context_t *gss_new_context(const sasl_utils_t *utils) 620 { 621 context_t *ret; 622 623 ret = utils->malloc(sizeof(context_t)); 624 if(!ret) return NULL; 625 626 memset(ret,0,sizeof(context_t)); 627 ret->utils = utils; 628 #ifdef _SUN_SDK_ 629 ret->gss_ctx = GSS_C_NO_CONTEXT; 630 ret->client_name = GSS_C_NO_NAME; 631 ret->server_name = GSS_C_NO_NAME; 632 ret->server_creds = GSS_C_NO_CREDENTIAL; 633 ret->client_creds = GSS_C_NO_CREDENTIAL; 634 if (get_oid(utils, &ret->mech_oid) != SASL_OK) { 635 utils->free(ret); 636 return (NULL); 637 } 638 #endif /* _SUN_SDK_ */ 639 640 ret->needsize = 4; 641 642 return ret; 643 } 644 645 static void sasl_gss_free_context_contents(context_t *text) 646 { 647 OM_uint32 maj_stat, min_stat; 648 649 if (!text) return; 650 651 if (text->gss_ctx != GSS_C_NO_CONTEXT) { 652 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER); 653 text->gss_ctx = GSS_C_NO_CONTEXT; 654 } 655 656 if (text->client_name != GSS_C_NO_NAME) { 657 maj_stat = gss_release_name(&min_stat,&text->client_name); 658 text->client_name = GSS_C_NO_NAME; 659 } 660 661 if (text->server_name != GSS_C_NO_NAME) { 662 maj_stat = gss_release_name(&min_stat,&text->server_name); 663 text->server_name = GSS_C_NO_NAME; 664 } 665 666 if ( text->server_creds != GSS_C_NO_CREDENTIAL) { 667 maj_stat = gss_release_cred(&min_stat, &text->server_creds); 668 text->server_creds = GSS_C_NO_CREDENTIAL; 669 } 670 671 #ifdef _SUN_SDK_ 672 if ( text->client_creds != GSS_C_NO_CREDENTIAL) { 673 maj_stat = gss_release_cred(&min_stat, &text->client_creds); 674 text->client_creds = GSS_C_NO_CREDENTIAL; 675 } 676 677 /* 678 * Note that the oid returned by rpc_gss_mech_to_oid should not 679 * be released 680 */ 681 #endif /* _SUN_SDK_ */ 682 683 if (text->out_buf) { 684 text->utils->free(text->out_buf); 685 text->out_buf = NULL; 686 } 687 688 if (text->encode_buf) { 689 text->utils->free(text->encode_buf); 690 text->encode_buf = NULL; 691 } 692 693 if (text->decode_buf) { 694 text->utils->free(text->decode_buf); 695 text->decode_buf = NULL; 696 } 697 698 if (text->decode_once_buf) { 699 text->utils->free(text->decode_once_buf); 700 text->decode_once_buf = NULL; 701 } 702 703 if (text->enc_in_buf) { 704 if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data); 705 text->utils->free(text->enc_in_buf); 706 text->enc_in_buf = NULL; 707 } 708 709 if (text->buffer) { 710 text->utils->free(text->buffer); 711 text->buffer = NULL; 712 } 713 714 if (text->authid) { /* works for both client and server */ 715 text->utils->free(text->authid); 716 text->authid = NULL; 717 } 718 } 719 720 #ifdef _SUN_SDK_ 721 722 #ifdef HAVE_RPC_GSS_MECH_TO_OID 723 #include <rpc/rpcsec_gss.h> 724 #endif /* HAVE_RPC_GSS_MECH_TO_OID */ 725 726 static int 727 get_oid(const sasl_utils_t *utils, gss_OID *oid) 728 { 729 #ifdef HAVE_RPC_GSS_MECH_TO_OID 730 static gss_OID_desc kerb_v5 = 731 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 732 /* 1.2.840.113554.1.2.2 */ 733 *oid = &kerb_v5; 734 #endif /* HAVE_RPC_GSS_MECH_TO_OID */ 735 return (SASL_OK); 736 } 737 738 static int 739 add_mech_to_set(context_t *text, gss_OID_set *desired_mechs) 740 { 741 OM_uint32 maj_stat, min_stat; 742 743 maj_stat = gss_create_empty_oid_set(&min_stat, desired_mechs); 744 745 if (GSS_ERROR(maj_stat)) { 746 sasl_gss_seterror(text->utils, maj_stat, min_stat); 747 sasl_gss_free_context_contents(text); 748 return SASL_FAIL; 749 } 750 751 maj_stat = gss_add_oid_set_member(&min_stat, text->mech_oid, desired_mechs); 752 if (GSS_ERROR(maj_stat)) { 753 sasl_gss_seterror(text->utils, maj_stat, min_stat); 754 sasl_gss_free_context_contents(text); 755 (void) gss_release_oid_set(&min_stat, desired_mechs); 756 return SASL_FAIL; 757 } 758 return SASL_OK; 759 } 760 #endif /* _SUN_SDK_ */ 761 762 static void gssapi_common_mech_dispose(void *conn_context, 763 const sasl_utils_t *utils) 764 { 765 #ifdef _SUN_SDK_ 766 if (conn_context == NULL) 767 return; 768 #ifdef _INTEGRATED_SOLARIS_ 769 convert_prompt(utils, &((context_t *)conn_context)->h, NULL); 770 #endif /* _INTEGRATED_SOLARIS_ */ 771 #endif /* _SUN_SDK_ */ 772 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 773 (void) LOCK_MUTEX(&global_mutex); 774 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 775 sasl_gss_free_context_contents((context_t *)(conn_context)); 776 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 777 UNLOCK_MUTEX(&global_mutex); 778 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 779 utils->free(conn_context); 780 } 781 782 /***************************** Server Section *****************************/ 783 784 static int 785 gssapi_server_mech_new(void *glob_context __attribute__((unused)), 786 sasl_server_params_t *params, 787 const char *challenge __attribute__((unused)), 788 unsigned challen __attribute__((unused)), 789 void **conn_context) 790 { 791 context_t *text; 792 793 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 794 if (LOCK_MUTEX(&global_mutex) < 0) 795 return (SASL_FAIL); 796 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 797 text = gss_new_context(params->utils); 798 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 799 UNLOCK_MUTEX(&global_mutex); 800 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 801 if (text == NULL) { 802 #ifndef _SUN_SDK_ 803 MEMERROR(params->utils); 804 #endif /* !_SUN_SDK_ */ 805 return SASL_NOMEM; 806 } 807 808 text->gss_ctx = GSS_C_NO_CONTEXT; 809 text->client_name = GSS_C_NO_NAME; 810 text->server_name = GSS_C_NO_NAME; 811 text->server_creds = GSS_C_NO_CREDENTIAL; 812 text->state = SASL_GSSAPI_STATE_AUTHNEG; 813 814 *conn_context = text; 815 816 return SASL_OK; 817 } 818 819 static int 820 gssapi_server_mech_step(void *conn_context, 821 sasl_server_params_t *params, 822 const char *clientin, 823 unsigned clientinlen, 824 const char **serverout, 825 unsigned *serveroutlen, 826 sasl_out_params_t *oparams) 827 { 828 context_t *text = (context_t *)conn_context; 829 gss_buffer_t input_token, output_token; 830 gss_buffer_desc real_input_token, real_output_token; 831 OM_uint32 maj_stat, min_stat; 832 #ifdef _SUN_SDK_ 833 OM_uint32 max_input_size; 834 gss_OID_set desired_mechs = GSS_C_NULL_OID_SET; 835 #endif /* _SUN_SDK_ */ 836 gss_buffer_desc name_token; 837 int ret; 838 839 input_token = &real_input_token; 840 output_token = &real_output_token; 841 output_token->value = NULL; output_token->length = 0; 842 input_token->value = NULL; input_token->length = 0; 843 844 if(!serverout) { 845 PARAMERROR(text->utils); 846 return SASL_BADPARAM; 847 } 848 849 *serverout = NULL; 850 *serveroutlen = 0; 851 852 switch (text->state) { 853 854 case SASL_GSSAPI_STATE_AUTHNEG: 855 if (text->server_name == GSS_C_NO_NAME) { /* only once */ 856 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN); 857 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char)); 858 if (name_token.value == NULL) { 859 MEMERROR(text->utils); 860 sasl_gss_free_context_contents(text); 861 return SASL_NOMEM; 862 } 863 #ifdef _SUN_SDK_ 864 snprintf(name_token.value, name_token.length + 1, 865 "%s@%s", params->service, params->serverFQDN); 866 #else 867 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN); 868 #endif /* _SUN_SDK_ */ 869 870 maj_stat = gss_import_name (&min_stat, 871 &name_token, 872 GSS_C_NT_HOSTBASED_SERVICE, 873 &text->server_name); 874 875 params->utils->free(name_token.value); 876 name_token.value = NULL; 877 878 if (GSS_ERROR(maj_stat)) { 879 sasl_gss_seterror(text->utils, maj_stat, min_stat); 880 sasl_gss_free_context_contents(text); 881 return SASL_FAIL; 882 } 883 884 if ( text->server_creds != GSS_C_NO_CREDENTIAL) { 885 maj_stat = gss_release_cred(&min_stat, &text->server_creds); 886 text->server_creds = GSS_C_NO_CREDENTIAL; 887 } 888 889 #ifdef _SUN_SDK_ 890 if (text->mech_oid != GSS_C_NULL_OID) { 891 ret = add_mech_to_set(text, &desired_mechs); 892 if (ret != SASL_OK) 893 return (ret); 894 } 895 #endif /* _SUN_SDK_ */ 896 897 maj_stat = gss_acquire_cred(&min_stat, 898 text->server_name, 899 GSS_C_INDEFINITE, 900 #ifdef _SUN_SDK_ 901 desired_mechs, 902 #else 903 GSS_C_NO_OID_SET, 904 #endif /* _SUN_SDK_ */ 905 GSS_C_ACCEPT, 906 &text->server_creds, 907 NULL, 908 NULL); 909 910 #ifdef _SUN_SDK_ 911 if (desired_mechs != GSS_C_NULL_OID_SET) { 912 OM_uint32 min_stat2; 913 (void) gss_release_oid_set(&min_stat2, &desired_mechs); 914 } 915 #endif /* _SUN_SDK_ */ 916 917 if (GSS_ERROR(maj_stat)) { 918 sasl_gss_seterror(text->utils, maj_stat, min_stat); 919 sasl_gss_free_context_contents(text); 920 return SASL_FAIL; 921 } 922 } 923 924 if (clientinlen) { 925 real_input_token.value = (void *)clientin; 926 real_input_token.length = clientinlen; 927 } 928 929 maj_stat = 930 gss_accept_sec_context(&min_stat, 931 &(text->gss_ctx), 932 text->server_creds, 933 input_token, 934 GSS_C_NO_CHANNEL_BINDINGS, 935 &text->client_name, 936 NULL, 937 output_token, 938 NULL, 939 NULL, 940 NULL); 941 942 if (GSS_ERROR(maj_stat)) { 943 #ifdef _SUN_SDK_ 944 /* log the local error info, set a more generic error */ 945 sasl_gss_log(text->utils, maj_stat, min_stat); 946 text->utils->seterror(text->utils->conn, SASL_NOLOG, 947 gettext("GSSAPI Failure: accept security context error")); 948 if (output_token->value) { 949 gss_release_buffer(&min_stat, output_token); 950 } 951 #else 952 if (output_token->value) { 953 gss_release_buffer(&min_stat, output_token); 954 } 955 text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context"); 956 text->utils->log(NULL, SASL_LOG_DEBUG, "GSSAPI Failure: gss_accept_sec_context"); 957 #endif /* _SUN_SDK_ */ 958 sasl_gss_free_context_contents(text); 959 return SASL_BADAUTH; 960 } 961 962 if (serveroutlen) 963 *serveroutlen = output_token->length; 964 if (output_token->value) { 965 if (serverout) { 966 ret = _plug_buf_alloc(text->utils, &(text->out_buf), 967 &(text->out_buf_len), *serveroutlen); 968 if(ret != SASL_OK) { 969 gss_release_buffer(&min_stat, output_token); 970 return ret; 971 } 972 memcpy(text->out_buf, output_token->value, *serveroutlen); 973 *serverout = text->out_buf; 974 } 975 976 gss_release_buffer(&min_stat, output_token); 977 } else { 978 /* No output token, send an empty string */ 979 *serverout = GSSAPI_BLANK_STRING; 980 #ifndef _SUN_SDK_ 981 serveroutlen = 0; 982 #endif /* !_SUN_SDK_ */ 983 } 984 985 986 if (maj_stat == GSS_S_COMPLETE) { 987 /* Switch to ssf negotiation */ 988 text->state = SASL_GSSAPI_STATE_SSFCAP; 989 } 990 991 return SASL_CONTINUE; 992 993 case SASL_GSSAPI_STATE_SSFCAP: { 994 unsigned char sasldata[4]; 995 gss_buffer_desc name_token; 996 #ifndef _SUN_SDK_ 997 gss_buffer_desc name_without_realm; 998 gss_name_t without = NULL; 999 int equal; 1000 #endif /* !_SUN_SDK_ */ 1001 1002 name_token.value = NULL; 1003 #ifndef _SUN_SDK_ 1004 name_without_realm.value = NULL; 1005 #endif /* !_SUN_SDK_ */ 1006 1007 /* We ignore whatever the client sent us at this stage */ 1008 1009 maj_stat = gss_display_name (&min_stat, 1010 text->client_name, 1011 &name_token, 1012 NULL); 1013 1014 if (GSS_ERROR(maj_stat)) { 1015 #ifndef _SUN_SDK_ 1016 if (name_without_realm.value) 1017 params->utils->free(name_without_realm.value); 1018 #endif /* !_SUN_SDK_ */ 1019 1020 if (name_token.value) 1021 gss_release_buffer(&min_stat, &name_token); 1022 #ifndef _SUN_SDK_ 1023 if (without) 1024 gss_release_name(&min_stat, &without); 1025 #endif /* !_SUN_SDK_ */ 1026 #ifdef _INTEGRATED_SOLARIS_ 1027 SETERROR(text->utils, gettext("GSSAPI Failure")); 1028 #else 1029 SETERROR(text->utils, "GSSAPI Failure"); 1030 #endif /* _INTEGRATED_SOLARIS_ */ 1031 sasl_gss_free_context_contents(text); 1032 return SASL_BADAUTH; 1033 } 1034 1035 #ifndef _SUN_SDK_ 1036 /* If the id contains a realm get the identifier for the user 1037 without the realm and see if it's the same id (i.e. 1038 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want 1039 to return the id (i.e. just "tmartin" */ 1040 if (strchr((char *) name_token.value, (int) '@') != NULL) { 1041 /* NOTE: libc malloc, as it is freed below by a gssapi internal 1042 * function! */ 1043 name_without_realm.value = malloc(strlen(name_token.value)+1); 1044 if (name_without_realm.value == NULL) { 1045 MEMERROR(text->utils); 1046 return SASL_NOMEM; 1047 } 1048 1049 strcpy(name_without_realm.value, name_token.value); 1050 1051 /* cut off string at '@' */ 1052 (strchr(name_without_realm.value,'@'))[0] = '\0'; 1053 1054 name_without_realm.length = strlen( (char *) name_without_realm.value ); 1055 1056 maj_stat = gss_import_name (&min_stat, 1057 &name_without_realm, 1058 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here, 1059 so use GSS_C_NT_USER_NAME instead if available. */ 1060 #ifdef HAVE_GSS_C_NT_USER_NAME 1061 GSS_C_NT_USER_NAME, 1062 #else 1063 GSS_C_NULL_OID, 1064 #endif 1065 &without); 1066 1067 if (GSS_ERROR(maj_stat)) { 1068 params->utils->free(name_without_realm.value); 1069 if (name_token.value) 1070 gss_release_buffer(&min_stat, &name_token); 1071 if (without) 1072 gss_release_name(&min_stat, &without); 1073 SETERROR(text->utils, "GSSAPI Failure"); 1074 sasl_gss_free_context_contents(text); 1075 return SASL_BADAUTH; 1076 } 1077 1078 maj_stat = gss_compare_name(&min_stat, 1079 text->client_name, 1080 without, 1081 &equal); 1082 1083 if (GSS_ERROR(maj_stat)) { 1084 params->utils->free(name_without_realm.value); 1085 if (name_token.value) 1086 gss_release_buffer(&min_stat, &name_token); 1087 if (without) 1088 gss_release_name(&min_stat, &without); 1089 SETERROR(text->utils, "GSSAPI Failure"); 1090 sasl_gss_free_context_contents(text); 1091 return SASL_BADAUTH; 1092 } 1093 1094 gss_release_name(&min_stat,&without); 1095 } else { 1096 equal = 0; 1097 } 1098 1099 if (equal) { 1100 text->authid = strdup(name_without_realm.value); 1101 1102 if (text->authid == NULL) { 1103 MEMERROR(params->utils); 1104 return SASL_NOMEM; 1105 } 1106 } else { 1107 text->authid = strdup(name_token.value); 1108 1109 if (text->authid == NULL) { 1110 MEMERROR(params->utils); 1111 return SASL_NOMEM; 1112 } 1113 } 1114 #else 1115 { 1116 ret = _plug_strdup(params->utils, name_token.value, 1117 &text->authid, NULL); 1118 } 1119 #endif /* _SUN_SDK_ */ 1120 1121 if (name_token.value) 1122 gss_release_buffer(&min_stat, &name_token); 1123 1124 #ifdef _SUN_SDK_ 1125 if (ret != SASL_OK) 1126 return (ret); 1127 #else 1128 if (name_without_realm.value) 1129 params->utils->free(name_without_realm.value); 1130 #endif /* _SUN_SDK_ */ 1131 1132 1133 /* we have to decide what sort of encryption/integrity/etc., 1134 we support */ 1135 if (params->props.max_ssf < params->external_ssf) { 1136 text->limitssf = 0; 1137 } else { 1138 text->limitssf = params->props.max_ssf - params->external_ssf; 1139 } 1140 if (params->props.min_ssf < params->external_ssf) { 1141 text->requiressf = 0; 1142 } else { 1143 text->requiressf = params->props.min_ssf - params->external_ssf; 1144 } 1145 1146 /* build up our security properties token */ 1147 if (params->props.maxbufsize > 0xFFFFFF) { 1148 /* make sure maxbufsize isn't too large */ 1149 /* maxbufsize = 0xFFFFFF */ 1150 sasldata[1] = sasldata[2] = sasldata[3] = 0xFF; 1151 } else { 1152 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF; 1153 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF; 1154 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF; 1155 } 1156 sasldata[0] = 0; 1157 if(text->requiressf != 0 && !params->props.maxbufsize) { 1158 #ifdef _SUN_SDK_ 1159 params->utils->log(params->utils->conn, SASL_LOG_ERR, 1160 "GSSAPI needs a security layer but one is forbidden"); 1161 #else 1162 params->utils->seterror(params->utils->conn, 0, 1163 "GSSAPI needs a security layer but one is forbidden"); 1164 #endif /* _SUN_SDK_ */ 1165 return SASL_TOOWEAK; 1166 } 1167 1168 if (text->requiressf == 0) { 1169 sasldata[0] |= 1; /* authentication */ 1170 } 1171 if (text->requiressf <= 1 && text->limitssf >= 1 1172 && params->props.maxbufsize) { 1173 sasldata[0] |= 2; 1174 } 1175 if (text->requiressf <= 56 && text->limitssf >= 56 1176 && params->props.maxbufsize) { 1177 sasldata[0] |= 4; 1178 } 1179 1180 real_input_token.value = (void *)sasldata; 1181 real_input_token.length = 4; 1182 1183 maj_stat = gss_wrap(&min_stat, 1184 text->gss_ctx, 1185 0, /* Just integrity checking here */ 1186 GSS_C_QOP_DEFAULT, 1187 input_token, 1188 NULL, 1189 output_token); 1190 1191 if (GSS_ERROR(maj_stat)) { 1192 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1193 if (output_token->value) 1194 gss_release_buffer(&min_stat, output_token); 1195 sasl_gss_free_context_contents(text); 1196 return SASL_FAIL; 1197 } 1198 1199 1200 if (serveroutlen) 1201 *serveroutlen = output_token->length; 1202 if (output_token->value) { 1203 if (serverout) { 1204 ret = _plug_buf_alloc(text->utils, &(text->out_buf), 1205 &(text->out_buf_len), *serveroutlen); 1206 if(ret != SASL_OK) { 1207 gss_release_buffer(&min_stat, output_token); 1208 return ret; 1209 } 1210 memcpy(text->out_buf, output_token->value, *serveroutlen); 1211 *serverout = text->out_buf; 1212 } 1213 1214 gss_release_buffer(&min_stat, output_token); 1215 } 1216 1217 /* Wait for ssf request and authid */ 1218 text->state = SASL_GSSAPI_STATE_SSFREQ; 1219 1220 return SASL_CONTINUE; 1221 } 1222 1223 case SASL_GSSAPI_STATE_SSFREQ: { 1224 int layerchoice; 1225 1226 real_input_token.value = (void *)clientin; 1227 real_input_token.length = clientinlen; 1228 1229 maj_stat = gss_unwrap(&min_stat, 1230 text->gss_ctx, 1231 input_token, 1232 output_token, 1233 NULL, 1234 NULL); 1235 1236 if (GSS_ERROR(maj_stat)) { 1237 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1238 sasl_gss_free_context_contents(text); 1239 return SASL_FAIL; 1240 } 1241 1242 layerchoice = (int)(((char *)(output_token->value))[0]); 1243 if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */ 1244 oparams->encode = NULL; 1245 oparams->decode = NULL; 1246 oparams->mech_ssf = 0; 1247 } else if (layerchoice == 2 && text->requiressf <= 1 && 1248 text->limitssf >= 1) { /* integrity */ 1249 oparams->encode=&gssapi_integrity_encode; 1250 oparams->decode=&gssapi_decode; 1251 oparams->mech_ssf=1; 1252 } else if (layerchoice == 4 && text->requiressf <= 56 && 1253 text->limitssf >= 56) { /* privacy */ 1254 oparams->encode = &gssapi_privacy_encode; 1255 oparams->decode = &gssapi_decode; 1256 oparams->mech_ssf = 56; 1257 } else { 1258 /* not a supported encryption layer */ 1259 #ifdef _SUN_SDK_ 1260 text->utils->log(text->utils->conn, SASL_LOG_ERR, 1261 "protocol violation: client requested invalid layer"); 1262 #else 1263 SETERROR(text->utils, 1264 "protocol violation: client requested invalid layer"); 1265 #endif /* _SUN_SDK_ */ 1266 /* Mark that we attempted negotiation */ 1267 oparams->mech_ssf = 2; 1268 if (output_token->value) 1269 gss_release_buffer(&min_stat, output_token); 1270 sasl_gss_free_context_contents(text); 1271 return SASL_FAIL; 1272 } 1273 1274 if (output_token->length > 4) { 1275 int ret; 1276 1277 ret = params->canon_user(params->utils->conn, 1278 ((char *) output_token->value) + 4, 1279 (output_token->length - 4) * sizeof(char), 1280 SASL_CU_AUTHZID, oparams); 1281 1282 if (ret != SASL_OK) { 1283 sasl_gss_free_context_contents(text); 1284 return ret; 1285 } 1286 1287 ret = params->canon_user(params->utils->conn, 1288 text->authid, 1289 0, /* strlen(text->authid) */ 1290 SASL_CU_AUTHID, oparams); 1291 if (ret != SASL_OK) { 1292 sasl_gss_free_context_contents(text); 1293 return ret; 1294 } 1295 } else if(output_token->length == 4) { 1296 /* null authzid */ 1297 int ret; 1298 1299 ret = params->canon_user(params->utils->conn, 1300 text->authid, 1301 0, /* strlen(text->authid) */ 1302 SASL_CU_AUTHZID | SASL_CU_AUTHID, 1303 oparams); 1304 1305 if (ret != SASL_OK) { 1306 sasl_gss_free_context_contents(text); 1307 return ret; 1308 } 1309 } else { 1310 #ifdef _SUN_SDK_ 1311 text->utils->log(text->utils->conn, SASL_LOG_ERR, 1312 "token too short"); 1313 #else 1314 SETERROR(text->utils, 1315 "token too short"); 1316 #endif /* _SUN_SDK_ */ 1317 gss_release_buffer(&min_stat, output_token); 1318 sasl_gss_free_context_contents(text); 1319 return SASL_FAIL; 1320 } 1321 1322 /* No matter what, set the rest of the oparams */ 1323 oparams->maxoutbuf = 1324 (((unsigned char *) output_token->value)[1] << 16) | 1325 (((unsigned char *) output_token->value)[2] << 8) | 1326 (((unsigned char *) output_token->value)[3] << 0); 1327 1328 #ifdef _SUN_SDK_ 1329 if (oparams->mech_ssf) { 1330 oparams->maxoutbuf -= 4; /* Allow for 4 byte tag */ 1331 maj_stat = gss_wrap_size_limit(&min_stat, 1332 text->gss_ctx, 1333 oparams->mech_ssf > 1, 1334 GSS_C_QOP_DEFAULT, 1335 oparams->maxoutbuf, 1336 &max_input_size); 1337 if (GSS_ERROR(maj_stat)) { 1338 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1339 (void) gss_release_buffer(&min_stat, output_token); 1340 sasl_gss_free_context_contents(text); 1341 return (SASL_FAIL); 1342 } 1343 1344 /* 1345 * gss_wrap_size_limit will return very big sizes for 1346 * small input values 1347 */ 1348 if (max_input_size < oparams->maxoutbuf) 1349 oparams->maxoutbuf = max_input_size; 1350 else { 1351 oparams->maxoutbuf = 0; 1352 } 1353 } 1354 #else 1355 if (oparams->mech_ssf) { 1356 /* xxx this is probably too big */ 1357 oparams->maxoutbuf -= 50; 1358 } 1359 #endif /* _SUN_SDK_ */ 1360 1361 gss_release_buffer(&min_stat, output_token); 1362 1363 text->state = SASL_GSSAPI_STATE_AUTHENTICATED; 1364 1365 oparams->doneflag = 1; 1366 1367 return SASL_OK; 1368 } 1369 1370 default: 1371 #ifdef _SUN_SDK_ 1372 params->utils->log(text->utils->conn, SASL_LOG_ERR, 1373 "Invalid GSSAPI server step %d", text->state); 1374 #else 1375 params->utils->log(NULL, SASL_LOG_ERR, 1376 "Invalid GSSAPI server step %d\n", text->state); 1377 #endif /* _SUN_SDK_ */ 1378 return SASL_FAIL; 1379 } 1380 1381 #ifndef _SUN_SDK_ 1382 return SASL_FAIL; /* should never get here */ 1383 #endif /* !_SUN_SDK_ */ 1384 } 1385 1386 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 1387 static int 1388 _gssapi_server_mech_step(void *conn_context, 1389 sasl_server_params_t *params, 1390 const char *clientin, 1391 unsigned clientinlen, 1392 const char **serverout, 1393 unsigned *serveroutlen, 1394 sasl_out_params_t *oparams) 1395 { 1396 int ret; 1397 1398 if (LOCK_MUTEX(&global_mutex) < 0) 1399 return (SASL_FAIL); 1400 1401 ret = gssapi_server_mech_step(conn_context, params, clientin, clientinlen, 1402 serverout, serveroutlen, oparams); 1403 1404 UNLOCK_MUTEX(&global_mutex); 1405 return (ret); 1406 } 1407 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 1408 1409 static sasl_server_plug_t gssapi_server_plugins[] = 1410 { 1411 { 1412 "GSSAPI", /* mech_name */ 1413 56, /* max_ssf */ 1414 SASL_SEC_NOPLAINTEXT 1415 | SASL_SEC_NOACTIVE 1416 | SASL_SEC_NOANONYMOUS 1417 | SASL_SEC_MUTUAL_AUTH, /* security_flags */ 1418 SASL_FEAT_WANT_CLIENT_FIRST 1419 | SASL_FEAT_ALLOWS_PROXY, /* features */ 1420 NULL, /* glob_context */ 1421 &gssapi_server_mech_new, /* mech_new */ 1422 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 1423 &_gssapi_server_mech_step, /* mech_step */ 1424 #else 1425 &gssapi_server_mech_step, /* mech_step */ 1426 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 1427 &gssapi_common_mech_dispose, /* mech_dispose */ 1428 NULL, /* mech_free */ 1429 NULL, /* setpass */ 1430 NULL, /* user_query */ 1431 NULL, /* idle */ 1432 NULL, /* mech_avail */ 1433 NULL /* spare */ 1434 } 1435 }; 1436 1437 int gssapiv2_server_plug_init( 1438 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY 1439 const sasl_utils_t *utils __attribute__((unused)), 1440 #else 1441 const sasl_utils_t *utils, 1442 #endif 1443 int maxversion, 1444 int *out_version, 1445 sasl_server_plug_t **pluglist, 1446 int *plugcount) 1447 { 1448 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY 1449 const char *keytab = NULL; 1450 char keytab_path[1024]; 1451 unsigned int rl; 1452 #endif 1453 1454 if (maxversion < SASL_SERVER_PLUG_VERSION) { 1455 return SASL_BADVERS; 1456 } 1457 1458 #ifndef _SUN_SDK_ 1459 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY 1460 /* unfortunately, we don't check for readability of keytab if it's 1461 the standard one, since we don't know where it is */ 1462 1463 /* FIXME: This code is broken */ 1464 1465 utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl); 1466 if (keytab != NULL) { 1467 if (access(keytab, R_OK) != 0) { 1468 utils->log(NULL, SASL_LOG_ERR, 1469 "Could not find keytab file: %s: %m", 1470 keytab, errno); 1471 return SASL_FAIL; 1472 } 1473 1474 if(strlen(keytab) > 1024) { 1475 utils->log(NULL, SASL_LOG_ERR, 1476 "path to keytab is > 1024 characters"); 1477 return SASL_BUFOVER; 1478 } 1479 1480 strncpy(keytab_path, keytab, 1024); 1481 1482 gsskrb5_register_acceptor_identity(keytab_path); 1483 } 1484 #endif 1485 #endif /* !_SUN_SDK_ */ 1486 1487 #ifdef _INTEGRATED_SOLARIS_ 1488 /* 1489 * Let libsasl know that we are a "Sun" plugin so that privacy 1490 * and integrity will be allowed. 1491 */ 1492 REG_PLUG("GSSAPI", gssapi_server_plugins); 1493 #endif /* _INTEGRATED_SOLARIS_ */ 1494 1495 *out_version = SASL_SERVER_PLUG_VERSION; 1496 *pluglist = gssapi_server_plugins; 1497 *plugcount = 1; 1498 1499 return SASL_OK; 1500 } 1501 1502 /***************************** Client Section *****************************/ 1503 1504 static int gssapi_client_mech_new(void *glob_context __attribute__((unused)), 1505 sasl_client_params_t *params, 1506 void **conn_context) 1507 { 1508 context_t *text; 1509 #ifdef _SUN_SDK_ 1510 const char *use_authid = NULL; 1511 #endif /* _SUN_SDK_ */ 1512 1513 /* holds state are in */ 1514 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 1515 if (LOCK_MUTEX(&global_mutex) < 0) 1516 return (SASL_FAIL); 1517 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 1518 text = gss_new_context(params->utils); 1519 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 1520 UNLOCK_MUTEX(&global_mutex); 1521 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 1522 if (text == NULL) { 1523 #ifndef _SUN_SDK_ 1524 MEMERROR(params->utils); 1525 #endif /* !_SUN_SDK_ */ 1526 return SASL_NOMEM; 1527 } 1528 1529 text->state = SASL_GSSAPI_STATE_AUTHNEG; 1530 text->gss_ctx = GSS_C_NO_CONTEXT; 1531 text->client_name = GSS_C_NO_NAME; 1532 text->server_creds = GSS_C_NO_CREDENTIAL; 1533 1534 #ifdef _SUN_SDK_ 1535 params->utils->getopt(params->utils->getopt_context, 1536 "GSSAPI", "use_authid", &use_authid, NULL); 1537 text->use_authid = (use_authid != NULL) && 1538 (*use_authid == 'y' || *use_authid == 'Y' || *use_authid == '1'); 1539 #endif /* _SUN_SDK_ */ 1540 1541 *conn_context = text; 1542 1543 return SASL_OK; 1544 } 1545 1546 static int gssapi_client_mech_step(void *conn_context, 1547 sasl_client_params_t *params, 1548 const char *serverin, 1549 unsigned serverinlen, 1550 sasl_interact_t **prompt_need, 1551 const char **clientout, 1552 unsigned *clientoutlen, 1553 sasl_out_params_t *oparams) 1554 { 1555 context_t *text = (context_t *)conn_context; 1556 gss_buffer_t input_token, output_token; 1557 gss_buffer_desc real_input_token, real_output_token; 1558 OM_uint32 maj_stat, min_stat; 1559 #ifdef _SUN_SDK_ 1560 OM_uint32 max_input_size; 1561 #endif /* _SUN_SDK_ */ 1562 gss_buffer_desc name_token; 1563 int ret; 1564 OM_uint32 req_flags, out_req_flags; 1565 input_token = &real_input_token; 1566 output_token = &real_output_token; 1567 output_token->value = NULL; 1568 input_token->value = NULL; 1569 input_token->length = 0; 1570 1571 *clientout = NULL; 1572 *clientoutlen = 0; 1573 1574 switch (text->state) { 1575 1576 case SASL_GSSAPI_STATE_AUTHNEG: 1577 /* try to get the userid */ 1578 #ifdef _SUN_SDK_ 1579 if (text->user == NULL || 1580 (text->use_authid && text->client_authid == NULL)) { 1581 int auth_result = SASL_OK; 1582 int user_result = SASL_OK; 1583 1584 if (text->use_authid && text->client_authid == NULL) { 1585 auth_result = _plug_get_authid(params->utils, 1586 &text->client_authid, 1587 prompt_need); 1588 1589 if ((auth_result != SASL_OK) && 1590 (auth_result != SASL_INTERACT)) { 1591 sasl_gss_free_context_contents(text); 1592 return auth_result; 1593 } 1594 } 1595 if (text->user == NULL) { 1596 user_result = _plug_get_userid(params->utils, &text->user, 1597 prompt_need); 1598 1599 if ((user_result != SASL_OK) && 1600 (user_result != SASL_INTERACT)) { 1601 sasl_gss_free_context_contents(text); 1602 return user_result; 1603 } 1604 } 1605 #else 1606 if (text->user == NULL) { 1607 int user_result = SASL_OK; 1608 1609 user_result = _plug_get_userid(params->utils, &text->user, 1610 prompt_need); 1611 1612 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) { 1613 sasl_gss_free_context_contents(text); 1614 return user_result; 1615 } 1616 #endif /* _SUN_SDK_ */ 1617 1618 /* free prompts we got */ 1619 if (prompt_need && *prompt_need) { 1620 params->utils->free(*prompt_need); 1621 *prompt_need = NULL; 1622 } 1623 1624 /* if there are prompts not filled in */ 1625 #ifdef _SUN_SDK_ 1626 if ((user_result == SASL_INTERACT) || 1627 (auth_result == SASL_INTERACT)) { 1628 /* make the prompt list */ 1629 #ifdef _INTEGRATED_SOLARIS_ 1630 int result = _plug_make_prompts(params->utils, &text->h, 1631 prompt_need, 1632 user_result == SASL_INTERACT ? 1633 convert_prompt(params->utils, &text->h, 1634 gettext("Please enter your authorization name")) 1635 : NULL, NULL, 1636 auth_result == SASL_INTERACT ? 1637 convert_prompt(params->utils, &text->h, 1638 gettext("Please enter your authentication name")) 1639 : NULL, NULL, 1640 NULL, NULL, 1641 NULL, NULL, NULL, 1642 NULL, NULL, NULL); 1643 #else 1644 int result = _plug_make_prompts(params->utils, prompt_need, 1645 user_result == SASL_INTERACT ? 1646 "Please enter your authorization name" 1647 : NULL, NULL, 1648 auth_result == SASL_INTERACT ? 1649 "Please enter your authentication name" 1650 : NULL, NULL, 1651 NULL, NULL, 1652 NULL, NULL, NULL, 1653 NULL, NULL, NULL); 1654 #endif /* _INTEGRATED_SOLARIS_ */ 1655 1656 if (result != SASL_OK) return result; 1657 1658 return SASL_INTERACT; 1659 } 1660 #else 1661 if (user_result == SASL_INTERACT) { 1662 /* make the prompt list */ 1663 int result = 1664 _plug_make_prompts(params->utils, prompt_need, 1665 user_result == SASL_INTERACT ? 1666 "Please enter your authorization name" : NULL, NULL, 1667 NULL, NULL, 1668 NULL, NULL, 1669 NULL, NULL, NULL, 1670 NULL, NULL, NULL); 1671 if (result != SASL_OK) return result; 1672 1673 return SASL_INTERACT; 1674 } 1675 #endif /* _SUN_SDK_ */ 1676 } 1677 1678 if (text->server_name == GSS_C_NO_NAME) { /* only once */ 1679 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN); 1680 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char)); 1681 if (name_token.value == NULL) { 1682 sasl_gss_free_context_contents(text); 1683 return SASL_NOMEM; 1684 } 1685 if (params->serverFQDN == NULL 1686 || strlen(params->serverFQDN) == 0) { 1687 #ifdef _SUN_SDK_ 1688 text->utils->log(text->utils->conn, SASL_LOG_ERR, 1689 "GSSAPI Failure: no serverFQDN"); 1690 #else 1691 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN"); 1692 #endif /* _SUN_SDK_ */ 1693 return SASL_FAIL; 1694 } 1695 1696 #ifdef _SUN_SDK_ 1697 snprintf(name_token.value, name_token.length + 1, 1698 "%s@%s", params->service, params->serverFQDN); 1699 #else 1700 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN); 1701 #endif /* _SUN_SDK_ */ 1702 1703 maj_stat = gss_import_name (&min_stat, 1704 &name_token, 1705 GSS_C_NT_HOSTBASED_SERVICE, 1706 &text->server_name); 1707 1708 params->utils->free(name_token.value); 1709 name_token.value = NULL; 1710 1711 if (GSS_ERROR(maj_stat)) { 1712 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1713 sasl_gss_free_context_contents(text); 1714 return SASL_FAIL; 1715 } 1716 } 1717 1718 if (serverinlen == 0) 1719 input_token = GSS_C_NO_BUFFER; 1720 1721 if (serverinlen) { 1722 real_input_token.value = (void *)serverin; 1723 real_input_token.length = serverinlen; 1724 } 1725 else if (text->gss_ctx != GSS_C_NO_CONTEXT ) { 1726 /* This can't happen under GSSAPI: we have a non-null context 1727 * and no input from the server. However, thanks to Imap, 1728 * which discards our first output, this happens all the time. 1729 * Throw away the context and try again. */ 1730 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER); 1731 text->gss_ctx = GSS_C_NO_CONTEXT; 1732 } 1733 1734 /* Setup req_flags properly */ 1735 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG; 1736 if(params->props.max_ssf > params->external_ssf) { 1737 /* We are requesting a security layer */ 1738 req_flags |= GSS_C_INTEG_FLAG; 1739 if(params->props.max_ssf - params->external_ssf > 56) { 1740 /* We want to try for privacy */ 1741 req_flags |= GSS_C_CONF_FLAG; 1742 } 1743 } 1744 1745 #ifdef _SUN_SDK_ 1746 if (text->use_authid && text->client_creds == GSS_C_NO_CREDENTIAL) { 1747 gss_OID_set desired_mechs = GSS_C_NULL_OID_SET; 1748 gss_buffer_desc name_token; 1749 1750 name_token.length = strlen(text->client_authid); 1751 name_token.value = (char *)text->client_authid; 1752 1753 maj_stat = gss_import_name (&min_stat, 1754 &name_token, 1755 #ifdef HAVE_GSS_C_NT_USER_NAME 1756 GSS_C_NT_USER_NAME, 1757 #else 1758 GSS_C_NULL_OID, 1759 #endif 1760 &text->client_name); 1761 if (GSS_ERROR(maj_stat)) { 1762 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1763 sasl_gss_free_context_contents(text); 1764 return SASL_FAIL; 1765 } 1766 1767 if (text->mech_oid != GSS_C_NULL_OID) { 1768 ret = add_mech_to_set(text, &desired_mechs); 1769 if (ret != SASL_OK) 1770 return (ret); 1771 } 1772 1773 maj_stat = gss_acquire_cred(&min_stat, 1774 text->client_name, 1775 GSS_C_INDEFINITE, 1776 desired_mechs, 1777 GSS_C_INITIATE, 1778 &text->client_creds, 1779 NULL, 1780 NULL); 1781 1782 if (desired_mechs != GSS_C_NULL_OID_SET) { 1783 OM_uint32 min_stat2; 1784 (void) gss_release_oid_set(&min_stat2, &desired_mechs); 1785 } 1786 1787 if (GSS_ERROR(maj_stat)) { 1788 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1789 sasl_gss_free_context_contents(text); 1790 return SASL_FAIL; 1791 } 1792 } 1793 #endif /* _SUN_SDK_ */ 1794 1795 maj_stat = gss_init_sec_context(&min_stat, 1796 #ifdef _SUN_SDK_ 1797 text->client_creds, 1798 #else 1799 GSS_C_NO_CREDENTIAL, 1800 #endif /* _SUN_SDK_ */ 1801 &text->gss_ctx, 1802 text->server_name, 1803 #ifdef _SUN_SDK_ 1804 text->mech_oid, 1805 #else 1806 GSS_C_NO_OID, 1807 #endif /* _SUN_SDK_ */ 1808 req_flags, 1809 0, 1810 GSS_C_NO_CHANNEL_BINDINGS, 1811 input_token, 1812 NULL, 1813 output_token, 1814 &out_req_flags, 1815 NULL); 1816 1817 if (GSS_ERROR(maj_stat)) { 1818 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1819 if (output_token->value) 1820 gss_release_buffer(&min_stat, output_token); 1821 sasl_gss_free_context_contents(text); 1822 return SASL_FAIL; 1823 } 1824 1825 *clientoutlen = output_token->length; 1826 1827 if (output_token->value) { 1828 if (clientout) { 1829 ret = _plug_buf_alloc(text->utils, &(text->out_buf), 1830 &(text->out_buf_len), *clientoutlen); 1831 if(ret != SASL_OK) { 1832 gss_release_buffer(&min_stat, output_token); 1833 return ret; 1834 } 1835 memcpy(text->out_buf, output_token->value, *clientoutlen); 1836 *clientout = text->out_buf; 1837 } 1838 1839 gss_release_buffer(&min_stat, output_token); 1840 } 1841 1842 if (maj_stat == GSS_S_COMPLETE) { 1843 maj_stat = gss_inquire_context(&min_stat, 1844 text->gss_ctx, 1845 &text->client_name, 1846 NULL, /* targ_name */ 1847 NULL, /* lifetime */ 1848 NULL, /* mech */ 1849 NULL, /* flags */ 1850 NULL, /* local init */ 1851 NULL); /* open */ 1852 1853 if (GSS_ERROR(maj_stat)) { 1854 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1855 sasl_gss_free_context_contents(text); 1856 return SASL_FAIL; 1857 } 1858 1859 name_token.length = 0; 1860 maj_stat = gss_display_name(&min_stat, 1861 text->client_name, 1862 &name_token, 1863 NULL); 1864 1865 if (GSS_ERROR(maj_stat)) { 1866 if (name_token.value) 1867 gss_release_buffer(&min_stat, &name_token); 1868 #ifdef _INTEGRATED_SOLARIS_ 1869 SETERROR(text->utils, gettext("GSSAPI Failure")); 1870 #else 1871 SETERROR(text->utils, "GSSAPI Failure"); 1872 #endif /* _INTEGRATED_SOLARIS_ */ 1873 sasl_gss_free_context_contents(text); 1874 return SASL_FAIL; 1875 } 1876 1877 if (text->user && text->user[0]) { 1878 ret = params->canon_user(params->utils->conn, 1879 text->user, 0, 1880 SASL_CU_AUTHZID, oparams); 1881 if (ret == SASL_OK) 1882 ret = params->canon_user(params->utils->conn, 1883 name_token.value, 0, 1884 SASL_CU_AUTHID, oparams); 1885 } else { 1886 ret = params->canon_user(params->utils->conn, 1887 name_token.value, 0, 1888 SASL_CU_AUTHID | SASL_CU_AUTHZID, 1889 oparams); 1890 } 1891 gss_release_buffer(&min_stat, &name_token); 1892 1893 if (ret != SASL_OK) return ret; 1894 1895 /* Switch to ssf negotiation */ 1896 text->state = SASL_GSSAPI_STATE_SSFCAP; 1897 } 1898 1899 return SASL_CONTINUE; 1900 1901 case SASL_GSSAPI_STATE_SSFCAP: { 1902 sasl_security_properties_t *secprops = &(params->props); 1903 unsigned int alen, external = params->external_ssf; 1904 sasl_ssf_t need, allowed; 1905 char serverhas, mychoice; 1906 1907 real_input_token.value = (void *) serverin; 1908 real_input_token.length = serverinlen; 1909 1910 maj_stat = gss_unwrap(&min_stat, 1911 text->gss_ctx, 1912 input_token, 1913 output_token, 1914 NULL, 1915 NULL); 1916 1917 if (GSS_ERROR(maj_stat)) { 1918 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1919 sasl_gss_free_context_contents(text); 1920 if (output_token->value) 1921 gss_release_buffer(&min_stat, output_token); 1922 return SASL_FAIL; 1923 } 1924 1925 /* taken from kerberos.c */ 1926 if (secprops->min_ssf > (56 + external)) { 1927 return SASL_TOOWEAK; 1928 } else if (secprops->min_ssf > secprops->max_ssf) { 1929 return SASL_BADPARAM; 1930 } 1931 1932 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */ 1933 if (secprops->max_ssf >= external) { 1934 allowed = secprops->max_ssf - external; 1935 } else { 1936 allowed = 0; 1937 } 1938 if (secprops->min_ssf >= external) { 1939 need = secprops->min_ssf - external; 1940 } else { 1941 /* good to go */ 1942 need = 0; 1943 } 1944 1945 /* bit mask of server support */ 1946 serverhas = ((char *)output_token->value)[0]; 1947 1948 /* if client didn't set use strongest layer available */ 1949 if (allowed >= 56 && need <= 56 && (serverhas & 4)) { 1950 /* encryption */ 1951 oparams->encode = &gssapi_privacy_encode; 1952 oparams->decode = &gssapi_decode; 1953 oparams->mech_ssf = 56; 1954 mychoice = 4; 1955 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) { 1956 /* integrity */ 1957 oparams->encode = &gssapi_integrity_encode; 1958 oparams->decode = &gssapi_decode; 1959 oparams->mech_ssf = 1; 1960 mychoice = 2; 1961 #ifdef _SUN_SDK_ 1962 } else if (need == 0 && (serverhas & 1)) { 1963 #else 1964 } else if (need <= 0 && (serverhas & 1)) { 1965 #endif /* _SUN_SDK_ */ 1966 /* no layer */ 1967 oparams->encode = NULL; 1968 oparams->decode = NULL; 1969 oparams->mech_ssf = 0; 1970 mychoice = 1; 1971 } else { 1972 /* there's no appropriate layering for us! */ 1973 sasl_gss_free_context_contents(text); 1974 return SASL_TOOWEAK; 1975 } 1976 1977 oparams->maxoutbuf = 1978 (((unsigned char *) output_token->value)[1] << 16) | 1979 (((unsigned char *) output_token->value)[2] << 8) | 1980 (((unsigned char *) output_token->value)[3] << 0); 1981 1982 #ifdef _SUN_SDK_ 1983 if (oparams->mech_ssf > 0) { 1984 oparams->maxoutbuf -= 4; /* Space for 4 byte length header */ 1985 maj_stat = gss_wrap_size_limit(&min_stat, 1986 text->gss_ctx, 1987 oparams->mech_ssf > 1, 1988 GSS_C_QOP_DEFAULT, 1989 oparams->maxoutbuf, 1990 &max_input_size); 1991 if (GSS_ERROR(maj_stat)) { 1992 sasl_gss_seterror(text->utils, maj_stat, min_stat); 1993 (void) gss_release_buffer(&min_stat, output_token); 1994 sasl_gss_free_context_contents(text); 1995 return (SASL_FAIL); 1996 } 1997 1998 /* 1999 * This is a workaround for a Solaris bug where 2000 * gss_wrap_size_limit may return very big sizes for 2001 * small input values 2002 */ 2003 if (max_input_size < oparams->maxoutbuf) 2004 oparams->maxoutbuf = max_input_size; 2005 else { 2006 oparams->maxoutbuf = 0; 2007 } 2008 } 2009 #else 2010 if(oparams->mech_ssf) { 2011 /* xxx probably too large */ 2012 oparams->maxoutbuf -= 50; 2013 } 2014 #endif /* _SUN_SDK_ */ 2015 2016 gss_release_buffer(&min_stat, output_token); 2017 2018 /* oparams->user is always set, due to canon_user requirements. 2019 * Make sure the client actually requested it though, by checking 2020 * if our context was set. 2021 */ 2022 if (text->user && text->user[0]) 2023 alen = strlen(oparams->user); 2024 else 2025 alen = 0; 2026 2027 input_token->length = 4 + alen; 2028 input_token->value = 2029 (char *)params->utils->malloc((input_token->length + 1)*sizeof(char)); 2030 if (input_token->value == NULL) { 2031 sasl_gss_free_context_contents(text); 2032 return SASL_NOMEM; 2033 } 2034 2035 if (alen) 2036 memcpy((char *)input_token->value+4,oparams->user,alen); 2037 2038 /* build up our security properties token */ 2039 if (params->props.maxbufsize > 0xFFFFFF) { 2040 /* make sure maxbufsize isn't too large */ 2041 /* maxbufsize = 0xFFFFFF */ 2042 ((unsigned char *)input_token->value)[1] = 0xFF; 2043 ((unsigned char *)input_token->value)[2] = 0xFF; 2044 ((unsigned char *)input_token->value)[3] = 0xFF; 2045 } else { 2046 ((unsigned char *)input_token->value)[1] = 2047 (params->props.maxbufsize >> 16) & 0xFF; 2048 ((unsigned char *)input_token->value)[2] = 2049 (params->props.maxbufsize >> 8) & 0xFF; 2050 ((unsigned char *)input_token->value)[3] = 2051 (params->props.maxbufsize >> 0) & 0xFF; 2052 } 2053 ((unsigned char *)input_token->value)[0] = mychoice; 2054 2055 maj_stat = gss_wrap (&min_stat, 2056 text->gss_ctx, 2057 0, /* Just integrity checking here */ 2058 GSS_C_QOP_DEFAULT, 2059 input_token, 2060 NULL, 2061 output_token); 2062 2063 params->utils->free(input_token->value); 2064 input_token->value = NULL; 2065 2066 if (GSS_ERROR(maj_stat)) { 2067 sasl_gss_seterror(text->utils, maj_stat, min_stat); 2068 if (output_token->value) 2069 gss_release_buffer(&min_stat, output_token); 2070 sasl_gss_free_context_contents(text); 2071 return SASL_FAIL; 2072 } 2073 2074 if (clientoutlen) 2075 *clientoutlen = output_token->length; 2076 if (output_token->value) { 2077 if (clientout) { 2078 ret = _plug_buf_alloc(text->utils, &(text->out_buf), 2079 &(text->out_buf_len), *clientoutlen); 2080 if (ret != SASL_OK) { 2081 gss_release_buffer(&min_stat, output_token); 2082 return ret; 2083 } 2084 memcpy(text->out_buf, output_token->value, *clientoutlen); 2085 *clientout = text->out_buf; 2086 } 2087 2088 gss_release_buffer(&min_stat, output_token); 2089 } 2090 2091 text->state = SASL_GSSAPI_STATE_AUTHENTICATED; 2092 2093 oparams->doneflag = 1; 2094 2095 return SASL_OK; 2096 } 2097 2098 default: 2099 #ifdef _SUN_SDK_ 2100 params->utils->log(params->utils->conn, SASL_LOG_ERR, 2101 "Invalid GSSAPI client step %d", text->state); 2102 #else 2103 params->utils->log(NULL, SASL_LOG_ERR, 2104 "Invalid GSSAPI client step %d\n", text->state); 2105 #endif /* _SUN_SDK_ */ 2106 return SASL_FAIL; 2107 } 2108 2109 #ifndef _SUN_SDK_ 2110 return SASL_FAIL; /* should never get here */ 2111 #endif /* !_SUN_SDK_ */ 2112 } 2113 2114 #ifdef _SUN_SDK_ 2115 static const unsigned long gssapi_required_prompts[] = { 2116 #else 2117 static const long gssapi_required_prompts[] = { 2118 #endif /* _SUN_SDK_ */ 2119 SASL_CB_LIST_END 2120 }; 2121 2122 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 2123 static int _gssapi_client_mech_step(void *conn_context, 2124 sasl_client_params_t *params, 2125 const char *serverin, 2126 unsigned serverinlen, 2127 sasl_interact_t **prompt_need, 2128 const char **clientout, 2129 unsigned *clientoutlen, 2130 sasl_out_params_t *oparams) 2131 { 2132 int ret; 2133 2134 if (LOCK_MUTEX(&global_mutex) < 0) 2135 return (SASL_FAIL); 2136 2137 ret = gssapi_client_mech_step(conn_context, params, serverin, serverinlen, 2138 prompt_need, clientout, clientoutlen, oparams); 2139 2140 UNLOCK_MUTEX(&global_mutex); 2141 return (ret); 2142 } 2143 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 2144 2145 static sasl_client_plug_t gssapi_client_plugins[] = 2146 { 2147 { 2148 "GSSAPI", /* mech_name */ 2149 56, /* max_ssf */ 2150 SASL_SEC_NOPLAINTEXT 2151 | SASL_SEC_NOACTIVE 2152 | SASL_SEC_NOANONYMOUS 2153 | SASL_SEC_MUTUAL_AUTH, /* security_flags */ 2154 SASL_FEAT_WANT_CLIENT_FIRST 2155 | SASL_FEAT_ALLOWS_PROXY, /* features */ 2156 gssapi_required_prompts, /* required_prompts */ 2157 NULL, /* glob_context */ 2158 &gssapi_client_mech_new, /* mech_new */ 2159 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT 2160 &_gssapi_client_mech_step, /* mech_step */ 2161 #else 2162 &gssapi_client_mech_step, /* mech_step */ 2163 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */ 2164 &gssapi_common_mech_dispose, /* mech_dispose */ 2165 NULL, /* mech_free */ 2166 NULL, /* idle */ 2167 NULL, /* spare */ 2168 NULL /* spare */ 2169 } 2170 }; 2171 2172 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)), 2173 int maxversion, 2174 int *out_version, 2175 sasl_client_plug_t **pluglist, 2176 int *plugcount) 2177 { 2178 if (maxversion < SASL_CLIENT_PLUG_VERSION) { 2179 SETERROR(utils, "Version mismatch in GSSAPI"); 2180 return SASL_BADVERS; 2181 } 2182 2183 #ifdef _INTEGRATED_SOLARIS_ 2184 /* 2185 * Let libsasl know that we are a "Sun" plugin so that privacy 2186 * and integrity will be allowed. 2187 */ 2188 REG_PLUG("GSSAPI", gssapi_client_plugins); 2189 #endif /* _INTEGRATED_SOLARIS_ */ 2190 2191 *out_version = SASL_CLIENT_PLUG_VERSION; 2192 *pluglist = gssapi_client_plugins; 2193 *plugcount = 1; 2194 2195 return SASL_OK; 2196 } 2197