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 }