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>
54 #include <gssapi/gssapi_ext.h>
56 # include <winsock2.h>
61 /* we also need io.h for access() prototype */
64 # include <sys/param.h>
65 # include <sys/socket.h>
66 # include <netinet/in.h>
67 # include <arpa/inet.h>
76 #include "plugin_common.h"
84 /***************************** Common Section *****************************/
86 static const char plugin_id[] = "$Id: gssapi.c,v 1.92 2004/07/21 14:39:06 rjs3 Exp $";
88 static const char * GSSAPI_BLANK_STRING = "";
90 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
91 extern gss_OID gss_nt_service_name;
92 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
95 #ifdef WANT_KERBEROS5_3DES
96 /* Check if CyberSafe flag is defined */
97 #ifdef CSF_GSS_C_DES3_FLAG
98 #define K5_MAX_SSF 112
101 /* Heimdal and MIT use the following */
102 #ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
103 #define K5_MAX_SSF 112
109 /* All Kerberos implementations support DES */
110 #define K5_MAX_SSF 56
113 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
114 * inspired by the kerberos mechanism and the gssapi_server and
115 * gssapi_client from the heimdal distribution by Assar Westerlund
116 * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>.
117 * See the configure.in file for details on dependencies.
119 * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
121 * This code was tested with the following distributions of Kerberos:
122 * Heimdal (http://www.pdc.kth.se/heimdal), MIT (http://web.mit.edu/kerberos/www/)
123 * CyberSafe (http://www.cybersafe.com/) and SEAM.
126 #ifdef GSS_USE_MUTEXES
127 #define GSS_LOCK_MUTEX(utils) \
128 if(((sasl_utils_t *)(utils))->mutex_lock(gss_mutex) != 0) { \
132 #define GSS_UNLOCK_MUTEX(utils) \
133 if(((sasl_utils_t *)(utils))->mutex_unlock(gss_mutex) != 0) { \
137 static void *gss_mutex = NULL;
139 #define GSS_LOCK_MUTEX(utils)
140 #define GSS_UNLOCK_MUTEX(utils)
143 static gss_OID_desc gss_spnego_mechanism_oid_desc =
144 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
145 static gss_OID_desc gss_krb5_mechanism_oid_desc =
146 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
147 static gss_OID_desc gss_eap_mechanism_oid_desc =
148 {9, (void *)"\x2b\x06\x01\x04\x01\xa9\x4a\x15\x01" };
150 typedef struct context {
153 gss_ctx_id_t gss_ctx;
155 gss_name_t client_name;
156 gss_name_t server_name;
157 gss_cred_id_t server_creds;
158 gss_cred_id_t client_creds;
160 sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
162 const sasl_utils_t *utils;
164 /* layers buffering */
165 decode_context_t decode_context;
167 char *encode_buf; /* For encoding/decoding mem management */
169 char *decode_once_buf;
170 unsigned encode_buf_len;
171 unsigned decode_buf_len;
172 unsigned decode_once_buf_len;
173 buffer_info_t *enc_in_buf;
175 char *out_buf; /* per-step mem management */
176 unsigned out_buf_len;
178 char *authid; /* hold the authid between steps - server */
179 const char *user; /* hold the userid between steps - client */
186 SASL_GSSAPI_STATE_AUTHNEG = 1,
187 SASL_GSSAPI_STATE_SSFCAP = 2,
188 SASL_GSSAPI_STATE_SSFREQ = 3,
189 SASL_GSSAPI_STATE_AUTHENTICATED = 4
192 /* sasl_gss_log: only logs status string returned from gss_display_status() */
193 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
194 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
197 sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
200 OM_uint32 maj_stat, min_stat;
205 unsigned int len, curlen = 0;
206 const char prefix[] = "GSSAPI Error: ";
208 len = sizeof(prefix);
209 ret = _plug_buf_alloc(utils, &out, &curlen, 256);
210 if(ret != SASL_OK) return SASL_OK;
216 GSS_LOCK_MUTEX(utils);
217 maj_stat = gss_display_status(&min_stat, maj,
218 GSS_C_GSS_CODE, GSS_C_NULL_OID,
220 GSS_UNLOCK_MUTEX(utils);
222 if(GSS_ERROR(maj_stat)) {
224 utils->log(utils->conn, SASL_LOG_FAIL,
225 "GSSAPI Failure: (could not get major error message)");
227 utils->seterror(utils->conn, 0,
229 "(could not get major error message)");
235 len += len + msg.length;
236 ret = _plug_buf_alloc(utils, &out, &curlen, len);
243 strcat(out, msg.value);
245 GSS_LOCK_MUTEX(utils);
246 gss_release_buffer(&min_stat, &msg);
247 GSS_UNLOCK_MUTEX(utils);
253 /* Now get the minor status */
256 ret = _plug_buf_alloc(utils, &out, &curlen, len);
266 GSS_LOCK_MUTEX(utils);
267 maj_stat = gss_display_status(&min_stat, min,
268 GSS_C_MECH_CODE, GSS_C_NULL_OID,
270 GSS_UNLOCK_MUTEX(utils);
272 if(GSS_ERROR(maj_stat)) {
274 utils->log(utils->conn, SASL_LOG_FAIL,
275 "GSSAPI Failure: (could not get minor error message)");
277 utils->seterror(utils->conn, 0,
279 "(could not get minor error message)");
285 len += len + msg.length;
287 ret = _plug_buf_alloc(utils, &out, &curlen, len);
293 strcat(out, msg.value);
295 GSS_LOCK_MUTEX(utils);
296 gss_release_buffer(&min_stat, &msg);
297 GSS_UNLOCK_MUTEX(utils);
304 ret = _plug_buf_alloc(utils, &out, &curlen, len);
313 utils->log(utils->conn, SASL_LOG_FAIL, out);
315 utils->seterror(utils->conn, 0, out);
323 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
324 const char **output, unsigned *outputlen, int privacy)
326 context_t *text = (context_t *)context;
327 OM_uint32 maj_stat, min_stat;
328 gss_buffer_t input_token, output_token;
329 gss_buffer_desc real_input_token, real_output_token;
331 struct buffer_info *inblob, bufinfo;
333 if(!output) return SASL_BADPARAM;
336 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
337 if(ret != SASL_OK) return ret;
338 inblob = text->enc_in_buf;
340 bufinfo.data = invec[0].iov_base;
341 bufinfo.curlen = invec[0].iov_len;
345 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
347 input_token = &real_input_token;
349 real_input_token.value = inblob->data;
350 real_input_token.length = inblob->curlen;
352 output_token = &real_output_token;
353 output_token->value = NULL;
354 output_token->length = 0;
356 GSS_LOCK_MUTEX(text->utils);
357 maj_stat = gss_wrap (&min_stat,
364 GSS_UNLOCK_MUTEX(text->utils);
366 if (GSS_ERROR(maj_stat))
368 sasl_gss_seterror(text->utils, maj_stat, min_stat);
369 if (output_token->value) {
370 GSS_LOCK_MUTEX(text->utils);
371 gss_release_buffer(&min_stat, output_token);
372 GSS_UNLOCK_MUTEX(text->utils);
377 if (output_token->value && output) {
380 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
381 &(text->encode_buf_len), output_token->length + 4);
383 if (ret != SASL_OK) {
384 GSS_LOCK_MUTEX(text->utils);
385 gss_release_buffer(&min_stat, output_token);
386 GSS_UNLOCK_MUTEX(text->utils);
390 len = htonl(output_token->length);
391 memcpy(text->encode_buf, &len, 4);
392 memcpy(text->encode_buf + 4, output_token->value, output_token->length);
396 *outputlen = output_token->length + 4;
399 *output = text->encode_buf;
401 if (output_token->value) {
402 GSS_LOCK_MUTEX(text->utils);
403 gss_release_buffer(&min_stat, output_token);
404 GSS_UNLOCK_MUTEX(text->utils);
409 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
410 unsigned numiov, const char **output,
413 return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
416 static int gssapi_integrity_encode(void *context, const struct iovec *invec,
417 unsigned numiov, const char **output,
420 return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
423 static int gssapi_decode_packet(void *context,
424 const char *input, unsigned inputlen,
425 char **output, unsigned *outputlen)
427 context_t *text = (context_t *) context;
428 OM_uint32 maj_stat, min_stat;
429 gss_buffer_t input_token, output_token;
430 gss_buffer_desc real_input_token, real_output_token;
433 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
434 SETERROR(text->utils, "GSSAPI Failure");
438 input_token = &real_input_token;
439 real_input_token.value = (char *) input;
440 real_input_token.length = inputlen;
442 output_token = &real_output_token;
443 output_token->value = NULL;
444 output_token->length = 0;
446 GSS_LOCK_MUTEX(text->utils);
447 maj_stat = gss_unwrap (&min_stat,
453 GSS_UNLOCK_MUTEX(text->utils);
455 if (GSS_ERROR(maj_stat))
457 sasl_gss_seterror(text->utils,maj_stat,min_stat);
458 if (output_token->value) {
459 GSS_LOCK_MUTEX(text->utils);
460 gss_release_buffer(&min_stat, output_token);
461 GSS_UNLOCK_MUTEX(text->utils);
467 *outputlen = output_token->length;
469 if (output_token->value) {
471 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
472 &text->decode_once_buf_len,
474 if(result != SASL_OK) {
475 GSS_LOCK_MUTEX(text->utils);
476 gss_release_buffer(&min_stat, output_token);
477 GSS_UNLOCK_MUTEX(text->utils);
480 *output = text->decode_once_buf;
481 memcpy(*output, output_token->value, *outputlen);
483 GSS_LOCK_MUTEX(text->utils);
484 gss_release_buffer(&min_stat, output_token);
485 GSS_UNLOCK_MUTEX(text->utils);
491 static int gssapi_decode(void *context,
492 const char *input, unsigned inputlen,
493 const char **output, unsigned *outputlen)
495 context_t *text = (context_t *) context;
498 ret = _plug_decode(&text->decode_context, input, inputlen,
499 &text->decode_buf, &text->decode_buf_len, outputlen,
500 gssapi_decode_packet, text);
502 *output = text->decode_buf;
507 static context_t *sasl_gss_new_context(const sasl_utils_t *utils)
511 ret = utils->malloc(sizeof(context_t));
512 if(!ret) return NULL;
514 memset(ret,0,sizeof(context_t));
520 static int sasl_gss_free_context_contents(context_t *text)
522 OM_uint32 maj_stat, min_stat;
524 if (!text) return SASL_OK;
526 GSS_LOCK_MUTEX(text->utils);
528 if (text->gss_ctx != GSS_C_NO_CONTEXT) {
529 maj_stat = gss_delete_sec_context(&min_stat,&text->gss_ctx,
531 text->gss_ctx = GSS_C_NO_CONTEXT;
534 if (text->client_name != GSS_C_NO_NAME) {
535 maj_stat = gss_release_name(&min_stat,&text->client_name);
536 text->client_name = GSS_C_NO_NAME;
539 if (text->server_name != GSS_C_NO_NAME) {
540 maj_stat = gss_release_name(&min_stat,&text->server_name);
541 text->server_name = GSS_C_NO_NAME;
544 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
545 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
546 text->server_creds = GSS_C_NO_CREDENTIAL;
549 if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
550 maj_stat = gss_release_cred(&min_stat, &text->client_creds);
551 text->client_creds = GSS_C_NO_CREDENTIAL;
554 GSS_UNLOCK_MUTEX(text->utils);
557 text->utils->free(text->out_buf);
558 text->out_buf = NULL;
561 if (text->encode_buf) {
562 text->utils->free(text->encode_buf);
563 text->encode_buf = NULL;
566 if (text->decode_buf) {
567 text->utils->free(text->decode_buf);
568 text->decode_buf = NULL;
571 if (text->decode_once_buf) {
572 text->utils->free(text->decode_once_buf);
573 text->decode_once_buf = NULL;
576 if (text->enc_in_buf) {
577 if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
578 text->utils->free(text->enc_in_buf);
579 text->enc_in_buf = NULL;
582 _plug_decode_free(&text->decode_context);
584 if (text->authid) { /* works for both client and server */
585 text->utils->free(text->authid);
593 static void gssapi_common_mech_dispose(void *conn_context,
594 const sasl_utils_t *utils)
596 sasl_gss_free_context_contents((context_t *)(conn_context));
597 utils->free(conn_context);
600 static void gssapi_common_mech_free(void *global_context __attribute__((unused)),
601 const sasl_utils_t *utils)
603 #ifdef GSS_USE_MUTEXES
605 utils->mutex_free(gss_mutex);
611 /***************************** Server Section *****************************/
614 _gssapi_server_mech_new(void *glob_context __attribute__((unused)),
615 sasl_server_params_t *params,
616 const char *challenge __attribute__((unused)),
617 unsigned challen __attribute__((unused)),
623 text = sasl_gss_new_context(params->utils);
625 MEMERROR(params->utils);
629 text->gss_ctx = GSS_C_NO_CONTEXT;
630 text->client_name = GSS_C_NO_NAME;
631 text->server_name = GSS_C_NO_NAME;
632 text->server_creds = GSS_C_NO_CREDENTIAL;
633 text->client_creds = GSS_C_NO_CREDENTIAL;
634 text->state = SASL_GSSAPI_STATE_AUTHNEG;
635 text->rfc2222_gss = rfc2222_gss;
637 *conn_context = text;
643 gssapi_server_mech_new(void *glob_context,
644 sasl_server_params_t *params,
645 const char *challenge,
649 return _gssapi_server_mech_new(glob_context, params, challenge,
650 challen, 1, conn_context);
654 gss_spnego_server_mech_new(void *glob_context,
655 sasl_server_params_t *params,
656 const char *challenge,
660 return _gssapi_server_mech_new(glob_context, params, challenge,
661 challen, 0, conn_context);
665 gssapi_server_mech_step(void *conn_context,
666 sasl_server_params_t *params,
667 const char *clientin,
668 unsigned clientinlen,
669 const char **serverout,
670 unsigned *serveroutlen,
671 sasl_out_params_t *oparams)
673 context_t *text = (context_t *)conn_context;
674 gss_buffer_t input_token, output_token;
675 gss_buffer_desc real_input_token, real_output_token;
676 OM_uint32 maj_stat = 0, min_stat = 0;
678 gss_buffer_desc name_token;
680 OM_uint32 out_flags = 0 ;
683 input_token = &real_input_token;
684 output_token = &real_output_token;
685 output_token->value = NULL; output_token->length = 0;
686 input_token->value = NULL; input_token->length = 0;
689 PARAMERROR(text->utils);
690 return SASL_BADPARAM;
696 switch (text->state) {
698 case SASL_GSSAPI_STATE_AUTHNEG:
699 if (text->server_name == GSS_C_NO_NAME) { /* only once */
700 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
701 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
702 if (name_token.value == NULL) {
703 MEMERROR(text->utils);
704 sasl_gss_free_context_contents(text);
707 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
709 GSS_LOCK_MUTEX(params->utils);
710 maj_stat = gss_import_name (&min_stat,
712 GSS_C_NT_HOSTBASED_SERVICE,
714 GSS_UNLOCK_MUTEX(params->utils);
716 params->utils->free(name_token.value);
717 name_token.value = NULL;
719 if (GSS_ERROR(maj_stat)) {
720 sasl_gss_seterror(text->utils, maj_stat, min_stat);
721 sasl_gss_free_context_contents(text);
725 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
726 GSS_LOCK_MUTEX(params->utils);
727 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
728 GSS_UNLOCK_MUTEX(params->utils);
729 text->server_creds = GSS_C_NO_CREDENTIAL;
732 GSS_LOCK_MUTEX(params->utils);
733 maj_stat = gss_acquire_cred(&min_stat,
741 GSS_UNLOCK_MUTEX(params->utils);
743 if (GSS_ERROR(maj_stat)) {
744 sasl_gss_seterror(text->utils, maj_stat, min_stat);
745 sasl_gss_free_context_contents(text);
751 real_input_token.value = (void *)clientin;
752 real_input_token.length = clientinlen;
756 GSS_LOCK_MUTEX(params->utils);
758 gss_accept_sec_context(&min_stat,
760 params->gss_creds ? params->gss_creds : text->server_creds,
762 GSS_C_NO_CHANNEL_BINDINGS,
768 &(text->client_creds));
769 GSS_UNLOCK_MUTEX(params->utils);
771 if (GSS_ERROR(maj_stat)) {
772 sasl_gss_log(text->utils, maj_stat, min_stat);
773 text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
774 if (output_token->value) {
775 GSS_LOCK_MUTEX(params->utils);
776 gss_release_buffer(&min_stat, output_token);
777 GSS_UNLOCK_MUTEX(params->utils);
779 sasl_gss_free_context_contents(text);
784 if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
785 (!(out_flags & GSS_C_DELEG_FLAG) ||
786 text->client_creds == GSS_C_NO_CREDENTIAL) )
788 text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
789 "GSSAPI warning: no credentials were passed");
790 /* continue with authentication */
794 *serveroutlen = output_token->length;
795 if (output_token->value) {
797 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
798 &(text->out_buf_len), *serveroutlen);
800 GSS_LOCK_MUTEX(params->utils);
801 gss_release_buffer(&min_stat, output_token);
802 GSS_UNLOCK_MUTEX(params->utils);
805 memcpy(text->out_buf, output_token->value, *serveroutlen);
806 *serverout = text->out_buf;
809 GSS_LOCK_MUTEX(params->utils);
810 gss_release_buffer(&min_stat, output_token);
811 GSS_UNLOCK_MUTEX(params->utils);
813 /* No output token, send an empty string */
814 *serverout = GSSAPI_BLANK_STRING;
818 if (maj_stat == GSS_S_COMPLETE) {
819 if (text->rfc2222_gss) {
820 /* Switch to ssf negotiation */
821 text->state = SASL_GSSAPI_STATE_SSFCAP;
822 return SASL_CONTINUE;
825 return SASL_CONTINUE;
827 /* Fall-through for non-RFC 2222 mechanisms such as GSS-SPNEGO */
829 case SASL_GSSAPI_STATE_SSFCAP: {
830 unsigned char sasldata[4];
831 gss_buffer_desc name_token;
832 gss_buffer_desc name_without_realm;
833 gss_name_t without = NULL;
836 name_token.value = NULL;
837 name_without_realm.value = NULL;
839 /* We ignore whatever the client sent us at this stage */
841 GSS_LOCK_MUTEX(params->utils);
842 maj_stat = gss_display_name (&min_stat,
846 GSS_UNLOCK_MUTEX(params->utils);
848 if (GSS_ERROR(maj_stat)) {
850 GSS_LOCK_MUTEX(params->utils);
851 gss_release_name(&min_stat, &without);
852 GSS_UNLOCK_MUTEX(params->utils);
854 SETERROR(text->utils, "GSSAPI Failure");
855 sasl_gss_free_context_contents(text);
859 /* If the id contains a realm get the identifier for the user
860 without the realm and see if it's the same id (i.e.
861 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
862 to return the id (i.e. just "tmartin" */
863 if (strchr((char *) name_token.value, (int) '@') != NULL) {
864 /* NOTE: libc malloc, as it is freed below by a gssapi internal
866 name_without_realm.value = params->utils->malloc(strlen(name_token.value)+1);
867 if (name_without_realm.value == NULL) {
868 if (name_token.value) {
869 GSS_LOCK_MUTEX(params->utils);
870 gss_release_buffer(&min_stat, &name_token);
871 GSS_UNLOCK_MUTEX(params->utils);
873 MEMERROR(text->utils);
877 strcpy(name_without_realm.value, name_token.value);
879 /* cut off string at '@' */
880 (strchr(name_without_realm.value,'@'))[0] = '\0';
882 name_without_realm.length = strlen( (char *) name_without_realm.value );
884 GSS_LOCK_MUTEX(params->utils);
885 maj_stat = gss_import_name (&min_stat,
887 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
888 so use GSS_C_NT_USER_NAME instead if available. */
889 #ifdef HAVE_GSS_C_NT_USER_NAME
895 GSS_UNLOCK_MUTEX(params->utils);
897 if (GSS_ERROR(maj_stat)) {
898 params->utils->free(name_without_realm.value);
899 if (name_token.value) {
900 GSS_LOCK_MUTEX(params->utils);
901 gss_release_buffer(&min_stat, &name_token);
902 GSS_UNLOCK_MUTEX(params->utils);
904 SETERROR(text->utils, "GSSAPI Failure");
905 sasl_gss_free_context_contents(text);
909 GSS_LOCK_MUTEX(params->utils);
910 maj_stat = gss_compare_name(&min_stat,
914 GSS_UNLOCK_MUTEX(params->utils);
916 if (GSS_ERROR(maj_stat)) {
917 params->utils->free(name_without_realm.value);
918 if (name_token.value) {
919 GSS_LOCK_MUTEX(params->utils);
920 gss_release_buffer(&min_stat, &name_token);
921 GSS_UNLOCK_MUTEX(params->utils);
924 GSS_LOCK_MUTEX(params->utils);
925 gss_release_name(&min_stat, &without);
926 GSS_UNLOCK_MUTEX(params->utils);
928 SETERROR(text->utils, "GSSAPI Failure");
929 sasl_gss_free_context_contents(text);
933 GSS_LOCK_MUTEX(params->utils);
934 gss_release_name(&min_stat,&without);
935 GSS_UNLOCK_MUTEX(params->utils);
942 text->authid = strdup(name_without_realm.value);
944 if (text->authid == NULL) {
945 MEMERROR(params->utils);
949 text->authid = strdup(name_token.value);
951 if (text->authid == NULL) {
952 MEMERROR(params->utils);
957 if (name_token.value) {
958 GSS_LOCK_MUTEX(params->utils);
959 gss_release_buffer(&min_stat, &name_token);
960 GSS_UNLOCK_MUTEX(params->utils);
962 if (name_without_realm.value) {
963 params->utils->free(name_without_realm.value);
966 /* we have to decide what sort of encryption/integrity/etc.,
968 if (params->props.max_ssf < params->external_ssf) {
971 text->limitssf = params->props.max_ssf - params->external_ssf;
973 if (params->props.min_ssf < params->external_ssf) {
974 text->requiressf = 0;
976 text->requiressf = params->props.min_ssf - params->external_ssf;
979 if (!text->rfc2222_gss) {
980 if (out_flags & GSS_C_CONF_FLAG)
982 else if (out_flags & GSS_C_INTEG_FLAG)
987 text->limitssf = 128; /* XXX */
992 /* build up our security properties token */
993 if (params->props.maxbufsize > 0xFFFFFF) {
994 /* make sure maxbufsize isn't too large */
995 /* maxbufsize = 0xFFFFFF */
996 sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
998 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
999 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
1000 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
1003 if(text->requiressf != 0 && !params->props.maxbufsize) {
1004 params->utils->seterror(params->utils->conn, 0,
1005 "GSSAPI needs a security layer but one is forbidden");
1006 return SASL_TOOWEAK;
1009 if (text->requiressf == 0) {
1010 sasldata[0] |= 1; /* authentication */
1012 if (text->requiressf <= 1 && text->limitssf >= 1
1013 && params->props.maxbufsize) {
1016 if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF
1017 && params->props.maxbufsize) {
1021 real_input_token.value = (void *)sasldata;
1022 real_input_token.length = 4;
1024 GSS_LOCK_MUTEX(params->utils);
1025 maj_stat = gss_wrap(&min_stat,
1027 0, /* Just integrity checking here */
1032 GSS_UNLOCK_MUTEX(params->utils);
1034 if (GSS_ERROR(maj_stat)) {
1035 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1036 if (output_token->value) {
1037 GSS_LOCK_MUTEX(params->utils);
1038 gss_release_buffer(&min_stat, output_token);
1039 GSS_UNLOCK_MUTEX(params->utils);
1041 sasl_gss_free_context_contents(text);
1047 *serveroutlen = output_token->length;
1048 if (output_token->value) {
1050 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1051 &(text->out_buf_len), *serveroutlen);
1052 if(ret != SASL_OK) {
1053 GSS_LOCK_MUTEX(params->utils);
1054 gss_release_buffer(&min_stat, output_token);
1055 GSS_UNLOCK_MUTEX(params->utils);
1058 memcpy(text->out_buf, output_token->value, *serveroutlen);
1059 *serverout = text->out_buf;
1062 GSS_LOCK_MUTEX(params->utils);
1063 gss_release_buffer(&min_stat, output_token);
1064 GSS_UNLOCK_MUTEX(params->utils);
1067 /* Wait for ssf request and authid */
1068 text->state = SASL_GSSAPI_STATE_SSFREQ;
1070 return SASL_CONTINUE;
1073 case SASL_GSSAPI_STATE_SSFREQ: {
1074 real_input_token.value = (void *)clientin;
1075 real_input_token.length = clientinlen;
1077 GSS_LOCK_MUTEX(params->utils);
1078 maj_stat = gss_unwrap(&min_stat,
1084 GSS_UNLOCK_MUTEX(params->utils);
1086 if (GSS_ERROR(maj_stat)) {
1087 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1088 sasl_gss_free_context_contents(text);
1092 layerchoice = (int)(((char *)(output_token->value))[0]);
1095 if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
1096 oparams->encode = NULL;
1097 oparams->decode = NULL;
1098 oparams->mech_ssf = 0;
1099 } else if (layerchoice == 2 && text->requiressf <= 1 &&
1100 text->limitssf >= 1) { /* integrity */
1101 oparams->encode=&gssapi_integrity_encode;
1102 oparams->decode=&gssapi_decode;
1103 oparams->mech_ssf=1;
1104 } else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF &&
1105 text->limitssf >= K5_MAX_SSF) { /* privacy */
1106 oparams->encode = &gssapi_privacy_encode;
1107 oparams->decode = &gssapi_decode;
1108 /* FIX ME: Need to extract the proper value here */
1109 oparams->mech_ssf = K5_MAX_SSF;
1111 /* not a supported encryption layer */
1112 SETERROR(text->utils,
1113 "protocol violation: client requested invalid layer");
1114 /* Mark that we attempted negotiation */
1115 oparams->mech_ssf = 2;
1116 if (output_token->value) {
1117 GSS_LOCK_MUTEX(params->utils);
1118 gss_release_buffer(&min_stat, output_token);
1119 GSS_UNLOCK_MUTEX(params->utils);
1121 sasl_gss_free_context_contents(text);
1125 if (output_token->length == 4 || !text->rfc2222_gss) {
1129 ret = params->canon_user(params->utils->conn,
1131 0, /* strlen(text->authid) */
1132 SASL_CU_AUTHZID | SASL_CU_AUTHID,
1135 if (ret != SASL_OK) {
1136 sasl_gss_free_context_contents(text);
1139 } else if (output_token->length > 4) {
1142 ret = params->canon_user(params->utils->conn,
1143 ((char *) output_token->value) + 4,
1144 (output_token->length - 4) * sizeof(char),
1145 SASL_CU_AUTHZID, oparams);
1147 if (ret != SASL_OK) {
1148 sasl_gss_free_context_contents(text);
1152 ret = params->canon_user(params->utils->conn,
1154 0, /* strlen(text->authid) */
1155 SASL_CU_AUTHID, oparams);
1156 if (ret != SASL_OK) {
1157 sasl_gss_free_context_contents(text);
1161 SETERROR(text->utils,
1163 GSS_LOCK_MUTEX(params->utils);
1164 gss_release_buffer(&min_stat, output_token);
1165 GSS_UNLOCK_MUTEX(params->utils);
1166 sasl_gss_free_context_contents(text);
1170 /* No matter what, set the rest of the oparams */
1172 if (text->client_creds != GSS_C_NO_CREDENTIAL) {
1173 oparams->client_creds = &text->client_creds;
1176 oparams->client_creds = NULL;
1179 oparams->gss_peer_name = text->client_name;
1180 oparams->gss_local_name = text->server_name;
1182 if (text->rfc2222_gss) {
1183 oparams->maxoutbuf =
1184 (((unsigned char *) output_token->value)[1] << 16) |
1185 (((unsigned char *) output_token->value)[2] << 8) |
1186 (((unsigned char *) output_token->value)[3] << 0);
1188 oparams->maxoutbuf = 0xFFFFFF;
1191 if (oparams->mech_ssf) {
1192 maj_stat = gss_wrap_size_limit( &min_stat,
1196 (OM_uint32) oparams->maxoutbuf,
1199 if(max_input > oparams->maxoutbuf) {
1200 /* Heimdal appears to get this wrong */
1201 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1203 /* This code is actually correct */
1204 oparams->maxoutbuf = max_input;
1208 GSS_LOCK_MUTEX(params->utils);
1209 gss_release_buffer(&min_stat, output_token);
1210 GSS_UNLOCK_MUTEX(params->utils);
1212 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1214 /* used by layers */
1215 _plug_decode_init(&text->decode_context, text->utils,
1216 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1217 params->props.maxbufsize);
1219 oparams->doneflag = 1;
1225 params->utils->log(NULL, SASL_LOG_ERR,
1226 "Invalid GSSAPI server step %d\n", text->state);
1230 return SASL_FAIL; /* should never get here */
1233 static sasl_server_plug_t gssapi_server_plugins[] =
1236 "GSSAPI", /* mech_name */
1237 K5_MAX_SSF, /* max_ssf */
1238 SASL_SEC_NOPLAINTEXT
1240 | SASL_SEC_NOANONYMOUS
1241 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1242 | SASL_SEC_PASS_CREDENTIALS,
1243 SASL_FEAT_WANT_CLIENT_FIRST
1244 | SASL_FEAT_ALLOWS_PROXY, /* features */
1245 NULL, /* glob_context */
1246 &gssapi_server_mech_new, /* mech_new */
1247 &gssapi_server_mech_step, /* mech_step */
1248 &gssapi_common_mech_dispose, /* mech_dispose */
1249 &gssapi_common_mech_free, /* mech_free */
1251 NULL, /* user_query */
1253 NULL, /* mech_avail */
1257 "GSS-SPNEGO", /* mech_name */
1258 K5_MAX_SSF, /* max_ssf */
1259 SASL_SEC_NOPLAINTEXT
1261 | SASL_SEC_NOANONYMOUS
1262 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1263 | SASL_SEC_PASS_CREDENTIALS,
1264 SASL_FEAT_WANT_CLIENT_FIRST
1265 | SASL_FEAT_ALLOWS_PROXY, /* features */
1266 NULL, /* glob_context */
1267 &gss_spnego_server_mech_new, /* mech_new */
1268 &gssapi_server_mech_step, /* mech_step */
1269 &gssapi_common_mech_dispose, /* mech_dispose */
1270 &gssapi_common_mech_free, /* mech_free */
1272 NULL, /* user_query */
1274 NULL, /* mech_avail */
1278 "GSS-EAP", /* mech_name */
1280 SASL_SEC_NOPLAINTEXT
1282 | SASL_SEC_MUTUAL_AUTH, /* security_flags */
1283 SASL_FEAT_WANT_CLIENT_FIRST
1284 | SASL_FEAT_ALLOWS_PROXY, /* features */
1285 NULL, /* glob_context */
1286 &gssapi_server_mech_new, /* mech_new */
1287 &gssapi_server_mech_step, /* mech_step */
1288 &gssapi_common_mech_dispose, /* mech_dispose */
1289 &gssapi_common_mech_free, /* mech_free */
1291 NULL, /* user_query */
1293 NULL, /* mech_avail */
1298 int gssapiv2_server_plug_init(
1299 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1300 const sasl_utils_t *utils __attribute__((unused)),
1302 const sasl_utils_t *utils,
1306 sasl_server_plug_t **pluglist,
1309 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1310 const char *keytab = NULL;
1311 char keytab_path[1024];
1315 if (maxversion < SASL_SERVER_PLUG_VERSION) {
1316 return SASL_BADVERS;
1319 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1320 /* unfortunately, we don't check for readability of keytab if it's
1321 the standard one, since we don't know where it is */
1323 /* FIXME: This code is broken */
1325 utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
1326 if (keytab != NULL) {
1327 if (access(keytab, R_OK) != 0) {
1328 utils->log(NULL, SASL_LOG_ERR,
1329 "Could not find keytab file: %s: %m",
1334 if(strlen(keytab) > 1024) {
1335 utils->log(NULL, SASL_LOG_ERR,
1336 "path to keytab is > 1024 characters");
1337 return SASL_BUFOVER;
1340 strncpy(keytab_path, keytab, 1024);
1342 gsskrb5_register_acceptor_identity(keytab_path);
1346 *out_version = SASL_SERVER_PLUG_VERSION;
1347 *pluglist = gssapi_server_plugins;
1348 *plugcount = sizeof(gssapi_server_plugins)/sizeof(gssapi_server_plugins[0]);
1350 #ifdef GSS_USE_MUTEXES
1352 gss_mutex = utils->mutex_alloc();
1362 /***************************** Client Section *****************************/
1364 static int _gssapi_client_mech_new(void *glob_context __attribute__((unused)),
1365 sasl_client_params_t *params,
1368 void **conn_context)
1372 /* holds state are in */
1373 text = sasl_gss_new_context(params->utils);
1375 MEMERROR(params->utils);
1379 text->state = SASL_GSSAPI_STATE_AUTHNEG;
1380 text->gss_ctx = GSS_C_NO_CONTEXT;
1381 text->client_name = GSS_C_NO_NAME;
1382 text->server_creds = GSS_C_NO_CREDENTIAL;
1383 text->client_creds = GSS_C_NO_CREDENTIAL;
1385 text->rfc2222_gss = rfc2222_gss;
1387 *conn_context = text;
1392 static int gssapi_client_mech_new(void *glob_context,
1393 sasl_client_params_t *params,
1394 void **conn_context)
1396 return _gssapi_client_mech_new(glob_context, params, &gss_krb5_mechanism_oid_desc,
1400 static int gss_spnego_client_mech_new(void *glob_context,
1401 sasl_client_params_t *params,
1402 void **conn_context)
1404 return _gssapi_client_mech_new(glob_context, params, &gss_spnego_mechanism_oid_desc,
1408 static int gss_eap_client_mech_new(void *glob_context,
1409 sasl_client_params_t *params,
1410 void **conn_context)
1412 return _gssapi_client_mech_new(glob_context, params, &gss_eap_mechanism_oid_desc,
1416 static int gssapi_client_mech_step(void *conn_context,
1417 sasl_client_params_t *params,
1418 const char *serverin,
1419 unsigned serverinlen,
1420 sasl_interact_t **prompt_need,
1421 const char **clientout,
1422 unsigned *clientoutlen,
1423 sasl_out_params_t *oparams)
1425 context_t *text = (context_t *)conn_context;
1426 gss_buffer_t input_token, output_token;
1427 gss_buffer_desc real_input_token, real_output_token;
1428 OM_uint32 maj_stat = 0, min_stat = 0;
1429 OM_uint32 max_input, out_flags;
1430 gss_buffer_desc name_token;
1431 int ret, serverhas = 0;
1432 OM_uint32 req_flags = 0, out_req_flags = 0;
1433 sasl_security_properties_t *secprops = &(params->props);
1435 input_token = &real_input_token;
1436 output_token = &real_output_token;
1437 output_token->value = NULL;
1438 input_token->value = NULL;
1439 input_token->length = 0;
1444 switch (text->state) {
1446 case SASL_GSSAPI_STATE_AUTHNEG:
1447 /* try to get the userid */
1448 if (text->user == NULL) {
1449 int user_result = SASL_OK;
1450 int pass_result = SASL_OK;
1452 user_result = _plug_get_userid(params->utils, &text->user,
1455 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
1456 sasl_gss_free_context_contents(text);
1460 /* free prompts we got */
1461 if (prompt_need && *prompt_need) {
1462 params->utils->free(*prompt_need);
1463 *prompt_need = NULL;
1466 if (params->gss_creds == GSS_C_NO_CREDENTIAL) {
1467 unsigned int free_password = 0;
1468 sasl_secret_t *password = NULL;
1470 pass_result = _plug_get_password(params->utils, &password,
1471 &free_password, prompt_need);
1472 if (pass_result == SASL_OK) {
1473 gss_buffer_desc pwBuf;
1474 gss_buffer_desc nameBuf;
1475 gss_OID_set_desc mechs;
1477 nameBuf.length = strlen(text->user);
1478 nameBuf.value = (void *)text->user;
1479 pwBuf.length = password->len;
1480 pwBuf.value = password->data;
1482 mechs.elements = text->mech;
1484 GSS_LOCK_MUTEX(params->utils);
1485 maj_stat = gss_import_name(&min_stat, &nameBuf,
1486 GSS_C_NT_USER_NAME, &text->client_name);
1487 if (maj_stat == GSS_S_COMPLETE) {
1488 maj_stat = gss_acquire_cred_with_password(&min_stat,
1490 &pwBuf, GSS_C_INDEFINITE,
1491 &mechs, GSS_C_INITIATE,
1492 &text->client_creds,
1494 if (GSS_ERROR(maj_stat)) {
1495 if (free_password) _plug_free_secret(params->utils, &password);
1496 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1497 GSS_UNLOCK_MUTEX(params->utils);
1498 sasl_gss_free_context_contents(text);
1502 GSS_UNLOCK_MUTEX(params->utils);
1503 if (free_password) _plug_free_secret(params->utils, &password);
1506 /* if there are prompts not filled in */
1507 if (user_result == SASL_INTERACT && text->mech != &gss_krb5_mechanism_oid_desc) {
1509 _plug_make_prompts(params->utils, prompt_need,
1510 user_result == SASL_INTERACT ?
1511 "Please enter your authorization name" : NULL,
1514 pass_result == SASL_INTERACT ?
1515 "Please enter your password" : NULL, NULL,
1518 if (result != SASL_OK) return result;
1519 return SASL_INTERACT;
1524 if (text->server_name == GSS_C_NO_NAME) { /* only once */
1525 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
1526 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
1527 if (name_token.value == NULL) {
1528 sasl_gss_free_context_contents(text);
1531 if (params->serverFQDN == NULL
1532 || strlen(params->serverFQDN) == 0) {
1533 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1537 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1539 GSS_LOCK_MUTEX(params->utils);
1540 maj_stat = gss_import_name (&min_stat,
1542 GSS_C_NT_HOSTBASED_SERVICE,
1543 &text->server_name);
1544 GSS_UNLOCK_MUTEX(params->utils);
1546 params->utils->free(name_token.value);
1547 name_token.value = NULL;
1549 if (GSS_ERROR(maj_stat)) {
1550 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1551 sasl_gss_free_context_contents(text);
1556 if (serverinlen == 0)
1557 input_token = GSS_C_NO_BUFFER;
1560 real_input_token.value = (void *)serverin;
1561 real_input_token.length = serverinlen;
1563 else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
1564 /* This can't happen under GSSAPI: we have a non-null context
1565 * and no input from the server. However, thanks to Imap,
1566 * which discards our first output, this happens all the time.
1567 * Throw away the context and try again. */
1568 GSS_LOCK_MUTEX(params->utils);
1569 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
1570 GSS_UNLOCK_MUTEX(params->utils);
1571 text->gss_ctx = GSS_C_NO_CONTEXT;
1574 /* Setup req_flags properly */
1575 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
1576 if(params->props.max_ssf > params->external_ssf) {
1577 /* We are requesting a security layer */
1578 req_flags |= GSS_C_INTEG_FLAG;
1579 /* Any SSF bigger than 1 is confidentiality. */
1580 /* Let's check if the client of the API requires confidentiality,
1581 and it wasn't already provided by an external layer */
1582 if(params->props.max_ssf - params->external_ssf > 1) {
1583 /* We want to try for privacy */
1584 req_flags |= GSS_C_CONF_FLAG;
1588 if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS)
1589 req_flags = req_flags | GSS_C_DELEG_FLAG;
1591 GSS_LOCK_MUTEX(params->utils);
1592 maj_stat = gss_init_sec_context(&min_stat,
1593 params->gss_creds ? params->gss_creds :
1600 GSS_C_NO_CHANNEL_BINDINGS,
1606 GSS_UNLOCK_MUTEX(params->utils);
1608 if (GSS_ERROR(maj_stat)) {
1609 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1610 if (output_token->value) {
1611 GSS_LOCK_MUTEX(params->utils);
1612 gss_release_buffer(&min_stat, output_token);
1613 GSS_UNLOCK_MUTEX(params->utils);
1615 sasl_gss_free_context_contents(text);
1619 if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_FLAG)) {
1620 text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
1621 /* not a fatal error */
1624 *clientoutlen = output_token->length;
1626 if (output_token->value) {
1628 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1629 &(text->out_buf_len), *clientoutlen);
1630 if(ret != SASL_OK) {
1631 GSS_LOCK_MUTEX(params->utils);
1632 gss_release_buffer(&min_stat, output_token);
1633 GSS_UNLOCK_MUTEX(params->utils);
1636 memcpy(text->out_buf, output_token->value, *clientoutlen);
1637 *clientout = text->out_buf;
1640 GSS_LOCK_MUTEX(params->utils);
1641 gss_release_buffer(&min_stat, output_token);
1642 GSS_UNLOCK_MUTEX(params->utils);
1645 if (maj_stat == GSS_S_COMPLETE) {
1646 GSS_LOCK_MUTEX(params->utils);
1647 if (text->client_name != GSS_C_NO_NAME)
1648 gss_release_name(&min_stat, &text->client_name);
1649 maj_stat = gss_inquire_context(&min_stat,
1652 NULL, /* targ_name */
1653 NULL, /* lifetime */
1655 /* FIX ME: Should check the resulting flags here */
1656 &out_flags, /* flags */
1657 NULL, /* local init */
1659 GSS_UNLOCK_MUTEX(params->utils);
1661 if (GSS_ERROR(maj_stat)) {
1662 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1663 sasl_gss_free_context_contents(text);
1667 name_token.length = 0;
1668 GSS_LOCK_MUTEX(params->utils);
1669 maj_stat = gss_display_name(&min_stat,
1673 GSS_UNLOCK_MUTEX(params->utils);
1675 if (GSS_ERROR(maj_stat)) {
1676 if (name_token.value) {
1677 GSS_LOCK_MUTEX(params->utils);
1678 gss_release_buffer(&min_stat, &name_token);
1679 GSS_UNLOCK_MUTEX(params->utils);
1681 SETERROR(text->utils, "GSSAPI Failure");
1682 sasl_gss_free_context_contents(text);
1686 if (text->user && text->user[0]) {
1687 ret = params->canon_user(params->utils->conn,
1689 SASL_CU_AUTHZID, oparams);
1691 ret = params->canon_user(params->utils->conn,
1692 name_token.value, 0,
1693 SASL_CU_AUTHID, oparams);
1695 ret = params->canon_user(params->utils->conn,
1696 name_token.value, 0,
1697 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1700 GSS_LOCK_MUTEX(params->utils);
1701 gss_release_buffer(&min_stat, &name_token);
1702 GSS_UNLOCK_MUTEX(params->utils);
1704 oparams->gss_peer_name = text->server_name;
1705 oparams->gss_local_name = text->client_name;
1707 if (ret != SASL_OK) return ret;
1709 if (text->rfc2222_gss) {
1710 /* Switch to ssf negotiation */
1711 text->state = SASL_GSSAPI_STATE_SSFCAP;
1712 return SASL_CONTINUE;
1715 if (out_flags & GSS_C_INTEG_FLAG)
1717 if (out_flags & GSS_C_CONF_FLAG)
1722 return SASL_CONTINUE;
1725 case SASL_GSSAPI_STATE_SSFCAP: {
1726 unsigned int alen, external = params->external_ssf;
1727 sasl_ssf_t need, allowed;
1730 real_input_token.value = (void *) serverin;
1731 real_input_token.length = serverinlen;
1733 GSS_LOCK_MUTEX(params->utils);
1734 maj_stat = gss_unwrap(&min_stat,
1740 GSS_UNLOCK_MUTEX(params->utils);
1742 if (GSS_ERROR(maj_stat)) {
1743 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1744 sasl_gss_free_context_contents(text);
1745 if (output_token->value) {
1746 GSS_LOCK_MUTEX(params->utils);
1747 gss_release_buffer(&min_stat, output_token);
1748 GSS_UNLOCK_MUTEX(params->utils);
1753 /* bit mask of server support */
1754 serverhas = ((char *)output_token->value)[0];
1757 /* taken from kerberos.c */
1758 if (secprops->min_ssf > (K5_MAX_SSF + external)) {
1759 return SASL_TOOWEAK;
1760 } else if (secprops->min_ssf > secprops->max_ssf) {
1761 return SASL_BADPARAM;
1764 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1765 if (secprops->max_ssf >= external) {
1766 allowed = secprops->max_ssf - external;
1770 if (secprops->min_ssf >= external) {
1771 need = secprops->min_ssf - external;
1777 /* if client didn't set use strongest layer available */
1778 if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) {
1780 oparams->encode = &gssapi_privacy_encode;
1781 oparams->decode = &gssapi_decode;
1782 /* FIX ME: Need to extract the proper value here */
1783 oparams->mech_ssf = K5_MAX_SSF;
1785 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1787 oparams->encode = &gssapi_integrity_encode;
1788 oparams->decode = &gssapi_decode;
1789 oparams->mech_ssf = 1;
1791 } else if (need <= 0 && (serverhas & 1)) {
1793 oparams->encode = NULL;
1794 oparams->decode = NULL;
1795 oparams->mech_ssf = 0;
1798 /* there's no appropriate layering for us! */
1799 sasl_gss_free_context_contents(text);
1800 return SASL_TOOWEAK;
1803 if (text->rfc2222_gss) {
1804 oparams->maxoutbuf =
1805 (((unsigned char *) output_token->value)[1] << 16) |
1806 (((unsigned char *) output_token->value)[2] << 8) |
1807 (((unsigned char *) output_token->value)[3] << 0);
1809 oparams->maxoutbuf = 0xFFFFFF;
1812 if(oparams->mech_ssf) {
1813 maj_stat = gss_wrap_size_limit( &min_stat,
1817 (OM_uint32) oparams->maxoutbuf,
1820 if(max_input > oparams->maxoutbuf) {
1821 /* Heimdal appears to get this wrong */
1822 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1824 /* This code is actually correct */
1825 oparams->maxoutbuf = max_input;
1829 GSS_LOCK_MUTEX(params->utils);
1830 gss_release_buffer(&min_stat, output_token);
1831 GSS_UNLOCK_MUTEX(params->utils);
1833 if (!text->rfc2222_gss) {
1834 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1836 oparams->doneflag = 1;
1838 /* used by layers */
1839 _plug_decode_init(&text->decode_context, text->utils,
1840 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1841 params->props.maxbufsize);
1845 /* oparams->user is always set, due to canon_user requirements.
1846 * Make sure the client actually requested it though, by checking
1847 * if our context was set.
1849 if (text->user && text->user[0])
1850 alen = strlen(oparams->user);
1854 input_token->length = 4 + alen;
1855 input_token->value =
1856 (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
1857 if (input_token->value == NULL) {
1858 sasl_gss_free_context_contents(text);
1863 memcpy((char *)input_token->value+4,oparams->user,alen);
1865 /* build up our security properties token */
1866 if (params->props.maxbufsize > 0xFFFFFF) {
1867 /* make sure maxbufsize isn't too large */
1868 /* maxbufsize = 0xFFFFFF */
1869 ((unsigned char *)input_token->value)[1] = 0xFF;
1870 ((unsigned char *)input_token->value)[2] = 0xFF;
1871 ((unsigned char *)input_token->value)[3] = 0xFF;
1873 ((unsigned char *)input_token->value)[1] =
1874 (params->props.maxbufsize >> 16) & 0xFF;
1875 ((unsigned char *)input_token->value)[2] =
1876 (params->props.maxbufsize >> 8) & 0xFF;
1877 ((unsigned char *)input_token->value)[3] =
1878 (params->props.maxbufsize >> 0) & 0xFF;
1880 ((unsigned char *)input_token->value)[0] = mychoice;
1882 GSS_LOCK_MUTEX(params->utils);
1883 maj_stat = gss_wrap (&min_stat,
1885 0, /* Just integrity checking here */
1890 GSS_UNLOCK_MUTEX(params->utils);
1892 params->utils->free(input_token->value);
1893 input_token->value = NULL;
1895 if (GSS_ERROR(maj_stat)) {
1896 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1897 if (output_token->value) {
1898 GSS_LOCK_MUTEX(params->utils);
1899 gss_release_buffer(&min_stat, output_token);
1900 GSS_UNLOCK_MUTEX(params->utils);
1902 sasl_gss_free_context_contents(text);
1907 *clientoutlen = output_token->length;
1908 if (output_token->value) {
1910 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1911 &(text->out_buf_len), *clientoutlen);
1912 if (ret != SASL_OK) {
1913 GSS_LOCK_MUTEX(params->utils);
1914 gss_release_buffer(&min_stat, output_token);
1915 GSS_UNLOCK_MUTEX(params->utils);
1918 memcpy(text->out_buf, output_token->value, *clientoutlen);
1919 *clientout = text->out_buf;
1922 GSS_LOCK_MUTEX(params->utils);
1923 gss_release_buffer(&min_stat, output_token);
1924 GSS_UNLOCK_MUTEX(params->utils);
1928 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1930 oparams->doneflag = 1;
1932 /* used by layers */
1933 _plug_decode_init(&text->decode_context, text->utils,
1934 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1935 params->props.maxbufsize);
1941 params->utils->log(NULL, SASL_LOG_ERR,
1942 "Invalid GSSAPI client step %d\n", text->state);
1946 return SASL_FAIL; /* should never get here */
1949 static const unsigned long gssapi_required_prompts[] = {
1953 static sasl_client_plug_t gssapi_client_plugins[] =
1956 "GSSAPI", /* mech_name */
1957 K5_MAX_SSF, /* max_ssf */
1958 SASL_SEC_NOPLAINTEXT
1960 | SASL_SEC_NOANONYMOUS
1961 | SASL_SEC_MUTUAL_AUTH
1962 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1963 SASL_FEAT_NEEDSERVERFQDN
1964 | SASL_FEAT_WANT_CLIENT_FIRST
1965 | SASL_FEAT_ALLOWS_PROXY, /* features */
1966 gssapi_required_prompts, /* required_prompts */
1967 NULL, /* glob_context */
1968 &gssapi_client_mech_new, /* mech_new */
1969 &gssapi_client_mech_step, /* mech_step */
1970 &gssapi_common_mech_dispose, /* mech_dispose */
1971 &gssapi_common_mech_free, /* mech_free */
1977 "GSS-SPNEGO", /* mech_name */
1978 K5_MAX_SSF, /* max_ssf */
1979 SASL_SEC_NOPLAINTEXT
1981 | SASL_SEC_NOANONYMOUS
1982 | SASL_SEC_MUTUAL_AUTH
1983 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1984 SASL_FEAT_NEEDSERVERFQDN
1985 | SASL_FEAT_WANT_CLIENT_FIRST
1986 | SASL_FEAT_ALLOWS_PROXY, /* features */
1987 gssapi_required_prompts, /* required_prompts */
1988 NULL, /* glob_context */
1989 &gss_spnego_client_mech_new, /* mech_new */
1990 &gssapi_client_mech_step, /* mech_step */
1991 &gssapi_common_mech_dispose, /* mech_dispose */
1992 &gssapi_common_mech_free, /* mech_free */
1998 "GSS-EAP", /* mech_name */
2000 SASL_SEC_NOPLAINTEXT
2002 | SASL_SEC_NOANONYMOUS
2003 | SASL_SEC_MUTUAL_AUTH
2004 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
2005 SASL_FEAT_NEEDSERVERFQDN
2006 | SASL_FEAT_WANT_CLIENT_FIRST
2007 | SASL_FEAT_ALLOWS_PROXY, /* features */
2008 gssapi_required_prompts, /* required_prompts */
2009 NULL, /* glob_context */
2010 &gss_eap_client_mech_new, /* mech_new */
2011 &gssapi_client_mech_step, /* mech_step */
2012 &gssapi_common_mech_dispose, /* mech_dispose */
2013 &gssapi_common_mech_free, /* mech_free */
2020 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
2023 sasl_client_plug_t **pluglist,
2026 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
2027 SETERROR(utils, "Version mismatch in GSSAPI");
2028 return SASL_BADVERS;
2031 *out_version = SASL_CLIENT_PLUG_VERSION;
2032 *pluglist = gssapi_client_plugins;
2033 *plugcount = sizeof(gssapi_client_plugins)/sizeof(gssapi_client_plugins[0]);
2035 #ifdef GSS_USE_MUTEXES
2037 gss_mutex = utils->mutex_alloc();