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>
77 #include "plugin_common.h"
85 /***************************** Common Section *****************************/
87 static const char plugin_id[] = "$Id: gssapi.c,v 1.92 2004/07/21 14:39:06 rjs3 Exp $";
89 static const char * GSSAPI_BLANK_STRING = "";
91 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
92 extern gss_OID gss_nt_service_name;
93 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
96 #ifdef WANT_KERBEROS5_3DES
97 /* Check if CyberSafe flag is defined */
98 #ifdef CSF_GSS_C_DES3_FLAG
99 #define K5_MAX_SSF 112
102 /* Heimdal and MIT use the following */
103 #ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
104 #define K5_MAX_SSF 112
110 /* All Kerberos implementations support DES */
111 #define K5_MAX_SSF 56
114 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
115 * inspired by the kerberos mechanism and the gssapi_server and
116 * gssapi_client from the heimdal distribution by Assar Westerlund
117 * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>.
118 * See the configure.in file for details on dependencies.
120 * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
122 * This code was tested with the following distributions of Kerberos:
123 * Heimdal (http://www.pdc.kth.se/heimdal), MIT (http://web.mit.edu/kerberos/www/)
124 * CyberSafe (http://www.cybersafe.com/) and SEAM.
127 #ifdef GSS_USE_MUTEXES
128 #define GSS_LOCK_MUTEX(utils) \
129 if(((sasl_utils_t *)(utils))->mutex_lock(gss_mutex) != 0) { \
133 #define GSS_UNLOCK_MUTEX(utils) \
134 if(((sasl_utils_t *)(utils))->mutex_unlock(gss_mutex) != 0) { \
138 static void *gss_mutex = NULL;
140 #define GSS_LOCK_MUTEX(utils)
141 #define GSS_UNLOCK_MUTEX(utils)
144 static gss_OID_desc gss_spnego_mechanism_oid_desc =
145 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
146 static gss_OID_desc gss_krb5_mechanism_oid_desc =
147 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
149 typedef struct context {
152 gss_ctx_id_t gss_ctx;
154 gss_name_t client_name;
155 gss_name_t server_name;
156 gss_cred_id_t server_creds;
157 gss_cred_id_t client_creds;
159 sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
161 const sasl_utils_t *utils;
163 /* layers buffering */
164 decode_context_t decode_context;
166 char *encode_buf; /* For encoding/decoding mem management */
168 char *decode_once_buf;
169 unsigned encode_buf_len;
170 unsigned decode_buf_len;
171 unsigned decode_once_buf_len;
172 buffer_info_t *enc_in_buf;
174 char *out_buf; /* per-step mem management */
175 unsigned out_buf_len;
177 char *authid; /* hold the authid between steps - server */
178 const char *user; /* hold the userid between steps - client */
183 sasl_secret_t *password;
184 unsigned int free_password;
189 SASL_GSSAPI_STATE_AUTHNEG = 1,
190 SASL_GSSAPI_STATE_SSFCAP = 2,
191 SASL_GSSAPI_STATE_SSFREQ = 3,
192 SASL_GSSAPI_STATE_AUTHENTICATED = 4
196 gssapi_get_init_creds(context_t *text,
197 sasl_client_params_t *params,
198 sasl_interact_t **prompt_need,
199 sasl_out_params_t *oparams);
201 /* sasl_gss_log: only logs status string returned from gss_display_status() */
202 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
203 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
206 sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
209 OM_uint32 maj_stat, min_stat;
214 unsigned int len, curlen = 0;
215 const char prefix[] = "GSSAPI Error: ";
217 len = sizeof(prefix);
218 ret = _plug_buf_alloc(utils, &out, &curlen, 256);
219 if(ret != SASL_OK) return SASL_OK;
225 GSS_LOCK_MUTEX(utils);
226 maj_stat = gss_display_status(&min_stat, maj,
227 GSS_C_GSS_CODE, GSS_C_NULL_OID,
229 GSS_UNLOCK_MUTEX(utils);
231 if(GSS_ERROR(maj_stat)) {
233 utils->log(utils->conn, SASL_LOG_FAIL,
234 "GSSAPI Failure: (could not get major error message)");
236 utils->seterror(utils->conn, 0,
238 "(could not get major error message)");
244 len += len + msg.length;
245 ret = _plug_buf_alloc(utils, &out, &curlen, len);
252 strcat(out, msg.value);
254 GSS_LOCK_MUTEX(utils);
255 gss_release_buffer(&min_stat, &msg);
256 GSS_UNLOCK_MUTEX(utils);
262 /* Now get the minor status */
265 ret = _plug_buf_alloc(utils, &out, &curlen, len);
275 GSS_LOCK_MUTEX(utils);
276 maj_stat = gss_display_status(&min_stat, min,
277 GSS_C_MECH_CODE, GSS_C_NULL_OID,
279 GSS_UNLOCK_MUTEX(utils);
281 if(GSS_ERROR(maj_stat)) {
283 utils->log(utils->conn, SASL_LOG_FAIL,
284 "GSSAPI Failure: (could not get minor error message)");
286 utils->seterror(utils->conn, 0,
288 "(could not get minor error message)");
294 len += len + msg.length;
296 ret = _plug_buf_alloc(utils, &out, &curlen, len);
302 strcat(out, msg.value);
304 GSS_LOCK_MUTEX(utils);
305 gss_release_buffer(&min_stat, &msg);
306 GSS_UNLOCK_MUTEX(utils);
313 ret = _plug_buf_alloc(utils, &out, &curlen, len);
322 utils->log(utils->conn, SASL_LOG_FAIL, out);
324 utils->seterror(utils->conn, 0, out);
332 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
333 const char **output, unsigned *outputlen, int privacy)
335 context_t *text = (context_t *)context;
336 OM_uint32 maj_stat, min_stat;
337 gss_buffer_t input_token, output_token;
338 gss_buffer_desc real_input_token, real_output_token;
340 struct buffer_info *inblob, bufinfo;
342 if(!output) return SASL_BADPARAM;
345 ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
346 if(ret != SASL_OK) return ret;
347 inblob = text->enc_in_buf;
349 bufinfo.data = invec[0].iov_base;
350 bufinfo.curlen = invec[0].iov_len;
354 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
356 input_token = &real_input_token;
358 real_input_token.value = inblob->data;
359 real_input_token.length = inblob->curlen;
361 output_token = &real_output_token;
362 output_token->value = NULL;
363 output_token->length = 0;
365 GSS_LOCK_MUTEX(text->utils);
366 maj_stat = gss_wrap (&min_stat,
373 GSS_UNLOCK_MUTEX(text->utils);
375 if (GSS_ERROR(maj_stat))
377 sasl_gss_seterror(text->utils, maj_stat, min_stat);
378 if (output_token->value) {
379 GSS_LOCK_MUTEX(text->utils);
380 gss_release_buffer(&min_stat, output_token);
381 GSS_UNLOCK_MUTEX(text->utils);
386 if (output_token->value && output) {
389 ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
390 &(text->encode_buf_len), output_token->length + 4);
392 if (ret != SASL_OK) {
393 GSS_LOCK_MUTEX(text->utils);
394 gss_release_buffer(&min_stat, output_token);
395 GSS_UNLOCK_MUTEX(text->utils);
399 len = htonl(output_token->length);
400 memcpy(text->encode_buf, &len, 4);
401 memcpy(text->encode_buf + 4, output_token->value, output_token->length);
405 *outputlen = output_token->length + 4;
408 *output = text->encode_buf;
410 if (output_token->value) {
411 GSS_LOCK_MUTEX(text->utils);
412 gss_release_buffer(&min_stat, output_token);
413 GSS_UNLOCK_MUTEX(text->utils);
418 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
419 unsigned numiov, const char **output,
422 return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
425 static int gssapi_integrity_encode(void *context, const struct iovec *invec,
426 unsigned numiov, const char **output,
429 return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
432 static int gssapi_decode_packet(void *context,
433 const char *input, unsigned inputlen,
434 char **output, unsigned *outputlen)
436 context_t *text = (context_t *) context;
437 OM_uint32 maj_stat, min_stat;
438 gss_buffer_t input_token, output_token;
439 gss_buffer_desc real_input_token, real_output_token;
442 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
443 SETERROR(text->utils, "GSSAPI Failure");
447 input_token = &real_input_token;
448 real_input_token.value = (char *) input;
449 real_input_token.length = inputlen;
451 output_token = &real_output_token;
452 output_token->value = NULL;
453 output_token->length = 0;
455 GSS_LOCK_MUTEX(text->utils);
456 maj_stat = gss_unwrap (&min_stat,
462 GSS_UNLOCK_MUTEX(text->utils);
464 if (GSS_ERROR(maj_stat))
466 sasl_gss_seterror(text->utils,maj_stat,min_stat);
467 if (output_token->value) {
468 GSS_LOCK_MUTEX(text->utils);
469 gss_release_buffer(&min_stat, output_token);
470 GSS_UNLOCK_MUTEX(text->utils);
476 *outputlen = output_token->length;
478 if (output_token->value) {
480 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
481 &text->decode_once_buf_len,
483 if(result != SASL_OK) {
484 GSS_LOCK_MUTEX(text->utils);
485 gss_release_buffer(&min_stat, output_token);
486 GSS_UNLOCK_MUTEX(text->utils);
489 *output = text->decode_once_buf;
490 memcpy(*output, output_token->value, *outputlen);
492 GSS_LOCK_MUTEX(text->utils);
493 gss_release_buffer(&min_stat, output_token);
494 GSS_UNLOCK_MUTEX(text->utils);
500 static int gssapi_decode(void *context,
501 const char *input, unsigned inputlen,
502 const char **output, unsigned *outputlen)
504 context_t *text = (context_t *) context;
507 ret = _plug_decode(&text->decode_context, input, inputlen,
508 &text->decode_buf, &text->decode_buf_len, outputlen,
509 gssapi_decode_packet, text);
511 *output = text->decode_buf;
516 static context_t *sasl_gss_new_context(const sasl_utils_t *utils)
520 ret = utils->malloc(sizeof(context_t));
521 if(!ret) return NULL;
523 memset(ret,0,sizeof(context_t));
529 static int sasl_gss_free_context_contents(context_t *text)
531 OM_uint32 maj_stat, min_stat;
533 if (!text) return SASL_OK;
535 GSS_LOCK_MUTEX(text->utils);
537 if (text->gss_ctx != GSS_C_NO_CONTEXT) {
538 maj_stat = gss_delete_sec_context(&min_stat,&text->gss_ctx,
540 text->gss_ctx = GSS_C_NO_CONTEXT;
543 if (text->client_name != GSS_C_NO_NAME) {
544 maj_stat = gss_release_name(&min_stat,&text->client_name);
545 text->client_name = GSS_C_NO_NAME;
548 if (text->server_name != GSS_C_NO_NAME) {
549 maj_stat = gss_release_name(&min_stat,&text->server_name);
550 text->server_name = GSS_C_NO_NAME;
553 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
554 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
555 text->server_creds = GSS_C_NO_CREDENTIAL;
558 if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
559 maj_stat = gss_release_cred(&min_stat, &text->client_creds);
560 text->client_creds = GSS_C_NO_CREDENTIAL;
563 GSS_UNLOCK_MUTEX(text->utils);
566 text->utils->free(text->out_buf);
567 text->out_buf = NULL;
570 if (text->encode_buf) {
571 text->utils->free(text->encode_buf);
572 text->encode_buf = NULL;
575 if (text->decode_buf) {
576 text->utils->free(text->decode_buf);
577 text->decode_buf = NULL;
580 if (text->decode_once_buf) {
581 text->utils->free(text->decode_once_buf);
582 text->decode_once_buf = NULL;
585 if (text->enc_in_buf) {
586 if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
587 text->utils->free(text->enc_in_buf);
588 text->enc_in_buf = NULL;
591 _plug_decode_free(&text->decode_context);
593 if (text->authid) { /* works for both client and server */
594 text->utils->free(text->authid);
598 if (text->free_password)
599 _plug_free_secret(text->utils, &text->password);
601 memset(text, 0, sizeof(*text));
606 static void gssapi_common_mech_dispose(void *conn_context,
607 const sasl_utils_t *utils)
609 sasl_gss_free_context_contents((context_t *)(conn_context));
610 utils->free(conn_context);
613 static void gssapi_common_mech_free(void *global_context __attribute__((unused)),
614 const sasl_utils_t *utils)
616 #ifdef GSS_USE_MUTEXES
618 utils->mutex_free(gss_mutex);
624 /***************************** Server Section *****************************/
627 _gssapi_server_mech_new(void *glob_context __attribute__((unused)),
628 sasl_server_params_t *params,
629 const char *challenge __attribute__((unused)),
630 unsigned challen __attribute__((unused)),
636 text = sasl_gss_new_context(params->utils);
638 MEMERROR(params->utils);
642 text->gss_ctx = GSS_C_NO_CONTEXT;
643 text->client_name = GSS_C_NO_NAME;
644 text->server_name = GSS_C_NO_NAME;
645 text->server_creds = GSS_C_NO_CREDENTIAL;
646 text->client_creds = GSS_C_NO_CREDENTIAL;
647 text->state = SASL_GSSAPI_STATE_AUTHNEG;
648 text->rfc2222_gss = rfc2222_gss;
650 *conn_context = text;
656 gssapi_server_mech_new(void *glob_context,
657 sasl_server_params_t *params,
658 const char *challenge,
662 return _gssapi_server_mech_new(glob_context, params, challenge,
663 challen, 1, conn_context);
667 gss_spnego_server_mech_new(void *glob_context,
668 sasl_server_params_t *params,
669 const char *challenge,
673 return _gssapi_server_mech_new(glob_context, params, challenge,
674 challen, 0, conn_context);
678 gssapi_server_mech_step(void *conn_context,
679 sasl_server_params_t *params,
680 const char *clientin,
681 unsigned clientinlen,
682 const char **serverout,
683 unsigned *serveroutlen,
684 sasl_out_params_t *oparams)
686 context_t *text = (context_t *)conn_context;
687 gss_buffer_t input_token, output_token;
688 gss_buffer_desc real_input_token, real_output_token;
689 OM_uint32 maj_stat = 0, min_stat = 0;
691 gss_buffer_desc name_token;
693 OM_uint32 out_flags = 0 ;
696 input_token = &real_input_token;
697 output_token = &real_output_token;
698 output_token->value = NULL; output_token->length = 0;
699 input_token->value = NULL; input_token->length = 0;
702 PARAMERROR(text->utils);
703 return SASL_BADPARAM;
709 switch (text->state) {
711 case SASL_GSSAPI_STATE_AUTHNEG:
712 if (text->server_name == GSS_C_NO_NAME) { /* only once */
713 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
714 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
715 if (name_token.value == NULL) {
716 MEMERROR(text->utils);
717 sasl_gss_free_context_contents(text);
720 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
722 GSS_LOCK_MUTEX(params->utils);
723 maj_stat = gss_import_name (&min_stat,
725 GSS_C_NT_HOSTBASED_SERVICE,
727 GSS_UNLOCK_MUTEX(params->utils);
729 params->utils->free(name_token.value);
730 name_token.value = NULL;
732 if (GSS_ERROR(maj_stat)) {
733 sasl_gss_seterror(text->utils, maj_stat, min_stat);
734 sasl_gss_free_context_contents(text);
738 if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
739 GSS_LOCK_MUTEX(params->utils);
740 maj_stat = gss_release_cred(&min_stat, &text->server_creds);
741 GSS_UNLOCK_MUTEX(params->utils);
742 text->server_creds = GSS_C_NO_CREDENTIAL;
745 GSS_LOCK_MUTEX(params->utils);
746 maj_stat = gss_acquire_cred(&min_stat,
754 GSS_UNLOCK_MUTEX(params->utils);
756 if (GSS_ERROR(maj_stat)) {
757 sasl_gss_seterror(text->utils, maj_stat, min_stat);
758 sasl_gss_free_context_contents(text);
764 real_input_token.value = (void *)clientin;
765 real_input_token.length = clientinlen;
769 GSS_LOCK_MUTEX(params->utils);
771 gss_accept_sec_context(&min_stat,
775 GSS_C_NO_CHANNEL_BINDINGS,
781 &(text->client_creds));
782 GSS_UNLOCK_MUTEX(params->utils);
784 if (GSS_ERROR(maj_stat)) {
785 sasl_gss_log(text->utils, maj_stat, min_stat);
786 text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
787 if (output_token->value) {
788 GSS_LOCK_MUTEX(params->utils);
789 gss_release_buffer(&min_stat, output_token);
790 GSS_UNLOCK_MUTEX(params->utils);
792 sasl_gss_free_context_contents(text);
797 if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
798 (!(out_flags & GSS_C_DELEG_FLAG) ||
799 text->client_creds == GSS_C_NO_CREDENTIAL) )
801 text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
802 "GSSAPI warning: no credentials were passed");
803 /* continue with authentication */
807 *serveroutlen = output_token->length;
808 if (output_token->value) {
810 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
811 &(text->out_buf_len), *serveroutlen);
813 GSS_LOCK_MUTEX(params->utils);
814 gss_release_buffer(&min_stat, output_token);
815 GSS_UNLOCK_MUTEX(params->utils);
818 memcpy(text->out_buf, output_token->value, *serveroutlen);
819 *serverout = text->out_buf;
822 GSS_LOCK_MUTEX(params->utils);
823 gss_release_buffer(&min_stat, output_token);
824 GSS_UNLOCK_MUTEX(params->utils);
826 /* No output token, send an empty string */
827 *serverout = GSSAPI_BLANK_STRING;
831 if (maj_stat == GSS_S_COMPLETE) {
832 if (text->rfc2222_gss) {
833 /* Switch to ssf negotiation */
834 text->state = SASL_GSSAPI_STATE_SSFCAP;
835 return SASL_CONTINUE;
838 return SASL_CONTINUE;
840 /* Fall-through for non-RFC 2222 mechanisms such as GSS-SPNEGO */
842 case SASL_GSSAPI_STATE_SSFCAP: {
843 unsigned char sasldata[4];
844 gss_buffer_desc name_token;
845 gss_buffer_desc name_without_realm;
846 gss_name_t without = NULL;
849 name_token.value = NULL;
850 name_without_realm.value = NULL;
852 /* We ignore whatever the client sent us at this stage */
854 GSS_LOCK_MUTEX(params->utils);
855 maj_stat = gss_display_name (&min_stat,
859 GSS_UNLOCK_MUTEX(params->utils);
861 if (GSS_ERROR(maj_stat)) {
863 GSS_LOCK_MUTEX(params->utils);
864 gss_release_name(&min_stat, &without);
865 GSS_UNLOCK_MUTEX(params->utils);
867 SETERROR(text->utils, "GSSAPI Failure");
868 sasl_gss_free_context_contents(text);
872 /* If the id contains a realm get the identifier for the user
873 without the realm and see if it's the same id (i.e.
874 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
875 to return the id (i.e. just "tmartin" */
876 if (strchr((char *) name_token.value, (int) '@') != NULL) {
877 /* NOTE: libc malloc, as it is freed below by a gssapi internal
879 name_without_realm.value = params->utils->malloc(strlen(name_token.value)+1);
880 if (name_without_realm.value == NULL) {
881 if (name_token.value) {
882 GSS_LOCK_MUTEX(params->utils);
883 gss_release_buffer(&min_stat, &name_token);
884 GSS_UNLOCK_MUTEX(params->utils);
886 MEMERROR(text->utils);
890 strcpy(name_without_realm.value, name_token.value);
892 /* cut off string at '@' */
893 (strchr(name_without_realm.value,'@'))[0] = '\0';
895 name_without_realm.length = strlen( (char *) name_without_realm.value );
897 GSS_LOCK_MUTEX(params->utils);
898 maj_stat = gss_import_name (&min_stat,
900 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
901 so use GSS_C_NT_USER_NAME instead if available. */
902 #ifdef HAVE_GSS_C_NT_USER_NAME
908 GSS_UNLOCK_MUTEX(params->utils);
910 if (GSS_ERROR(maj_stat)) {
911 params->utils->free(name_without_realm.value);
912 if (name_token.value) {
913 GSS_LOCK_MUTEX(params->utils);
914 gss_release_buffer(&min_stat, &name_token);
915 GSS_UNLOCK_MUTEX(params->utils);
917 SETERROR(text->utils, "GSSAPI Failure");
918 sasl_gss_free_context_contents(text);
922 GSS_LOCK_MUTEX(params->utils);
923 maj_stat = gss_compare_name(&min_stat,
927 GSS_UNLOCK_MUTEX(params->utils);
929 if (GSS_ERROR(maj_stat)) {
930 params->utils->free(name_without_realm.value);
931 if (name_token.value) {
932 GSS_LOCK_MUTEX(params->utils);
933 gss_release_buffer(&min_stat, &name_token);
934 GSS_UNLOCK_MUTEX(params->utils);
937 GSS_LOCK_MUTEX(params->utils);
938 gss_release_name(&min_stat, &without);
939 GSS_UNLOCK_MUTEX(params->utils);
941 SETERROR(text->utils, "GSSAPI Failure");
942 sasl_gss_free_context_contents(text);
946 GSS_LOCK_MUTEX(params->utils);
947 gss_release_name(&min_stat,&without);
948 GSS_UNLOCK_MUTEX(params->utils);
955 text->authid = strdup(name_without_realm.value);
957 if (text->authid == NULL) {
958 MEMERROR(params->utils);
962 text->authid = strdup(name_token.value);
964 if (text->authid == NULL) {
965 MEMERROR(params->utils);
970 if (name_token.value) {
971 GSS_LOCK_MUTEX(params->utils);
972 gss_release_buffer(&min_stat, &name_token);
973 GSS_UNLOCK_MUTEX(params->utils);
975 if (name_without_realm.value) {
976 params->utils->free(name_without_realm.value);
979 /* we have to decide what sort of encryption/integrity/etc.,
981 if (params->props.max_ssf < params->external_ssf) {
984 text->limitssf = params->props.max_ssf - params->external_ssf;
986 if (params->props.min_ssf < params->external_ssf) {
987 text->requiressf = 0;
989 text->requiressf = params->props.min_ssf - params->external_ssf;
992 if (!text->rfc2222_gss) {
993 if (out_flags & GSS_C_CONF_FLAG)
995 else if (out_flags & GSS_C_INTEG_FLAG)
1000 text->limitssf = 128; /* XXX */
1005 /* build up our security properties token */
1006 if (params->props.maxbufsize > 0xFFFFFF) {
1007 /* make sure maxbufsize isn't too large */
1008 /* maxbufsize = 0xFFFFFF */
1009 sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
1011 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
1012 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
1013 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
1016 if(text->requiressf != 0 && !params->props.maxbufsize) {
1017 params->utils->seterror(params->utils->conn, 0,
1018 "GSSAPI needs a security layer but one is forbidden");
1019 return SASL_TOOWEAK;
1022 if (text->requiressf == 0) {
1023 sasldata[0] |= 1; /* authentication */
1025 if (text->requiressf <= 1 && text->limitssf >= 1
1026 && params->props.maxbufsize) {
1029 if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF
1030 && params->props.maxbufsize) {
1034 real_input_token.value = (void *)sasldata;
1035 real_input_token.length = 4;
1037 GSS_LOCK_MUTEX(params->utils);
1038 maj_stat = gss_wrap(&min_stat,
1040 0, /* Just integrity checking here */
1045 GSS_UNLOCK_MUTEX(params->utils);
1047 if (GSS_ERROR(maj_stat)) {
1048 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1049 if (output_token->value) {
1050 GSS_LOCK_MUTEX(params->utils);
1051 gss_release_buffer(&min_stat, output_token);
1052 GSS_UNLOCK_MUTEX(params->utils);
1054 sasl_gss_free_context_contents(text);
1060 *serveroutlen = output_token->length;
1061 if (output_token->value) {
1063 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1064 &(text->out_buf_len), *serveroutlen);
1065 if(ret != SASL_OK) {
1066 GSS_LOCK_MUTEX(params->utils);
1067 gss_release_buffer(&min_stat, output_token);
1068 GSS_UNLOCK_MUTEX(params->utils);
1071 memcpy(text->out_buf, output_token->value, *serveroutlen);
1072 *serverout = text->out_buf;
1075 GSS_LOCK_MUTEX(params->utils);
1076 gss_release_buffer(&min_stat, output_token);
1077 GSS_UNLOCK_MUTEX(params->utils);
1080 /* Wait for ssf request and authid */
1081 text->state = SASL_GSSAPI_STATE_SSFREQ;
1083 return SASL_CONTINUE;
1086 case SASL_GSSAPI_STATE_SSFREQ: {
1087 real_input_token.value = (void *)clientin;
1088 real_input_token.length = clientinlen;
1090 GSS_LOCK_MUTEX(params->utils);
1091 maj_stat = gss_unwrap(&min_stat,
1097 GSS_UNLOCK_MUTEX(params->utils);
1099 if (GSS_ERROR(maj_stat)) {
1100 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1101 sasl_gss_free_context_contents(text);
1105 layerchoice = (int)(((char *)(output_token->value))[0]);
1108 if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
1109 oparams->encode = NULL;
1110 oparams->decode = NULL;
1111 oparams->mech_ssf = 0;
1112 } else if (layerchoice == 2 && text->requiressf <= 1 &&
1113 text->limitssf >= 1) { /* integrity */
1114 oparams->encode=&gssapi_integrity_encode;
1115 oparams->decode=&gssapi_decode;
1116 oparams->mech_ssf=1;
1117 } else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF &&
1118 text->limitssf >= K5_MAX_SSF) { /* privacy */
1119 oparams->encode = &gssapi_privacy_encode;
1120 oparams->decode = &gssapi_decode;
1121 /* FIX ME: Need to extract the proper value here */
1122 oparams->mech_ssf = K5_MAX_SSF;
1124 /* not a supported encryption layer */
1125 SETERROR(text->utils,
1126 "protocol violation: client requested invalid layer");
1127 /* Mark that we attempted negotiation */
1128 oparams->mech_ssf = 2;
1129 if (output_token->value) {
1130 GSS_LOCK_MUTEX(params->utils);
1131 gss_release_buffer(&min_stat, output_token);
1132 GSS_UNLOCK_MUTEX(params->utils);
1134 sasl_gss_free_context_contents(text);
1138 if (output_token->length == 4 || !text->rfc2222_gss) {
1142 ret = params->canon_user(params->utils->conn,
1144 0, /* strlen(text->authid) */
1145 SASL_CU_AUTHZID | SASL_CU_AUTHID,
1148 if (ret != SASL_OK) {
1149 sasl_gss_free_context_contents(text);
1152 } else if (output_token->length > 4) {
1155 ret = params->canon_user(params->utils->conn,
1156 ((char *) output_token->value) + 4,
1157 (output_token->length - 4) * sizeof(char),
1158 SASL_CU_AUTHZID, oparams);
1160 if (ret != SASL_OK) {
1161 sasl_gss_free_context_contents(text);
1165 ret = params->canon_user(params->utils->conn,
1167 0, /* strlen(text->authid) */
1168 SASL_CU_AUTHID, oparams);
1169 if (ret != SASL_OK) {
1170 sasl_gss_free_context_contents(text);
1174 SETERROR(text->utils,
1176 GSS_LOCK_MUTEX(params->utils);
1177 gss_release_buffer(&min_stat, output_token);
1178 GSS_UNLOCK_MUTEX(params->utils);
1179 sasl_gss_free_context_contents(text);
1183 /* No matter what, set the rest of the oparams */
1185 if (text->client_creds != GSS_C_NO_CREDENTIAL) {
1186 oparams->client_creds = &text->client_creds;
1189 oparams->client_creds = NULL;
1192 oparams->gss_peer_name = text->client_name;
1193 oparams->gss_local_name = text->server_name;
1195 if (text->rfc2222_gss) {
1196 oparams->maxoutbuf =
1197 (((unsigned char *) output_token->value)[1] << 16) |
1198 (((unsigned char *) output_token->value)[2] << 8) |
1199 (((unsigned char *) output_token->value)[3] << 0);
1201 oparams->maxoutbuf = 0xFFFFFF;
1204 if (oparams->mech_ssf) {
1205 maj_stat = gss_wrap_size_limit( &min_stat,
1209 (OM_uint32) oparams->maxoutbuf,
1212 if(max_input > oparams->maxoutbuf) {
1213 /* Heimdal appears to get this wrong */
1214 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1216 /* This code is actually correct */
1217 oparams->maxoutbuf = max_input;
1221 GSS_LOCK_MUTEX(params->utils);
1222 gss_release_buffer(&min_stat, output_token);
1223 GSS_UNLOCK_MUTEX(params->utils);
1225 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1227 /* used by layers */
1228 _plug_decode_init(&text->decode_context, text->utils,
1229 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1230 params->props.maxbufsize);
1232 oparams->doneflag = 1;
1238 params->utils->log(NULL, SASL_LOG_ERR,
1239 "Invalid GSSAPI server step %d\n", text->state);
1243 return SASL_FAIL; /* should never get here */
1246 static sasl_server_plug_t gssapi_server_plugins[] =
1249 "GSSAPI", /* mech_name */
1250 K5_MAX_SSF, /* max_ssf */
1251 SASL_SEC_NOPLAINTEXT
1253 | SASL_SEC_NOANONYMOUS
1254 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1255 | SASL_SEC_PASS_CREDENTIALS,
1256 SASL_FEAT_WANT_CLIENT_FIRST
1257 | SASL_FEAT_ALLOWS_PROXY, /* features */
1258 NULL, /* glob_context */
1259 &gssapi_server_mech_new, /* mech_new */
1260 &gssapi_server_mech_step, /* mech_step */
1261 &gssapi_common_mech_dispose, /* mech_dispose */
1262 &gssapi_common_mech_free, /* mech_free */
1264 NULL, /* user_query */
1266 NULL, /* mech_avail */
1270 "GSS-SPNEGO", /* mech_name */
1271 K5_MAX_SSF, /* max_ssf */
1272 SASL_SEC_NOPLAINTEXT
1274 | SASL_SEC_NOANONYMOUS
1275 | SASL_SEC_MUTUAL_AUTH /* security_flags */
1276 | SASL_SEC_PASS_CREDENTIALS,
1277 SASL_FEAT_WANT_CLIENT_FIRST
1278 | SASL_FEAT_ALLOWS_PROXY, /* features */
1279 NULL, /* glob_context */
1280 &gss_spnego_server_mech_new, /* mech_new */
1281 &gssapi_server_mech_step, /* mech_step */
1282 &gssapi_common_mech_dispose, /* mech_dispose */
1283 &gssapi_common_mech_free, /* mech_free */
1285 NULL, /* user_query */
1287 NULL, /* mech_avail */
1292 int gssapiv2_server_plug_init(
1293 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1294 const sasl_utils_t *utils __attribute__((unused)),
1296 const sasl_utils_t *utils,
1300 sasl_server_plug_t **pluglist,
1303 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1304 const char *keytab = NULL;
1305 char keytab_path[1024];
1309 if (maxversion < SASL_SERVER_PLUG_VERSION) {
1310 return SASL_BADVERS;
1313 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1314 /* unfortunately, we don't check for readability of keytab if it's
1315 the standard one, since we don't know where it is */
1317 /* FIXME: This code is broken */
1319 utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
1320 if (keytab != NULL) {
1321 if (access(keytab, R_OK) != 0) {
1322 utils->log(NULL, SASL_LOG_ERR,
1323 "Could not find keytab file: %s: %m",
1328 if(strlen(keytab) > 1024) {
1329 utils->log(NULL, SASL_LOG_ERR,
1330 "path to keytab is > 1024 characters");
1331 return SASL_BUFOVER;
1334 strncpy(keytab_path, keytab, 1024);
1336 gsskrb5_register_acceptor_identity(keytab_path);
1340 *out_version = SASL_SERVER_PLUG_VERSION;
1341 *pluglist = gssapi_server_plugins;
1342 *plugcount = sizeof(gssapi_server_plugins)/sizeof(gssapi_server_plugins[0]);
1344 #ifdef GSS_USE_MUTEXES
1346 gss_mutex = utils->mutex_alloc();
1356 /***************************** Client Section *****************************/
1358 static int _gssapi_client_mech_new(void *glob_context __attribute__((unused)),
1359 sasl_client_params_t *params,
1362 void **conn_context)
1366 /* holds state are in */
1367 text = sasl_gss_new_context(params->utils);
1369 MEMERROR(params->utils);
1373 text->state = SASL_GSSAPI_STATE_AUTHNEG;
1374 text->gss_ctx = GSS_C_NO_CONTEXT;
1375 text->client_name = GSS_C_NO_NAME;
1376 text->server_creds = GSS_C_NO_CREDENTIAL;
1377 text->client_creds = GSS_C_NO_CREDENTIAL;
1379 text->rfc2222_gss = rfc2222_gss;
1381 *conn_context = text;
1386 static int gssapi_client_mech_new(void *glob_context,
1387 sasl_client_params_t *params,
1388 void **conn_context)
1390 return _gssapi_client_mech_new(glob_context, params, &gss_krb5_mechanism_oid_desc,
1394 static int gss_spnego_client_mech_new(void *glob_context,
1395 sasl_client_params_t *params,
1396 void **conn_context)
1398 return _gssapi_client_mech_new(glob_context, params, &gss_spnego_mechanism_oid_desc,
1402 static int gssapi_client_mech_step(void *conn_context,
1403 sasl_client_params_t *params,
1404 const char *serverin,
1405 unsigned serverinlen,
1406 sasl_interact_t **prompt_need,
1407 const char **clientout,
1408 unsigned *clientoutlen,
1409 sasl_out_params_t *oparams)
1411 context_t *text = (context_t *)conn_context;
1412 gss_buffer_t input_token, output_token;
1413 gss_buffer_desc real_input_token, real_output_token;
1414 OM_uint32 maj_stat = 0, min_stat = 0;
1415 OM_uint32 max_input, out_flags;
1416 gss_buffer_desc name_token;
1417 int ret, serverhas = 0;
1418 OM_uint32 req_flags = 0, out_req_flags = 0;
1419 sasl_security_properties_t *secprops = &(params->props);
1421 input_token = &real_input_token;
1422 output_token = &real_output_token;
1423 output_token->value = NULL;
1424 input_token->value = NULL;
1425 input_token->length = 0;
1430 switch (text->state) {
1432 case SASL_GSSAPI_STATE_AUTHNEG:
1433 /* try to get the userid */
1434 if (text->gss_ctx == GSS_C_NO_CONTEXT) {
1435 ret = gssapi_get_init_creds(text, params, prompt_need, oparams);
1436 if (ret != SASL_OK) {
1438 sasl_gss_free_context_contents(text);
1442 if (text->server_name == GSS_C_NO_NAME) { /* only once */
1443 name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
1444 name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
1445 if (name_token.value == NULL) {
1446 sasl_gss_free_context_contents(text);
1449 if (params->serverFQDN == NULL
1450 || strlen(params->serverFQDN) == 0) {
1451 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1455 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1457 GSS_LOCK_MUTEX(params->utils);
1458 maj_stat = gss_import_name (&min_stat,
1460 GSS_C_NT_HOSTBASED_SERVICE,
1461 &text->server_name);
1462 GSS_UNLOCK_MUTEX(params->utils);
1464 params->utils->free(name_token.value);
1465 name_token.value = NULL;
1467 if (GSS_ERROR(maj_stat)) {
1468 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1469 sasl_gss_free_context_contents(text);
1474 if (serverinlen == 0)
1475 input_token = GSS_C_NO_BUFFER;
1478 real_input_token.value = (void *)serverin;
1479 real_input_token.length = serverinlen;
1481 else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
1482 /* This can't happen under GSSAPI: we have a non-null context
1483 * and no input from the server. However, thanks to Imap,
1484 * which discards our first output, this happens all the time.
1485 * Throw away the context and try again. */
1486 GSS_LOCK_MUTEX(params->utils);
1487 maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
1488 GSS_UNLOCK_MUTEX(params->utils);
1489 text->gss_ctx = GSS_C_NO_CONTEXT;
1492 /* Setup req_flags properly */
1493 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
1494 if(params->props.max_ssf > params->external_ssf) {
1495 /* We are requesting a security layer */
1496 req_flags |= GSS_C_INTEG_FLAG;
1497 /* Any SSF bigger than 1 is confidentiality. */
1498 /* Let's check if the client of the API requires confidentiality,
1499 and it wasn't already provided by an external layer */
1500 if(params->props.max_ssf - params->external_ssf > 1) {
1501 /* We want to try for privacy */
1502 req_flags |= GSS_C_CONF_FLAG;
1506 if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS)
1507 req_flags = req_flags | GSS_C_DELEG_FLAG;
1509 GSS_LOCK_MUTEX(params->utils);
1510 maj_stat = gss_init_sec_context(&min_stat,
1511 params->gss_creds ? params->gss_creds :
1518 GSS_C_NO_CHANNEL_BINDINGS,
1524 GSS_UNLOCK_MUTEX(params->utils);
1526 if (GSS_ERROR(maj_stat)) {
1527 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1528 if (output_token->value) {
1529 GSS_LOCK_MUTEX(params->utils);
1530 gss_release_buffer(&min_stat, output_token);
1531 GSS_UNLOCK_MUTEX(params->utils);
1533 sasl_gss_free_context_contents(text);
1537 if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_FLAG)) {
1538 text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
1539 /* not a fatal error */
1542 *clientoutlen = output_token->length;
1544 if (output_token->value) {
1546 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1547 &(text->out_buf_len), *clientoutlen);
1548 if(ret != SASL_OK) {
1549 GSS_LOCK_MUTEX(params->utils);
1550 gss_release_buffer(&min_stat, output_token);
1551 GSS_UNLOCK_MUTEX(params->utils);
1554 memcpy(text->out_buf, output_token->value, *clientoutlen);
1555 *clientout = text->out_buf;
1558 GSS_LOCK_MUTEX(params->utils);
1559 gss_release_buffer(&min_stat, output_token);
1560 GSS_UNLOCK_MUTEX(params->utils);
1563 if (maj_stat == GSS_S_COMPLETE) {
1564 GSS_LOCK_MUTEX(params->utils);
1565 if (text->client_name != GSS_C_NO_NAME)
1566 gss_release_name(&min_stat, &text->client_name);
1567 maj_stat = gss_inquire_context(&min_stat,
1570 NULL, /* targ_name */
1571 NULL, /* lifetime */
1573 /* FIX ME: Should check the resulting flags here */
1574 &out_flags, /* flags */
1575 NULL, /* local init */
1577 GSS_UNLOCK_MUTEX(params->utils);
1579 if (GSS_ERROR(maj_stat)) {
1580 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1581 sasl_gss_free_context_contents(text);
1585 name_token.length = 0;
1586 GSS_LOCK_MUTEX(params->utils);
1587 maj_stat = gss_display_name(&min_stat,
1591 GSS_UNLOCK_MUTEX(params->utils);
1593 if (GSS_ERROR(maj_stat)) {
1594 if (name_token.value) {
1595 GSS_LOCK_MUTEX(params->utils);
1596 gss_release_buffer(&min_stat, &name_token);
1597 GSS_UNLOCK_MUTEX(params->utils);
1599 SETERROR(text->utils, "GSSAPI Failure");
1600 sasl_gss_free_context_contents(text);
1604 if (text->user && text->user[0]) {
1605 ret = params->canon_user(params->utils->conn,
1607 SASL_CU_AUTHZID, oparams);
1609 ret = params->canon_user(params->utils->conn,
1610 name_token.value, 0,
1611 SASL_CU_AUTHID, oparams);
1613 ret = params->canon_user(params->utils->conn,
1614 name_token.value, 0,
1615 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1618 GSS_LOCK_MUTEX(params->utils);
1619 gss_release_buffer(&min_stat, &name_token);
1620 GSS_UNLOCK_MUTEX(params->utils);
1622 oparams->gss_peer_name = text->server_name;
1623 oparams->gss_local_name = text->client_name;
1625 if (ret != SASL_OK) return ret;
1627 if (text->rfc2222_gss) {
1628 /* Switch to ssf negotiation */
1629 text->state = SASL_GSSAPI_STATE_SSFCAP;
1630 return SASL_CONTINUE;
1633 if (out_flags & GSS_C_INTEG_FLAG)
1635 if (out_flags & GSS_C_CONF_FLAG)
1640 return SASL_CONTINUE;
1643 case SASL_GSSAPI_STATE_SSFCAP: {
1644 unsigned int alen, external = params->external_ssf;
1645 sasl_ssf_t need, allowed;
1648 real_input_token.value = (void *) serverin;
1649 real_input_token.length = serverinlen;
1651 GSS_LOCK_MUTEX(params->utils);
1652 maj_stat = gss_unwrap(&min_stat,
1658 GSS_UNLOCK_MUTEX(params->utils);
1660 if (GSS_ERROR(maj_stat)) {
1661 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1662 sasl_gss_free_context_contents(text);
1663 if (output_token->value) {
1664 GSS_LOCK_MUTEX(params->utils);
1665 gss_release_buffer(&min_stat, output_token);
1666 GSS_UNLOCK_MUTEX(params->utils);
1671 /* bit mask of server support */
1672 serverhas = ((char *)output_token->value)[0];
1675 /* taken from kerberos.c */
1676 if (secprops->min_ssf > (K5_MAX_SSF + external)) {
1677 return SASL_TOOWEAK;
1678 } else if (secprops->min_ssf > secprops->max_ssf) {
1679 return SASL_BADPARAM;
1682 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1683 if (secprops->max_ssf >= external) {
1684 allowed = secprops->max_ssf - external;
1688 if (secprops->min_ssf >= external) {
1689 need = secprops->min_ssf - external;
1695 /* if client didn't set use strongest layer available */
1696 if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) {
1698 oparams->encode = &gssapi_privacy_encode;
1699 oparams->decode = &gssapi_decode;
1700 /* FIX ME: Need to extract the proper value here */
1701 oparams->mech_ssf = K5_MAX_SSF;
1703 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1705 oparams->encode = &gssapi_integrity_encode;
1706 oparams->decode = &gssapi_decode;
1707 oparams->mech_ssf = 1;
1709 } else if (need <= 0 && (serverhas & 1)) {
1711 oparams->encode = NULL;
1712 oparams->decode = NULL;
1713 oparams->mech_ssf = 0;
1716 /* there's no appropriate layering for us! */
1717 sasl_gss_free_context_contents(text);
1718 return SASL_TOOWEAK;
1721 if (text->rfc2222_gss) {
1722 oparams->maxoutbuf =
1723 (((unsigned char *) output_token->value)[1] << 16) |
1724 (((unsigned char *) output_token->value)[2] << 8) |
1725 (((unsigned char *) output_token->value)[3] << 0);
1727 oparams->maxoutbuf = 0xFFFFFF;
1730 if(oparams->mech_ssf) {
1731 maj_stat = gss_wrap_size_limit( &min_stat,
1735 (OM_uint32) oparams->maxoutbuf,
1738 if(max_input > oparams->maxoutbuf) {
1739 /* Heimdal appears to get this wrong */
1740 oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
1742 /* This code is actually correct */
1743 oparams->maxoutbuf = max_input;
1747 GSS_LOCK_MUTEX(params->utils);
1748 gss_release_buffer(&min_stat, output_token);
1749 GSS_UNLOCK_MUTEX(params->utils);
1751 if (!text->rfc2222_gss) {
1752 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1754 oparams->doneflag = 1;
1756 /* used by layers */
1757 _plug_decode_init(&text->decode_context, text->utils,
1758 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1759 params->props.maxbufsize);
1763 /* oparams->user is always set, due to canon_user requirements.
1764 * Make sure the client actually requested it though, by checking
1765 * if our context was set.
1767 if (text->user && text->user[0])
1768 alen = strlen(oparams->user);
1772 input_token->length = 4 + alen;
1773 input_token->value =
1774 (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
1775 if (input_token->value == NULL) {
1776 sasl_gss_free_context_contents(text);
1781 memcpy((char *)input_token->value+4,oparams->user,alen);
1783 /* build up our security properties token */
1784 if (params->props.maxbufsize > 0xFFFFFF) {
1785 /* make sure maxbufsize isn't too large */
1786 /* maxbufsize = 0xFFFFFF */
1787 ((unsigned char *)input_token->value)[1] = 0xFF;
1788 ((unsigned char *)input_token->value)[2] = 0xFF;
1789 ((unsigned char *)input_token->value)[3] = 0xFF;
1791 ((unsigned char *)input_token->value)[1] =
1792 (params->props.maxbufsize >> 16) & 0xFF;
1793 ((unsigned char *)input_token->value)[2] =
1794 (params->props.maxbufsize >> 8) & 0xFF;
1795 ((unsigned char *)input_token->value)[3] =
1796 (params->props.maxbufsize >> 0) & 0xFF;
1798 ((unsigned char *)input_token->value)[0] = mychoice;
1800 GSS_LOCK_MUTEX(params->utils);
1801 maj_stat = gss_wrap (&min_stat,
1803 0, /* Just integrity checking here */
1808 GSS_UNLOCK_MUTEX(params->utils);
1810 params->utils->free(input_token->value);
1811 input_token->value = NULL;
1813 if (GSS_ERROR(maj_stat)) {
1814 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1815 if (output_token->value) {
1816 GSS_LOCK_MUTEX(params->utils);
1817 gss_release_buffer(&min_stat, output_token);
1818 GSS_UNLOCK_MUTEX(params->utils);
1820 sasl_gss_free_context_contents(text);
1825 *clientoutlen = output_token->length;
1826 if (output_token->value) {
1828 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1829 &(text->out_buf_len), *clientoutlen);
1830 if (ret != SASL_OK) {
1831 GSS_LOCK_MUTEX(params->utils);
1832 gss_release_buffer(&min_stat, output_token);
1833 GSS_UNLOCK_MUTEX(params->utils);
1836 memcpy(text->out_buf, output_token->value, *clientoutlen);
1837 *clientout = text->out_buf;
1840 GSS_LOCK_MUTEX(params->utils);
1841 gss_release_buffer(&min_stat, output_token);
1842 GSS_UNLOCK_MUTEX(params->utils);
1846 text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1848 oparams->doneflag = 1;
1850 /* used by layers */
1851 _plug_decode_init(&text->decode_context, text->utils,
1852 (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
1853 params->props.maxbufsize);
1859 params->utils->log(NULL, SASL_LOG_ERR,
1860 "Invalid GSSAPI client step %d\n", text->state);
1864 return SASL_FAIL; /* should never get here */
1867 static const unsigned long gssapi_required_prompts[] = {
1871 static sasl_client_plug_t gssapi_client_plugins[] =
1874 "GSSAPI", /* mech_name */
1875 K5_MAX_SSF, /* max_ssf */
1876 SASL_SEC_NOPLAINTEXT
1878 | SASL_SEC_NOANONYMOUS
1879 | SASL_SEC_MUTUAL_AUTH
1880 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1881 SASL_FEAT_NEEDSERVERFQDN
1882 | SASL_FEAT_WANT_CLIENT_FIRST
1883 | SASL_FEAT_ALLOWS_PROXY, /* features */
1884 gssapi_required_prompts, /* required_prompts */
1885 NULL, /* glob_context */
1886 &gssapi_client_mech_new, /* mech_new */
1887 &gssapi_client_mech_step, /* mech_step */
1888 &gssapi_common_mech_dispose, /* mech_dispose */
1889 &gssapi_common_mech_free, /* mech_free */
1895 "GSS-SPNEGO", /* mech_name */
1896 K5_MAX_SSF, /* max_ssf */
1897 SASL_SEC_NOPLAINTEXT
1899 | SASL_SEC_NOANONYMOUS
1900 | SASL_SEC_MUTUAL_AUTH
1901 | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
1902 SASL_FEAT_NEEDSERVERFQDN
1903 | SASL_FEAT_WANT_CLIENT_FIRST
1904 | SASL_FEAT_ALLOWS_PROXY, /* features */
1905 gssapi_required_prompts, /* required_prompts */
1906 NULL, /* glob_context */
1907 &gss_spnego_client_mech_new, /* mech_new */
1908 &gssapi_client_mech_step, /* mech_step */
1909 &gssapi_common_mech_dispose, /* mech_dispose */
1910 &gssapi_common_mech_free, /* mech_free */
1917 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
1920 sasl_client_plug_t **pluglist,
1923 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
1924 SETERROR(utils, "Version mismatch in GSSAPI");
1925 return SASL_BADVERS;
1928 *out_version = SASL_CLIENT_PLUG_VERSION;
1929 *pluglist = gssapi_client_plugins;
1930 *plugcount = sizeof(gssapi_client_plugins)/sizeof(gssapi_client_plugins[0]);
1932 #ifdef GSS_USE_MUTEXES
1934 gss_mutex = utils->mutex_alloc();
1944 #define GOT_CREDS(text, params) ((text)->client_creds != NULL || (params)->gss_creds != NULL)
1945 #define CRED_ERROR(status) ((status) == GSS_S_CRED_UNAVAIL || (status) == GSS_S_NO_CRED)
1948 * Determine the authentication identity from the application supplied
1949 * GSS credential, the application supplied identity, and the default
1950 * GSS credential, in that order. Then, acquire credentials.
1953 gssapi_get_init_creds(context_t *text,
1954 sasl_client_params_t *params,
1955 sasl_interact_t **prompt_need,
1956 sasl_out_params_t *oparams)
1958 int result = SASL_OK;
1959 const char *authid = NULL, *userid = NULL;
1960 int user_result = SASL_OK;
1961 int auth_result = SASL_OK;
1962 int pass_result = SASL_OK;
1963 OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0;
1964 gss_OID_set_desc mechs;
1965 gss_buffer_desc cred_authid = GSS_C_EMPTY_BUFFER;
1966 gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
1969 mechs.elements = (gss_OID)text->mech;
1972 * Get the authentication identity from the application.
1974 if (oparams->authid == NULL) {
1975 auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
1976 if (auth_result != SASL_OK && auth_result != SASL_INTERACT) {
1977 result = auth_result;
1983 * Get the authorization identity from the application.
1985 if (oparams->user == NULL) {
1986 user_result = _plug_get_userid(params->utils, &userid, prompt_need);
1987 if (user_result != SASL_OK && user_result != SASL_INTERACT) {
1988 result = user_result;
1994 * Canonicalize the authentication and authorization identities before
1995 * calling GSS_Import_name.
1997 if (auth_result == SASL_OK && user_result == SASL_OK &&
1998 oparams->authid == NULL) {
1999 if (userid == NULL || userid[0] == '\0') {
2000 result = params->canon_user(params->utils->conn, authid, 0,
2001 SASL_CU_AUTHID | SASL_CU_AUTHZID,
2004 result = params->canon_user(params->utils->conn,
2005 authid, 0, SASL_CU_AUTHID, oparams);
2006 if (result != SASL_OK)
2009 result = params->canon_user(params->utils->conn,
2010 userid, 0, SASL_CU_AUTHZID, oparams);
2011 if (result != SASL_OK)
2015 if (oparams->authid != NULL) {
2016 name_buf.length = strlen(oparams->authid);
2017 name_buf.value = (void *)oparams->authid;
2019 assert(text->client_name == GSS_C_NO_NAME);
2021 maj_stat = gss_import_name(&min_stat,
2024 &text->client_name);
2025 if (GSS_ERROR(maj_stat))
2028 /* The authid may have changed after prompting, so free any creds */
2029 gss_release_cred(&min_stat, &text->client_creds);
2034 * If application didn't provide an authid, then use the default
2035 * credential. If that doesn't work, give up.
2037 if (!GOT_CREDS(text, params) && oparams->authid == NULL) {
2038 maj_stat = gss_acquire_cred(&min_stat,
2043 &text->client_creds,
2046 if (GSS_ERROR(maj_stat))
2049 assert(text->client_name == GSS_C_NO_NAME);
2051 maj_stat = gss_inquire_cred(&min_stat,
2053 ? (gss_cred_id_t)params->gss_creds
2054 : text->client_creds,
2059 if (GSS_ERROR(maj_stat)) {
2060 /* Maybe there was no default credential */
2061 auth_result = SASL_INTERACT;
2065 maj_stat = gss_display_name(&min_stat,
2069 if (GSS_ERROR(maj_stat))
2072 if (userid == NULL || userid[0] == '\0') {
2073 result = params->canon_user(params->utils->conn,
2074 cred_authid.value, cred_authid.length,
2075 SASL_CU_AUTHID | SASL_CU_AUTHZID,
2078 result = params->canon_user(params->utils->conn,
2079 cred_authid.value, cred_authid.length,
2080 SASL_CU_AUTHID, oparams);
2081 if (result != SASL_OK)
2084 result = params->canon_user(params->utils->conn,
2085 cred_authid.value, cred_authid.length,
2086 SASL_CU_AUTHZID, oparams);
2087 if (result != SASL_OK)
2093 * Armed with the authentication identity, try to get a credential without
2096 if (!GOT_CREDS(text, params) && text->client_name != GSS_C_NO_NAME) {
2097 maj_stat = gss_acquire_cred(&min_stat,
2102 &text->client_creds,
2105 if (GSS_ERROR(maj_stat) && !CRED_ERROR(maj_stat))
2110 * If that failed, try to get a credential with a password.
2112 if (!GOT_CREDS(text, params)) {
2113 if (text->password == NULL) {
2114 pass_result = _plug_get_password(params->utils, &text->password,
2115 &text->free_password, prompt_need);
2116 if (pass_result != SASL_OK && pass_result != SASL_INTERACT) {
2117 result = pass_result;
2122 if (text->password != NULL) {
2123 gss_buffer_desc password_buf;
2125 password_buf.length = text->password->len;
2126 password_buf.value = text->password->data;
2128 maj_stat = gss_acquire_cred_with_password(&min_stat,
2134 &text->client_creds,
2137 if (GSS_ERROR(maj_stat))
2142 maj_stat = GSS_S_COMPLETE;
2146 /* free prompts we got */
2147 if (prompt_need && *prompt_need) {
2148 params->utils->free(*prompt_need);
2149 *prompt_need = NULL;
2152 /* if there are prompts not filled in */
2153 if (user_result == SASL_INTERACT || auth_result == SASL_INTERACT ||
2154 pass_result == SASL_INTERACT) {
2155 /* make the prompt list */
2157 _plug_make_prompts(params->utils, prompt_need,
2158 user_result == SASL_INTERACT ?
2159 "Please enter your authorization name" : NULL,
2161 auth_result == SASL_INTERACT ?
2162 "Please enter your authentication name" : NULL,
2164 pass_result == SASL_INTERACT ?
2165 "Please enter your password" : NULL, NULL,
2169 if (result == SASL_OK)
2170 result = SASL_INTERACT;
2174 if (result == SASL_OK && maj_stat != GSS_S_COMPLETE) {
2175 sasl_gss_seterror(text->utils, maj_stat, min_stat);
2179 gss_release_buffer(&min_stat, &cred_authid);