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>
53 #ifdef HAVE_GSSAPI_GSSAPI_EXT_H
54 #include <gssapi/gssapi_ext.h>
57 # include <winsock2.h>
62 /* we also need io.h for access() prototype */
65 # include <sys/param.h>
66 # include <sys/socket.h>
67 # include <netinet/in.h>
68 # include <arpa/inet.h>
78 #include "plugin_common.h"
86 /***************************** Common Section *****************************/
88 static const char plugin_id[] = "$Id: gssapi.c,v 1.92 2004/07/21 14:39:06 rjs3 Exp $";
90 static const char * GSSAPI_BLANK_STRING = "";
92 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
93 extern gss_OID gss_nt_service_name;
94 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
97 #ifdef WANT_KERBEROS5_3DES
98 /* Check if CyberSafe flag is defined */
99 #ifdef CSF_GSS_C_DES3_FLAG
100 #define K5_MAX_SSF 112
103 /* Heimdal and MIT use the following */
104 #ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
105 #define K5_MAX_SSF 112
111 /* All Kerberos implementations support DES */
112 #define K5_MAX_SSF 56
115 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
116 * inspired by the kerberos mechanism and the gssapi_server and
117 * gssapi_client from the heimdal distribution by Assar Westerlund
118 * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>.
119 * See the configure.in file for details on dependencies.
121 * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
123 * This code was tested with the following distributions of Kerberos:
124 * Heimdal (http://www.pdc.kth.se/heimdal), MIT (http://web.mit.edu/kerberos/www/)
125 * CyberSafe (http://www.cybersafe.com/) and SEAM.
128 #ifdef GSS_USE_MUTEXES
129 #define GSS_LOCK_MUTEX(utils) \
130 if(((sasl_utils_t *)(utils))->mutex_lock(gss_mutex) != 0) { \
134 #define GSS_UNLOCK_MUTEX(utils) \
135 if(((sasl_utils_t *)(utils))->mutex_unlock(gss_mutex) != 0) { \
139 static void *gss_mutex = NULL;
141 #define GSS_LOCK_MUTEX(utils)
142 #define GSS_UNLOCK_MUTEX(utils)
145 static gss_OID_desc gss_spnego_mechanism_oid_desc =
146 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
147 static gss_OID_desc gss_krb5_mechanism_oid_desc =
148 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
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 */
184 sasl_secret_t *password;
185 unsigned int free_password;
190 SASL_GSSAPI_STATE_AUTHNEG = 1,
191 SASL_GSSAPI_STATE_SSFCAP = 2,
192 SASL_GSSAPI_STATE_SSFREQ = 3,
193 SASL_GSSAPI_STATE_AUTHENTICATED = 4
197 gssapi_get_init_creds(context_t *text,
198 sasl_client_params_t *params,
199 sasl_interact_t **prompt_need,
200 sasl_out_params_t *oparams);
202 /* sasl_gss_log: only logs status string returned from gss_display_status() */
203 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
204 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
207 sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
210 OM_uint32 maj_stat, min_stat;
215 unsigned int len, curlen = 0;
216 const char prefix[] = "GSSAPI Error: ";
218 len = sizeof(prefix);
219 ret = _plug_buf_alloc(utils, &out, &curlen, 256);
220 if(ret != SASL_OK) return SASL_OK;
226 GSS_LOCK_MUTEX(utils);
227 maj_stat = gss_display_status(&min_stat, maj,
228 GSS_C_GSS_CODE, GSS_C_NULL_OID,
230 GSS_UNLOCK_MUTEX(utils);
232 if(GSS_ERROR(maj_stat)) {
234 utils->log(utils->conn, SASL_LOG_FAIL,
235 "GSSAPI Failure: (could not get major error message)");
237 utils->seterror(utils->conn, 0,
239 "(could not get major error message)");
245 len += len + msg.length;
246 ret = _plug_buf_alloc(utils, &out, &curlen, len);
253 strcat(out, msg.value);
255 GSS_LOCK_MUTEX(utils);
256 gss_release_buffer(&min_stat, &msg);
257 GSS_UNLOCK_MUTEX(utils);
263 /* Now get the minor status */
266 ret = _plug_buf_alloc(utils, &out, &curlen, len);
276 GSS_LOCK_MUTEX(utils);
277 maj_stat = gss_display_status(&min_stat, min,
278 GSS_C_MECH_CODE, GSS_C_NULL_OID,
280 GSS_UNLOCK_MUTEX(utils);
282 if(GSS_ERROR(maj_stat)) {
284 utils->log(utils->conn, SASL_LOG_FAIL,
285 "GSSAPI Failure: (could not get minor error message)");
287 utils->seterror(utils->conn, 0,
289 "(could not get minor error message)");
295 len += len + msg.length;
297 ret = _plug_buf_alloc(utils, &out, &curlen, len);
303 strcat(out, msg.value);
305 GSS_LOCK_MUTEX(utils);
306 gss_release_buffer(&min_stat, &msg);
307 GSS_UNLOCK_MUTEX(utils);
314 ret = _plug_buf_alloc(utils, &out, &curlen, len);
323 utils->log(utils->conn, SASL_LOG_FAIL, out);
325 utils->seterror(utils->conn, 0, out);
333 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
334 const char **output, unsigned *outputlen, int privacy)
336 context_t *text = (context_t *)context;
337 OM_uint32 maj_stat, min_stat;
338 gss_buffer_t input_token, output_token;
339 gss_buffer_desc real_input_token, real_output_token;
341 struct buffer_info *inblob, bufinfo;
343 if(!output) return SASL_BADPARAM;
346 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
347 if(ret != SASL_OK) return ret;
348 inblob = text->enc_in_buf;
350 bufinfo.data = invec[0].iov_base;
351 bufinfo.curlen = invec[0].iov_len;
355 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
357 input_token = &real_input_token;
359 real_input_token.value = inblob->data;
360 real_input_token.length = inblob->curlen;
362 output_token = &real_output_token;
363 output_token->value = NULL;
364 output_token->length = 0;
366 GSS_LOCK_MUTEX(text->utils);
367 maj_stat = gss_wrap (&min_stat,
374 GSS_UNLOCK_MUTEX(text->utils);
376 if (GSS_ERROR(maj_stat))
378 sasl_gss_seterror(text->utils, maj_stat, min_stat);
379 if (output_token->value) {
380 GSS_LOCK_MUTEX(text->utils);
381 gss_release_buffer(&min_stat, output_token);
382 GSS_UNLOCK_MUTEX(text->utils);
387 if (output_token->value && output) {
390 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
391 &(text->encode_buf_len), output_token->length + 4);
393 if (ret != SASL_OK) {
394 GSS_LOCK_MUTEX(text->utils);
395 gss_release_buffer(&min_stat, output_token);
396 GSS_UNLOCK_MUTEX(text->utils);
400 len = htonl(output_token->length);
401 memcpy(text->encode_buf, &len, 4);
402 memcpy(text->encode_buf + 4, output_token->value, output_token->length);
406 *outputlen = output_token->length + 4;
409 *output = text->encode_buf;
411 if (output_token->value) {
412 GSS_LOCK_MUTEX(text->utils);
413 gss_release_buffer(&min_stat, output_token);
414 GSS_UNLOCK_MUTEX(text->utils);
419 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
420 unsigned numiov, const char **output,
423 return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
426 static int gssapi_integrity_encode(void *context, const struct iovec *invec,
427 unsigned numiov, const char **output,
430 return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
433 static int gssapi_decode_packet(void *context,
434 const char *input, unsigned inputlen,
435 char **output, unsigned *outputlen)
437 context_t *text = (context_t *) context;
438 OM_uint32 maj_stat, min_stat;
439 gss_buffer_t input_token, output_token;
440 gss_buffer_desc real_input_token, real_output_token;
443 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
444 SETERROR(text->utils, "GSSAPI Failure");
448 input_token = &real_input_token;
449 real_input_token.value = (char *) input;
450 real_input_token.length = inputlen;
452 output_token = &real_output_token;
453 output_token->value = NULL;
454 output_token->length = 0;
456 GSS_LOCK_MUTEX(text->utils);
457 maj_stat = gss_unwrap (&min_stat,
463 GSS_UNLOCK_MUTEX(text->utils);
465 if (GSS_ERROR(maj_stat))
467 sasl_gss_seterror(text->utils,maj_stat,min_stat);
468 if (output_token->value) {
469 GSS_LOCK_MUTEX(text->utils);
470 gss_release_buffer(&min_stat, output_token);
471 GSS_UNLOCK_MUTEX(text->utils);
477 *outputlen = output_token->length;
479 if (output_token->value) {
481 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
482 &text->decode_once_buf_len,
484 if(result != SASL_OK) {
485 GSS_LOCK_MUTEX(text->utils);
486 gss_release_buffer(&min_stat, output_token);
487 GSS_UNLOCK_MUTEX(text->utils);
490 *output = text->decode_once_buf;
491 memcpy(*output, output_token->value, *outputlen);
493 GSS_LOCK_MUTEX(text->utils);
494 gss_release_buffer(&min_stat, output_token);
495 GSS_UNLOCK_MUTEX(text->utils);
501 static int gssapi_decode(void *context,
502 const char *input, unsigned inputlen,
503 const char **output, unsigned *outputlen)
505 context_t *text = (context_t *) context;
508 ret = _plug_decode(&text->decode_context, input, inputlen,
509 &text->decode_buf, &text->decode_buf_len, outputlen,
510 gssapi_decode_packet, text);
512 *output = text->decode_buf;
517 static context_t *sasl_gss_new_context(const sasl_utils_t *utils)
521 ret = utils->malloc(sizeof(context_t));
522 if(!ret) return NULL;
524 memset(ret,0,sizeof(context_t));
530 static int sasl_gss_free_context_contents(context_t *text)
532 OM_uint32 maj_stat, min_stat;
534 if (!text) return SASL_OK;
536 GSS_LOCK_MUTEX(text->utils);
538 if (text->gss_ctx != GSS_C_NO_CONTEXT) {
539 maj_stat = gss_delete_sec_context(&min_stat,&text->gss_ctx,
541 text->gss_ctx = GSS_C_NO_CONTEXT;
544 if (text->client_name != GSS_C_NO_NAME) {
545 maj_stat = gss_release_name(&min_stat,&text->client_name);
546 text->client_name = GSS_C_NO_NAME;
549 if (text->server_name != GSS_C_NO_NAME) {
550 maj_stat = gss_release_name(&min_stat,&text->server_name);
551 text->server_name = GSS_C_NO_NAME;
554 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
555 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
556 text->server_creds = GSS_C_NO_CREDENTIAL;
559 if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
560 maj_stat = gss_release_cred(&min_stat, &text->client_creds);
561 text->client_creds = GSS_C_NO_CREDENTIAL;
564 GSS_UNLOCK_MUTEX(text->utils);
567 text->utils->free(text->out_buf);
568 text->out_buf = NULL;
571 if (text->encode_buf) {
572 text->utils->free(text->encode_buf);
573 text->encode_buf = NULL;
576 if (text->decode_buf) {
577 text->utils->free(text->decode_buf);
578 text->decode_buf = NULL;
581 if (text->decode_once_buf) {
582 text->utils->free(text->decode_once_buf);
583 text->decode_once_buf = NULL;
586 if (text->enc_in_buf) {
587 if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
588 text->utils->free(text->enc_in_buf);
589 text->enc_in_buf = NULL;
592 _plug_decode_free(&text->decode_context);
594 if (text->authid) { /* works for both client and server */
595 text->utils->free(text->authid);
599 if (text->free_password)
600 _plug_free_secret(text->utils, &text->password);
602 memset(text, 0, sizeof(*text));
607 static void gssapi_common_mech_dispose(void *conn_context,
608 const sasl_utils_t *utils)
610 sasl_gss_free_context_contents((context_t *)(conn_context));
611 utils->free(conn_context);
614 static void gssapi_common_mech_free(void *global_context __attribute__((unused)),
615 const sasl_utils_t *utils)
617 #ifdef GSS_USE_MUTEXES
619 utils->mutex_free(gss_mutex);
625 /***************************** Server Section *****************************/
628 _gssapi_server_mech_new(void *glob_context __attribute__((unused)),
629 sasl_server_params_t *params,
630 const char *challenge __attribute__((unused)),
631 unsigned challen __attribute__((unused)),
637 text = sasl_gss_new_context(params->utils);
639 MEMERROR(params->utils);
643 text->gss_ctx = GSS_C_NO_CONTEXT;
644 text->client_name = GSS_C_NO_NAME;
645 text->server_name = GSS_C_NO_NAME;
646 text->server_creds = GSS_C_NO_CREDENTIAL;
647 text->client_creds = GSS_C_NO_CREDENTIAL;
648 text->state = SASL_GSSAPI_STATE_AUTHNEG;
649 text->rfc2222_gss = rfc2222_gss;
651 *conn_context = text;
657 gssapi_server_mech_new(void *glob_context,
658 sasl_server_params_t *params,
659 const char *challenge,
663 return _gssapi_server_mech_new(glob_context, params, challenge,
664 challen, 1, conn_context);
668 gss_spnego_server_mech_new(void *glob_context,
669 sasl_server_params_t *params,
670 const char *challenge,
674 return _gssapi_server_mech_new(glob_context, params, challenge,
675 challen, 0, conn_context);
679 gssapi_server_mech_step(void *conn_context,
680 sasl_server_params_t *params,
681 const char *clientin,
682 unsigned clientinlen,
683 const char **serverout,
684 unsigned *serveroutlen,
685 sasl_out_params_t *oparams)
687 context_t *text = (context_t *)conn_context;
688 gss_buffer_t input_token, output_token;
689 gss_buffer_desc real_input_token, real_output_token;
690 OM_uint32 maj_stat = 0, min_stat = 0;
692 gss_buffer_desc name_token;
694 OM_uint32 out_flags = 0 ;
697 input_token = &real_input_token;
698 output_token = &real_output_token;
699 output_token->value = NULL; output_token->length = 0;
700 input_token->value = NULL; input_token->length = 0;
703 PARAMERROR(text->utils);
704 return SASL_BADPARAM;
710 switch (text->state) {
712 case SASL_GSSAPI_STATE_AUTHNEG:
713 if (text->server_name == GSS_C_NO_NAME) { /* only once */
714 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
715 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
716 if (name_token.value == NULL) {
717 MEMERROR(text->utils);
718 sasl_gss_free_context_contents(text);
721 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
723 GSS_LOCK_MUTEX(params->utils);
724 maj_stat = gss_import_name (&min_stat,
726 GSS_C_NT_HOSTBASED_SERVICE,
728 GSS_UNLOCK_MUTEX(params->utils);
730 params->utils->free(name_token.value);
731 name_token.value = NULL;
733 if (GSS_ERROR(maj_stat)) {
734 sasl_gss_seterror(text->utils, maj_stat, min_stat);
735 sasl_gss_free_context_contents(text);
739 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
740 GSS_LOCK_MUTEX(params->utils);
741 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
742 GSS_UNLOCK_MUTEX(params->utils);
743 text->server_creds = GSS_C_NO_CREDENTIAL;
746 GSS_LOCK_MUTEX(params->utils);
747 maj_stat = gss_acquire_cred(&min_stat,
755 GSS_UNLOCK_MUTEX(params->utils);
757 if (GSS_ERROR(maj_stat)) {
758 sasl_gss_seterror(text->utils, maj_stat, min_stat);
759 sasl_gss_free_context_contents(text);
765 real_input_token.value = (void *)clientin;
766 real_input_token.length = clientinlen;
770 GSS_LOCK_MUTEX(params->utils);
772 gss_accept_sec_context(&min_stat,
776 GSS_C_NO_CHANNEL_BINDINGS,
782 &(text->client_creds));
783 GSS_UNLOCK_MUTEX(params->utils);
785 if (GSS_ERROR(maj_stat)) {
786 sasl_gss_log(text->utils, maj_stat, min_stat);
787 text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
788 if (output_token->value) {
789 GSS_LOCK_MUTEX(params->utils);
790 gss_release_buffer(&min_stat, output_token);
791 GSS_UNLOCK_MUTEX(params->utils);
793 sasl_gss_free_context_contents(text);
798 if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
799 (!(out_flags & GSS_C_DELEG_FLAG) ||
800 text->client_creds == GSS_C_NO_CREDENTIAL) )
802 text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
803 "GSSAPI warning: no credentials were passed");
804 /* continue with authentication */
808 *serveroutlen = output_token->length;
809 if (output_token->value) {
811 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
812 &(text->out_buf_len), *serveroutlen);
814 GSS_LOCK_MUTEX(params->utils);
815 gss_release_buffer(&min_stat, output_token);
816 GSS_UNLOCK_MUTEX(params->utils);
819 memcpy(text->out_buf, output_token->value, *serveroutlen);
820 *serverout = text->out_buf;
823 GSS_LOCK_MUTEX(params->utils);
824 gss_release_buffer(&min_stat, output_token);
825 GSS_UNLOCK_MUTEX(params->utils);
827 /* No output token, send an empty string */
828 *serverout = GSSAPI_BLANK_STRING;
832 if (maj_stat == GSS_S_COMPLETE) {
833 if (text->rfc2222_gss) {
834 /* Switch to ssf negotiation */
835 text->state = SASL_GSSAPI_STATE_SSFCAP;
836 return SASL_CONTINUE;
839 return SASL_CONTINUE;
841 /* Fall-through for non-RFC 2222 mechanisms such as GSS-SPNEGO */
843 case SASL_GSSAPI_STATE_SSFCAP: {
844 unsigned char sasldata[4];
845 gss_buffer_desc name_token;
846 gss_buffer_desc name_without_realm;
847 gss_name_t without = NULL;
850 name_token.value = NULL;
851 name_without_realm.value = NULL;
853 /* We ignore whatever the client sent us at this stage */
855 GSS_LOCK_MUTEX(params->utils);
856 maj_stat = gss_display_name (&min_stat,
860 GSS_UNLOCK_MUTEX(params->utils);
862 if (GSS_ERROR(maj_stat)) {
864 GSS_LOCK_MUTEX(params->utils);
865 gss_release_name(&min_stat, &without);
866 GSS_UNLOCK_MUTEX(params->utils);
868 SETERROR(text->utils, "GSSAPI Failure");
869 sasl_gss_free_context_contents(text);
873 /* If the id contains a realm get the identifier for the user
874 without the realm and see if it's the same id (i.e.
875 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
876 to return the id (i.e. just "tmartin" */
877 if (strchr((char *) name_token.value, (int) '@') != NULL) {
878 /* NOTE: libc malloc, as it is freed below by a gssapi internal
880 name_without_realm.value = params->utils->malloc(strlen(name_token.value)+1);
881 if (name_without_realm.value == NULL) {
882 if (name_token.value) {
883 GSS_LOCK_MUTEX(params->utils);
884 gss_release_buffer(&min_stat, &name_token);
885 GSS_UNLOCK_MUTEX(params->utils);
887 MEMERROR(text->utils);
891 strcpy(name_without_realm.value, name_token.value);
893 /* cut off string at '@' */
894 (strchr(name_without_realm.value,'@'))[0] = '\0';
896 name_without_realm.length = strlen( (char *) name_without_realm.value );
898 GSS_LOCK_MUTEX(params->utils);
899 maj_stat = gss_import_name (&min_stat,
901 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
902 so use GSS_C_NT_USER_NAME instead if available. */
903 #ifdef HAVE_GSS_C_NT_USER_NAME
909 GSS_UNLOCK_MUTEX(params->utils);
911 if (GSS_ERROR(maj_stat)) {
912 params->utils->free(name_without_realm.value);
913 if (name_token.value) {
914 GSS_LOCK_MUTEX(params->utils);
915 gss_release_buffer(&min_stat, &name_token);
916 GSS_UNLOCK_MUTEX(params->utils);
918 SETERROR(text->utils, "GSSAPI Failure");
919 sasl_gss_free_context_contents(text);
923 GSS_LOCK_MUTEX(params->utils);
924 maj_stat = gss_compare_name(&min_stat,
928 GSS_UNLOCK_MUTEX(params->utils);
930 if (GSS_ERROR(maj_stat)) {
931 params->utils->free(name_without_realm.value);
932 if (name_token.value) {
933 GSS_LOCK_MUTEX(params->utils);
934 gss_release_buffer(&min_stat, &name_token);
935 GSS_UNLOCK_MUTEX(params->utils);
938 GSS_LOCK_MUTEX(params->utils);
939 gss_release_name(&min_stat, &without);
940 GSS_UNLOCK_MUTEX(params->utils);
942 SETERROR(text->utils, "GSSAPI Failure");
943 sasl_gss_free_context_contents(text);
947 GSS_LOCK_MUTEX(params->utils);
948 gss_release_name(&min_stat,&without);
949 GSS_UNLOCK_MUTEX(params->utils);
956 text->authid = strdup(name_without_realm.value);
958 if (text->authid == NULL) {
959 MEMERROR(params->utils);
963 text->authid = strdup(name_token.value);
965 if (text->authid == NULL) {
966 MEMERROR(params->utils);
971 if (name_token.value) {
972 GSS_LOCK_MUTEX(params->utils);
973 gss_release_buffer(&min_stat, &name_token);
974 GSS_UNLOCK_MUTEX(params->utils);
976 if (name_without_realm.value) {
977 params->utils->free(name_without_realm.value);
980 /* we have to decide what sort of encryption/integrity/etc.,
982 if (params->props.max_ssf < params->external_ssf) {
985 text->limitssf = params->props.max_ssf - params->external_ssf;
987 if (params->props.min_ssf < params->external_ssf) {
988 text->requiressf = 0;
990 text->requiressf = params->props.min_ssf - params->external_ssf;
993 if (!text->rfc2222_gss) {
994 if (out_flags & GSS_C_CONF_FLAG)
996 else if (out_flags & GSS_C_INTEG_FLAG)
1001 text->limitssf = 128; /* XXX */
1006 /* build up our security properties token */
1007 if (params->props.maxbufsize > 0xFFFFFF) {
1008 /* make sure maxbufsize isn't too large */
1009 /* maxbufsize = 0xFFFFFF */
1010 sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
1012 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
1013 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
1014 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
1017 if(text->requiressf != 0 && !params->props.maxbufsize) {
1018 params->utils->seterror(params->utils->conn, 0,
1019 "GSSAPI needs a security layer but one is forbidden");
1020 return SASL_TOOWEAK;
1023 if (text->requiressf == 0) {
1024 sasldata[0] |= 1; /* authentication */
1026 if (text->requiressf <= 1 && text->limitssf >= 1
1027 && params->props.maxbufsize) {
1030 if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF
1031 && params->props.maxbufsize) {
1035 real_input_token.value = (void *)sasldata;
1036 real_input_token.length = 4;
1038 GSS_LOCK_MUTEX(params->utils);
1039 maj_stat = gss_wrap(&min_stat,
1041 0, /* Just integrity checking here */
1046 GSS_UNLOCK_MUTEX(params->utils);
1048 if (GSS_ERROR(maj_stat)) {
1049 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1050 if (output_token->value) {
1051 GSS_LOCK_MUTEX(params->utils);
1052 gss_release_buffer(&min_stat, output_token);
1053 GSS_UNLOCK_MUTEX(params->utils);
1055 sasl_gss_free_context_contents(text);
1061 *serveroutlen = output_token->length;
1062 if (output_token->value) {
1064 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1065 &(text->out_buf_len), *serveroutlen);
1066 if(ret != SASL_OK) {
1067 GSS_LOCK_MUTEX(params->utils);
1068 gss_release_buffer(&min_stat, output_token);
1069 GSS_UNLOCK_MUTEX(params->utils);
1072 memcpy(text->out_buf, output_token->value, *serveroutlen);
1073 *serverout = text->out_buf;
1076 GSS_LOCK_MUTEX(params->utils);
1077 gss_release_buffer(&min_stat, output_token);
1078 GSS_UNLOCK_MUTEX(params->utils);
1081 /* Wait for ssf request and authid */
1082 text->state = SASL_GSSAPI_STATE_SSFREQ;
1084 return SASL_CONTINUE;
1087 case SASL_GSSAPI_STATE_SSFREQ: {
1088 real_input_token.value = (void *)clientin;
1089 real_input_token.length = clientinlen;
1091 GSS_LOCK_MUTEX(params->utils);
1092 maj_stat = gss_unwrap(&min_stat,
1098 GSS_UNLOCK_MUTEX(params->utils);
1100 if (GSS_ERROR(maj_stat)) {
1101 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1102 sasl_gss_free_context_contents(text);
1106 layerchoice = (int)(((char *)(output_token->value))[0]);
1109 if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
1110 oparams->encode = NULL;
1111 oparams->decode = NULL;
1112 oparams->mech_ssf = 0;
1113 } else if (layerchoice == 2 && text->requiressf <= 1 &&
1114 text->limitssf >= 1) { /* integrity */
1115 oparams->encode=&gssapi_integrity_encode;
1116 oparams->decode=&gssapi_decode;
1117 oparams->mech_ssf=1;
1118 } else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF &&
1119 text->limitssf >= K5_MAX_SSF) { /* privacy */
1120 oparams->encode = &gssapi_privacy_encode;
1121 oparams->decode = &gssapi_decode;
1122 /* FIX ME: Need to extract the proper value here */
1123 oparams->mech_ssf = K5_MAX_SSF;
1125 /* not a supported encryption layer */
1126 SETERROR(text->utils,
1127 "protocol violation: client requested invalid layer");
1128 /* Mark that we attempted negotiation */
1129 oparams->mech_ssf = 2;
1130 if (output_token->value) {
1131 GSS_LOCK_MUTEX(params->utils);
1132 gss_release_buffer(&min_stat, output_token);
1133 GSS_UNLOCK_MUTEX(params->utils);
1135 sasl_gss_free_context_contents(text);
1139 if (output_token->length == 4 || !text->rfc2222_gss) {
1143 ret = params->canon_user(params->utils->conn,
1145 0, /* strlen(text->authid) */
1146 SASL_CU_AUTHZID | SASL_CU_AUTHID,
1149 if (ret != SASL_OK) {
1150 sasl_gss_free_context_contents(text);
1153 } else if (output_token->length > 4) {
1156 ret = params->canon_user(params->utils->conn,
1157 ((char *) output_token->value) + 4,
1158 (output_token->length - 4) * sizeof(char),
1159 SASL_CU_AUTHZID, oparams);
1161 if (ret != SASL_OK) {
1162 sasl_gss_free_context_contents(text);
1166 ret = params->canon_user(params->utils->conn,
1168 0, /* strlen(text->authid) */
1169 SASL_CU_AUTHID, oparams);
1170 if (ret != SASL_OK) {
1171 sasl_gss_free_context_contents(text);
1175 SETERROR(text->utils,
1177 GSS_LOCK_MUTEX(params->utils);
1178 gss_release_buffer(&min_stat, output_token);
1179 GSS_UNLOCK_MUTEX(params->utils);
1180 sasl_gss_free_context_contents(text);
1184 /* No matter what, set the rest of the oparams */
1186 if (text->client_creds != GSS_C_NO_CREDENTIAL) {
1187 oparams->client_creds = &text->client_creds;
1190 oparams->client_creds = NULL;
1193 oparams->gss_peer_name = text->client_name;
1194 oparams->gss_local_name = text->server_name;
1196 if (text->rfc2222_gss) {
1197 oparams->maxoutbuf =
1198 (((unsigned char *) output_token->value)[1] << 16) |
1199 (((unsigned char *) output_token->value)[2] << 8) |
1200 (((unsigned char *) output_token->value)[3] << 0);
1202 oparams->maxoutbuf = 0xFFFFFF;
1205 if (oparams->mech_ssf) {
1206 maj_stat = gss_wrap_size_limit( &min_stat,
1210 (OM_uint32) oparams->maxoutbuf,
1213 if(max_input > oparams->maxoutbuf) {
1214 /* Heimdal appears to get this wrong */
1215 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1217 /* This code is actually correct */
1218 oparams->maxoutbuf = max_input;
1222 GSS_LOCK_MUTEX(params->utils);
1223 gss_release_buffer(&min_stat, output_token);
1224 GSS_UNLOCK_MUTEX(params->utils);
1226 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1228 /* used by layers */
1229 _plug_decode_init(&text->decode_context, text->utils,
1230 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1231 params->props.maxbufsize);
1233 oparams->doneflag = 1;
1239 params->utils->log(NULL, SASL_LOG_ERR,
1240 "Invalid GSSAPI server step %d\n", text->state);
1244 return SASL_FAIL; /* should never get here */
1247 static sasl_server_plug_t gssapi_server_plugins[] =
1250 "GSSAPI", /* mech_name */
1251 K5_MAX_SSF, /* max_ssf */
1252 SASL_SEC_NOPLAINTEXT
1254 | SASL_SEC_NOANONYMOUS
1255 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1256 | SASL_SEC_PASS_CREDENTIALS,
1257 SASL_FEAT_WANT_CLIENT_FIRST
1258 | SASL_FEAT_ALLOWS_PROXY, /* features */
1259 NULL, /* glob_context */
1260 &gssapi_server_mech_new, /* mech_new */
1261 &gssapi_server_mech_step, /* mech_step */
1262 &gssapi_common_mech_dispose, /* mech_dispose */
1263 &gssapi_common_mech_free, /* mech_free */
1265 NULL, /* user_query */
1267 NULL, /* mech_avail */
1271 "GSS-SPNEGO", /* mech_name */
1272 K5_MAX_SSF, /* max_ssf */
1273 SASL_SEC_NOPLAINTEXT
1275 | SASL_SEC_NOANONYMOUS
1276 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1277 | SASL_SEC_PASS_CREDENTIALS,
1278 SASL_FEAT_WANT_CLIENT_FIRST
1279 | SASL_FEAT_ALLOWS_PROXY, /* features */
1280 NULL, /* glob_context */
1281 &gss_spnego_server_mech_new, /* mech_new */
1282 &gssapi_server_mech_step, /* mech_step */
1283 &gssapi_common_mech_dispose, /* mech_dispose */
1284 &gssapi_common_mech_free, /* mech_free */
1286 NULL, /* user_query */
1288 NULL, /* mech_avail */
1293 int gssapiv2_server_plug_init(
1294 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1295 const sasl_utils_t *utils __attribute__((unused)),
1297 const sasl_utils_t *utils,
1301 sasl_server_plug_t **pluglist,
1304 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1305 const char *keytab = NULL;
1306 char keytab_path[1024];
1310 if (maxversion < SASL_SERVER_PLUG_VERSION) {
1311 return SASL_BADVERS;
1314 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1315 /* unfortunately, we don't check for readability of keytab if it's
1316 the standard one, since we don't know where it is */
1318 /* FIXME: This code is broken */
1320 utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
1321 if (keytab != NULL) {
1322 if (access(keytab, R_OK) != 0) {
1323 utils->log(NULL, SASL_LOG_ERR,
1324 "Could not find keytab file: %s: %m",
1329 if(strlen(keytab) > 1024) {
1330 utils->log(NULL, SASL_LOG_ERR,
1331 "path to keytab is > 1024 characters");
1332 return SASL_BUFOVER;
1335 strncpy(keytab_path, keytab, 1024);
1337 gsskrb5_register_acceptor_identity(keytab_path);
1341 *out_version = SASL_SERVER_PLUG_VERSION;
1342 *pluglist = gssapi_server_plugins;
1343 *plugcount = sizeof(gssapi_server_plugins)/sizeof(gssapi_server_plugins[0]);
1345 #ifdef GSS_USE_MUTEXES
1347 gss_mutex = utils->mutex_alloc();
1357 /***************************** Client Section *****************************/
1359 static int _gssapi_client_mech_new(void *glob_context __attribute__((unused)),
1360 sasl_client_params_t *params,
1363 void **conn_context)
1367 /* holds state are in */
1368 text = sasl_gss_new_context(params->utils);
1370 MEMERROR(params->utils);
1374 text->state = SASL_GSSAPI_STATE_AUTHNEG;
1375 text->gss_ctx = GSS_C_NO_CONTEXT;
1376 text->client_name = GSS_C_NO_NAME;
1377 text->server_creds = GSS_C_NO_CREDENTIAL;
1378 text->client_creds = GSS_C_NO_CREDENTIAL;
1380 text->rfc2222_gss = rfc2222_gss;
1382 *conn_context = text;
1387 static int gssapi_client_mech_new(void *glob_context,
1388 sasl_client_params_t *params,
1389 void **conn_context)
1391 return _gssapi_client_mech_new(glob_context, params, &gss_krb5_mechanism_oid_desc,
1395 static int gss_spnego_client_mech_new(void *glob_context,
1396 sasl_client_params_t *params,
1397 void **conn_context)
1399 return _gssapi_client_mech_new(glob_context, params, &gss_spnego_mechanism_oid_desc,
1403 static int gssapi_client_mech_step(void *conn_context,
1404 sasl_client_params_t *params,
1405 const char *serverin,
1406 unsigned serverinlen,
1407 sasl_interact_t **prompt_need,
1408 const char **clientout,
1409 unsigned *clientoutlen,
1410 sasl_out_params_t *oparams)
1412 context_t *text = (context_t *)conn_context;
1413 gss_buffer_t input_token, output_token;
1414 gss_buffer_desc real_input_token, real_output_token;
1415 OM_uint32 maj_stat = 0, min_stat = 0;
1416 OM_uint32 max_input, out_flags;
1417 gss_buffer_desc name_token;
1418 int ret, serverhas = 0;
1419 OM_uint32 req_flags = 0, out_req_flags = 0;
1420 sasl_security_properties_t *secprops = &(params->props);
1422 input_token = &real_input_token;
1423 output_token = &real_output_token;
1424 output_token->value = NULL;
1425 input_token->value = NULL;
1426 input_token->length = 0;
1431 switch (text->state) {
1433 case SASL_GSSAPI_STATE_AUTHNEG:
1434 /* try to get the userid */
1435 if (text->gss_ctx == GSS_C_NO_CONTEXT) {
1436 ret = gssapi_get_init_creds(text, params, prompt_need, oparams);
1437 if (ret != SASL_OK) {
1439 sasl_gss_free_context_contents(text);
1443 if (text->server_name == GSS_C_NO_NAME) { /* only once */
1444 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
1445 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
1446 if (name_token.value == NULL) {
1447 sasl_gss_free_context_contents(text);
1450 if (params->serverFQDN == NULL
1451 || strlen(params->serverFQDN) == 0) {
1452 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1456 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1458 GSS_LOCK_MUTEX(params->utils);
1459 maj_stat = gss_import_name (&min_stat,
1461 GSS_C_NT_HOSTBASED_SERVICE,
1462 &text->server_name);
1463 GSS_UNLOCK_MUTEX(params->utils);
1465 params->utils->free(name_token.value);
1466 name_token.value = NULL;
1468 if (GSS_ERROR(maj_stat)) {
1469 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1470 sasl_gss_free_context_contents(text);
1475 if (serverinlen == 0)
1476 input_token = GSS_C_NO_BUFFER;
1479 real_input_token.value = (void *)serverin;
1480 real_input_token.length = serverinlen;
1482 else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
1483 /* This can't happen under GSSAPI: we have a non-null context
1484 * and no input from the server. However, thanks to Imap,
1485 * which discards our first output, this happens all the time.
1486 * Throw away the context and try again. */
1487 GSS_LOCK_MUTEX(params->utils);
1488 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
1489 GSS_UNLOCK_MUTEX(params->utils);
1490 text->gss_ctx = GSS_C_NO_CONTEXT;
1493 /* Setup req_flags properly */
1494 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
1495 if(params->props.max_ssf > params->external_ssf) {
1496 /* We are requesting a security layer */
1497 req_flags |= GSS_C_INTEG_FLAG;
1498 /* Any SSF bigger than 1 is confidentiality. */
1499 /* Let's check if the client of the API requires confidentiality,
1500 and it wasn't already provided by an external layer */
1501 if(params->props.max_ssf - params->external_ssf > 1) {
1502 /* We want to try for privacy */
1503 req_flags |= GSS_C_CONF_FLAG;
1507 if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS)
1508 req_flags = req_flags | GSS_C_DELEG_FLAG;
1510 GSS_LOCK_MUTEX(params->utils);
1511 maj_stat = gss_init_sec_context(&min_stat,
1512 params->gss_creds ? params->gss_creds :
1519 GSS_C_NO_CHANNEL_BINDINGS,
1525 GSS_UNLOCK_MUTEX(params->utils);
1527 if (GSS_ERROR(maj_stat)) {
1528 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1529 if (output_token->value) {
1530 GSS_LOCK_MUTEX(params->utils);
1531 gss_release_buffer(&min_stat, output_token);
1532 GSS_UNLOCK_MUTEX(params->utils);
1534 sasl_gss_free_context_contents(text);
1538 if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_FLAG)) {
1539 text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
1540 /* not a fatal error */
1543 *clientoutlen = output_token->length;
1545 if (output_token->value) {
1547 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1548 &(text->out_buf_len), *clientoutlen);
1549 if(ret != SASL_OK) {
1550 GSS_LOCK_MUTEX(params->utils);
1551 gss_release_buffer(&min_stat, output_token);
1552 GSS_UNLOCK_MUTEX(params->utils);
1555 memcpy(text->out_buf, output_token->value, *clientoutlen);
1556 *clientout = text->out_buf;
1559 GSS_LOCK_MUTEX(params->utils);
1560 gss_release_buffer(&min_stat, output_token);
1561 GSS_UNLOCK_MUTEX(params->utils);
1564 if (maj_stat == GSS_S_COMPLETE) {
1565 GSS_LOCK_MUTEX(params->utils);
1566 if (text->client_name != GSS_C_NO_NAME)
1567 gss_release_name(&min_stat, &text->client_name);
1568 maj_stat = gss_inquire_context(&min_stat,
1571 NULL, /* targ_name */
1572 NULL, /* lifetime */
1574 /* FIX ME: Should check the resulting flags here */
1575 &out_flags, /* flags */
1576 NULL, /* local init */
1578 GSS_UNLOCK_MUTEX(params->utils);
1580 if (GSS_ERROR(maj_stat)) {
1581 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1582 sasl_gss_free_context_contents(text);
1586 name_token.length = 0;
1587 GSS_LOCK_MUTEX(params->utils);
1588 maj_stat = gss_display_name(&min_stat,
1592 GSS_UNLOCK_MUTEX(params->utils);
1594 if (GSS_ERROR(maj_stat)) {
1595 if (name_token.value) {
1596 GSS_LOCK_MUTEX(params->utils);
1597 gss_release_buffer(&min_stat, &name_token);
1598 GSS_UNLOCK_MUTEX(params->utils);
1600 SETERROR(text->utils, "GSSAPI Failure");
1601 sasl_gss_free_context_contents(text);
1605 if (text->user && text->user[0]) {
1606 ret = params->canon_user(params->utils->conn,
1608 SASL_CU_AUTHZID, oparams);
1610 ret = params->canon_user(params->utils->conn,
1611 name_token.value, 0,
1612 SASL_CU_AUTHID, oparams);
1614 ret = params->canon_user(params->utils->conn,
1615 name_token.value, 0,
1616 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1619 GSS_LOCK_MUTEX(params->utils);
1620 gss_release_buffer(&min_stat, &name_token);
1621 GSS_UNLOCK_MUTEX(params->utils);
1623 oparams->gss_peer_name = text->server_name;
1624 oparams->gss_local_name = text->client_name;
1626 if (ret != SASL_OK) return ret;
1628 if (text->rfc2222_gss) {
1629 /* Switch to ssf negotiation */
1630 text->state = SASL_GSSAPI_STATE_SSFCAP;
1631 return SASL_CONTINUE;
1634 if (out_flags & GSS_C_INTEG_FLAG)
1636 if (out_flags & GSS_C_CONF_FLAG)
1641 return SASL_CONTINUE;
1644 case SASL_GSSAPI_STATE_SSFCAP: {
1645 unsigned int alen, external = params->external_ssf;
1646 sasl_ssf_t need, allowed;
1649 real_input_token.value = (void *) serverin;
1650 real_input_token.length = serverinlen;
1652 GSS_LOCK_MUTEX(params->utils);
1653 maj_stat = gss_unwrap(&min_stat,
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);
1664 if (output_token->value) {
1665 GSS_LOCK_MUTEX(params->utils);
1666 gss_release_buffer(&min_stat, output_token);
1667 GSS_UNLOCK_MUTEX(params->utils);
1672 /* bit mask of server support */
1673 serverhas = ((char *)output_token->value)[0];
1676 /* taken from kerberos.c */
1677 if (secprops->min_ssf > (K5_MAX_SSF + external)) {
1678 return SASL_TOOWEAK;
1679 } else if (secprops->min_ssf > secprops->max_ssf) {
1680 return SASL_BADPARAM;
1683 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1684 if (secprops->max_ssf >= external) {
1685 allowed = secprops->max_ssf - external;
1689 if (secprops->min_ssf >= external) {
1690 need = secprops->min_ssf - external;
1696 /* if client didn't set use strongest layer available */
1697 if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) {
1699 oparams->encode = &gssapi_privacy_encode;
1700 oparams->decode = &gssapi_decode;
1701 /* FIX ME: Need to extract the proper value here */
1702 oparams->mech_ssf = K5_MAX_SSF;
1704 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1706 oparams->encode = &gssapi_integrity_encode;
1707 oparams->decode = &gssapi_decode;
1708 oparams->mech_ssf = 1;
1710 } else if (need <= 0 && (serverhas & 1)) {
1712 oparams->encode = NULL;
1713 oparams->decode = NULL;
1714 oparams->mech_ssf = 0;
1717 /* there's no appropriate layering for us! */
1718 sasl_gss_free_context_contents(text);
1719 return SASL_TOOWEAK;
1722 if (text->rfc2222_gss) {
1723 oparams->maxoutbuf =
1724 (((unsigned char *) output_token->value)[1] << 16) |
1725 (((unsigned char *) output_token->value)[2] << 8) |
1726 (((unsigned char *) output_token->value)[3] << 0);
1728 oparams->maxoutbuf = 0xFFFFFF;
1731 if(oparams->mech_ssf) {
1732 maj_stat = gss_wrap_size_limit( &min_stat,
1736 (OM_uint32) oparams->maxoutbuf,
1739 if(max_input > oparams->maxoutbuf) {
1740 /* Heimdal appears to get this wrong */
1741 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1743 /* This code is actually correct */
1744 oparams->maxoutbuf = max_input;
1748 GSS_LOCK_MUTEX(params->utils);
1749 gss_release_buffer(&min_stat, output_token);
1750 GSS_UNLOCK_MUTEX(params->utils);
1752 if (!text->rfc2222_gss) {
1753 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1755 oparams->doneflag = 1;
1757 /* used by layers */
1758 _plug_decode_init(&text->decode_context, text->utils,
1759 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1760 params->props.maxbufsize);
1764 /* oparams->user is always set, due to canon_user requirements.
1765 * Make sure the client actually requested it though, by checking
1766 * if our context was set.
1768 if (text->user && text->user[0])
1769 alen = strlen(oparams->user);
1773 input_token->length = 4 + alen;
1774 input_token->value =
1775 (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
1776 if (input_token->value == NULL) {
1777 sasl_gss_free_context_contents(text);
1782 memcpy((char *)input_token->value+4,oparams->user,alen);
1784 /* build up our security properties token */
1785 if (params->props.maxbufsize > 0xFFFFFF) {
1786 /* make sure maxbufsize isn't too large */
1787 /* maxbufsize = 0xFFFFFF */
1788 ((unsigned char *)input_token->value)[1] = 0xFF;
1789 ((unsigned char *)input_token->value)[2] = 0xFF;
1790 ((unsigned char *)input_token->value)[3] = 0xFF;
1792 ((unsigned char *)input_token->value)[1] =
1793 (params->props.maxbufsize >> 16) & 0xFF;
1794 ((unsigned char *)input_token->value)[2] =
1795 (params->props.maxbufsize >> 8) & 0xFF;
1796 ((unsigned char *)input_token->value)[3] =
1797 (params->props.maxbufsize >> 0) & 0xFF;
1799 ((unsigned char *)input_token->value)[0] = mychoice;
1801 GSS_LOCK_MUTEX(params->utils);
1802 maj_stat = gss_wrap (&min_stat,
1804 0, /* Just integrity checking here */
1809 GSS_UNLOCK_MUTEX(params->utils);
1811 params->utils->free(input_token->value);
1812 input_token->value = NULL;
1814 if (GSS_ERROR(maj_stat)) {
1815 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1816 if (output_token->value) {
1817 GSS_LOCK_MUTEX(params->utils);
1818 gss_release_buffer(&min_stat, output_token);
1819 GSS_UNLOCK_MUTEX(params->utils);
1821 sasl_gss_free_context_contents(text);
1826 *clientoutlen = output_token->length;
1827 if (output_token->value) {
1829 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1830 &(text->out_buf_len), *clientoutlen);
1831 if (ret != SASL_OK) {
1832 GSS_LOCK_MUTEX(params->utils);
1833 gss_release_buffer(&min_stat, output_token);
1834 GSS_UNLOCK_MUTEX(params->utils);
1837 memcpy(text->out_buf, output_token->value, *clientoutlen);
1838 *clientout = text->out_buf;
1841 GSS_LOCK_MUTEX(params->utils);
1842 gss_release_buffer(&min_stat, output_token);
1843 GSS_UNLOCK_MUTEX(params->utils);
1847 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1849 oparams->doneflag = 1;
1851 /* used by layers */
1852 _plug_decode_init(&text->decode_context, text->utils,
1853 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1854 params->props.maxbufsize);
1860 params->utils->log(NULL, SASL_LOG_ERR,
1861 "Invalid GSSAPI client step %d\n", text->state);
1865 return SASL_FAIL; /* should never get here */
1868 static const unsigned long gssapi_required_prompts[] = {
1872 static sasl_client_plug_t gssapi_client_plugins[] =
1875 "GSSAPI", /* mech_name */
1876 K5_MAX_SSF, /* max_ssf */
1877 SASL_SEC_NOPLAINTEXT
1879 | SASL_SEC_NOANONYMOUS
1880 | SASL_SEC_MUTUAL_AUTH
1881 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1882 SASL_FEAT_NEEDSERVERFQDN
1883 | SASL_FEAT_WANT_CLIENT_FIRST
1884 | SASL_FEAT_ALLOWS_PROXY, /* features */
1885 gssapi_required_prompts, /* required_prompts */
1886 NULL, /* glob_context */
1887 &gssapi_client_mech_new, /* mech_new */
1888 &gssapi_client_mech_step, /* mech_step */
1889 &gssapi_common_mech_dispose, /* mech_dispose */
1890 &gssapi_common_mech_free, /* mech_free */
1896 "GSS-SPNEGO", /* mech_name */
1897 K5_MAX_SSF, /* max_ssf */
1898 SASL_SEC_NOPLAINTEXT
1900 | SASL_SEC_NOANONYMOUS
1901 | SASL_SEC_MUTUAL_AUTH
1902 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1903 SASL_FEAT_NEEDSERVERFQDN
1904 | SASL_FEAT_WANT_CLIENT_FIRST
1905 | SASL_FEAT_ALLOWS_PROXY, /* features */
1906 gssapi_required_prompts, /* required_prompts */
1907 NULL, /* glob_context */
1908 &gss_spnego_client_mech_new, /* mech_new */
1909 &gssapi_client_mech_step, /* mech_step */
1910 &gssapi_common_mech_dispose, /* mech_dispose */
1911 &gssapi_common_mech_free, /* mech_free */
1918 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
1921 sasl_client_plug_t **pluglist,
1924 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
1925 SETERROR(utils, "Version mismatch in GSSAPI");
1926 return SASL_BADVERS;
1929 *out_version = SASL_CLIENT_PLUG_VERSION;
1930 *pluglist = gssapi_client_plugins;
1931 *plugcount = sizeof(gssapi_client_plugins)/sizeof(gssapi_client_plugins[0]);
1933 #ifdef GSS_USE_MUTEXES
1935 gss_mutex = utils->mutex_alloc();
1945 #define GOT_CREDS(text, params) ((text)->client_creds != NULL || (params)->gss_creds != NULL)
1946 #define CRED_ERROR(status) ((status) == GSS_S_CRED_UNAVAIL || (status) == GSS_S_NO_CRED)
1949 * Determine the authentication identity from the application supplied
1950 * GSS credential, the application supplied identity, and the default
1951 * GSS credential, in that order. Then, acquire credentials.
1954 gssapi_get_init_creds(context_t *text,
1955 sasl_client_params_t *params,
1956 sasl_interact_t **prompt_need,
1957 sasl_out_params_t *oparams)
1959 int result = SASL_OK;
1960 const char *authid = NULL, *userid = NULL;
1961 int user_result = SASL_OK;
1962 int auth_result = SASL_OK;
1963 int pass_result = SASL_OK;
1964 OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0;
1965 gss_OID_set_desc mechs;
1966 gss_buffer_desc cred_authid = GSS_C_EMPTY_BUFFER;
1967 gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
1970 mechs.elements = (gss_OID)text->mech;
1973 * Get the authentication identity from the application.
1975 if (oparams->authid == NULL) {
1976 auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
1977 if (auth_result != SASL_OK && auth_result != SASL_INTERACT) {
1978 result = auth_result;
1984 * Get the authorization identity from the application.
1986 if (oparams->user == NULL) {
1987 user_result = _plug_get_userid(params->utils, &userid, prompt_need);
1988 if (user_result != SASL_OK && user_result != SASL_INTERACT) {
1989 result = user_result;
1995 * Canonicalize the authentication and authorization identities before
1996 * calling GSS_Import_name.
1998 if (auth_result == SASL_OK && user_result == SASL_OK &&
1999 oparams->authid == NULL) {
2000 if (userid == NULL || userid[0] == '\0') {
2001 result = params->canon_user(params->utils->conn, authid, 0,
2002 SASL_CU_AUTHID | SASL_CU_AUTHZID,
2005 result = params->canon_user(params->utils->conn,
2006 authid, 0, SASL_CU_AUTHID, oparams);
2007 if (result != SASL_OK)
2010 result = params->canon_user(params->utils->conn,
2011 userid, 0, SASL_CU_AUTHZID, oparams);
2012 if (result != SASL_OK)
2016 if (oparams->authid != NULL) {
2017 name_buf.length = strlen(oparams->authid);
2018 name_buf.value = (void *)oparams->authid;
2020 assert(text->client_name == GSS_C_NO_NAME);
2022 maj_stat = gss_import_name(&min_stat,
2025 &text->client_name);
2026 if (GSS_ERROR(maj_stat))
2029 /* The authid may have changed after prompting, so free any creds */
2030 gss_release_cred(&min_stat, &text->client_creds);
2035 * If application didn't provide an authid, then use the default
2036 * credential. If that doesn't work, give up.
2038 if (!GOT_CREDS(text, params) && oparams->authid == NULL) {
2039 maj_stat = gss_acquire_cred(&min_stat,
2044 &text->client_creds,
2047 if (GSS_ERROR(maj_stat))
2050 assert(text->client_name == GSS_C_NO_NAME);
2052 maj_stat = gss_inquire_cred(&min_stat,
2054 ? (gss_cred_id_t)params->gss_creds
2055 : text->client_creds,
2060 if (GSS_ERROR(maj_stat)) {
2061 /* Maybe there was no default credential */
2062 auth_result = SASL_INTERACT;
2066 maj_stat = gss_display_name(&min_stat,
2070 if (GSS_ERROR(maj_stat))
2073 if (userid == NULL || userid[0] == '\0') {
2074 result = params->canon_user(params->utils->conn,
2075 cred_authid.value, cred_authid.length,
2076 SASL_CU_AUTHID | SASL_CU_AUTHZID,
2079 result = params->canon_user(params->utils->conn,
2080 cred_authid.value, cred_authid.length,
2081 SASL_CU_AUTHID, oparams);
2082 if (result != SASL_OK)
2085 result = params->canon_user(params->utils->conn,
2086 cred_authid.value, cred_authid.length,
2087 SASL_CU_AUTHZID, oparams);
2088 if (result != SASL_OK)
2094 * Armed with the authentication identity, try to get a credential without
2097 if (!GOT_CREDS(text, params) && text->client_name != GSS_C_NO_NAME) {
2098 maj_stat = gss_acquire_cred(&min_stat,
2103 &text->client_creds,
2106 if (GSS_ERROR(maj_stat) && !CRED_ERROR(maj_stat))
2111 * If that failed, try to get a credential with a password.
2113 if (!GOT_CREDS(text, params)) {
2114 if (text->password == NULL) {
2115 pass_result = _plug_get_password(params->utils, &text->password,
2116 &text->free_password, prompt_need);
2117 if (pass_result != SASL_OK && pass_result != SASL_INTERACT) {
2118 result = pass_result;
2123 if (text->password != NULL) {
2124 gss_buffer_desc password_buf;
2126 password_buf.length = text->password->len;
2127 password_buf.value = text->password->data;
2129 maj_stat = gss_acquire_cred_with_password(&min_stat,
2135 &text->client_creds,
2138 if (GSS_ERROR(maj_stat))
2143 maj_stat = GSS_S_COMPLETE;
2147 /* free prompts we got */
2148 if (prompt_need && *prompt_need) {
2149 params->utils->free(*prompt_need);
2150 *prompt_need = NULL;
2153 /* if there are prompts not filled in */
2154 if (user_result == SASL_INTERACT || auth_result == SASL_INTERACT ||
2155 pass_result == SASL_INTERACT) {
2156 /* make the prompt list */
2158 _plug_make_prompts(params->utils, prompt_need,
2159 user_result == SASL_INTERACT ?
2160 "Please enter your authorization name" : NULL,
2162 auth_result == SASL_INTERACT ?
2163 "Please enter your authentication name" : NULL,
2165 pass_result == SASL_INTERACT ?
2166 "Please enter your password" : NULL, NULL,
2170 if (result == SASL_OK)
2171 result = SASL_INTERACT;
2175 if (result == SASL_OK && maj_stat != GSS_S_COMPLETE) {
2176 sasl_gss_seterror(text->utils, maj_stat, min_stat);
2180 gss_release_buffer(&min_stat, &cred_authid);