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