3 * Rob Siemborski (SASL v2 Conversion)
4 * $Id: gssapi.c,v 1.92 2004/07/21 14:39:06 rjs3 Exp $
7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
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.
51 #include <gssapi/gssapi.h>
55 # include <winsock2.h>
60 /* we also need io.h for access() prototype */
63 # include <sys/param.h>
64 # include <sys/socket.h>
65 # include <netinet/in.h>
66 # include <arpa/inet.h>
75 #include "plugin_common.h"
83 /***************************** Common Section *****************************/
85 static const char plugin_id[] = "$Id: gssapi.c,v 1.92 2004/07/21 14:39:06 rjs3 Exp $";
87 static const char * GSSAPI_BLANK_STRING = "";
89 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
90 extern gss_OID gss_nt_service_name;
91 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
94 #ifdef WANT_KERBEROS5_3DES
95 /* Check if CyberSafe flag is defined */
96 #ifdef CSF_GSS_C_DES3_FLAG
97 #define K5_MAX_SSF 112
100 /* Heimdal and MIT use the following */
101 #ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
102 #define K5_MAX_SSF 112
108 /* All Kerberos implementations support DES */
109 #define K5_MAX_SSF 56
112 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
113 * inspired by the kerberos mechanism and the gssapi_server and
114 * gssapi_client from the heimdal distribution by Assar Westerlund
115 * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>.
116 * See the configure.in file for details on dependencies.
118 * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
120 * This code was tested with the following distributions of Kerberos:
121 * Heimdal (http://www.pdc.kth.se/heimdal), MIT (http://web.mit.edu/kerberos/www/)
122 * CyberSafe (http://www.cybersafe.com/) and SEAM.
125 #ifdef GSS_USE_MUTEXES
126 #define GSS_LOCK_MUTEX(utils) \
127 if(((sasl_utils_t *)(utils))->mutex_lock(gss_mutex) != 0) { \
131 #define GSS_UNLOCK_MUTEX(utils) \
132 if(((sasl_utils_t *)(utils))->mutex_unlock(gss_mutex) != 0) { \
136 static void *gss_mutex = NULL;
138 #define GSS_LOCK_MUTEX(utils)
139 #define GSS_UNLOCK_MUTEX(utils)
142 typedef struct context {
145 gss_ctx_id_t gss_ctx;
146 gss_name_t client_name;
147 gss_name_t server_name;
148 gss_cred_id_t server_creds;
149 gss_cred_id_t client_creds;
151 sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
153 const sasl_utils_t *utils;
155 /* layers buffering */
156 decode_context_t decode_context;
158 char *encode_buf; /* For encoding/decoding mem management */
160 char *decode_once_buf;
161 unsigned encode_buf_len;
162 unsigned decode_buf_len;
163 unsigned decode_once_buf_len;
164 buffer_info_t *enc_in_buf;
166 char *out_buf; /* per-step mem management */
167 unsigned out_buf_len;
169 char *authid; /* hold the authid between steps - server */
170 const char *user; /* hold the userid between steps - client */
174 SASL_GSSAPI_STATE_AUTHNEG = 1,
175 SASL_GSSAPI_STATE_SSFCAP = 2,
176 SASL_GSSAPI_STATE_SSFREQ = 3,
177 SASL_GSSAPI_STATE_AUTHENTICATED = 4
180 /* sasl_gss_log: only logs status string returned from gss_display_status() */
181 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
182 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
185 sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
188 OM_uint32 maj_stat, min_stat;
193 size_t len, curlen = 0;
194 const char prefix[] = "GSSAPI Error: ";
196 len = sizeof(prefix);
197 ret = _plug_buf_alloc(utils, &out, &curlen, 256);
198 if(ret != SASL_OK) return SASL_OK;
204 GSS_LOCK_MUTEX(utils);
205 maj_stat = gss_display_status(&min_stat, maj,
206 GSS_C_GSS_CODE, GSS_C_NULL_OID,
208 GSS_UNLOCK_MUTEX(utils);
210 if(GSS_ERROR(maj_stat)) {
212 utils->log(utils->conn, SASL_LOG_FAIL,
213 "GSSAPI Failure: (could not get major error message)");
215 utils->seterror(utils->conn, 0,
217 "(could not get major error message)");
223 len += len + msg.length;
224 ret = _plug_buf_alloc(utils, &out, &curlen, len);
231 strcat(out, msg.value);
233 GSS_LOCK_MUTEX(utils);
234 gss_release_buffer(&min_stat, &msg);
235 GSS_UNLOCK_MUTEX(utils);
241 /* Now get the minor status */
244 ret = _plug_buf_alloc(utils, &out, &curlen, len);
254 GSS_LOCK_MUTEX(utils);
255 maj_stat = gss_display_status(&min_stat, min,
256 GSS_C_MECH_CODE, GSS_C_NULL_OID,
258 GSS_UNLOCK_MUTEX(utils);
260 if(GSS_ERROR(maj_stat)) {
262 utils->log(utils->conn, SASL_LOG_FAIL,
263 "GSSAPI Failure: (could not get minor error message)");
265 utils->seterror(utils->conn, 0,
267 "(could not get minor error message)");
273 len += len + msg.length;
275 ret = _plug_buf_alloc(utils, &out, &curlen, len);
281 strcat(out, msg.value);
283 GSS_LOCK_MUTEX(utils);
284 gss_release_buffer(&min_stat, &msg);
285 GSS_UNLOCK_MUTEX(utils);
292 ret = _plug_buf_alloc(utils, &out, &curlen, len);
301 utils->log(utils->conn, SASL_LOG_FAIL, out);
303 utils->seterror(utils->conn, 0, out);
311 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
312 const char **output, unsigned *outputlen, int privacy)
314 context_t *text = (context_t *)context;
315 OM_uint32 maj_stat, min_stat;
316 gss_buffer_t input_token, output_token;
317 gss_buffer_desc real_input_token, real_output_token;
319 struct buffer_info *inblob, bufinfo;
321 if(!output) return SASL_BADPARAM;
324 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
325 if(ret != SASL_OK) return ret;
326 inblob = text->enc_in_buf;
328 bufinfo.data = invec[0].iov_base;
329 bufinfo.curlen = invec[0].iov_len;
333 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
335 input_token = &real_input_token;
337 real_input_token.value = inblob->data;
338 real_input_token.length = inblob->curlen;
340 output_token = &real_output_token;
341 output_token->value = NULL;
342 output_token->length = 0;
344 GSS_LOCK_MUTEX(text->utils);
345 maj_stat = gss_wrap (&min_stat,
352 GSS_UNLOCK_MUTEX(text->utils);
354 if (GSS_ERROR(maj_stat))
356 sasl_gss_seterror(text->utils, maj_stat, min_stat);
357 if (output_token->value) {
358 GSS_LOCK_MUTEX(text->utils);
359 gss_release_buffer(&min_stat, output_token);
360 GSS_UNLOCK_MUTEX(text->utils);
365 if (output_token->value && output) {
368 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
369 &(text->encode_buf_len), output_token->length + 4);
371 if (ret != SASL_OK) {
372 GSS_LOCK_MUTEX(text->utils);
373 gss_release_buffer(&min_stat, output_token);
374 GSS_UNLOCK_MUTEX(text->utils);
378 len = htonl(output_token->length);
379 memcpy(text->encode_buf, &len, 4);
380 memcpy(text->encode_buf + 4, output_token->value, output_token->length);
384 *outputlen = output_token->length + 4;
387 *output = text->encode_buf;
389 if (output_token->value) {
390 GSS_LOCK_MUTEX(text->utils);
391 gss_release_buffer(&min_stat, output_token);
392 GSS_UNLOCK_MUTEX(text->utils);
397 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
398 unsigned numiov, const char **output,
401 return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
404 static int gssapi_integrity_encode(void *context, const struct iovec *invec,
405 unsigned numiov, const char **output,
408 return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
411 static int gssapi_decode_packet(void *context,
412 const char *input, unsigned inputlen,
413 char **output, unsigned *outputlen)
415 context_t *text = (context_t *) context;
416 OM_uint32 maj_stat, min_stat;
417 gss_buffer_t input_token, output_token;
418 gss_buffer_desc real_input_token, real_output_token;
421 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
422 SETERROR(text->utils, "GSSAPI Failure");
426 input_token = &real_input_token;
427 real_input_token.value = (char *) input;
428 real_input_token.length = inputlen;
430 output_token = &real_output_token;
431 output_token->value = NULL;
432 output_token->length = 0;
434 GSS_LOCK_MUTEX(text->utils);
435 maj_stat = gss_unwrap (&min_stat,
441 GSS_UNLOCK_MUTEX(text->utils);
443 if (GSS_ERROR(maj_stat))
445 sasl_gss_seterror(text->utils,maj_stat,min_stat);
446 if (output_token->value) {
447 GSS_LOCK_MUTEX(text->utils);
448 gss_release_buffer(&min_stat, output_token);
449 GSS_UNLOCK_MUTEX(text->utils);
455 *outputlen = output_token->length;
457 if (output_token->value) {
459 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
460 &text->decode_once_buf_len,
462 if(result != SASL_OK) {
463 GSS_LOCK_MUTEX(text->utils);
464 gss_release_buffer(&min_stat, output_token);
465 GSS_UNLOCK_MUTEX(text->utils);
468 *output = text->decode_once_buf;
469 memcpy(*output, output_token->value, *outputlen);
471 GSS_LOCK_MUTEX(text->utils);
472 gss_release_buffer(&min_stat, output_token);
473 GSS_UNLOCK_MUTEX(text->utils);
479 static int gssapi_decode(void *context,
480 const char *input, unsigned inputlen,
481 const char **output, unsigned *outputlen)
483 context_t *text = (context_t *) context;
486 ret = _plug_decode(&text->decode_context, input, inputlen,
487 &text->decode_buf, &text->decode_buf_len, outputlen,
488 gssapi_decode_packet, text);
490 *output = text->decode_buf;
495 static context_t *sasl_gss_new_context(const sasl_utils_t *utils)
499 ret = utils->malloc(sizeof(context_t));
500 if(!ret) return NULL;
502 memset(ret,0,sizeof(context_t));
508 static int sasl_gss_free_context_contents(context_t *text)
510 OM_uint32 maj_stat, min_stat;
512 if (!text) return SASL_OK;
514 GSS_LOCK_MUTEX(text->utils);
516 if (text->gss_ctx != GSS_C_NO_CONTEXT) {
517 maj_stat = gss_delete_sec_context(&min_stat,&text->gss_ctx,
519 text->gss_ctx = GSS_C_NO_CONTEXT;
522 if (text->client_name != GSS_C_NO_NAME) {
523 maj_stat = gss_release_name(&min_stat,&text->client_name);
524 text->client_name = GSS_C_NO_NAME;
527 if (text->server_name != GSS_C_NO_NAME) {
528 maj_stat = gss_release_name(&min_stat,&text->server_name);
529 text->server_name = GSS_C_NO_NAME;
532 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
533 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
534 text->server_creds = GSS_C_NO_CREDENTIAL;
537 if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
538 maj_stat = gss_release_cred(&min_stat, &text->client_creds);
539 text->client_creds = GSS_C_NO_CREDENTIAL;
542 GSS_UNLOCK_MUTEX(text->utils);
545 text->utils->free(text->out_buf);
546 text->out_buf = NULL;
549 if (text->encode_buf) {
550 text->utils->free(text->encode_buf);
551 text->encode_buf = NULL;
554 if (text->decode_buf) {
555 text->utils->free(text->decode_buf);
556 text->decode_buf = NULL;
559 if (text->decode_once_buf) {
560 text->utils->free(text->decode_once_buf);
561 text->decode_once_buf = NULL;
564 if (text->enc_in_buf) {
565 if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
566 text->utils->free(text->enc_in_buf);
567 text->enc_in_buf = NULL;
570 _plug_decode_free(&text->decode_context);
572 if (text->authid) { /* works for both client and server */
573 text->utils->free(text->authid);
581 static void gssapi_common_mech_dispose(void *conn_context,
582 const sasl_utils_t *utils)
584 sasl_gss_free_context_contents((context_t *)(conn_context));
585 utils->free(conn_context);
588 static void gssapi_common_mech_free(void *global_context __attribute__((unused)),
589 const sasl_utils_t *utils)
591 #ifdef GSS_USE_MUTEXES
593 utils->mutex_free(gss_mutex);
599 /***************************** Server Section *****************************/
602 gssapi_server_mech_new(void *glob_context __attribute__((unused)),
603 sasl_server_params_t *params,
604 const char *challenge __attribute__((unused)),
605 unsigned challen __attribute__((unused)),
610 text = sasl_gss_new_context(params->utils);
612 MEMERROR(params->utils);
616 text->gss_ctx = GSS_C_NO_CONTEXT;
617 text->client_name = GSS_C_NO_NAME;
618 text->server_name = GSS_C_NO_NAME;
619 text->server_creds = GSS_C_NO_CREDENTIAL;
620 text->client_creds = GSS_C_NO_CREDENTIAL;
621 text->state = SASL_GSSAPI_STATE_AUTHNEG;
623 *conn_context = text;
629 gssapi_server_mech_step(void *conn_context,
630 sasl_server_params_t *params,
631 const char *clientin,
632 unsigned clientinlen,
633 const char **serverout,
634 unsigned *serveroutlen,
635 sasl_out_params_t *oparams)
637 context_t *text = (context_t *)conn_context;
638 gss_buffer_t input_token, output_token;
639 gss_buffer_desc real_input_token, real_output_token;
640 OM_uint32 maj_stat = 0, min_stat = 0;
642 gss_buffer_desc name_token;
643 int ret, out_flags = 0 ;
645 input_token = &real_input_token;
646 output_token = &real_output_token;
647 output_token->value = NULL; output_token->length = 0;
648 input_token->value = NULL; input_token->length = 0;
651 PARAMERROR(text->utils);
652 return SASL_BADPARAM;
658 switch (text->state) {
660 case SASL_GSSAPI_STATE_AUTHNEG:
661 if (text->server_name == GSS_C_NO_NAME) { /* only once */
662 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
663 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
664 if (name_token.value == NULL) {
665 MEMERROR(text->utils);
666 sasl_gss_free_context_contents(text);
669 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
671 GSS_LOCK_MUTEX(params->utils);
672 maj_stat = gss_import_name (&min_stat,
674 GSS_C_NT_HOSTBASED_SERVICE,
676 GSS_UNLOCK_MUTEX(params->utils);
678 params->utils->free(name_token.value);
679 name_token.value = NULL;
681 if (GSS_ERROR(maj_stat)) {
682 sasl_gss_seterror(text->utils, maj_stat, min_stat);
683 sasl_gss_free_context_contents(text);
687 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
688 GSS_LOCK_MUTEX(params->utils);
689 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
690 GSS_UNLOCK_MUTEX(params->utils);
691 text->server_creds = GSS_C_NO_CREDENTIAL;
694 GSS_LOCK_MUTEX(params->utils);
695 maj_stat = gss_acquire_cred(&min_stat,
703 GSS_UNLOCK_MUTEX(params->utils);
705 if (GSS_ERROR(maj_stat)) {
706 sasl_gss_seterror(text->utils, maj_stat, min_stat);
707 sasl_gss_free_context_contents(text);
713 real_input_token.value = (void *)clientin;
714 real_input_token.length = clientinlen;
718 GSS_LOCK_MUTEX(params->utils);
720 gss_accept_sec_context(&min_stat,
724 GSS_C_NO_CHANNEL_BINDINGS,
730 &(text->client_creds));
731 GSS_UNLOCK_MUTEX(params->utils);
733 if (GSS_ERROR(maj_stat)) {
734 sasl_gss_log(text->utils, maj_stat, min_stat);
735 text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
736 if (output_token->value) {
737 GSS_LOCK_MUTEX(params->utils);
738 gss_release_buffer(&min_stat, output_token);
739 GSS_UNLOCK_MUTEX(params->utils);
741 sasl_gss_free_context_contents(text);
746 if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
747 (!(out_flags & GSS_C_DELEG_FLAG) ||
748 text->client_creds == GSS_C_NO_CREDENTIAL) )
750 text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
751 "GSSAPI warning: no credentials were passed");
752 /* continue with authentication */
756 *serveroutlen = output_token->length;
757 if (output_token->value) {
759 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
760 &(text->out_buf_len), *serveroutlen);
762 GSS_LOCK_MUTEX(params->utils);
763 gss_release_buffer(&min_stat, output_token);
764 GSS_UNLOCK_MUTEX(params->utils);
767 memcpy(text->out_buf, output_token->value, *serveroutlen);
768 *serverout = text->out_buf;
771 GSS_LOCK_MUTEX(params->utils);
772 gss_release_buffer(&min_stat, output_token);
773 GSS_UNLOCK_MUTEX(params->utils);
775 /* No output token, send an empty string */
776 *serverout = GSSAPI_BLANK_STRING;
780 if (maj_stat == GSS_S_COMPLETE) {
781 /* Switch to ssf negotiation */
782 text->state = SASL_GSSAPI_STATE_SSFCAP;
785 return SASL_CONTINUE;
787 case SASL_GSSAPI_STATE_SSFCAP: {
788 unsigned char sasldata[4];
789 gss_buffer_desc name_token;
790 gss_buffer_desc name_without_realm;
791 gss_name_t without = NULL;
794 name_token.value = NULL;
795 name_without_realm.value = NULL;
797 /* We ignore whatever the client sent us at this stage */
799 GSS_LOCK_MUTEX(params->utils);
800 maj_stat = gss_display_name (&min_stat,
804 GSS_UNLOCK_MUTEX(params->utils);
806 if (GSS_ERROR(maj_stat)) {
808 GSS_LOCK_MUTEX(params->utils);
809 gss_release_name(&min_stat, &without);
810 GSS_UNLOCK_MUTEX(params->utils);
812 SETERROR(text->utils, "GSSAPI Failure");
813 sasl_gss_free_context_contents(text);
817 /* If the id contains a realm get the identifier for the user
818 without the realm and see if it's the same id (i.e.
819 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
820 to return the id (i.e. just "tmartin" */
821 if (strchr((char *) name_token.value, (int) '@') != NULL) {
822 /* NOTE: libc malloc, as it is freed below by a gssapi internal
824 name_without_realm.value = params->utils->malloc(strlen(name_token.value)+1);
825 if (name_without_realm.value == NULL) {
826 if (name_token.value) {
827 GSS_LOCK_MUTEX(params->utils);
828 gss_release_buffer(&min_stat, &name_token);
829 GSS_UNLOCK_MUTEX(params->utils);
831 MEMERROR(text->utils);
835 strcpy(name_without_realm.value, name_token.value);
837 /* cut off string at '@' */
838 (strchr(name_without_realm.value,'@'))[0] = '\0';
840 name_without_realm.length = strlen( (char *) name_without_realm.value );
842 GSS_LOCK_MUTEX(params->utils);
843 maj_stat = gss_import_name (&min_stat,
845 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
846 so use GSS_C_NT_USER_NAME instead if available. */
847 #ifdef HAVE_GSS_C_NT_USER_NAME
853 GSS_UNLOCK_MUTEX(params->utils);
855 if (GSS_ERROR(maj_stat)) {
856 params->utils->free(name_without_realm.value);
857 if (name_token.value) {
858 GSS_LOCK_MUTEX(params->utils);
859 gss_release_buffer(&min_stat, &name_token);
860 GSS_UNLOCK_MUTEX(params->utils);
862 SETERROR(text->utils, "GSSAPI Failure");
863 sasl_gss_free_context_contents(text);
867 GSS_LOCK_MUTEX(params->utils);
868 maj_stat = gss_compare_name(&min_stat,
872 GSS_UNLOCK_MUTEX(params->utils);
874 if (GSS_ERROR(maj_stat)) {
875 params->utils->free(name_without_realm.value);
876 if (name_token.value) {
877 GSS_LOCK_MUTEX(params->utils);
878 gss_release_buffer(&min_stat, &name_token);
879 GSS_UNLOCK_MUTEX(params->utils);
882 GSS_LOCK_MUTEX(params->utils);
883 gss_release_name(&min_stat, &without);
884 GSS_UNLOCK_MUTEX(params->utils);
886 SETERROR(text->utils, "GSSAPI Failure");
887 sasl_gss_free_context_contents(text);
891 GSS_LOCK_MUTEX(params->utils);
892 gss_release_name(&min_stat,&without);
893 GSS_UNLOCK_MUTEX(params->utils);
900 text->authid = strdup(name_without_realm.value);
902 if (text->authid == NULL) {
903 MEMERROR(params->utils);
907 text->authid = strdup(name_token.value);
909 if (text->authid == NULL) {
910 MEMERROR(params->utils);
915 if (name_token.value) {
916 GSS_LOCK_MUTEX(params->utils);
917 gss_release_buffer(&min_stat, &name_token);
918 GSS_UNLOCK_MUTEX(params->utils);
920 if (name_without_realm.value) {
921 params->utils->free(name_without_realm.value);
924 /* we have to decide what sort of encryption/integrity/etc.,
926 if (params->props.max_ssf < params->external_ssf) {
929 text->limitssf = params->props.max_ssf - params->external_ssf;
931 if (params->props.min_ssf < params->external_ssf) {
932 text->requiressf = 0;
934 text->requiressf = params->props.min_ssf - params->external_ssf;
937 /* build up our security properties token */
938 if (params->props.maxbufsize > 0xFFFFFF) {
939 /* make sure maxbufsize isn't too large */
940 /* maxbufsize = 0xFFFFFF */
941 sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
943 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
944 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
945 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
948 if(text->requiressf != 0 && !params->props.maxbufsize) {
949 params->utils->seterror(params->utils->conn, 0,
950 "GSSAPI needs a security layer but one is forbidden");
954 if (text->requiressf == 0) {
955 sasldata[0] |= 1; /* authentication */
957 if (text->requiressf <= 1 && text->limitssf >= 1
958 && params->props.maxbufsize) {
961 if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF
962 && params->props.maxbufsize) {
966 real_input_token.value = (void *)sasldata;
967 real_input_token.length = 4;
969 GSS_LOCK_MUTEX(params->utils);
970 maj_stat = gss_wrap(&min_stat,
972 0, /* Just integrity checking here */
977 GSS_UNLOCK_MUTEX(params->utils);
979 if (GSS_ERROR(maj_stat)) {
980 sasl_gss_seterror(text->utils, maj_stat, min_stat);
981 if (output_token->value) {
982 GSS_LOCK_MUTEX(params->utils);
983 gss_release_buffer(&min_stat, output_token);
984 GSS_UNLOCK_MUTEX(params->utils);
986 sasl_gss_free_context_contents(text);
992 *serveroutlen = output_token->length;
993 if (output_token->value) {
995 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
996 &(text->out_buf_len), *serveroutlen);
998 GSS_LOCK_MUTEX(params->utils);
999 gss_release_buffer(&min_stat, output_token);
1000 GSS_UNLOCK_MUTEX(params->utils);
1003 memcpy(text->out_buf, output_token->value, *serveroutlen);
1004 *serverout = text->out_buf;
1007 GSS_LOCK_MUTEX(params->utils);
1008 gss_release_buffer(&min_stat, output_token);
1009 GSS_UNLOCK_MUTEX(params->utils);
1012 /* Wait for ssf request and authid */
1013 text->state = SASL_GSSAPI_STATE_SSFREQ;
1015 return SASL_CONTINUE;
1018 case SASL_GSSAPI_STATE_SSFREQ: {
1021 real_input_token.value = (void *)clientin;
1022 real_input_token.length = clientinlen;
1024 GSS_LOCK_MUTEX(params->utils);
1025 maj_stat = gss_unwrap(&min_stat,
1031 GSS_UNLOCK_MUTEX(params->utils);
1033 if (GSS_ERROR(maj_stat)) {
1034 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1035 sasl_gss_free_context_contents(text);
1039 layerchoice = (int)(((char *)(output_token->value))[0]);
1040 if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
1041 oparams->encode = NULL;
1042 oparams->decode = NULL;
1043 oparams->mech_ssf = 0;
1044 } else if (layerchoice == 2 && text->requiressf <= 1 &&
1045 text->limitssf >= 1) { /* integrity */
1046 oparams->encode=&gssapi_integrity_encode;
1047 oparams->decode=&gssapi_decode;
1048 oparams->mech_ssf=1;
1049 } else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF &&
1050 text->limitssf >= K5_MAX_SSF) { /* privacy */
1051 oparams->encode = &gssapi_privacy_encode;
1052 oparams->decode = &gssapi_decode;
1053 /* FIX ME: Need to extract the proper value here */
1054 oparams->mech_ssf = K5_MAX_SSF;
1056 /* not a supported encryption layer */
1057 SETERROR(text->utils,
1058 "protocol violation: client requested invalid layer");
1059 /* Mark that we attempted negotiation */
1060 oparams->mech_ssf = 2;
1061 if (output_token->value) {
1062 GSS_LOCK_MUTEX(params->utils);
1063 gss_release_buffer(&min_stat, output_token);
1064 GSS_UNLOCK_MUTEX(params->utils);
1066 sasl_gss_free_context_contents(text);
1070 if (output_token->length > 4) {
1073 ret = params->canon_user(params->utils->conn,
1074 ((char *) output_token->value) + 4,
1075 (output_token->length - 4) * sizeof(char),
1076 SASL_CU_AUTHZID, oparams);
1078 if (ret != SASL_OK) {
1079 sasl_gss_free_context_contents(text);
1083 ret = params->canon_user(params->utils->conn,
1085 0, /* strlen(text->authid) */
1086 SASL_CU_AUTHID, oparams);
1087 if (ret != SASL_OK) {
1088 sasl_gss_free_context_contents(text);
1091 } else if(output_token->length == 4) {
1095 ret = params->canon_user(params->utils->conn,
1097 0, /* strlen(text->authid) */
1098 SASL_CU_AUTHZID | SASL_CU_AUTHID,
1101 if (ret != SASL_OK) {
1102 sasl_gss_free_context_contents(text);
1106 SETERROR(text->utils,
1108 GSS_LOCK_MUTEX(params->utils);
1109 gss_release_buffer(&min_stat, output_token);
1110 GSS_UNLOCK_MUTEX(params->utils);
1111 sasl_gss_free_context_contents(text);
1115 /* No matter what, set the rest of the oparams */
1117 if (text->client_creds != GSS_C_NO_CREDENTIAL) {
1118 oparams->client_creds = &text->client_creds;
1121 oparams->client_creds = NULL;
1124 oparams->maxoutbuf =
1125 (((unsigned char *) output_token->value)[1] << 16) |
1126 (((unsigned char *) output_token->value)[2] << 8) |
1127 (((unsigned char *) output_token->value)[3] << 0);
1129 if (oparams->mech_ssf) {
1130 maj_stat = gss_wrap_size_limit( &min_stat,
1134 (OM_uint32) oparams->maxoutbuf,
1137 if(max_input > oparams->maxoutbuf) {
1138 /* Heimdal appears to get this wrong */
1139 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1141 /* This code is actually correct */
1142 oparams->maxoutbuf = max_input;
1146 GSS_LOCK_MUTEX(params->utils);
1147 gss_release_buffer(&min_stat, output_token);
1148 GSS_UNLOCK_MUTEX(params->utils);
1150 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1152 /* used by layers */
1153 _plug_decode_init(&text->decode_context, text->utils,
1154 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1155 params->props.maxbufsize);
1157 oparams->doneflag = 1;
1163 params->utils->log(NULL, SASL_LOG_ERR,
1164 "Invalid GSSAPI server step %d\n", text->state);
1168 return SASL_FAIL; /* should never get here */
1171 static sasl_server_plug_t gssapi_server_plugins[] =
1174 "GSSAPI", /* mech_name */
1175 K5_MAX_SSF, /* max_ssf */
1176 SASL_SEC_NOPLAINTEXT
1178 | SASL_SEC_NOANONYMOUS
1179 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1180 | SASL_SEC_PASS_CREDENTIALS,
1181 SASL_FEAT_WANT_CLIENT_FIRST
1182 | SASL_FEAT_ALLOWS_PROXY, /* features */
1183 NULL, /* glob_context */
1184 &gssapi_server_mech_new, /* mech_new */
1185 &gssapi_server_mech_step, /* mech_step */
1186 &gssapi_common_mech_dispose, /* mech_dispose */
1187 &gssapi_common_mech_free, /* mech_free */
1189 NULL, /* user_query */
1191 NULL, /* mech_avail */
1196 int gssapiv2_server_plug_init(
1197 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1198 const sasl_utils_t *utils __attribute__((unused)),
1200 const sasl_utils_t *utils,
1204 sasl_server_plug_t **pluglist,
1207 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1208 const char *keytab = NULL;
1209 char keytab_path[1024];
1213 if (maxversion < SASL_SERVER_PLUG_VERSION) {
1214 return SASL_BADVERS;
1217 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1218 /* unfortunately, we don't check for readability of keytab if it's
1219 the standard one, since we don't know where it is */
1221 /* FIXME: This code is broken */
1223 utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
1224 if (keytab != NULL) {
1225 if (access(keytab, R_OK) != 0) {
1226 utils->log(NULL, SASL_LOG_ERR,
1227 "Could not find keytab file: %s: %m",
1232 if(strlen(keytab) > 1024) {
1233 utils->log(NULL, SASL_LOG_ERR,
1234 "path to keytab is > 1024 characters");
1235 return SASL_BUFOVER;
1238 strncpy(keytab_path, keytab, 1024);
1240 gsskrb5_register_acceptor_identity(keytab_path);
1244 *out_version = SASL_SERVER_PLUG_VERSION;
1245 *pluglist = gssapi_server_plugins;
1248 #ifdef GSS_USE_MUTEXES
1250 gss_mutex = utils->mutex_alloc();
1260 /***************************** Client Section *****************************/
1262 static int gssapi_client_mech_new(void *glob_context __attribute__((unused)),
1263 sasl_client_params_t *params,
1264 void **conn_context)
1268 /* holds state are in */
1269 text = sasl_gss_new_context(params->utils);
1271 MEMERROR(params->utils);
1275 text->state = SASL_GSSAPI_STATE_AUTHNEG;
1276 text->gss_ctx = GSS_C_NO_CONTEXT;
1277 text->client_name = GSS_C_NO_NAME;
1278 text->server_creds = GSS_C_NO_CREDENTIAL;
1279 text->client_creds = GSS_C_NO_CREDENTIAL;
1281 *conn_context = text;
1286 static int gssapi_client_mech_step(void *conn_context,
1287 sasl_client_params_t *params,
1288 const char *serverin,
1289 unsigned serverinlen,
1290 sasl_interact_t **prompt_need,
1291 const char **clientout,
1292 unsigned *clientoutlen,
1293 sasl_out_params_t *oparams)
1295 context_t *text = (context_t *)conn_context;
1296 gss_buffer_t input_token, output_token;
1297 gss_buffer_desc real_input_token, real_output_token;
1298 OM_uint32 maj_stat = 0, min_stat = 0;
1299 OM_uint32 max_input;
1300 gss_buffer_desc name_token;
1302 OM_uint32 req_flags = 0, out_req_flags = 0;
1303 input_token = &real_input_token;
1304 output_token = &real_output_token;
1305 output_token->value = NULL;
1306 input_token->value = NULL;
1307 input_token->length = 0;
1312 switch (text->state) {
1314 case SASL_GSSAPI_STATE_AUTHNEG:
1315 /* try to get the userid */
1316 if (text->user == NULL) {
1317 int user_result = SASL_OK;
1319 user_result = _plug_get_userid(params->utils, &text->user,
1322 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
1323 sasl_gss_free_context_contents(text);
1327 /* free prompts we got */
1328 if (prompt_need && *prompt_need) {
1329 params->utils->free(*prompt_need);
1330 *prompt_need = NULL;
1333 /* if there are prompts not filled in */
1334 if (user_result == SASL_INTERACT) {
1335 /* make the prompt list */
1337 _plug_make_prompts(params->utils, prompt_need,
1338 user_result == SASL_INTERACT ?
1339 "Please enter your authorization name" : NULL, NULL,
1344 if (result != SASL_OK) return result;
1346 return SASL_INTERACT;
1350 if (text->server_name == GSS_C_NO_NAME) { /* only once */
1351 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
1352 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
1353 if (name_token.value == NULL) {
1354 sasl_gss_free_context_contents(text);
1357 if (params->serverFQDN == NULL
1358 || strlen(params->serverFQDN) == 0) {
1359 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1363 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1365 GSS_LOCK_MUTEX(params->utils);
1366 maj_stat = gss_import_name (&min_stat,
1368 GSS_C_NT_HOSTBASED_SERVICE,
1369 &text->server_name);
1370 GSS_UNLOCK_MUTEX(params->utils);
1372 params->utils->free(name_token.value);
1373 name_token.value = NULL;
1375 if (GSS_ERROR(maj_stat)) {
1376 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1377 sasl_gss_free_context_contents(text);
1382 if (serverinlen == 0)
1383 input_token = GSS_C_NO_BUFFER;
1386 real_input_token.value = (void *)serverin;
1387 real_input_token.length = serverinlen;
1389 else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
1390 /* This can't happen under GSSAPI: we have a non-null context
1391 * and no input from the server. However, thanks to Imap,
1392 * which discards our first output, this happens all the time.
1393 * Throw away the context and try again. */
1394 GSS_LOCK_MUTEX(params->utils);
1395 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
1396 GSS_UNLOCK_MUTEX(params->utils);
1397 text->gss_ctx = GSS_C_NO_CONTEXT;
1400 /* Setup req_flags properly */
1401 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
1402 if(params->props.max_ssf > params->external_ssf) {
1403 /* We are requesting a security layer */
1404 req_flags |= GSS_C_INTEG_FLAG;
1405 /* Any SSF bigger than 1 is confidentiality. */
1406 /* Let's check if the client of the API requires confidentiality,
1407 and it wasn't already provided by an external layer */
1408 if(params->props.max_ssf - params->external_ssf > 1) {
1409 /* We want to try for privacy */
1410 req_flags |= GSS_C_CONF_FLAG;
1414 if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS)
1415 req_flags = req_flags | GSS_C_DELEG_FLAG;
1417 GSS_LOCK_MUTEX(params->utils);
1418 maj_stat = gss_init_sec_context(&min_stat,
1419 GSS_C_NO_CREDENTIAL,
1425 GSS_C_NO_CHANNEL_BINDINGS,
1431 GSS_UNLOCK_MUTEX(params->utils);
1433 if (GSS_ERROR(maj_stat)) {
1434 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1435 if (output_token->value) {
1436 GSS_LOCK_MUTEX(params->utils);
1437 gss_release_buffer(&min_stat, output_token);
1438 GSS_UNLOCK_MUTEX(params->utils);
1440 sasl_gss_free_context_contents(text);
1444 if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_FLAG)) {
1445 text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
1446 /* not a fatal error */
1449 *clientoutlen = output_token->length;
1451 if (output_token->value) {
1453 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1454 &(text->out_buf_len), *clientoutlen);
1455 if(ret != SASL_OK) {
1456 GSS_LOCK_MUTEX(params->utils);
1457 gss_release_buffer(&min_stat, output_token);
1458 GSS_UNLOCK_MUTEX(params->utils);
1461 memcpy(text->out_buf, output_token->value, *clientoutlen);
1462 *clientout = text->out_buf;
1465 GSS_LOCK_MUTEX(params->utils);
1466 gss_release_buffer(&min_stat, output_token);
1467 GSS_UNLOCK_MUTEX(params->utils);
1470 if (maj_stat == GSS_S_COMPLETE) {
1471 GSS_LOCK_MUTEX(params->utils);
1472 maj_stat = gss_inquire_context(&min_stat,
1475 NULL, /* targ_name */
1476 NULL, /* lifetime */
1478 /* FIX ME: Should check the resulting flags here */
1480 NULL, /* local init */
1482 GSS_UNLOCK_MUTEX(params->utils);
1484 if (GSS_ERROR(maj_stat)) {
1485 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1486 sasl_gss_free_context_contents(text);
1490 name_token.length = 0;
1491 GSS_LOCK_MUTEX(params->utils);
1492 maj_stat = gss_display_name(&min_stat,
1496 GSS_UNLOCK_MUTEX(params->utils);
1498 if (GSS_ERROR(maj_stat)) {
1499 if (name_token.value) {
1500 GSS_LOCK_MUTEX(params->utils);
1501 gss_release_buffer(&min_stat, &name_token);
1502 GSS_UNLOCK_MUTEX(params->utils);
1504 SETERROR(text->utils, "GSSAPI Failure");
1505 sasl_gss_free_context_contents(text);
1509 if (text->user && text->user[0]) {
1510 ret = params->canon_user(params->utils->conn,
1512 SASL_CU_AUTHZID, oparams);
1514 ret = params->canon_user(params->utils->conn,
1515 name_token.value, 0,
1516 SASL_CU_AUTHID, oparams);
1518 ret = params->canon_user(params->utils->conn,
1519 name_token.value, 0,
1520 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1523 GSS_LOCK_MUTEX(params->utils);
1524 gss_release_buffer(&min_stat, &name_token);
1525 GSS_UNLOCK_MUTEX(params->utils);
1527 if (ret != SASL_OK) return ret;
1529 /* Switch to ssf negotiation */
1530 text->state = SASL_GSSAPI_STATE_SSFCAP;
1533 return SASL_CONTINUE;
1535 case SASL_GSSAPI_STATE_SSFCAP: {
1536 sasl_security_properties_t *secprops = &(params->props);
1537 unsigned int alen, external = params->external_ssf;
1538 sasl_ssf_t need, allowed;
1539 char serverhas, mychoice;
1541 real_input_token.value = (void *) serverin;
1542 real_input_token.length = serverinlen;
1544 GSS_LOCK_MUTEX(params->utils);
1545 maj_stat = gss_unwrap(&min_stat,
1551 GSS_UNLOCK_MUTEX(params->utils);
1553 if (GSS_ERROR(maj_stat)) {
1554 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1555 sasl_gss_free_context_contents(text);
1556 if (output_token->value) {
1557 GSS_LOCK_MUTEX(params->utils);
1558 gss_release_buffer(&min_stat, output_token);
1559 GSS_UNLOCK_MUTEX(params->utils);
1564 /* taken from kerberos.c */
1565 if (secprops->min_ssf > (K5_MAX_SSF + external)) {
1566 return SASL_TOOWEAK;
1567 } else if (secprops->min_ssf > secprops->max_ssf) {
1568 return SASL_BADPARAM;
1571 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1572 if (secprops->max_ssf >= external) {
1573 allowed = secprops->max_ssf - external;
1577 if (secprops->min_ssf >= external) {
1578 need = secprops->min_ssf - external;
1584 /* bit mask of server support */
1585 serverhas = ((char *)output_token->value)[0];
1587 /* if client didn't set use strongest layer available */
1588 if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) {
1590 oparams->encode = &gssapi_privacy_encode;
1591 oparams->decode = &gssapi_decode;
1592 /* FIX ME: Need to extract the proper value here */
1593 oparams->mech_ssf = K5_MAX_SSF;
1595 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1597 oparams->encode = &gssapi_integrity_encode;
1598 oparams->decode = &gssapi_decode;
1599 oparams->mech_ssf = 1;
1601 } else if (need <= 0 && (serverhas & 1)) {
1603 oparams->encode = NULL;
1604 oparams->decode = NULL;
1605 oparams->mech_ssf = 0;
1608 /* there's no appropriate layering for us! */
1609 sasl_gss_free_context_contents(text);
1610 return SASL_TOOWEAK;
1613 oparams->maxoutbuf =
1614 (((unsigned char *) output_token->value)[1] << 16) |
1615 (((unsigned char *) output_token->value)[2] << 8) |
1616 (((unsigned char *) output_token->value)[3] << 0);
1618 if(oparams->mech_ssf) {
1619 maj_stat = gss_wrap_size_limit( &min_stat,
1623 (OM_uint32) oparams->maxoutbuf,
1626 if(max_input > oparams->maxoutbuf) {
1627 /* Heimdal appears to get this wrong */
1628 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1630 /* This code is actually correct */
1631 oparams->maxoutbuf = max_input;
1635 GSS_LOCK_MUTEX(params->utils);
1636 gss_release_buffer(&min_stat, output_token);
1637 GSS_UNLOCK_MUTEX(params->utils);
1639 /* oparams->user is always set, due to canon_user requirements.
1640 * Make sure the client actually requested it though, by checking
1641 * if our context was set.
1643 if (text->user && text->user[0])
1644 alen = strlen(oparams->user);
1648 input_token->length = 4 + alen;
1649 input_token->value =
1650 (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
1651 if (input_token->value == NULL) {
1652 sasl_gss_free_context_contents(text);
1657 memcpy((char *)input_token->value+4,oparams->user,alen);
1659 /* build up our security properties token */
1660 if (params->props.maxbufsize > 0xFFFFFF) {
1661 /* make sure maxbufsize isn't too large */
1662 /* maxbufsize = 0xFFFFFF */
1663 ((unsigned char *)input_token->value)[1] = 0xFF;
1664 ((unsigned char *)input_token->value)[2] = 0xFF;
1665 ((unsigned char *)input_token->value)[3] = 0xFF;
1667 ((unsigned char *)input_token->value)[1] =
1668 (params->props.maxbufsize >> 16) & 0xFF;
1669 ((unsigned char *)input_token->value)[2] =
1670 (params->props.maxbufsize >> 8) & 0xFF;
1671 ((unsigned char *)input_token->value)[3] =
1672 (params->props.maxbufsize >> 0) & 0xFF;
1674 ((unsigned char *)input_token->value)[0] = mychoice;
1676 GSS_LOCK_MUTEX(params->utils);
1677 maj_stat = gss_wrap (&min_stat,
1679 0, /* Just integrity checking here */
1684 GSS_UNLOCK_MUTEX(params->utils);
1686 params->utils->free(input_token->value);
1687 input_token->value = NULL;
1689 if (GSS_ERROR(maj_stat)) {
1690 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1691 if (output_token->value) {
1692 GSS_LOCK_MUTEX(params->utils);
1693 gss_release_buffer(&min_stat, output_token);
1694 GSS_UNLOCK_MUTEX(params->utils);
1696 sasl_gss_free_context_contents(text);
1701 *clientoutlen = output_token->length;
1702 if (output_token->value) {
1704 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1705 &(text->out_buf_len), *clientoutlen);
1706 if (ret != SASL_OK) {
1707 GSS_LOCK_MUTEX(params->utils);
1708 gss_release_buffer(&min_stat, output_token);
1709 GSS_UNLOCK_MUTEX(params->utils);
1712 memcpy(text->out_buf, output_token->value, *clientoutlen);
1713 *clientout = text->out_buf;
1716 GSS_LOCK_MUTEX(params->utils);
1717 gss_release_buffer(&min_stat, output_token);
1718 GSS_UNLOCK_MUTEX(params->utils);
1722 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1724 oparams->doneflag = 1;
1726 /* used by layers */
1727 _plug_decode_init(&text->decode_context, text->utils,
1728 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1729 params->props.maxbufsize);
1735 params->utils->log(NULL, SASL_LOG_ERR,
1736 "Invalid GSSAPI client step %d\n", text->state);
1740 return SASL_FAIL; /* should never get here */
1743 static const long gssapi_required_prompts[] = {
1747 static sasl_client_plug_t gssapi_client_plugins[] =
1750 "GSSAPI", /* mech_name */
1751 K5_MAX_SSF, /* max_ssf */
1752 SASL_SEC_NOPLAINTEXT
1754 | SASL_SEC_NOANONYMOUS
1755 | SASL_SEC_MUTUAL_AUTH
1756 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1757 SASL_FEAT_NEEDSERVERFQDN
1758 | SASL_FEAT_WANT_CLIENT_FIRST
1759 | SASL_FEAT_ALLOWS_PROXY, /* features */
1760 gssapi_required_prompts, /* required_prompts */
1761 NULL, /* glob_context */
1762 &gssapi_client_mech_new, /* mech_new */
1763 &gssapi_client_mech_step, /* mech_step */
1764 &gssapi_common_mech_dispose, /* mech_dispose */
1765 &gssapi_common_mech_free, /* mech_free */
1772 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
1775 sasl_client_plug_t **pluglist,
1778 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
1779 SETERROR(utils, "Version mismatch in GSSAPI");
1780 return SASL_BADVERS;
1783 *out_version = SASL_CLIENT_PLUG_VERSION;
1784 *pluglist = gssapi_client_plugins;
1787 #ifdef GSS_USE_MUTEXES
1789 gss_mutex = utils->mutex_alloc();