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"};
148 typedef struct context {
151 gss_ctx_id_t gss_ctx;
153 gss_name_t client_name;
154 gss_name_t server_name;
155 gss_cred_id_t server_creds;
156 gss_cred_id_t client_creds;
158 sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
160 const sasl_utils_t *utils;
162 /* layers buffering */
163 decode_context_t decode_context;
165 char *encode_buf; /* For encoding/decoding mem management */
167 char *decode_once_buf;
168 unsigned encode_buf_len;
169 unsigned decode_buf_len;
170 unsigned decode_once_buf_len;
171 buffer_info_t *enc_in_buf;
173 char *out_buf; /* per-step mem management */
174 unsigned out_buf_len;
176 char *authid; /* hold the authid between steps - server */
177 const char *user; /* hold the userid between steps - client */
184 SASL_GSSAPI_STATE_AUTHNEG = 1,
185 SASL_GSSAPI_STATE_SSFCAP = 2,
186 SASL_GSSAPI_STATE_SSFREQ = 3,
187 SASL_GSSAPI_STATE_AUTHENTICATED = 4
190 /* sasl_gss_log: only logs status string returned from gss_display_status() */
191 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
192 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
195 sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
198 OM_uint32 maj_stat, min_stat;
203 unsigned int len, curlen = 0;
204 const char prefix[] = "GSSAPI Error: ";
206 len = sizeof(prefix);
207 ret = _plug_buf_alloc(utils, &out, &curlen, 256);
208 if(ret != SASL_OK) return SASL_OK;
214 GSS_LOCK_MUTEX(utils);
215 maj_stat = gss_display_status(&min_stat, maj,
216 GSS_C_GSS_CODE, GSS_C_NULL_OID,
218 GSS_UNLOCK_MUTEX(utils);
220 if(GSS_ERROR(maj_stat)) {
222 utils->log(utils->conn, SASL_LOG_FAIL,
223 "GSSAPI Failure: (could not get major error message)");
225 utils->seterror(utils->conn, 0,
227 "(could not get major error message)");
233 len += len + msg.length;
234 ret = _plug_buf_alloc(utils, &out, &curlen, len);
241 strcat(out, msg.value);
243 GSS_LOCK_MUTEX(utils);
244 gss_release_buffer(&min_stat, &msg);
245 GSS_UNLOCK_MUTEX(utils);
251 /* Now get the minor status */
254 ret = _plug_buf_alloc(utils, &out, &curlen, len);
264 GSS_LOCK_MUTEX(utils);
265 maj_stat = gss_display_status(&min_stat, min,
266 GSS_C_MECH_CODE, GSS_C_NULL_OID,
268 GSS_UNLOCK_MUTEX(utils);
270 if(GSS_ERROR(maj_stat)) {
272 utils->log(utils->conn, SASL_LOG_FAIL,
273 "GSSAPI Failure: (could not get minor error message)");
275 utils->seterror(utils->conn, 0,
277 "(could not get minor error message)");
283 len += len + msg.length;
285 ret = _plug_buf_alloc(utils, &out, &curlen, len);
291 strcat(out, msg.value);
293 GSS_LOCK_MUTEX(utils);
294 gss_release_buffer(&min_stat, &msg);
295 GSS_UNLOCK_MUTEX(utils);
302 ret = _plug_buf_alloc(utils, &out, &curlen, len);
311 utils->log(utils->conn, SASL_LOG_FAIL, out);
313 utils->seterror(utils->conn, 0, out);
321 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
322 const char **output, unsigned *outputlen, int privacy)
324 context_t *text = (context_t *)context;
325 OM_uint32 maj_stat, min_stat;
326 gss_buffer_t input_token, output_token;
327 gss_buffer_desc real_input_token, real_output_token;
329 struct buffer_info *inblob, bufinfo;
331 if(!output) return SASL_BADPARAM;
334 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
335 if(ret != SASL_OK) return ret;
336 inblob = text->enc_in_buf;
338 bufinfo.data = invec[0].iov_base;
339 bufinfo.curlen = invec[0].iov_len;
343 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
345 input_token = &real_input_token;
347 real_input_token.value = inblob->data;
348 real_input_token.length = inblob->curlen;
350 output_token = &real_output_token;
351 output_token->value = NULL;
352 output_token->length = 0;
354 GSS_LOCK_MUTEX(text->utils);
355 maj_stat = gss_wrap (&min_stat,
362 GSS_UNLOCK_MUTEX(text->utils);
364 if (GSS_ERROR(maj_stat))
366 sasl_gss_seterror(text->utils, maj_stat, min_stat);
367 if (output_token->value) {
368 GSS_LOCK_MUTEX(text->utils);
369 gss_release_buffer(&min_stat, output_token);
370 GSS_UNLOCK_MUTEX(text->utils);
375 if (output_token->value && output) {
378 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
379 &(text->encode_buf_len), output_token->length + 4);
381 if (ret != SASL_OK) {
382 GSS_LOCK_MUTEX(text->utils);
383 gss_release_buffer(&min_stat, output_token);
384 GSS_UNLOCK_MUTEX(text->utils);
388 len = htonl(output_token->length);
389 memcpy(text->encode_buf, &len, 4);
390 memcpy(text->encode_buf + 4, output_token->value, output_token->length);
394 *outputlen = output_token->length + 4;
397 *output = text->encode_buf;
399 if (output_token->value) {
400 GSS_LOCK_MUTEX(text->utils);
401 gss_release_buffer(&min_stat, output_token);
402 GSS_UNLOCK_MUTEX(text->utils);
407 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
408 unsigned numiov, const char **output,
411 return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
414 static int gssapi_integrity_encode(void *context, const struct iovec *invec,
415 unsigned numiov, const char **output,
418 return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
421 static int gssapi_decode_packet(void *context,
422 const char *input, unsigned inputlen,
423 char **output, unsigned *outputlen)
425 context_t *text = (context_t *) context;
426 OM_uint32 maj_stat, min_stat;
427 gss_buffer_t input_token, output_token;
428 gss_buffer_desc real_input_token, real_output_token;
431 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
432 SETERROR(text->utils, "GSSAPI Failure");
436 input_token = &real_input_token;
437 real_input_token.value = (char *) input;
438 real_input_token.length = inputlen;
440 output_token = &real_output_token;
441 output_token->value = NULL;
442 output_token->length = 0;
444 GSS_LOCK_MUTEX(text->utils);
445 maj_stat = gss_unwrap (&min_stat,
451 GSS_UNLOCK_MUTEX(text->utils);
453 if (GSS_ERROR(maj_stat))
455 sasl_gss_seterror(text->utils,maj_stat,min_stat);
456 if (output_token->value) {
457 GSS_LOCK_MUTEX(text->utils);
458 gss_release_buffer(&min_stat, output_token);
459 GSS_UNLOCK_MUTEX(text->utils);
465 *outputlen = output_token->length;
467 if (output_token->value) {
469 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
470 &text->decode_once_buf_len,
472 if(result != SASL_OK) {
473 GSS_LOCK_MUTEX(text->utils);
474 gss_release_buffer(&min_stat, output_token);
475 GSS_UNLOCK_MUTEX(text->utils);
478 *output = text->decode_once_buf;
479 memcpy(*output, output_token->value, *outputlen);
481 GSS_LOCK_MUTEX(text->utils);
482 gss_release_buffer(&min_stat, output_token);
483 GSS_UNLOCK_MUTEX(text->utils);
489 static int gssapi_decode(void *context,
490 const char *input, unsigned inputlen,
491 const char **output, unsigned *outputlen)
493 context_t *text = (context_t *) context;
496 ret = _plug_decode(&text->decode_context, input, inputlen,
497 &text->decode_buf, &text->decode_buf_len, outputlen,
498 gssapi_decode_packet, text);
500 *output = text->decode_buf;
505 static context_t *sasl_gss_new_context(const sasl_utils_t *utils)
509 ret = utils->malloc(sizeof(context_t));
510 if(!ret) return NULL;
512 memset(ret,0,sizeof(context_t));
518 static int sasl_gss_free_context_contents(context_t *text)
520 OM_uint32 maj_stat, min_stat;
522 if (!text) return SASL_OK;
524 GSS_LOCK_MUTEX(text->utils);
526 if (text->gss_ctx != GSS_C_NO_CONTEXT) {
527 maj_stat = gss_delete_sec_context(&min_stat,&text->gss_ctx,
529 text->gss_ctx = GSS_C_NO_CONTEXT;
532 if (text->client_name != GSS_C_NO_NAME) {
533 maj_stat = gss_release_name(&min_stat,&text->client_name);
534 text->client_name = GSS_C_NO_NAME;
537 if (text->server_name != GSS_C_NO_NAME) {
538 maj_stat = gss_release_name(&min_stat,&text->server_name);
539 text->server_name = GSS_C_NO_NAME;
542 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
543 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
544 text->server_creds = GSS_C_NO_CREDENTIAL;
547 if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
548 maj_stat = gss_release_cred(&min_stat, &text->client_creds);
549 text->client_creds = GSS_C_NO_CREDENTIAL;
552 GSS_UNLOCK_MUTEX(text->utils);
555 text->utils->free(text->out_buf);
556 text->out_buf = NULL;
559 if (text->encode_buf) {
560 text->utils->free(text->encode_buf);
561 text->encode_buf = NULL;
564 if (text->decode_buf) {
565 text->utils->free(text->decode_buf);
566 text->decode_buf = NULL;
569 if (text->decode_once_buf) {
570 text->utils->free(text->decode_once_buf);
571 text->decode_once_buf = NULL;
574 if (text->enc_in_buf) {
575 if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
576 text->utils->free(text->enc_in_buf);
577 text->enc_in_buf = NULL;
580 _plug_decode_free(&text->decode_context);
582 if (text->authid) { /* works for both client and server */
583 text->utils->free(text->authid);
591 static void gssapi_common_mech_dispose(void *conn_context,
592 const sasl_utils_t *utils)
594 sasl_gss_free_context_contents((context_t *)(conn_context));
595 utils->free(conn_context);
598 static void gssapi_common_mech_free(void *global_context __attribute__((unused)),
599 const sasl_utils_t *utils)
601 #ifdef GSS_USE_MUTEXES
603 utils->mutex_free(gss_mutex);
609 /***************************** Server Section *****************************/
612 _gssapi_server_mech_new(void *glob_context __attribute__((unused)),
613 sasl_server_params_t *params,
614 const char *challenge __attribute__((unused)),
615 unsigned challen __attribute__((unused)),
621 text = sasl_gss_new_context(params->utils);
623 MEMERROR(params->utils);
627 text->gss_ctx = GSS_C_NO_CONTEXT;
628 text->client_name = GSS_C_NO_NAME;
629 text->server_name = GSS_C_NO_NAME;
630 text->server_creds = GSS_C_NO_CREDENTIAL;
631 text->client_creds = GSS_C_NO_CREDENTIAL;
632 text->state = SASL_GSSAPI_STATE_AUTHNEG;
633 text->rfc2222_gss = rfc2222_gss;
635 *conn_context = text;
641 gssapi_server_mech_new(void *glob_context,
642 sasl_server_params_t *params,
643 const char *challenge,
647 return _gssapi_server_mech_new(glob_context, params, challenge,
648 challen, 1, conn_context);
652 gss_spnego_server_mech_new(void *glob_context,
653 sasl_server_params_t *params,
654 const char *challenge,
658 return _gssapi_server_mech_new(glob_context, params, challenge,
659 challen, 0, conn_context);
663 gssapi_server_mech_step(void *conn_context,
664 sasl_server_params_t *params,
665 const char *clientin,
666 unsigned clientinlen,
667 const char **serverout,
668 unsigned *serveroutlen,
669 sasl_out_params_t *oparams)
671 context_t *text = (context_t *)conn_context;
672 gss_buffer_t input_token, output_token;
673 gss_buffer_desc real_input_token, real_output_token;
674 OM_uint32 maj_stat = 0, min_stat = 0;
676 gss_buffer_desc name_token;
678 OM_uint32 out_flags = 0 ;
681 input_token = &real_input_token;
682 output_token = &real_output_token;
683 output_token->value = NULL; output_token->length = 0;
684 input_token->value = NULL; input_token->length = 0;
687 PARAMERROR(text->utils);
688 return SASL_BADPARAM;
694 switch (text->state) {
696 case SASL_GSSAPI_STATE_AUTHNEG:
697 if (text->server_name == GSS_C_NO_NAME) { /* only once */
698 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
699 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
700 if (name_token.value == NULL) {
701 MEMERROR(text->utils);
702 sasl_gss_free_context_contents(text);
705 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
707 GSS_LOCK_MUTEX(params->utils);
708 maj_stat = gss_import_name (&min_stat,
710 GSS_C_NT_HOSTBASED_SERVICE,
712 GSS_UNLOCK_MUTEX(params->utils);
714 params->utils->free(name_token.value);
715 name_token.value = NULL;
717 if (GSS_ERROR(maj_stat)) {
718 sasl_gss_seterror(text->utils, maj_stat, min_stat);
719 sasl_gss_free_context_contents(text);
723 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
724 GSS_LOCK_MUTEX(params->utils);
725 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
726 GSS_UNLOCK_MUTEX(params->utils);
727 text->server_creds = GSS_C_NO_CREDENTIAL;
730 GSS_LOCK_MUTEX(params->utils);
731 maj_stat = gss_acquire_cred(&min_stat,
739 GSS_UNLOCK_MUTEX(params->utils);
741 if (GSS_ERROR(maj_stat)) {
742 sasl_gss_seterror(text->utils, maj_stat, min_stat);
743 sasl_gss_free_context_contents(text);
749 real_input_token.value = (void *)clientin;
750 real_input_token.length = clientinlen;
754 GSS_LOCK_MUTEX(params->utils);
756 gss_accept_sec_context(&min_stat,
758 params->gss_creds ? params->gss_creds : text->server_creds,
760 GSS_C_NO_CHANNEL_BINDINGS,
766 &(text->client_creds));
767 GSS_UNLOCK_MUTEX(params->utils);
769 if (GSS_ERROR(maj_stat)) {
770 sasl_gss_log(text->utils, maj_stat, min_stat);
771 text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
772 if (output_token->value) {
773 GSS_LOCK_MUTEX(params->utils);
774 gss_release_buffer(&min_stat, output_token);
775 GSS_UNLOCK_MUTEX(params->utils);
777 sasl_gss_free_context_contents(text);
782 if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
783 (!(out_flags & GSS_C_DELEG_FLAG) ||
784 text->client_creds == GSS_C_NO_CREDENTIAL) )
786 text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
787 "GSSAPI warning: no credentials were passed");
788 /* continue with authentication */
792 *serveroutlen = output_token->length;
793 if (output_token->value) {
795 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
796 &(text->out_buf_len), *serveroutlen);
798 GSS_LOCK_MUTEX(params->utils);
799 gss_release_buffer(&min_stat, output_token);
800 GSS_UNLOCK_MUTEX(params->utils);
803 memcpy(text->out_buf, output_token->value, *serveroutlen);
804 *serverout = text->out_buf;
807 GSS_LOCK_MUTEX(params->utils);
808 gss_release_buffer(&min_stat, output_token);
809 GSS_UNLOCK_MUTEX(params->utils);
811 /* No output token, send an empty string */
812 *serverout = GSSAPI_BLANK_STRING;
816 if (maj_stat == GSS_S_COMPLETE) {
817 if (text->rfc2222_gss) {
818 /* Switch to ssf negotiation */
819 text->state = SASL_GSSAPI_STATE_SSFCAP;
820 return SASL_CONTINUE;
823 return SASL_CONTINUE;
825 /* Fall-through for non-RFC 2222 mechanisms such as GSS-SPNEGO */
827 case SASL_GSSAPI_STATE_SSFCAP: {
828 unsigned char sasldata[4];
829 gss_buffer_desc name_token;
830 gss_buffer_desc name_without_realm;
831 gss_name_t without = NULL;
834 name_token.value = NULL;
835 name_without_realm.value = NULL;
837 /* We ignore whatever the client sent us at this stage */
839 GSS_LOCK_MUTEX(params->utils);
840 maj_stat = gss_display_name (&min_stat,
844 GSS_UNLOCK_MUTEX(params->utils);
846 if (GSS_ERROR(maj_stat)) {
848 GSS_LOCK_MUTEX(params->utils);
849 gss_release_name(&min_stat, &without);
850 GSS_UNLOCK_MUTEX(params->utils);
852 SETERROR(text->utils, "GSSAPI Failure");
853 sasl_gss_free_context_contents(text);
857 /* If the id contains a realm get the identifier for the user
858 without the realm and see if it's the same id (i.e.
859 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
860 to return the id (i.e. just "tmartin" */
861 if (strchr((char *) name_token.value, (int) '@') != NULL) {
862 /* NOTE: libc malloc, as it is freed below by a gssapi internal
864 name_without_realm.value = params->utils->malloc(strlen(name_token.value)+1);
865 if (name_without_realm.value == NULL) {
866 if (name_token.value) {
867 GSS_LOCK_MUTEX(params->utils);
868 gss_release_buffer(&min_stat, &name_token);
869 GSS_UNLOCK_MUTEX(params->utils);
871 MEMERROR(text->utils);
875 strcpy(name_without_realm.value, name_token.value);
877 /* cut off string at '@' */
878 (strchr(name_without_realm.value,'@'))[0] = '\0';
880 name_without_realm.length = strlen( (char *) name_without_realm.value );
882 GSS_LOCK_MUTEX(params->utils);
883 maj_stat = gss_import_name (&min_stat,
885 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
886 so use GSS_C_NT_USER_NAME instead if available. */
887 #ifdef HAVE_GSS_C_NT_USER_NAME
893 GSS_UNLOCK_MUTEX(params->utils);
895 if (GSS_ERROR(maj_stat)) {
896 params->utils->free(name_without_realm.value);
897 if (name_token.value) {
898 GSS_LOCK_MUTEX(params->utils);
899 gss_release_buffer(&min_stat, &name_token);
900 GSS_UNLOCK_MUTEX(params->utils);
902 SETERROR(text->utils, "GSSAPI Failure");
903 sasl_gss_free_context_contents(text);
907 GSS_LOCK_MUTEX(params->utils);
908 maj_stat = gss_compare_name(&min_stat,
912 GSS_UNLOCK_MUTEX(params->utils);
914 if (GSS_ERROR(maj_stat)) {
915 params->utils->free(name_without_realm.value);
916 if (name_token.value) {
917 GSS_LOCK_MUTEX(params->utils);
918 gss_release_buffer(&min_stat, &name_token);
919 GSS_UNLOCK_MUTEX(params->utils);
922 GSS_LOCK_MUTEX(params->utils);
923 gss_release_name(&min_stat, &without);
924 GSS_UNLOCK_MUTEX(params->utils);
926 SETERROR(text->utils, "GSSAPI Failure");
927 sasl_gss_free_context_contents(text);
931 GSS_LOCK_MUTEX(params->utils);
932 gss_release_name(&min_stat,&without);
933 GSS_UNLOCK_MUTEX(params->utils);
940 text->authid = strdup(name_without_realm.value);
942 if (text->authid == NULL) {
943 MEMERROR(params->utils);
947 text->authid = strdup(name_token.value);
949 if (text->authid == NULL) {
950 MEMERROR(params->utils);
955 if (name_token.value) {
956 GSS_LOCK_MUTEX(params->utils);
957 gss_release_buffer(&min_stat, &name_token);
958 GSS_UNLOCK_MUTEX(params->utils);
960 if (name_without_realm.value) {
961 params->utils->free(name_without_realm.value);
964 /* we have to decide what sort of encryption/integrity/etc.,
966 if (params->props.max_ssf < params->external_ssf) {
969 text->limitssf = params->props.max_ssf - params->external_ssf;
971 if (params->props.min_ssf < params->external_ssf) {
972 text->requiressf = 0;
974 text->requiressf = params->props.min_ssf - params->external_ssf;
977 if (!text->rfc2222_gss) {
978 if (out_flags & GSS_C_CONF_FLAG)
980 else if (out_flags & GSS_C_INTEG_FLAG)
985 text->limitssf = 128; /* XXX */
990 /* build up our security properties token */
991 if (params->props.maxbufsize > 0xFFFFFF) {
992 /* make sure maxbufsize isn't too large */
993 /* maxbufsize = 0xFFFFFF */
994 sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
996 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
997 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
998 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
1001 if(text->requiressf != 0 && !params->props.maxbufsize) {
1002 params->utils->seterror(params->utils->conn, 0,
1003 "GSSAPI needs a security layer but one is forbidden");
1004 return SASL_TOOWEAK;
1007 if (text->requiressf == 0) {
1008 sasldata[0] |= 1; /* authentication */
1010 if (text->requiressf <= 1 && text->limitssf >= 1
1011 && params->props.maxbufsize) {
1014 if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF
1015 && params->props.maxbufsize) {
1019 real_input_token.value = (void *)sasldata;
1020 real_input_token.length = 4;
1022 GSS_LOCK_MUTEX(params->utils);
1023 maj_stat = gss_wrap(&min_stat,
1025 0, /* Just integrity checking here */
1030 GSS_UNLOCK_MUTEX(params->utils);
1032 if (GSS_ERROR(maj_stat)) {
1033 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1034 if (output_token->value) {
1035 GSS_LOCK_MUTEX(params->utils);
1036 gss_release_buffer(&min_stat, output_token);
1037 GSS_UNLOCK_MUTEX(params->utils);
1039 sasl_gss_free_context_contents(text);
1045 *serveroutlen = output_token->length;
1046 if (output_token->value) {
1048 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1049 &(text->out_buf_len), *serveroutlen);
1050 if(ret != SASL_OK) {
1051 GSS_LOCK_MUTEX(params->utils);
1052 gss_release_buffer(&min_stat, output_token);
1053 GSS_UNLOCK_MUTEX(params->utils);
1056 memcpy(text->out_buf, output_token->value, *serveroutlen);
1057 *serverout = text->out_buf;
1060 GSS_LOCK_MUTEX(params->utils);
1061 gss_release_buffer(&min_stat, output_token);
1062 GSS_UNLOCK_MUTEX(params->utils);
1065 /* Wait for ssf request and authid */
1066 text->state = SASL_GSSAPI_STATE_SSFREQ;
1068 return SASL_CONTINUE;
1071 case SASL_GSSAPI_STATE_SSFREQ: {
1072 real_input_token.value = (void *)clientin;
1073 real_input_token.length = clientinlen;
1075 GSS_LOCK_MUTEX(params->utils);
1076 maj_stat = gss_unwrap(&min_stat,
1082 GSS_UNLOCK_MUTEX(params->utils);
1084 if (GSS_ERROR(maj_stat)) {
1085 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1086 sasl_gss_free_context_contents(text);
1090 layerchoice = (int)(((char *)(output_token->value))[0]);
1093 if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
1094 oparams->encode = NULL;
1095 oparams->decode = NULL;
1096 oparams->mech_ssf = 0;
1097 } else if (layerchoice == 2 && text->requiressf <= 1 &&
1098 text->limitssf >= 1) { /* integrity */
1099 oparams->encode=&gssapi_integrity_encode;
1100 oparams->decode=&gssapi_decode;
1101 oparams->mech_ssf=1;
1102 } else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF &&
1103 text->limitssf >= K5_MAX_SSF) { /* privacy */
1104 oparams->encode = &gssapi_privacy_encode;
1105 oparams->decode = &gssapi_decode;
1106 /* FIX ME: Need to extract the proper value here */
1107 oparams->mech_ssf = K5_MAX_SSF;
1109 /* not a supported encryption layer */
1110 SETERROR(text->utils,
1111 "protocol violation: client requested invalid layer");
1112 /* Mark that we attempted negotiation */
1113 oparams->mech_ssf = 2;
1114 if (output_token->value) {
1115 GSS_LOCK_MUTEX(params->utils);
1116 gss_release_buffer(&min_stat, output_token);
1117 GSS_UNLOCK_MUTEX(params->utils);
1119 sasl_gss_free_context_contents(text);
1123 if (output_token->length == 4 || !text->rfc2222_gss) {
1127 ret = params->canon_user(params->utils->conn,
1129 0, /* strlen(text->authid) */
1130 SASL_CU_AUTHZID | SASL_CU_AUTHID,
1133 if (ret != SASL_OK) {
1134 sasl_gss_free_context_contents(text);
1137 } else if (output_token->length > 4) {
1140 ret = params->canon_user(params->utils->conn,
1141 ((char *) output_token->value) + 4,
1142 (output_token->length - 4) * sizeof(char),
1143 SASL_CU_AUTHZID, oparams);
1145 if (ret != SASL_OK) {
1146 sasl_gss_free_context_contents(text);
1150 ret = params->canon_user(params->utils->conn,
1152 0, /* strlen(text->authid) */
1153 SASL_CU_AUTHID, oparams);
1154 if (ret != SASL_OK) {
1155 sasl_gss_free_context_contents(text);
1159 SETERROR(text->utils,
1161 GSS_LOCK_MUTEX(params->utils);
1162 gss_release_buffer(&min_stat, output_token);
1163 GSS_UNLOCK_MUTEX(params->utils);
1164 sasl_gss_free_context_contents(text);
1168 /* No matter what, set the rest of the oparams */
1170 if (text->client_creds != GSS_C_NO_CREDENTIAL) {
1171 oparams->client_creds = &text->client_creds;
1174 oparams->client_creds = NULL;
1177 oparams->gss_peer_name = text->client_name;
1178 oparams->gss_local_name = text->server_name;
1180 if (text->rfc2222_gss) {
1181 oparams->maxoutbuf =
1182 (((unsigned char *) output_token->value)[1] << 16) |
1183 (((unsigned char *) output_token->value)[2] << 8) |
1184 (((unsigned char *) output_token->value)[3] << 0);
1186 oparams->maxoutbuf = 0xFFFFFF;
1189 if (oparams->mech_ssf) {
1190 maj_stat = gss_wrap_size_limit( &min_stat,
1194 (OM_uint32) oparams->maxoutbuf,
1197 if(max_input > oparams->maxoutbuf) {
1198 /* Heimdal appears to get this wrong */
1199 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1201 /* This code is actually correct */
1202 oparams->maxoutbuf = max_input;
1206 GSS_LOCK_MUTEX(params->utils);
1207 gss_release_buffer(&min_stat, output_token);
1208 GSS_UNLOCK_MUTEX(params->utils);
1210 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1212 /* used by layers */
1213 _plug_decode_init(&text->decode_context, text->utils,
1214 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1215 params->props.maxbufsize);
1217 oparams->doneflag = 1;
1223 params->utils->log(NULL, SASL_LOG_ERR,
1224 "Invalid GSSAPI server step %d\n", text->state);
1228 return SASL_FAIL; /* should never get here */
1231 static sasl_server_plug_t gssapi_server_plugins[] =
1234 "GSSAPI", /* mech_name */
1235 K5_MAX_SSF, /* max_ssf */
1236 SASL_SEC_NOPLAINTEXT
1238 | SASL_SEC_NOANONYMOUS
1239 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1240 | SASL_SEC_PASS_CREDENTIALS,
1241 SASL_FEAT_WANT_CLIENT_FIRST
1242 | SASL_FEAT_ALLOWS_PROXY, /* features */
1243 NULL, /* glob_context */
1244 &gssapi_server_mech_new, /* mech_new */
1245 &gssapi_server_mech_step, /* mech_step */
1246 &gssapi_common_mech_dispose, /* mech_dispose */
1247 &gssapi_common_mech_free, /* mech_free */
1249 NULL, /* user_query */
1251 NULL, /* mech_avail */
1255 "GSS-SPNEGO", /* mech_name */
1256 K5_MAX_SSF, /* max_ssf */
1257 SASL_SEC_NOPLAINTEXT
1259 | SASL_SEC_NOANONYMOUS
1260 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1261 | SASL_SEC_PASS_CREDENTIALS,
1262 SASL_FEAT_WANT_CLIENT_FIRST
1263 | SASL_FEAT_ALLOWS_PROXY, /* features */
1264 NULL, /* glob_context */
1265 &gss_spnego_server_mech_new, /* mech_new */
1266 &gssapi_server_mech_step, /* mech_step */
1267 &gssapi_common_mech_dispose, /* mech_dispose */
1268 &gssapi_common_mech_free, /* mech_free */
1270 NULL, /* user_query */
1272 NULL, /* mech_avail */
1277 int gssapiv2_server_plug_init(
1278 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1279 const sasl_utils_t *utils __attribute__((unused)),
1281 const sasl_utils_t *utils,
1285 sasl_server_plug_t **pluglist,
1288 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1289 const char *keytab = NULL;
1290 char keytab_path[1024];
1294 if (maxversion < SASL_SERVER_PLUG_VERSION) {
1295 return SASL_BADVERS;
1298 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1299 /* unfortunately, we don't check for readability of keytab if it's
1300 the standard one, since we don't know where it is */
1302 /* FIXME: This code is broken */
1304 utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
1305 if (keytab != NULL) {
1306 if (access(keytab, R_OK) != 0) {
1307 utils->log(NULL, SASL_LOG_ERR,
1308 "Could not find keytab file: %s: %m",
1313 if(strlen(keytab) > 1024) {
1314 utils->log(NULL, SASL_LOG_ERR,
1315 "path to keytab is > 1024 characters");
1316 return SASL_BUFOVER;
1319 strncpy(keytab_path, keytab, 1024);
1321 gsskrb5_register_acceptor_identity(keytab_path);
1325 *out_version = SASL_SERVER_PLUG_VERSION;
1326 *pluglist = gssapi_server_plugins;
1327 *plugcount = sizeof(gssapi_server_plugins)/sizeof(gssapi_server_plugins[0]);
1329 #ifdef GSS_USE_MUTEXES
1331 gss_mutex = utils->mutex_alloc();
1341 /***************************** Client Section *****************************/
1343 static int _gssapi_client_mech_new(void *glob_context __attribute__((unused)),
1344 sasl_client_params_t *params,
1347 void **conn_context)
1351 /* holds state are in */
1352 text = sasl_gss_new_context(params->utils);
1354 MEMERROR(params->utils);
1358 text->state = SASL_GSSAPI_STATE_AUTHNEG;
1359 text->gss_ctx = GSS_C_NO_CONTEXT;
1360 text->client_name = GSS_C_NO_NAME;
1361 text->server_creds = GSS_C_NO_CREDENTIAL;
1362 text->client_creds = GSS_C_NO_CREDENTIAL;
1364 text->rfc2222_gss = rfc2222_gss;
1366 *conn_context = text;
1371 static int gssapi_client_mech_new(void *glob_context,
1372 sasl_client_params_t *params,
1373 void **conn_context)
1375 return _gssapi_client_mech_new(glob_context, params, &gss_krb5_mechanism_oid_desc,
1379 static int gss_spnego_client_mech_new(void *glob_context,
1380 sasl_client_params_t *params,
1381 void **conn_context)
1383 return _gssapi_client_mech_new(glob_context, params, &gss_spnego_mechanism_oid_desc,
1387 static int gssapi_client_mech_step(void *conn_context,
1388 sasl_client_params_t *params,
1389 const char *serverin,
1390 unsigned serverinlen,
1391 sasl_interact_t **prompt_need,
1392 const char **clientout,
1393 unsigned *clientoutlen,
1394 sasl_out_params_t *oparams)
1396 context_t *text = (context_t *)conn_context;
1397 gss_buffer_t input_token, output_token;
1398 gss_buffer_desc real_input_token, real_output_token;
1399 OM_uint32 maj_stat = 0, min_stat = 0;
1400 OM_uint32 max_input, out_flags;
1401 gss_buffer_desc name_token;
1402 int ret, serverhas = 0;
1403 OM_uint32 req_flags = 0, out_req_flags = 0;
1404 sasl_security_properties_t *secprops = &(params->props);
1406 input_token = &real_input_token;
1407 output_token = &real_output_token;
1408 output_token->value = NULL;
1409 input_token->value = NULL;
1410 input_token->length = 0;
1415 switch (text->state) {
1417 case SASL_GSSAPI_STATE_AUTHNEG:
1418 /* try to get the userid */
1419 if (text->user == NULL) {
1420 int user_result = SASL_OK;
1421 int pass_result = SASL_OK;
1423 user_result = _plug_get_userid(params->utils, &text->user,
1426 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
1427 sasl_gss_free_context_contents(text);
1431 /* free prompts we got */
1432 if (prompt_need && *prompt_need) {
1433 params->utils->free(*prompt_need);
1434 *prompt_need = NULL;
1437 if (params->gss_creds == GSS_C_NO_CREDENTIAL) {
1438 unsigned int free_password = 0;
1439 sasl_secret_t *password = NULL;
1441 pass_result = _plug_get_password(params->utils, &password,
1442 &free_password, prompt_need);
1443 if (pass_result == SASL_OK) {
1444 gss_buffer_desc pwBuf;
1445 gss_buffer_desc nameBuf;
1446 gss_OID_set_desc mechs;
1448 nameBuf.length = strlen(text->user);
1449 nameBuf.value = (void *)text->user;
1450 pwBuf.length = password->len;
1451 pwBuf.value = password->data;
1453 mechs.elements = text->mech;
1455 GSS_LOCK_MUTEX(params->utils);
1456 maj_stat = gss_import_name(&min_stat, &nameBuf,
1457 GSS_C_NT_USER_NAME, &text->client_name);
1458 if (maj_stat == GSS_S_COMPLETE) {
1459 maj_stat = gss_acquire_cred_with_password(&min_stat,
1461 &pwBuf, GSS_C_INDEFINITE,
1462 &mechs, GSS_C_INITIATE,
1463 &text->client_creds,
1465 if (GSS_ERROR(maj_stat)) {
1466 if (free_password) _plug_free_secret(params->utils, &password);
1467 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1468 GSS_UNLOCK_MUTEX(params->utils);
1469 sasl_gss_free_context_contents(text);
1473 GSS_UNLOCK_MUTEX(params->utils);
1474 if (free_password) _plug_free_secret(params->utils, &password);
1477 /* if there are prompts not filled in */
1478 if (user_result == SASL_INTERACT && text->mech != &gss_krb5_mechanism_oid_desc) {
1480 _plug_make_prompts(params->utils, prompt_need,
1481 user_result == SASL_INTERACT ?
1482 "Please enter your authorization name" : NULL,
1485 pass_result == SASL_INTERACT ?
1486 "Please enter your password" : NULL, NULL,
1489 if (result != SASL_OK) return result;
1490 return SASL_INTERACT;
1495 if (text->server_name == GSS_C_NO_NAME) { /* only once */
1496 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
1497 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
1498 if (name_token.value == NULL) {
1499 sasl_gss_free_context_contents(text);
1502 if (params->serverFQDN == NULL
1503 || strlen(params->serverFQDN) == 0) {
1504 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1508 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1510 GSS_LOCK_MUTEX(params->utils);
1511 maj_stat = gss_import_name (&min_stat,
1513 GSS_C_NT_HOSTBASED_SERVICE,
1514 &text->server_name);
1515 GSS_UNLOCK_MUTEX(params->utils);
1517 params->utils->free(name_token.value);
1518 name_token.value = NULL;
1520 if (GSS_ERROR(maj_stat)) {
1521 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1522 sasl_gss_free_context_contents(text);
1527 if (serverinlen == 0)
1528 input_token = GSS_C_NO_BUFFER;
1531 real_input_token.value = (void *)serverin;
1532 real_input_token.length = serverinlen;
1534 else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
1535 /* This can't happen under GSSAPI: we have a non-null context
1536 * and no input from the server. However, thanks to Imap,
1537 * which discards our first output, this happens all the time.
1538 * Throw away the context and try again. */
1539 GSS_LOCK_MUTEX(params->utils);
1540 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
1541 GSS_UNLOCK_MUTEX(params->utils);
1542 text->gss_ctx = GSS_C_NO_CONTEXT;
1545 /* Setup req_flags properly */
1546 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
1547 if(params->props.max_ssf > params->external_ssf) {
1548 /* We are requesting a security layer */
1549 req_flags |= GSS_C_INTEG_FLAG;
1550 /* Any SSF bigger than 1 is confidentiality. */
1551 /* Let's check if the client of the API requires confidentiality,
1552 and it wasn't already provided by an external layer */
1553 if(params->props.max_ssf - params->external_ssf > 1) {
1554 /* We want to try for privacy */
1555 req_flags |= GSS_C_CONF_FLAG;
1559 if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS)
1560 req_flags = req_flags | GSS_C_DELEG_FLAG;
1562 GSS_LOCK_MUTEX(params->utils);
1563 maj_stat = gss_init_sec_context(&min_stat,
1564 params->gss_creds ? params->gss_creds :
1571 GSS_C_NO_CHANNEL_BINDINGS,
1577 GSS_UNLOCK_MUTEX(params->utils);
1579 if (GSS_ERROR(maj_stat)) {
1580 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1581 if (output_token->value) {
1582 GSS_LOCK_MUTEX(params->utils);
1583 gss_release_buffer(&min_stat, output_token);
1584 GSS_UNLOCK_MUTEX(params->utils);
1586 sasl_gss_free_context_contents(text);
1590 if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_FLAG)) {
1591 text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
1592 /* not a fatal error */
1595 *clientoutlen = output_token->length;
1597 if (output_token->value) {
1599 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1600 &(text->out_buf_len), *clientoutlen);
1601 if(ret != SASL_OK) {
1602 GSS_LOCK_MUTEX(params->utils);
1603 gss_release_buffer(&min_stat, output_token);
1604 GSS_UNLOCK_MUTEX(params->utils);
1607 memcpy(text->out_buf, output_token->value, *clientoutlen);
1608 *clientout = text->out_buf;
1611 GSS_LOCK_MUTEX(params->utils);
1612 gss_release_buffer(&min_stat, output_token);
1613 GSS_UNLOCK_MUTEX(params->utils);
1616 if (maj_stat == GSS_S_COMPLETE) {
1617 GSS_LOCK_MUTEX(params->utils);
1618 if (text->client_name != GSS_C_NO_NAME)
1619 gss_release_name(&min_stat, &text->client_name);
1620 maj_stat = gss_inquire_context(&min_stat,
1623 NULL, /* targ_name */
1624 NULL, /* lifetime */
1626 /* FIX ME: Should check the resulting flags here */
1627 &out_flags, /* flags */
1628 NULL, /* local init */
1630 GSS_UNLOCK_MUTEX(params->utils);
1632 if (GSS_ERROR(maj_stat)) {
1633 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1634 sasl_gss_free_context_contents(text);
1638 name_token.length = 0;
1639 GSS_LOCK_MUTEX(params->utils);
1640 maj_stat = gss_display_name(&min_stat,
1644 GSS_UNLOCK_MUTEX(params->utils);
1646 if (GSS_ERROR(maj_stat)) {
1647 if (name_token.value) {
1648 GSS_LOCK_MUTEX(params->utils);
1649 gss_release_buffer(&min_stat, &name_token);
1650 GSS_UNLOCK_MUTEX(params->utils);
1652 SETERROR(text->utils, "GSSAPI Failure");
1653 sasl_gss_free_context_contents(text);
1657 if (text->user && text->user[0]) {
1658 ret = params->canon_user(params->utils->conn,
1660 SASL_CU_AUTHZID, oparams);
1662 ret = params->canon_user(params->utils->conn,
1663 name_token.value, 0,
1664 SASL_CU_AUTHID, oparams);
1666 ret = params->canon_user(params->utils->conn,
1667 name_token.value, 0,
1668 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1671 GSS_LOCK_MUTEX(params->utils);
1672 gss_release_buffer(&min_stat, &name_token);
1673 GSS_UNLOCK_MUTEX(params->utils);
1675 oparams->gss_peer_name = text->server_name;
1676 oparams->gss_local_name = text->client_name;
1678 if (ret != SASL_OK) return ret;
1680 if (text->rfc2222_gss) {
1681 /* Switch to ssf negotiation */
1682 text->state = SASL_GSSAPI_STATE_SSFCAP;
1683 return SASL_CONTINUE;
1686 if (out_flags & GSS_C_INTEG_FLAG)
1688 if (out_flags & GSS_C_CONF_FLAG)
1693 return SASL_CONTINUE;
1696 case SASL_GSSAPI_STATE_SSFCAP: {
1697 unsigned int alen, external = params->external_ssf;
1698 sasl_ssf_t need, allowed;
1701 real_input_token.value = (void *) serverin;
1702 real_input_token.length = serverinlen;
1704 GSS_LOCK_MUTEX(params->utils);
1705 maj_stat = gss_unwrap(&min_stat,
1711 GSS_UNLOCK_MUTEX(params->utils);
1713 if (GSS_ERROR(maj_stat)) {
1714 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1715 sasl_gss_free_context_contents(text);
1716 if (output_token->value) {
1717 GSS_LOCK_MUTEX(params->utils);
1718 gss_release_buffer(&min_stat, output_token);
1719 GSS_UNLOCK_MUTEX(params->utils);
1724 /* bit mask of server support */
1725 serverhas = ((char *)output_token->value)[0];
1728 /* taken from kerberos.c */
1729 if (secprops->min_ssf > (K5_MAX_SSF + external)) {
1730 return SASL_TOOWEAK;
1731 } else if (secprops->min_ssf > secprops->max_ssf) {
1732 return SASL_BADPARAM;
1735 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1736 if (secprops->max_ssf >= external) {
1737 allowed = secprops->max_ssf - external;
1741 if (secprops->min_ssf >= external) {
1742 need = secprops->min_ssf - external;
1748 /* if client didn't set use strongest layer available */
1749 if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) {
1751 oparams->encode = &gssapi_privacy_encode;
1752 oparams->decode = &gssapi_decode;
1753 /* FIX ME: Need to extract the proper value here */
1754 oparams->mech_ssf = K5_MAX_SSF;
1756 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1758 oparams->encode = &gssapi_integrity_encode;
1759 oparams->decode = &gssapi_decode;
1760 oparams->mech_ssf = 1;
1762 } else if (need <= 0 && (serverhas & 1)) {
1764 oparams->encode = NULL;
1765 oparams->decode = NULL;
1766 oparams->mech_ssf = 0;
1769 /* there's no appropriate layering for us! */
1770 sasl_gss_free_context_contents(text);
1771 return SASL_TOOWEAK;
1774 if (text->rfc2222_gss) {
1775 oparams->maxoutbuf =
1776 (((unsigned char *) output_token->value)[1] << 16) |
1777 (((unsigned char *) output_token->value)[2] << 8) |
1778 (((unsigned char *) output_token->value)[3] << 0);
1780 oparams->maxoutbuf = 0xFFFFFF;
1783 if(oparams->mech_ssf) {
1784 maj_stat = gss_wrap_size_limit( &min_stat,
1788 (OM_uint32) oparams->maxoutbuf,
1791 if(max_input > oparams->maxoutbuf) {
1792 /* Heimdal appears to get this wrong */
1793 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1795 /* This code is actually correct */
1796 oparams->maxoutbuf = max_input;
1800 GSS_LOCK_MUTEX(params->utils);
1801 gss_release_buffer(&min_stat, output_token);
1802 GSS_UNLOCK_MUTEX(params->utils);
1804 if (!text->rfc2222_gss) {
1805 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1807 oparams->doneflag = 1;
1809 /* used by layers */
1810 _plug_decode_init(&text->decode_context, text->utils,
1811 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1812 params->props.maxbufsize);
1816 /* oparams->user is always set, due to canon_user requirements.
1817 * Make sure the client actually requested it though, by checking
1818 * if our context was set.
1820 if (text->user && text->user[0])
1821 alen = strlen(oparams->user);
1825 input_token->length = 4 + alen;
1826 input_token->value =
1827 (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
1828 if (input_token->value == NULL) {
1829 sasl_gss_free_context_contents(text);
1834 memcpy((char *)input_token->value+4,oparams->user,alen);
1836 /* build up our security properties token */
1837 if (params->props.maxbufsize > 0xFFFFFF) {
1838 /* make sure maxbufsize isn't too large */
1839 /* maxbufsize = 0xFFFFFF */
1840 ((unsigned char *)input_token->value)[1] = 0xFF;
1841 ((unsigned char *)input_token->value)[2] = 0xFF;
1842 ((unsigned char *)input_token->value)[3] = 0xFF;
1844 ((unsigned char *)input_token->value)[1] =
1845 (params->props.maxbufsize >> 16) & 0xFF;
1846 ((unsigned char *)input_token->value)[2] =
1847 (params->props.maxbufsize >> 8) & 0xFF;
1848 ((unsigned char *)input_token->value)[3] =
1849 (params->props.maxbufsize >> 0) & 0xFF;
1851 ((unsigned char *)input_token->value)[0] = mychoice;
1853 GSS_LOCK_MUTEX(params->utils);
1854 maj_stat = gss_wrap (&min_stat,
1856 0, /* Just integrity checking here */
1861 GSS_UNLOCK_MUTEX(params->utils);
1863 params->utils->free(input_token->value);
1864 input_token->value = NULL;
1866 if (GSS_ERROR(maj_stat)) {
1867 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1868 if (output_token->value) {
1869 GSS_LOCK_MUTEX(params->utils);
1870 gss_release_buffer(&min_stat, output_token);
1871 GSS_UNLOCK_MUTEX(params->utils);
1873 sasl_gss_free_context_contents(text);
1878 *clientoutlen = output_token->length;
1879 if (output_token->value) {
1881 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1882 &(text->out_buf_len), *clientoutlen);
1883 if (ret != SASL_OK) {
1884 GSS_LOCK_MUTEX(params->utils);
1885 gss_release_buffer(&min_stat, output_token);
1886 GSS_UNLOCK_MUTEX(params->utils);
1889 memcpy(text->out_buf, output_token->value, *clientoutlen);
1890 *clientout = text->out_buf;
1893 GSS_LOCK_MUTEX(params->utils);
1894 gss_release_buffer(&min_stat, output_token);
1895 GSS_UNLOCK_MUTEX(params->utils);
1899 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1901 oparams->doneflag = 1;
1903 /* used by layers */
1904 _plug_decode_init(&text->decode_context, text->utils,
1905 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1906 params->props.maxbufsize);
1912 params->utils->log(NULL, SASL_LOG_ERR,
1913 "Invalid GSSAPI client step %d\n", text->state);
1917 return SASL_FAIL; /* should never get here */
1920 static const unsigned long gssapi_required_prompts[] = {
1924 static sasl_client_plug_t gssapi_client_plugins[] =
1927 "GSSAPI", /* mech_name */
1928 K5_MAX_SSF, /* max_ssf */
1929 SASL_SEC_NOPLAINTEXT
1931 | SASL_SEC_NOANONYMOUS
1932 | SASL_SEC_MUTUAL_AUTH
1933 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1934 SASL_FEAT_NEEDSERVERFQDN
1935 | SASL_FEAT_WANT_CLIENT_FIRST
1936 | SASL_FEAT_ALLOWS_PROXY, /* features */
1937 gssapi_required_prompts, /* required_prompts */
1938 NULL, /* glob_context */
1939 &gssapi_client_mech_new, /* mech_new */
1940 &gssapi_client_mech_step, /* mech_step */
1941 &gssapi_common_mech_dispose, /* mech_dispose */
1942 &gssapi_common_mech_free, /* mech_free */
1948 "GSS-SPNEGO", /* mech_name */
1949 K5_MAX_SSF, /* max_ssf */
1950 SASL_SEC_NOPLAINTEXT
1952 | SASL_SEC_NOANONYMOUS
1953 | SASL_SEC_MUTUAL_AUTH
1954 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1955 SASL_FEAT_NEEDSERVERFQDN
1956 | SASL_FEAT_WANT_CLIENT_FIRST
1957 | SASL_FEAT_ALLOWS_PROXY, /* features */
1958 gssapi_required_prompts, /* required_prompts */
1959 NULL, /* glob_context */
1960 &gss_spnego_client_mech_new, /* mech_new */
1961 &gssapi_client_mech_step, /* mech_step */
1962 &gssapi_common_mech_dispose, /* mech_dispose */
1963 &gssapi_common_mech_free, /* mech_free */
1970 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
1973 sasl_client_plug_t **pluglist,
1976 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
1977 SETERROR(utils, "Version mismatch in GSSAPI");
1978 return SASL_BADVERS;
1981 *out_version = SASL_CLIENT_PLUG_VERSION;
1982 *pluglist = gssapi_client_plugins;
1983 *plugcount = sizeof(gssapi_client_plugins)/sizeof(gssapi_client_plugins[0]);
1985 #ifdef GSS_USE_MUTEXES
1987 gss_mutex = utils->mutex_alloc();