2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * Rob Siemborski (SASL v2 Conversion)
9 * $Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $
12 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in
23 * the documentation and/or other materials provided with the
26 * 3. The name "Carnegie Mellon University" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For permission or any other legal
29 * details, please contact
30 * Office of Technology Transfer
31 * Carnegie Mellon University
33 * Pittsburgh, PA 15213-3890
34 * (412) 268-4387, fax: (412) 268-7395
35 * tech-transfer@andrew.cmu.edu
37 * 4. Redistributions of any form whatsoever must retain the following
39 * "This product includes software developed by Computing Services
40 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
42 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
43 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
44 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
45 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
47 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
48 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56 #include <gssapi/gssapi.h>
65 /* we also need io.h for access() prototype */
68 # include <sys/param.h>
69 # include <sys/socket.h>
70 # include <netinet/in.h>
71 # include <arpa/inet.h>
80 #include "plugin_common.h"
89 /* This must be after sasl.h */
90 # include "saslgssapi.h"
93 /***************************** Common Section *****************************/
96 static const char plugin_id
[] = "$Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $";
97 #endif /* !_SUN_SDK_ */
99 static const char * GSSAPI_BLANK_STRING
= "";
101 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
102 extern gss_OID gss_nt_service_name
;
103 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
108 get_oid(const sasl_utils_t
*utils
, gss_OID
*oid
);
109 #ifdef GSSAPI_PROTECT
110 DEFINE_STATIC_MUTEX(global_mutex
);
111 #endif /* GSSAPI_PROTECT */
112 #endif /* _SUN_SDK_ */
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.
119 * Heimdal can be obtained from http://www.pdc.kth.se/heimdal
121 * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
124 typedef struct context
{
127 gss_ctx_id_t gss_ctx
;
128 gss_name_t client_name
;
129 gss_name_t server_name
;
130 gss_cred_id_t server_creds
;
131 sasl_ssf_t limitssf
, requiressf
; /* application defined bounds, for the
134 gss_cred_id_t client_creds
;
137 #endif /* _SUN_SDK_ */
138 const sasl_utils_t
*utils
;
140 /* layers buffering */
146 #endif /* _SUN_SDK_ */
154 #endif /* _SUN_SDK_ */
157 char *encode_buf
; /* For encoding/decoding mem management */
159 char *decode_once_buf
;
160 unsigned encode_buf_len
;
161 unsigned decode_buf_len
;
162 unsigned decode_once_buf_len
;
163 buffer_info_t
*enc_in_buf
;
165 char *out_buf
; /* per-step mem management */
166 unsigned out_buf_len
;
168 char *authid
; /* hold the authid between steps - server */
169 const char *user
; /* hold the userid between steps - client */
171 const char *client_authid
;
172 #endif /* _SUN_SDK_ */
173 #ifdef _INTEGRATED_SOLARIS_
175 #endif /* _INTEGRATED_SOLARIS_ */
179 SASL_GSSAPI_STATE_AUTHNEG
= 1,
180 SASL_GSSAPI_STATE_SSFCAP
= 2,
181 SASL_GSSAPI_STATE_SSFREQ
= 3,
182 SASL_GSSAPI_STATE_AUTHENTICATED
= 4
186 /* sasl_gss_log only logs gss_display_status() error string */
187 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(text,y,z,1)
188 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(text,y,z,0)
190 sasl_gss_seterror_(const context_t
*text
, OM_uint32 maj
, OM_uint32 min
,
194 sasl_gss_seterror(const sasl_utils_t
*utils
, OM_uint32 maj
, OM_uint32 min
)
195 #endif /* _SUN_SDK_ */
197 OM_uint32 maj_stat
, min_stat
;
203 unsigned len
, curlen
= 0;
204 const sasl_utils_t
*utils
= text
->utils
;
205 char *prefix
= dgettext(TEXT_DOMAIN
, "GSSAPI Error: ");
207 size_t len
, curlen
= 0;
208 const char prefix
[] = "GSSAPI Error: ";
209 #endif /* _SUN_SDK_ */
213 len
= sizeof(prefix
);
214 ret
= _plug_buf_alloc(utils
, &out
, &curlen
, 256);
215 if(ret
!= SASL_OK
) return;
221 maj_stat
= gss_display_status(&min_stat
, maj
,
223 GSS_C_GSS_CODE
, text
->mech_oid
,
225 GSS_C_GSS_CODE
, GSS_C_NULL_OID
,
226 #endif /* _SUN_SDK_ */
228 if(GSS_ERROR(maj_stat
)) {
231 utils
->log(text
->utils
->conn
, SASL_LOG_FAIL
,
232 "GSSAPI Failure: (could not get major error message)");
234 #endif /* _SUN_SDK_ */
235 #ifdef _INTEGRATED_SOLARIS_
236 utils
->seterror(utils
->conn
, 0,
237 gettext("GSSAPI Failure "
238 "(could not get major error message)"));
241 #endif /* _SUN_SDK_ */
243 utils
->seterror(utils
->conn
, 0,
245 "(could not get major error message)");
248 #endif /* _SUN_SDK_ */
249 #endif /* _INTEGRATED_SOLARIS_ */
254 len
+= len
+ msg
.length
;
255 ret
= _plug_buf_alloc(utils
, &out
, &curlen
, len
);
262 strcat(out
, msg
.value
);
264 gss_release_buffer(&min_stat
, &msg
);
270 /* Now get the minor status */
273 ret
= _plug_buf_alloc(utils
, &out
, &curlen
, len
);
283 maj_stat
= gss_display_status(&min_stat
, min
,
285 GSS_C_MECH_CODE
, text
->mech_oid
,
287 GSS_C_MECH_CODE
, GSS_C_NULL_OID
,
288 #endif /* _SUN_SDK_ */
290 if(GSS_ERROR(maj_stat
)) {
293 utils
->log(text
->utils
->conn
, SASL_LOG_FAIL
,
294 "GSSAPI Failure: (could not get minor error message)");
296 #endif /* _SUN_SDK_ */
297 #ifdef _INTEGRATED_SOLARIS_
298 utils
->seterror(utils
->conn
, 0,
299 gettext("GSSAPI Failure "
300 "(could not get minor error message)"));
303 #endif /* _SUN_SDK_ */
305 utils
->seterror(utils
->conn
, 0,
307 "(could not get minor error message)");
310 #endif /* _SUN_SDK_ */
311 #endif /* _INTEGRATED_SOLARIS_ */
316 len
+= len
+ msg
.length
;
317 ret
= _plug_buf_alloc(utils
, &out
, &curlen
, len
);
324 strcat(out
, msg
.value
);
326 gss_release_buffer(&min_stat
, &msg
);
333 ret
= _plug_buf_alloc(utils
, &out
, &curlen
, len
);
343 utils
->log(text
->utils
->conn
, SASL_LOG_FAIL
, out
);
345 utils
->seterror(utils
->conn
, 0, out
);
348 utils
->seterror(utils
->conn
, 0, out
);
349 #endif /* _SUN_SDK_ */
354 sasl_gss_encode(void *context
, const struct iovec
*invec
, unsigned numiov
,
355 const char **output
, unsigned *outputlen
, int privacy
)
357 context_t
*text
= (context_t
*)context
;
358 OM_uint32 maj_stat
, min_stat
;
359 gss_buffer_t input_token
, output_token
;
360 gss_buffer_desc real_input_token
, real_output_token
;
362 struct buffer_info
*inblob
, bufinfo
;
364 if(!output
) return SASL_BADPARAM
;
367 ret
= _plug_iovec_to_buf(text
->utils
, invec
, numiov
, &text
->enc_in_buf
);
368 if(ret
!= SASL_OK
) return ret
;
369 inblob
= text
->enc_in_buf
;
371 bufinfo
.data
= invec
[0].iov_base
;
372 bufinfo
.curlen
= invec
[0].iov_len
;
376 if (text
->state
!= SASL_GSSAPI_STATE_AUTHENTICATED
) return SASL_NOTDONE
;
378 input_token
= &real_input_token
;
380 real_input_token
.value
= inblob
->data
;
381 real_input_token
.length
= inblob
->curlen
;
383 output_token
= &real_output_token
;
384 output_token
->value
= NULL
;
385 output_token
->length
= 0;
387 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
388 if (LOCK_MUTEX(&global_mutex
) < 0)
390 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
391 maj_stat
= gss_wrap (&min_stat
,
399 if (GSS_ERROR(maj_stat
))
401 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
402 if (output_token
->value
)
403 gss_release_buffer(&min_stat
, output_token
);
404 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
405 UNLOCK_MUTEX(&global_mutex
);
406 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
410 if (output_token
->value
&& output
) {
413 ret
= _plug_buf_alloc(text
->utils
, &(text
->encode_buf
),
414 &(text
->encode_buf_len
), output_token
->length
+ 4);
416 if (ret
!= SASL_OK
) {
417 gss_release_buffer(&min_stat
, output_token
);
418 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
419 UNLOCK_MUTEX(&global_mutex
);
420 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
424 len
= htonl(output_token
->length
);
425 memcpy(text
->encode_buf
, &len
, 4);
426 memcpy(text
->encode_buf
+ 4, output_token
->value
, output_token
->length
);
430 *outputlen
= output_token
->length
+ 4;
433 *output
= text
->encode_buf
;
435 if (output_token
->value
)
436 gss_release_buffer(&min_stat
, output_token
);
438 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
439 UNLOCK_MUTEX(&global_mutex
);
440 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
445 static int gssapi_privacy_encode(void *context
, const struct iovec
*invec
,
446 unsigned numiov
, const char **output
,
449 return sasl_gss_encode(context
,invec
,numiov
,output
,outputlen
,1);
452 static int gssapi_integrity_encode(void *context
, const struct iovec
*invec
,
453 unsigned numiov
, const char **output
,
456 return sasl_gss_encode(context
,invec
,numiov
,output
,outputlen
,0);
459 #define myMIN(a,b) (((a) < (b)) ? (a) : (b))
461 static int gssapi_decode_once(void *context
,
462 const char **input
, unsigned *inputlen
,
463 char **output
, unsigned *outputlen
)
465 context_t
*text
= (context_t
*) context
;
466 OM_uint32 maj_stat
, min_stat
;
467 gss_buffer_t input_token
, output_token
;
468 gss_buffer_desc real_input_token
, real_output_token
;
472 if (text
->state
!= SASL_GSSAPI_STATE_AUTHENTICATED
) {
473 #ifdef _INTEGRATED_SOLARIS_
474 SETERROR(text
->utils
, gettext("GSSAPI Failure"));
476 SETERROR(text
->utils
, "GSSAPI Failure");
477 #endif /* _INTEGRATED_SOLARIS_ */
481 /* first we need to extract a packet */
482 if (text
->needsize
> 0) {
483 /* how long is it? */
484 int tocopy
= myMIN(text
->needsize
, *inputlen
);
486 memcpy(text
->sizebuf
+ 4 - text
->needsize
, *input
, tocopy
);
487 text
->needsize
-= tocopy
;
491 if (text
->needsize
== 0) {
492 /* got the entire size */
493 memcpy(&text
->size
, text
->sizebuf
, 4);
494 text
->size
= ntohl(text
->size
);
498 if (text
->size
> 0xFFFFFF) {
499 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
500 "Illegal size in sasl_gss_decode_once");
502 if (text
->size
> 0xFFFFFF || text
->size
<= 0) {
503 SETERROR(text
->utils
, "Illegal size in sasl_gss_decode_once");
504 #endif /* _SUN_SDK_ */
508 if (text
->bufsize
< text
->size
+ 5) {
509 result
= _plug_buf_alloc(text
->utils
, &text
->buffer
,
510 &(text
->bufsize
), text
->size
+5);
511 if(result
!= SASL_OK
) return result
;
514 if (*inputlen
== 0) {
515 /* need more data ! */
523 diff
= text
->size
- text
->cursize
;
525 if (*inputlen
< diff
) {
526 /* ok, let's queue it up; not enough data */
527 memcpy(text
->buffer
+ text
->cursize
, *input
, *inputlen
);
528 text
->cursize
+= *inputlen
;
534 memcpy(text
->buffer
+ text
->cursize
, *input
, diff
);
539 input_token
= &real_input_token
;
540 real_input_token
.value
= text
->buffer
;
541 real_input_token
.length
= text
->size
;
543 output_token
= &real_output_token
;
544 output_token
->value
= NULL
;
545 output_token
->length
= 0;
547 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
548 if (LOCK_MUTEX(&global_mutex
) < 0)
550 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
552 maj_stat
= gss_unwrap (&min_stat
,
559 if (GSS_ERROR(maj_stat
))
561 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
562 if (output_token
->value
)
563 gss_release_buffer(&min_stat
, output_token
);
564 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
565 UNLOCK_MUTEX(&global_mutex
);
566 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
571 *outputlen
= output_token
->length
;
573 if (output_token
->value
) {
575 result
= _plug_buf_alloc(text
->utils
, &text
->decode_once_buf
,
576 &text
->decode_once_buf_len
,
578 if(result
!= SASL_OK
) {
579 gss_release_buffer(&min_stat
, output_token
);
580 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
581 UNLOCK_MUTEX(&global_mutex
);
582 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
585 *output
= text
->decode_once_buf
;
586 memcpy(*output
, output_token
->value
, *outputlen
);
588 gss_release_buffer(&min_stat
, output_token
);
590 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
591 UNLOCK_MUTEX(&global_mutex
);
592 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
594 /* reset for the next packet */
597 #endif /* !_SUN_SDK_ */
603 static int gssapi_decode(void *context
,
604 const char *input
, unsigned inputlen
,
605 const char **output
, unsigned *outputlen
)
607 context_t
*text
= (context_t
*) context
;
610 ret
= _plug_decode(text
->utils
, context
, input
, inputlen
,
611 &text
->decode_buf
, &text
->decode_buf_len
, outputlen
,
614 *output
= text
->decode_buf
;
619 static context_t
*gss_new_context(const sasl_utils_t
*utils
)
623 ret
= utils
->malloc(sizeof(context_t
));
624 if(!ret
) return NULL
;
626 memset(ret
,0,sizeof(context_t
));
629 ret
->gss_ctx
= GSS_C_NO_CONTEXT
;
630 ret
->client_name
= GSS_C_NO_NAME
;
631 ret
->server_name
= GSS_C_NO_NAME
;
632 ret
->server_creds
= GSS_C_NO_CREDENTIAL
;
633 ret
->client_creds
= GSS_C_NO_CREDENTIAL
;
634 if (get_oid(utils
, &ret
->mech_oid
) != SASL_OK
) {
638 #endif /* _SUN_SDK_ */
645 static void sasl_gss_free_context_contents(context_t
*text
)
647 OM_uint32 maj_stat
, min_stat
;
651 if (text
->gss_ctx
!= GSS_C_NO_CONTEXT
) {
652 maj_stat
= gss_delete_sec_context (&min_stat
,&text
->gss_ctx
,GSS_C_NO_BUFFER
);
653 text
->gss_ctx
= GSS_C_NO_CONTEXT
;
656 if (text
->client_name
!= GSS_C_NO_NAME
) {
657 maj_stat
= gss_release_name(&min_stat
,&text
->client_name
);
658 text
->client_name
= GSS_C_NO_NAME
;
661 if (text
->server_name
!= GSS_C_NO_NAME
) {
662 maj_stat
= gss_release_name(&min_stat
,&text
->server_name
);
663 text
->server_name
= GSS_C_NO_NAME
;
666 if ( text
->server_creds
!= GSS_C_NO_CREDENTIAL
) {
667 maj_stat
= gss_release_cred(&min_stat
, &text
->server_creds
);
668 text
->server_creds
= GSS_C_NO_CREDENTIAL
;
672 if ( text
->client_creds
!= GSS_C_NO_CREDENTIAL
) {
673 maj_stat
= gss_release_cred(&min_stat
, &text
->client_creds
);
674 text
->client_creds
= GSS_C_NO_CREDENTIAL
;
678 * Note that the oid returned by rpc_gss_mech_to_oid should not
681 #endif /* _SUN_SDK_ */
684 text
->utils
->free(text
->out_buf
);
685 text
->out_buf
= NULL
;
688 if (text
->encode_buf
) {
689 text
->utils
->free(text
->encode_buf
);
690 text
->encode_buf
= NULL
;
693 if (text
->decode_buf
) {
694 text
->utils
->free(text
->decode_buf
);
695 text
->decode_buf
= NULL
;
698 if (text
->decode_once_buf
) {
699 text
->utils
->free(text
->decode_once_buf
);
700 text
->decode_once_buf
= NULL
;
703 if (text
->enc_in_buf
) {
704 if(text
->enc_in_buf
->data
) text
->utils
->free(text
->enc_in_buf
->data
);
705 text
->utils
->free(text
->enc_in_buf
);
706 text
->enc_in_buf
= NULL
;
710 text
->utils
->free(text
->buffer
);
714 if (text
->authid
) { /* works for both client and server */
715 text
->utils
->free(text
->authid
);
722 #ifdef HAVE_RPC_GSS_MECH_TO_OID
723 #include <rpc/rpcsec_gss.h>
724 #endif /* HAVE_RPC_GSS_MECH_TO_OID */
727 get_oid(const sasl_utils_t
*utils
, gss_OID
*oid
)
729 #ifdef HAVE_RPC_GSS_MECH_TO_OID
730 static gss_OID_desc kerb_v5
=
731 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
732 /* 1.2.840.113554.1.2.2 */
734 #endif /* HAVE_RPC_GSS_MECH_TO_OID */
739 add_mech_to_set(context_t
*text
, gss_OID_set
*desired_mechs
)
741 OM_uint32 maj_stat
, min_stat
;
743 maj_stat
= gss_create_empty_oid_set(&min_stat
, desired_mechs
);
745 if (GSS_ERROR(maj_stat
)) {
746 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
747 sasl_gss_free_context_contents(text
);
751 maj_stat
= gss_add_oid_set_member(&min_stat
, text
->mech_oid
, desired_mechs
);
752 if (GSS_ERROR(maj_stat
)) {
753 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
754 sasl_gss_free_context_contents(text
);
755 (void) gss_release_oid_set(&min_stat
, desired_mechs
);
760 #endif /* _SUN_SDK_ */
762 static void gssapi_common_mech_dispose(void *conn_context
,
763 const sasl_utils_t
*utils
)
766 if (conn_context
== NULL
)
768 #ifdef _INTEGRATED_SOLARIS_
769 convert_prompt(utils
, &((context_t
*)conn_context
)->h
, NULL
);
770 #endif /* _INTEGRATED_SOLARIS_ */
771 #endif /* _SUN_SDK_ */
772 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
773 (void) LOCK_MUTEX(&global_mutex
);
774 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
775 sasl_gss_free_context_contents((context_t
*)(conn_context
));
776 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
777 UNLOCK_MUTEX(&global_mutex
);
778 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
779 utils
->free(conn_context
);
782 /***************************** Server Section *****************************/
785 gssapi_server_mech_new(void *glob_context
__attribute__((unused
)),
786 sasl_server_params_t
*params
,
787 const char *challenge
__attribute__((unused
)),
788 unsigned challen
__attribute__((unused
)),
793 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
794 if (LOCK_MUTEX(&global_mutex
) < 0)
796 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
797 text
= gss_new_context(params
->utils
);
798 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
799 UNLOCK_MUTEX(&global_mutex
);
800 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
803 MEMERROR(params
->utils
);
804 #endif /* !_SUN_SDK_ */
808 text
->gss_ctx
= GSS_C_NO_CONTEXT
;
809 text
->client_name
= GSS_C_NO_NAME
;
810 text
->server_name
= GSS_C_NO_NAME
;
811 text
->server_creds
= GSS_C_NO_CREDENTIAL
;
812 text
->state
= SASL_GSSAPI_STATE_AUTHNEG
;
814 *conn_context
= text
;
820 gssapi_server_mech_step(void *conn_context
,
821 sasl_server_params_t
*params
,
822 const char *clientin
,
823 unsigned clientinlen
,
824 const char **serverout
,
825 unsigned *serveroutlen
,
826 sasl_out_params_t
*oparams
)
828 context_t
*text
= (context_t
*)conn_context
;
829 gss_buffer_t input_token
, output_token
;
830 gss_buffer_desc real_input_token
, real_output_token
;
831 OM_uint32 maj_stat
, min_stat
;
833 OM_uint32 max_input_size
;
834 gss_OID_set desired_mechs
= GSS_C_NULL_OID_SET
;
835 #endif /* _SUN_SDK_ */
836 gss_buffer_desc name_token
;
839 input_token
= &real_input_token
;
840 output_token
= &real_output_token
;
841 output_token
->value
= NULL
; output_token
->length
= 0;
842 input_token
->value
= NULL
; input_token
->length
= 0;
845 PARAMERROR(text
->utils
);
846 return SASL_BADPARAM
;
852 switch (text
->state
) {
854 case SASL_GSSAPI_STATE_AUTHNEG
:
855 if (text
->server_name
== GSS_C_NO_NAME
) { /* only once */
856 name_token
.length
= strlen(params
->service
) + 1 + strlen(params
->serverFQDN
);
857 name_token
.value
= (char *)params
->utils
->malloc((name_token
.length
+ 1) * sizeof(char));
858 if (name_token
.value
== NULL
) {
859 MEMERROR(text
->utils
);
860 sasl_gss_free_context_contents(text
);
864 snprintf(name_token
.value
, name_token
.length
+ 1,
865 "%s@%s", params
->service
, params
->serverFQDN
);
867 sprintf(name_token
.value
,"%s@%s", params
->service
, params
->serverFQDN
);
868 #endif /* _SUN_SDK_ */
870 maj_stat
= gss_import_name (&min_stat
,
872 GSS_C_NT_HOSTBASED_SERVICE
,
875 params
->utils
->free(name_token
.value
);
876 name_token
.value
= NULL
;
878 if (GSS_ERROR(maj_stat
)) {
879 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
880 sasl_gss_free_context_contents(text
);
884 if ( text
->server_creds
!= GSS_C_NO_CREDENTIAL
) {
885 maj_stat
= gss_release_cred(&min_stat
, &text
->server_creds
);
886 text
->server_creds
= GSS_C_NO_CREDENTIAL
;
890 if (text
->mech_oid
!= GSS_C_NULL_OID
) {
891 ret
= add_mech_to_set(text
, &desired_mechs
);
895 #endif /* _SUN_SDK_ */
897 maj_stat
= gss_acquire_cred(&min_stat
,
904 #endif /* _SUN_SDK_ */
911 if (desired_mechs
!= GSS_C_NULL_OID_SET
) {
913 (void) gss_release_oid_set(&min_stat2
, &desired_mechs
);
915 #endif /* _SUN_SDK_ */
917 if (GSS_ERROR(maj_stat
)) {
918 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
919 sasl_gss_free_context_contents(text
);
925 real_input_token
.value
= (void *)clientin
;
926 real_input_token
.length
= clientinlen
;
930 gss_accept_sec_context(&min_stat
,
934 GSS_C_NO_CHANNEL_BINDINGS
,
942 if (GSS_ERROR(maj_stat
)) {
944 /* log the local error info, set a more generic error */
945 sasl_gss_log(text
->utils
, maj_stat
, min_stat
);
946 text
->utils
->seterror(text
->utils
->conn
, SASL_NOLOG
,
947 gettext("GSSAPI Failure: accept security context error"));
948 if (output_token
->value
) {
949 gss_release_buffer(&min_stat
, output_token
);
952 if (output_token
->value
) {
953 gss_release_buffer(&min_stat
, output_token
);
955 text
->utils
->seterror(text
->utils
->conn
, SASL_NOLOG
, "GSSAPI Failure: gss_accept_sec_context");
956 text
->utils
->log(NULL
, SASL_LOG_DEBUG
, "GSSAPI Failure: gss_accept_sec_context");
957 #endif /* _SUN_SDK_ */
958 sasl_gss_free_context_contents(text
);
963 *serveroutlen
= output_token
->length
;
964 if (output_token
->value
) {
966 ret
= _plug_buf_alloc(text
->utils
, &(text
->out_buf
),
967 &(text
->out_buf_len
), *serveroutlen
);
969 gss_release_buffer(&min_stat
, output_token
);
972 memcpy(text
->out_buf
, output_token
->value
, *serveroutlen
);
973 *serverout
= text
->out_buf
;
976 gss_release_buffer(&min_stat
, output_token
);
978 /* No output token, send an empty string */
979 *serverout
= GSSAPI_BLANK_STRING
;
982 #endif /* !_SUN_SDK_ */
986 if (maj_stat
== GSS_S_COMPLETE
) {
987 /* Switch to ssf negotiation */
988 text
->state
= SASL_GSSAPI_STATE_SSFCAP
;
991 return SASL_CONTINUE
;
993 case SASL_GSSAPI_STATE_SSFCAP
: {
994 unsigned char sasldata
[4];
995 gss_buffer_desc name_token
;
997 gss_buffer_desc name_without_realm
;
998 gss_name_t without
= NULL
;
1000 #endif /* !_SUN_SDK_ */
1002 name_token
.value
= NULL
;
1004 name_without_realm
.value
= NULL
;
1005 #endif /* !_SUN_SDK_ */
1007 /* We ignore whatever the client sent us at this stage */
1009 maj_stat
= gss_display_name (&min_stat
,
1014 if (GSS_ERROR(maj_stat
)) {
1016 if (name_without_realm
.value
)
1017 params
->utils
->free(name_without_realm
.value
);
1018 #endif /* !_SUN_SDK_ */
1020 if (name_token
.value
)
1021 gss_release_buffer(&min_stat
, &name_token
);
1024 gss_release_name(&min_stat
, &without
);
1025 #endif /* !_SUN_SDK_ */
1026 #ifdef _INTEGRATED_SOLARIS_
1027 SETERROR(text
->utils
, gettext("GSSAPI Failure"));
1029 SETERROR(text
->utils
, "GSSAPI Failure");
1030 #endif /* _INTEGRATED_SOLARIS_ */
1031 sasl_gss_free_context_contents(text
);
1032 return SASL_BADAUTH
;
1036 /* If the id contains a realm get the identifier for the user
1037 without the realm and see if it's the same id (i.e.
1038 tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
1039 to return the id (i.e. just "tmartin" */
1040 if (strchr((char *) name_token
.value
, (int) '@') != NULL
) {
1041 /* NOTE: libc malloc, as it is freed below by a gssapi internal
1043 name_without_realm
.value
= malloc(strlen(name_token
.value
)+1);
1044 if (name_without_realm
.value
== NULL
) {
1045 MEMERROR(text
->utils
);
1049 strcpy(name_without_realm
.value
, name_token
.value
);
1051 /* cut off string at '@' */
1052 (strchr(name_without_realm
.value
,'@'))[0] = '\0';
1054 name_without_realm
.length
= strlen( (char *) name_without_realm
.value
);
1056 maj_stat
= gss_import_name (&min_stat
,
1057 &name_without_realm
,
1058 /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
1059 so use GSS_C_NT_USER_NAME instead if available. */
1060 #ifdef HAVE_GSS_C_NT_USER_NAME
1067 if (GSS_ERROR(maj_stat
)) {
1068 params
->utils
->free(name_without_realm
.value
);
1069 if (name_token
.value
)
1070 gss_release_buffer(&min_stat
, &name_token
);
1072 gss_release_name(&min_stat
, &without
);
1073 SETERROR(text
->utils
, "GSSAPI Failure");
1074 sasl_gss_free_context_contents(text
);
1075 return SASL_BADAUTH
;
1078 maj_stat
= gss_compare_name(&min_stat
,
1083 if (GSS_ERROR(maj_stat
)) {
1084 params
->utils
->free(name_without_realm
.value
);
1085 if (name_token
.value
)
1086 gss_release_buffer(&min_stat
, &name_token
);
1088 gss_release_name(&min_stat
, &without
);
1089 SETERROR(text
->utils
, "GSSAPI Failure");
1090 sasl_gss_free_context_contents(text
);
1091 return SASL_BADAUTH
;
1094 gss_release_name(&min_stat
,&without
);
1100 text
->authid
= strdup(name_without_realm
.value
);
1102 if (text
->authid
== NULL
) {
1103 MEMERROR(params
->utils
);
1107 text
->authid
= strdup(name_token
.value
);
1109 if (text
->authid
== NULL
) {
1110 MEMERROR(params
->utils
);
1116 ret
= _plug_strdup(params
->utils
, name_token
.value
,
1117 &text
->authid
, NULL
);
1119 #endif /* _SUN_SDK_ */
1121 if (name_token
.value
)
1122 gss_release_buffer(&min_stat
, &name_token
);
1128 if (name_without_realm
.value
)
1129 params
->utils
->free(name_without_realm
.value
);
1130 #endif /* _SUN_SDK_ */
1133 /* we have to decide what sort of encryption/integrity/etc.,
1135 if (params
->props
.max_ssf
< params
->external_ssf
) {
1138 text
->limitssf
= params
->props
.max_ssf
- params
->external_ssf
;
1140 if (params
->props
.min_ssf
< params
->external_ssf
) {
1141 text
->requiressf
= 0;
1143 text
->requiressf
= params
->props
.min_ssf
- params
->external_ssf
;
1146 /* build up our security properties token */
1147 if (params
->props
.maxbufsize
> 0xFFFFFF) {
1148 /* make sure maxbufsize isn't too large */
1149 /* maxbufsize = 0xFFFFFF */
1150 sasldata
[1] = sasldata
[2] = sasldata
[3] = 0xFF;
1152 sasldata
[1] = (params
->props
.maxbufsize
>> 16) & 0xFF;
1153 sasldata
[2] = (params
->props
.maxbufsize
>> 8) & 0xFF;
1154 sasldata
[3] = (params
->props
.maxbufsize
>> 0) & 0xFF;
1157 if(text
->requiressf
!= 0 && !params
->props
.maxbufsize
) {
1159 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
1160 "GSSAPI needs a security layer but one is forbidden");
1162 params
->utils
->seterror(params
->utils
->conn
, 0,
1163 "GSSAPI needs a security layer but one is forbidden");
1164 #endif /* _SUN_SDK_ */
1165 return SASL_TOOWEAK
;
1168 if (text
->requiressf
== 0) {
1169 sasldata
[0] |= 1; /* authentication */
1171 if (text
->requiressf
<= 1 && text
->limitssf
>= 1
1172 && params
->props
.maxbufsize
) {
1175 if (text
->requiressf
<= 56 && text
->limitssf
>= 56
1176 && params
->props
.maxbufsize
) {
1180 real_input_token
.value
= (void *)sasldata
;
1181 real_input_token
.length
= 4;
1183 maj_stat
= gss_wrap(&min_stat
,
1185 0, /* Just integrity checking here */
1191 if (GSS_ERROR(maj_stat
)) {
1192 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1193 if (output_token
->value
)
1194 gss_release_buffer(&min_stat
, output_token
);
1195 sasl_gss_free_context_contents(text
);
1201 *serveroutlen
= output_token
->length
;
1202 if (output_token
->value
) {
1204 ret
= _plug_buf_alloc(text
->utils
, &(text
->out_buf
),
1205 &(text
->out_buf_len
), *serveroutlen
);
1206 if(ret
!= SASL_OK
) {
1207 gss_release_buffer(&min_stat
, output_token
);
1210 memcpy(text
->out_buf
, output_token
->value
, *serveroutlen
);
1211 *serverout
= text
->out_buf
;
1214 gss_release_buffer(&min_stat
, output_token
);
1217 /* Wait for ssf request and authid */
1218 text
->state
= SASL_GSSAPI_STATE_SSFREQ
;
1220 return SASL_CONTINUE
;
1223 case SASL_GSSAPI_STATE_SSFREQ
: {
1226 real_input_token
.value
= (void *)clientin
;
1227 real_input_token
.length
= clientinlen
;
1229 maj_stat
= gss_unwrap(&min_stat
,
1236 if (GSS_ERROR(maj_stat
)) {
1237 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1238 sasl_gss_free_context_contents(text
);
1242 layerchoice
= (int)(((char *)(output_token
->value
))[0]);
1243 if (layerchoice
== 1 && text
->requiressf
== 0) { /* no encryption */
1244 oparams
->encode
= NULL
;
1245 oparams
->decode
= NULL
;
1246 oparams
->mech_ssf
= 0;
1247 } else if (layerchoice
== 2 && text
->requiressf
<= 1 &&
1248 text
->limitssf
>= 1) { /* integrity */
1249 oparams
->encode
=&gssapi_integrity_encode
;
1250 oparams
->decode
=&gssapi_decode
;
1251 oparams
->mech_ssf
=1;
1252 } else if (layerchoice
== 4 && text
->requiressf
<= 56 &&
1253 text
->limitssf
>= 56) { /* privacy */
1254 oparams
->encode
= &gssapi_privacy_encode
;
1255 oparams
->decode
= &gssapi_decode
;
1256 oparams
->mech_ssf
= 56;
1258 /* not a supported encryption layer */
1260 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
1261 "protocol violation: client requested invalid layer");
1263 SETERROR(text
->utils
,
1264 "protocol violation: client requested invalid layer");
1265 #endif /* _SUN_SDK_ */
1266 /* Mark that we attempted negotiation */
1267 oparams
->mech_ssf
= 2;
1268 if (output_token
->value
)
1269 gss_release_buffer(&min_stat
, output_token
);
1270 sasl_gss_free_context_contents(text
);
1274 if (output_token
->length
> 4) {
1277 ret
= params
->canon_user(params
->utils
->conn
,
1278 ((char *) output_token
->value
) + 4,
1279 (output_token
->length
- 4) * sizeof(char),
1280 SASL_CU_AUTHZID
, oparams
);
1282 if (ret
!= SASL_OK
) {
1283 sasl_gss_free_context_contents(text
);
1287 ret
= params
->canon_user(params
->utils
->conn
,
1289 0, /* strlen(text->authid) */
1290 SASL_CU_AUTHID
, oparams
);
1291 if (ret
!= SASL_OK
) {
1292 sasl_gss_free_context_contents(text
);
1295 } else if(output_token
->length
== 4) {
1299 ret
= params
->canon_user(params
->utils
->conn
,
1301 0, /* strlen(text->authid) */
1302 SASL_CU_AUTHZID
| SASL_CU_AUTHID
,
1305 if (ret
!= SASL_OK
) {
1306 sasl_gss_free_context_contents(text
);
1311 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
1314 SETERROR(text
->utils
,
1316 #endif /* _SUN_SDK_ */
1317 gss_release_buffer(&min_stat
, output_token
);
1318 sasl_gss_free_context_contents(text
);
1322 /* No matter what, set the rest of the oparams */
1323 oparams
->maxoutbuf
=
1324 (((unsigned char *) output_token
->value
)[1] << 16) |
1325 (((unsigned char *) output_token
->value
)[2] << 8) |
1326 (((unsigned char *) output_token
->value
)[3] << 0);
1329 if (oparams
->mech_ssf
) {
1330 oparams
->maxoutbuf
-= 4; /* Allow for 4 byte tag */
1331 maj_stat
= gss_wrap_size_limit(&min_stat
,
1333 oparams
->mech_ssf
> 1,
1337 if (GSS_ERROR(maj_stat
)) {
1338 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1339 (void) gss_release_buffer(&min_stat
, output_token
);
1340 sasl_gss_free_context_contents(text
);
1345 * gss_wrap_size_limit will return very big sizes for
1346 * small input values
1348 if (max_input_size
< oparams
->maxoutbuf
)
1349 oparams
->maxoutbuf
= max_input_size
;
1351 oparams
->maxoutbuf
= 0;
1355 if (oparams
->mech_ssf
) {
1356 /* xxx this is probably too big */
1357 oparams
->maxoutbuf
-= 50;
1359 #endif /* _SUN_SDK_ */
1361 gss_release_buffer(&min_stat
, output_token
);
1363 text
->state
= SASL_GSSAPI_STATE_AUTHENTICATED
;
1365 oparams
->doneflag
= 1;
1372 params
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
1373 "Invalid GSSAPI server step %d", text
->state
);
1375 params
->utils
->log(NULL
, SASL_LOG_ERR
,
1376 "Invalid GSSAPI server step %d\n", text
->state
);
1377 #endif /* _SUN_SDK_ */
1382 return SASL_FAIL
; /* should never get here */
1383 #endif /* !_SUN_SDK_ */
1386 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1388 _gssapi_server_mech_step(void *conn_context
,
1389 sasl_server_params_t
*params
,
1390 const char *clientin
,
1391 unsigned clientinlen
,
1392 const char **serverout
,
1393 unsigned *serveroutlen
,
1394 sasl_out_params_t
*oparams
)
1398 if (LOCK_MUTEX(&global_mutex
) < 0)
1401 ret
= gssapi_server_mech_step(conn_context
, params
, clientin
, clientinlen
,
1402 serverout
, serveroutlen
, oparams
);
1404 UNLOCK_MUTEX(&global_mutex
);
1407 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1409 static sasl_server_plug_t gssapi_server_plugins
[] =
1412 "GSSAPI", /* mech_name */
1414 SASL_SEC_NOPLAINTEXT
1416 | SASL_SEC_NOANONYMOUS
1417 | SASL_SEC_MUTUAL_AUTH
, /* security_flags */
1418 SASL_FEAT_WANT_CLIENT_FIRST
1419 | SASL_FEAT_ALLOWS_PROXY
, /* features */
1420 NULL
, /* glob_context */
1421 &gssapi_server_mech_new
, /* mech_new */
1422 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1423 &_gssapi_server_mech_step
, /* mech_step */
1425 &gssapi_server_mech_step
, /* mech_step */
1426 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1427 &gssapi_common_mech_dispose
, /* mech_dispose */
1428 NULL
, /* mech_free */
1430 NULL
, /* user_query */
1432 NULL
, /* mech_avail */
1437 int gssapiv2_server_plug_init(
1438 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1439 const sasl_utils_t
*utils
__attribute__((unused
)),
1441 const sasl_utils_t
*utils
,
1445 sasl_server_plug_t
**pluglist
,
1448 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1449 const char *keytab
= NULL
;
1450 char keytab_path
[1024];
1454 if (maxversion
< SASL_SERVER_PLUG_VERSION
) {
1455 return SASL_BADVERS
;
1459 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1460 /* unfortunately, we don't check for readability of keytab if it's
1461 the standard one, since we don't know where it is */
1463 /* FIXME: This code is broken */
1465 utils
->getopt(utils
->getopt_context
, "GSSAPI", "keytab", &keytab
, &rl
);
1466 if (keytab
!= NULL
) {
1467 if (access(keytab
, R_OK
) != 0) {
1468 utils
->log(NULL
, SASL_LOG_ERR
,
1469 "Could not find keytab file: %s: %m",
1474 if(strlen(keytab
) > 1024) {
1475 utils
->log(NULL
, SASL_LOG_ERR
,
1476 "path to keytab is > 1024 characters");
1477 return SASL_BUFOVER
;
1480 strncpy(keytab_path
, keytab
, 1024);
1482 gsskrb5_register_acceptor_identity(keytab_path
);
1485 #endif /* !_SUN_SDK_ */
1487 #ifdef _INTEGRATED_SOLARIS_
1489 * Let libsasl know that we are a "Sun" plugin so that privacy
1490 * and integrity will be allowed.
1492 REG_PLUG("GSSAPI", gssapi_server_plugins
);
1493 #endif /* _INTEGRATED_SOLARIS_ */
1495 *out_version
= SASL_SERVER_PLUG_VERSION
;
1496 *pluglist
= gssapi_server_plugins
;
1502 /***************************** Client Section *****************************/
1504 static int gssapi_client_mech_new(void *glob_context
__attribute__((unused
)),
1505 sasl_client_params_t
*params
,
1506 void **conn_context
)
1510 const char *use_authid
= NULL
;
1511 #endif /* _SUN_SDK_ */
1513 /* holds state are in */
1514 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1515 if (LOCK_MUTEX(&global_mutex
) < 0)
1517 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1518 text
= gss_new_context(params
->utils
);
1519 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1520 UNLOCK_MUTEX(&global_mutex
);
1521 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1524 MEMERROR(params
->utils
);
1525 #endif /* !_SUN_SDK_ */
1529 text
->state
= SASL_GSSAPI_STATE_AUTHNEG
;
1530 text
->gss_ctx
= GSS_C_NO_CONTEXT
;
1531 text
->client_name
= GSS_C_NO_NAME
;
1532 text
->server_creds
= GSS_C_NO_CREDENTIAL
;
1535 params
->utils
->getopt(params
->utils
->getopt_context
,
1536 "GSSAPI", "use_authid", &use_authid
, NULL
);
1537 text
->use_authid
= (use_authid
!= NULL
) &&
1538 (*use_authid
== 'y' || *use_authid
== 'Y' || *use_authid
== '1');
1539 #endif /* _SUN_SDK_ */
1541 *conn_context
= text
;
1546 static int gssapi_client_mech_step(void *conn_context
,
1547 sasl_client_params_t
*params
,
1548 const char *serverin
,
1549 unsigned serverinlen
,
1550 sasl_interact_t
**prompt_need
,
1551 const char **clientout
,
1552 unsigned *clientoutlen
,
1553 sasl_out_params_t
*oparams
)
1555 context_t
*text
= (context_t
*)conn_context
;
1556 gss_buffer_t input_token
, output_token
;
1557 gss_buffer_desc real_input_token
, real_output_token
;
1558 OM_uint32 maj_stat
, min_stat
;
1560 OM_uint32 max_input_size
;
1561 #endif /* _SUN_SDK_ */
1562 gss_buffer_desc name_token
;
1564 OM_uint32 req_flags
, out_req_flags
;
1565 input_token
= &real_input_token
;
1566 output_token
= &real_output_token
;
1567 output_token
->value
= NULL
;
1568 input_token
->value
= NULL
;
1569 input_token
->length
= 0;
1574 switch (text
->state
) {
1576 case SASL_GSSAPI_STATE_AUTHNEG
:
1577 /* try to get the userid */
1579 if (text
->user
== NULL
||
1580 (text
->use_authid
&& text
->client_authid
== NULL
)) {
1581 int auth_result
= SASL_OK
;
1582 int user_result
= SASL_OK
;
1584 if (text
->use_authid
&& text
->client_authid
== NULL
) {
1585 auth_result
= _plug_get_authid(params
->utils
,
1586 &text
->client_authid
,
1589 if ((auth_result
!= SASL_OK
) &&
1590 (auth_result
!= SASL_INTERACT
)) {
1591 sasl_gss_free_context_contents(text
);
1595 if (text
->user
== NULL
) {
1596 user_result
= _plug_get_userid(params
->utils
, &text
->user
,
1599 if ((user_result
!= SASL_OK
) &&
1600 (user_result
!= SASL_INTERACT
)) {
1601 sasl_gss_free_context_contents(text
);
1606 if (text
->user
== NULL
) {
1607 int user_result
= SASL_OK
;
1609 user_result
= _plug_get_userid(params
->utils
, &text
->user
,
1612 if ((user_result
!= SASL_OK
) && (user_result
!= SASL_INTERACT
)) {
1613 sasl_gss_free_context_contents(text
);
1616 #endif /* _SUN_SDK_ */
1618 /* free prompts we got */
1619 if (prompt_need
&& *prompt_need
) {
1620 params
->utils
->free(*prompt_need
);
1621 *prompt_need
= NULL
;
1624 /* if there are prompts not filled in */
1626 if ((user_result
== SASL_INTERACT
) ||
1627 (auth_result
== SASL_INTERACT
)) {
1628 /* make the prompt list */
1629 #ifdef _INTEGRATED_SOLARIS_
1630 int result
= _plug_make_prompts(params
->utils
, &text
->h
,
1632 user_result
== SASL_INTERACT
?
1633 convert_prompt(params
->utils
, &text
->h
,
1634 gettext("Please enter your authorization name"))
1636 auth_result
== SASL_INTERACT
?
1637 convert_prompt(params
->utils
, &text
->h
,
1638 gettext("Please enter your authentication name"))
1644 int result
= _plug_make_prompts(params
->utils
, prompt_need
,
1645 user_result
== SASL_INTERACT
?
1646 "Please enter your authorization name"
1648 auth_result
== SASL_INTERACT
?
1649 "Please enter your authentication name"
1654 #endif /* _INTEGRATED_SOLARIS_ */
1656 if (result
!= SASL_OK
) return result
;
1658 return SASL_INTERACT
;
1661 if (user_result
== SASL_INTERACT
) {
1662 /* make the prompt list */
1664 _plug_make_prompts(params
->utils
, prompt_need
,
1665 user_result
== SASL_INTERACT
?
1666 "Please enter your authorization name" : NULL
, NULL
,
1671 if (result
!= SASL_OK
) return result
;
1673 return SASL_INTERACT
;
1675 #endif /* _SUN_SDK_ */
1678 if (text
->server_name
== GSS_C_NO_NAME
) { /* only once */
1679 name_token
.length
= strlen(params
->service
) + 1 + strlen(params
->serverFQDN
);
1680 name_token
.value
= (char *)params
->utils
->malloc((name_token
.length
+ 1) * sizeof(char));
1681 if (name_token
.value
== NULL
) {
1682 sasl_gss_free_context_contents(text
);
1685 if (params
->serverFQDN
== NULL
1686 || strlen(params
->serverFQDN
) == 0) {
1688 text
->utils
->log(text
->utils
->conn
, SASL_LOG_ERR
,
1689 "GSSAPI Failure: no serverFQDN");
1691 SETERROR(text
->utils
, "GSSAPI Failure: no serverFQDN");
1692 #endif /* _SUN_SDK_ */
1697 snprintf(name_token
.value
, name_token
.length
+ 1,
1698 "%s@%s", params
->service
, params
->serverFQDN
);
1700 sprintf(name_token
.value
,"%s@%s", params
->service
, params
->serverFQDN
);
1701 #endif /* _SUN_SDK_ */
1703 maj_stat
= gss_import_name (&min_stat
,
1705 GSS_C_NT_HOSTBASED_SERVICE
,
1706 &text
->server_name
);
1708 params
->utils
->free(name_token
.value
);
1709 name_token
.value
= NULL
;
1711 if (GSS_ERROR(maj_stat
)) {
1712 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1713 sasl_gss_free_context_contents(text
);
1718 if (serverinlen
== 0)
1719 input_token
= GSS_C_NO_BUFFER
;
1722 real_input_token
.value
= (void *)serverin
;
1723 real_input_token
.length
= serverinlen
;
1725 else if (text
->gss_ctx
!= GSS_C_NO_CONTEXT
) {
1726 /* This can't happen under GSSAPI: we have a non-null context
1727 * and no input from the server. However, thanks to Imap,
1728 * which discards our first output, this happens all the time.
1729 * Throw away the context and try again. */
1730 maj_stat
= gss_delete_sec_context (&min_stat
,&text
->gss_ctx
,GSS_C_NO_BUFFER
);
1731 text
->gss_ctx
= GSS_C_NO_CONTEXT
;
1734 /* Setup req_flags properly */
1735 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_SEQUENCE_FLAG
;
1736 if(params
->props
.max_ssf
> params
->external_ssf
) {
1737 /* We are requesting a security layer */
1738 req_flags
|= GSS_C_INTEG_FLAG
;
1739 if(params
->props
.max_ssf
- params
->external_ssf
> 56) {
1740 /* We want to try for privacy */
1741 req_flags
|= GSS_C_CONF_FLAG
;
1746 if (text
->use_authid
&& text
->client_creds
== GSS_C_NO_CREDENTIAL
) {
1747 gss_OID_set desired_mechs
= GSS_C_NULL_OID_SET
;
1748 gss_buffer_desc name_token
;
1750 name_token
.length
= strlen(text
->client_authid
);
1751 name_token
.value
= (char *)text
->client_authid
;
1753 maj_stat
= gss_import_name (&min_stat
,
1755 #ifdef HAVE_GSS_C_NT_USER_NAME
1760 &text
->client_name
);
1761 if (GSS_ERROR(maj_stat
)) {
1762 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1763 sasl_gss_free_context_contents(text
);
1767 if (text
->mech_oid
!= GSS_C_NULL_OID
) {
1768 ret
= add_mech_to_set(text
, &desired_mechs
);
1773 maj_stat
= gss_acquire_cred(&min_stat
,
1778 &text
->client_creds
,
1782 if (desired_mechs
!= GSS_C_NULL_OID_SET
) {
1783 OM_uint32 min_stat2
;
1784 (void) gss_release_oid_set(&min_stat2
, &desired_mechs
);
1787 if (GSS_ERROR(maj_stat
)) {
1788 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1789 sasl_gss_free_context_contents(text
);
1793 #endif /* _SUN_SDK_ */
1795 maj_stat
= gss_init_sec_context(&min_stat
,
1799 GSS_C_NO_CREDENTIAL
,
1800 #endif /* _SUN_SDK_ */
1807 #endif /* _SUN_SDK_ */
1810 GSS_C_NO_CHANNEL_BINDINGS
,
1817 if (GSS_ERROR(maj_stat
)) {
1818 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1819 if (output_token
->value
)
1820 gss_release_buffer(&min_stat
, output_token
);
1821 sasl_gss_free_context_contents(text
);
1825 *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_release_buffer(&min_stat
, output_token
);
1835 memcpy(text
->out_buf
, output_token
->value
, *clientoutlen
);
1836 *clientout
= text
->out_buf
;
1839 gss_release_buffer(&min_stat
, output_token
);
1842 if (maj_stat
== GSS_S_COMPLETE
) {
1843 maj_stat
= gss_inquire_context(&min_stat
,
1846 NULL
, /* targ_name */
1847 NULL
, /* lifetime */
1850 NULL
, /* local init */
1853 if (GSS_ERROR(maj_stat
)) {
1854 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1855 sasl_gss_free_context_contents(text
);
1859 name_token
.length
= 0;
1860 maj_stat
= gss_display_name(&min_stat
,
1865 if (GSS_ERROR(maj_stat
)) {
1866 if (name_token
.value
)
1867 gss_release_buffer(&min_stat
, &name_token
);
1868 #ifdef _INTEGRATED_SOLARIS_
1869 SETERROR(text
->utils
, gettext("GSSAPI Failure"));
1871 SETERROR(text
->utils
, "GSSAPI Failure");
1872 #endif /* _INTEGRATED_SOLARIS_ */
1873 sasl_gss_free_context_contents(text
);
1877 if (text
->user
&& text
->user
[0]) {
1878 ret
= params
->canon_user(params
->utils
->conn
,
1880 SASL_CU_AUTHZID
, oparams
);
1882 ret
= params
->canon_user(params
->utils
->conn
,
1883 name_token
.value
, 0,
1884 SASL_CU_AUTHID
, oparams
);
1886 ret
= params
->canon_user(params
->utils
->conn
,
1887 name_token
.value
, 0,
1888 SASL_CU_AUTHID
| SASL_CU_AUTHZID
,
1891 gss_release_buffer(&min_stat
, &name_token
);
1893 if (ret
!= SASL_OK
) return ret
;
1895 /* Switch to ssf negotiation */
1896 text
->state
= SASL_GSSAPI_STATE_SSFCAP
;
1899 return SASL_CONTINUE
;
1901 case SASL_GSSAPI_STATE_SSFCAP
: {
1902 sasl_security_properties_t
*secprops
= &(params
->props
);
1903 unsigned int alen
, external
= params
->external_ssf
;
1904 sasl_ssf_t need
, allowed
;
1905 char serverhas
, mychoice
;
1907 real_input_token
.value
= (void *) serverin
;
1908 real_input_token
.length
= serverinlen
;
1910 maj_stat
= gss_unwrap(&min_stat
,
1917 if (GSS_ERROR(maj_stat
)) {
1918 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1919 sasl_gss_free_context_contents(text
);
1920 if (output_token
->value
)
1921 gss_release_buffer(&min_stat
, output_token
);
1925 /* taken from kerberos.c */
1926 if (secprops
->min_ssf
> (56 + external
)) {
1927 return SASL_TOOWEAK
;
1928 } else if (secprops
->min_ssf
> secprops
->max_ssf
) {
1929 return SASL_BADPARAM
;
1932 /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1933 if (secprops
->max_ssf
>= external
) {
1934 allowed
= secprops
->max_ssf
- external
;
1938 if (secprops
->min_ssf
>= external
) {
1939 need
= secprops
->min_ssf
- external
;
1945 /* bit mask of server support */
1946 serverhas
= ((char *)output_token
->value
)[0];
1948 /* if client didn't set use strongest layer available */
1949 if (allowed
>= 56 && need
<= 56 && (serverhas
& 4)) {
1951 oparams
->encode
= &gssapi_privacy_encode
;
1952 oparams
->decode
= &gssapi_decode
;
1953 oparams
->mech_ssf
= 56;
1955 } else if (allowed
>= 1 && need
<= 1 && (serverhas
& 2)) {
1957 oparams
->encode
= &gssapi_integrity_encode
;
1958 oparams
->decode
= &gssapi_decode
;
1959 oparams
->mech_ssf
= 1;
1962 } else if (need
== 0 && (serverhas
& 1)) {
1964 } else if (need
<= 0 && (serverhas
& 1)) {
1965 #endif /* _SUN_SDK_ */
1967 oparams
->encode
= NULL
;
1968 oparams
->decode
= NULL
;
1969 oparams
->mech_ssf
= 0;
1972 /* there's no appropriate layering for us! */
1973 sasl_gss_free_context_contents(text
);
1974 return SASL_TOOWEAK
;
1977 oparams
->maxoutbuf
=
1978 (((unsigned char *) output_token
->value
)[1] << 16) |
1979 (((unsigned char *) output_token
->value
)[2] << 8) |
1980 (((unsigned char *) output_token
->value
)[3] << 0);
1983 if (oparams
->mech_ssf
> 0) {
1984 oparams
->maxoutbuf
-= 4; /* Space for 4 byte length header */
1985 maj_stat
= gss_wrap_size_limit(&min_stat
,
1987 oparams
->mech_ssf
> 1,
1991 if (GSS_ERROR(maj_stat
)) {
1992 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
1993 (void) gss_release_buffer(&min_stat
, output_token
);
1994 sasl_gss_free_context_contents(text
);
1999 * This is a workaround for a Solaris bug where
2000 * gss_wrap_size_limit may return very big sizes for
2001 * small input values
2003 if (max_input_size
< oparams
->maxoutbuf
)
2004 oparams
->maxoutbuf
= max_input_size
;
2006 oparams
->maxoutbuf
= 0;
2010 if(oparams
->mech_ssf
) {
2011 /* xxx probably too large */
2012 oparams
->maxoutbuf
-= 50;
2014 #endif /* _SUN_SDK_ */
2016 gss_release_buffer(&min_stat
, output_token
);
2018 /* oparams->user is always set, due to canon_user requirements.
2019 * Make sure the client actually requested it though, by checking
2020 * if our context was set.
2022 if (text
->user
&& text
->user
[0])
2023 alen
= strlen(oparams
->user
);
2027 input_token
->length
= 4 + alen
;
2028 input_token
->value
=
2029 (char *)params
->utils
->malloc((input_token
->length
+ 1)*sizeof(char));
2030 if (input_token
->value
== NULL
) {
2031 sasl_gss_free_context_contents(text
);
2036 memcpy((char *)input_token
->value
+4,oparams
->user
,alen
);
2038 /* build up our security properties token */
2039 if (params
->props
.maxbufsize
> 0xFFFFFF) {
2040 /* make sure maxbufsize isn't too large */
2041 /* maxbufsize = 0xFFFFFF */
2042 ((unsigned char *)input_token
->value
)[1] = 0xFF;
2043 ((unsigned char *)input_token
->value
)[2] = 0xFF;
2044 ((unsigned char *)input_token
->value
)[3] = 0xFF;
2046 ((unsigned char *)input_token
->value
)[1] =
2047 (params
->props
.maxbufsize
>> 16) & 0xFF;
2048 ((unsigned char *)input_token
->value
)[2] =
2049 (params
->props
.maxbufsize
>> 8) & 0xFF;
2050 ((unsigned char *)input_token
->value
)[3] =
2051 (params
->props
.maxbufsize
>> 0) & 0xFF;
2053 ((unsigned char *)input_token
->value
)[0] = mychoice
;
2055 maj_stat
= gss_wrap (&min_stat
,
2057 0, /* Just integrity checking here */
2063 params
->utils
->free(input_token
->value
);
2064 input_token
->value
= NULL
;
2066 if (GSS_ERROR(maj_stat
)) {
2067 sasl_gss_seterror(text
->utils
, maj_stat
, min_stat
);
2068 if (output_token
->value
)
2069 gss_release_buffer(&min_stat
, output_token
);
2070 sasl_gss_free_context_contents(text
);
2075 *clientoutlen
= output_token
->length
;
2076 if (output_token
->value
) {
2078 ret
= _plug_buf_alloc(text
->utils
, &(text
->out_buf
),
2079 &(text
->out_buf_len
), *clientoutlen
);
2080 if (ret
!= SASL_OK
) {
2081 gss_release_buffer(&min_stat
, output_token
);
2084 memcpy(text
->out_buf
, output_token
->value
, *clientoutlen
);
2085 *clientout
= text
->out_buf
;
2088 gss_release_buffer(&min_stat
, output_token
);
2091 text
->state
= SASL_GSSAPI_STATE_AUTHENTICATED
;
2093 oparams
->doneflag
= 1;
2100 params
->utils
->log(params
->utils
->conn
, SASL_LOG_ERR
,
2101 "Invalid GSSAPI client step %d", text
->state
);
2103 params
->utils
->log(NULL
, SASL_LOG_ERR
,
2104 "Invalid GSSAPI client step %d\n", text
->state
);
2105 #endif /* _SUN_SDK_ */
2110 return SASL_FAIL
; /* should never get here */
2111 #endif /* !_SUN_SDK_ */
2115 static const unsigned long gssapi_required_prompts
[] = {
2117 static const long gssapi_required_prompts
[] = {
2118 #endif /* _SUN_SDK_ */
2122 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
2123 static int _gssapi_client_mech_step(void *conn_context
,
2124 sasl_client_params_t
*params
,
2125 const char *serverin
,
2126 unsigned serverinlen
,
2127 sasl_interact_t
**prompt_need
,
2128 const char **clientout
,
2129 unsigned *clientoutlen
,
2130 sasl_out_params_t
*oparams
)
2134 if (LOCK_MUTEX(&global_mutex
) < 0)
2137 ret
= gssapi_client_mech_step(conn_context
, params
, serverin
, serverinlen
,
2138 prompt_need
, clientout
, clientoutlen
, oparams
);
2140 UNLOCK_MUTEX(&global_mutex
);
2143 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
2145 static sasl_client_plug_t gssapi_client_plugins
[] =
2148 "GSSAPI", /* mech_name */
2150 SASL_SEC_NOPLAINTEXT
2152 | SASL_SEC_NOANONYMOUS
2153 | SASL_SEC_MUTUAL_AUTH
, /* security_flags */
2154 SASL_FEAT_WANT_CLIENT_FIRST
2155 | SASL_FEAT_ALLOWS_PROXY
, /* features */
2156 gssapi_required_prompts
, /* required_prompts */
2157 NULL
, /* glob_context */
2158 &gssapi_client_mech_new
, /* mech_new */
2159 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
2160 &_gssapi_client_mech_step
, /* mech_step */
2162 &gssapi_client_mech_step
, /* mech_step */
2163 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
2164 &gssapi_common_mech_dispose
, /* mech_dispose */
2165 NULL
, /* mech_free */
2172 int gssapiv2_client_plug_init(const sasl_utils_t
*utils
__attribute__((unused
)),
2175 sasl_client_plug_t
**pluglist
,
2178 if (maxversion
< SASL_CLIENT_PLUG_VERSION
) {
2179 SETERROR(utils
, "Version mismatch in GSSAPI");
2180 return SASL_BADVERS
;
2183 #ifdef _INTEGRATED_SOLARIS_
2185 * Let libsasl know that we are a "Sun" plugin so that privacy
2186 * and integrity will be allowed.
2188 REG_PLUG("GSSAPI", gssapi_client_plugins
);
2189 #endif /* _INTEGRATED_SOLARIS_ */
2191 *out_version
= SASL_CLIENT_PLUG_VERSION
;
2192 *pluglist
= gssapi_client_plugins
;