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