dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / sasl_plugins / gssapi / gssapi.c
blob2b03caf706586883ffe65f2b2cb6c7805c2f181e
1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* GSSAPI SASL plugin
7 * Leif Johansson
8 * Rob Siemborski (SASL v2 Conversion)
9 * $Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $
11 /*
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
16 * are met:
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
24 * distribution.
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
32 * 5000 Forbes Avenue
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
38 * acknowledgment:
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.
51 #include <config.h>
53 #ifdef HAVE_GSSAPI_H
54 #include <gssapi.h>
55 #else
56 #include <gssapi/gssapi.h>
57 #endif
59 #ifdef WIN32
60 # include <winsock.h>
62 # ifndef R_OK
63 # define R_OK 04
64 # endif
65 /* we also need io.h for access() prototype */
66 # include <io.h>
67 #else
68 # include <sys/param.h>
69 # include <sys/socket.h>
70 # include <netinet/in.h>
71 # include <arpa/inet.h>
72 # include <netdb.h>
73 #endif /* WIN32 */
74 #include <fcntl.h>
75 #include <stdio.h>
76 #include <sasl.h>
77 #include <saslutil.h>
78 #include <saslplug.h>
80 #include "plugin_common.h"
82 #ifdef HAVE_UNISTD_H
83 #include <unistd.h>
84 #endif
86 #include <errno.h>
88 #ifdef WIN32
89 /* This must be after sasl.h */
90 # include "saslgssapi.h"
91 #endif /* WIN32 */
93 /***************************** Common Section *****************************/
95 #ifndef _SUN_SDK_
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
104 #endif
106 #ifdef _SUN_SDK_
107 static int
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 {
125 int state;
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
132 server */
133 #ifdef _SUN_SDK_
134 gss_cred_id_t client_creds;
135 gss_OID mech_oid;
136 int use_authid;
137 #endif /* _SUN_SDK_ */
138 const sasl_utils_t *utils;
140 /* layers buffering */
141 char *buffer;
142 #ifdef _SUN_SDK_
143 unsigned bufsize;
144 #else
145 int bufsize;
146 #endif /* _SUN_SDK_ */
147 char sizebuf[4];
148 #ifdef _SUN_SDK_
149 unsigned cursize;
150 unsigned size;
151 #else
152 int cursize;
153 int size;
154 #endif /* _SUN_SDK_ */
155 unsigned needsize;
157 char *encode_buf; /* For encoding/decoding mem management */
158 char *decode_buf;
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 */
170 #ifdef _SUN_SDK_
171 const char *client_authid;
172 #endif /* _SUN_SDK_ */
173 #ifdef _INTEGRATED_SOLARIS_
174 void *h;
175 #endif /* _INTEGRATED_SOLARIS_ */
176 } context_t;
178 enum {
179 SASL_GSSAPI_STATE_AUTHNEG = 1,
180 SASL_GSSAPI_STATE_SSFCAP = 2,
181 SASL_GSSAPI_STATE_SSFREQ = 3,
182 SASL_GSSAPI_STATE_AUTHENTICATED = 4
185 #ifdef _SUN_SDK_
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)
189 static void
190 sasl_gss_seterror_(const context_t *text, OM_uint32 maj, OM_uint32 min,
191 int logonly)
192 #else
193 static void
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;
198 gss_buffer_desc msg;
199 OM_uint32 msg_ctx;
200 int ret;
201 char *out = NULL;
202 #ifdef _SUN_SDK_
203 unsigned len, curlen = 0;
204 const sasl_utils_t *utils = text->utils;
205 char *prefix = dgettext(TEXT_DOMAIN, "GSSAPI Error: ");
206 #else
207 size_t len, curlen = 0;
208 const char prefix[] = "GSSAPI Error: ";
209 #endif /* _SUN_SDK_ */
211 if(!utils) return;
213 len = sizeof(prefix);
214 ret = _plug_buf_alloc(utils, &out, &curlen, 256);
215 if(ret != SASL_OK) return;
217 strcpy(out, prefix);
219 msg_ctx = 0;
220 while (1) {
221 maj_stat = gss_display_status(&min_stat, maj,
222 #ifdef _SUN_SDK_
223 GSS_C_GSS_CODE, text->mech_oid,
224 #else
225 GSS_C_GSS_CODE, GSS_C_NULL_OID,
226 #endif /* _SUN_SDK_ */
227 &msg_ctx, &msg);
228 if(GSS_ERROR(maj_stat)) {
229 #ifdef _SUN_SDK_
230 if (logonly) {
231 utils->log(text->utils->conn, SASL_LOG_FAIL,
232 "GSSAPI Failure: (could not get major error message)");
233 } else {
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)"));
239 #ifdef _SUN_SDK_
241 #endif /* _SUN_SDK_ */
242 #else
243 utils->seterror(utils->conn, 0,
244 "GSSAPI Failure "
245 "(could not get major error message)");
246 #ifdef _SUN_SDK_
248 #endif /* _SUN_SDK_ */
249 #endif /* _INTEGRATED_SOLARIS_ */
250 utils->free(out);
251 return;
254 len += len + msg.length;
255 ret = _plug_buf_alloc(utils, &out, &curlen, len);
257 if(ret != SASL_OK) {
258 utils->free(out);
259 return;
262 strcat(out, msg.value);
264 gss_release_buffer(&min_stat, &msg);
266 if (!msg_ctx)
267 break;
270 /* Now get the minor status */
272 len += 2;
273 ret = _plug_buf_alloc(utils, &out, &curlen, len);
274 if(ret != SASL_OK) {
275 utils->free(out);
276 return;
279 strcat(out, " (");
281 msg_ctx = 0;
282 while (1) {
283 maj_stat = gss_display_status(&min_stat, min,
284 #ifdef _SUN_SDK_
285 GSS_C_MECH_CODE, text->mech_oid,
286 #else
287 GSS_C_MECH_CODE, GSS_C_NULL_OID,
288 #endif /* _SUN_SDK_ */
289 &msg_ctx, &msg);
290 if(GSS_ERROR(maj_stat)) {
291 #ifdef _SUN_SDK_
292 if (logonly) {
293 utils->log(text->utils->conn, SASL_LOG_FAIL,
294 "GSSAPI Failure: (could not get minor error message)");
295 } else {
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)"));
301 #ifdef _SUN_SDK_
303 #endif /* _SUN_SDK_ */
304 #else
305 utils->seterror(utils->conn, 0,
306 "GSSAPI Failure "
307 "(could not get minor error message)");
308 #ifdef _SUN_SDK_
310 #endif /* _SUN_SDK_ */
311 #endif /* _INTEGRATED_SOLARIS_ */
312 utils->free(out);
313 return;
316 len += len + msg.length;
317 ret = _plug_buf_alloc(utils, &out, &curlen, len);
319 if(ret != SASL_OK) {
320 utils->free(out);
321 return;
324 strcat(out, msg.value);
326 gss_release_buffer(&min_stat, &msg);
328 if (!msg_ctx)
329 break;
332 len += 1;
333 ret = _plug_buf_alloc(utils, &out, &curlen, len);
334 if(ret != SASL_OK) {
335 utils->free(out);
336 return;
339 strcat(out, ")");
341 #ifdef _SUN_SDK_
342 if (logonly) {
343 utils->log(text->utils->conn, SASL_LOG_FAIL, out);
344 } else {
345 utils->seterror(utils->conn, 0, out);
347 #else
348 utils->seterror(utils->conn, 0, out);
349 #endif /* _SUN_SDK_ */
350 utils->free(out);
353 static int
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;
361 int ret;
362 struct buffer_info *inblob, bufinfo;
364 if(!output) return SASL_BADPARAM;
366 if(numiov > 1) {
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;
370 } else {
371 bufinfo.data = invec[0].iov_base;
372 bufinfo.curlen = invec[0].iov_len;
373 inblob = &bufinfo;
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)
389 return (SASL_FAIL);
390 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
391 maj_stat = gss_wrap (&min_stat,
392 text->gss_ctx,
393 privacy,
394 GSS_C_QOP_DEFAULT,
395 input_token,
396 NULL,
397 output_token);
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 */
407 return SASL_FAIL;
410 if (output_token->value && output) {
411 int len;
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 */
421 return ret;
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);
429 if (outputlen) {
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 */
442 return SASL_OK;
445 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
446 unsigned numiov, const char **output,
447 unsigned *outputlen)
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,
454 unsigned *outputlen)
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;
469 int result;
470 unsigned diff;
472 if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
473 #ifdef _INTEGRATED_SOLARIS_
474 SETERROR(text->utils, gettext("GSSAPI Failure"));
475 #else
476 SETERROR(text->utils, "GSSAPI Failure");
477 #endif /* _INTEGRATED_SOLARIS_ */
478 return SASL_NOTDONE;
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;
488 *input += tocopy;
489 *inputlen -= tocopy;
491 if (text->needsize == 0) {
492 /* got the entire size */
493 memcpy(&text->size, text->sizebuf, 4);
494 text->size = ntohl(text->size);
495 text->cursize = 0;
497 #ifdef _SUN_SDK_
498 if (text->size > 0xFFFFFF) {
499 text->utils->log(text->utils->conn, SASL_LOG_ERR,
500 "Illegal size in sasl_gss_decode_once");
501 #else
502 if (text->size > 0xFFFFFF || text->size <= 0) {
503 SETERROR(text->utils, "Illegal size in sasl_gss_decode_once");
504 #endif /* _SUN_SDK_ */
505 return SASL_FAIL;
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 ! */
516 *outputlen = 0;
517 *output = NULL;
519 return SASL_OK;
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;
529 *inputlen = 0;
530 *outputlen = 0;
531 *output = NULL;
532 return SASL_OK;
533 } else {
534 memcpy(text->buffer + text->cursize, *input, diff);
535 *input += diff;
536 *inputlen -= 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)
549 return (SASL_FAIL);
550 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
552 maj_stat = gss_unwrap (&min_stat,
553 text->gss_ctx,
554 input_token,
555 output_token,
556 NULL,
557 NULL);
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 */
567 return SASL_FAIL;
570 if (outputlen)
571 *outputlen = output_token->length;
573 if (output_token->value) {
574 if (output) {
575 result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
576 &text->decode_once_buf_len,
577 *outputlen);
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 */
583 return result;
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 */
595 #ifndef _SUN_SDK_
596 text->size = -1;
597 #endif /* !_SUN_SDK_ */
598 text->needsize = 4;
600 return SASL_OK;
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;
608 int ret;
610 ret = _plug_decode(text->utils, context, input, inputlen,
611 &text->decode_buf, &text->decode_buf_len, outputlen,
612 gssapi_decode_once);
614 *output = text->decode_buf;
616 return ret;
619 static context_t *gss_new_context(const sasl_utils_t *utils)
621 context_t *ret;
623 ret = utils->malloc(sizeof(context_t));
624 if(!ret) return NULL;
626 memset(ret,0,sizeof(context_t));
627 ret->utils = utils;
628 #ifdef _SUN_SDK_
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) {
635 utils->free(ret);
636 return (NULL);
638 #endif /* _SUN_SDK_ */
640 ret->needsize = 4;
642 return ret;
645 static void sasl_gss_free_context_contents(context_t *text)
647 OM_uint32 maj_stat, min_stat;
649 if (!text) return;
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;
671 #ifdef _SUN_SDK_
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
679 * be released
681 #endif /* _SUN_SDK_ */
683 if (text->out_buf) {
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;
709 if (text->buffer) {
710 text->utils->free(text->buffer);
711 text->buffer = NULL;
714 if (text->authid) { /* works for both client and server */
715 text->utils->free(text->authid);
716 text->authid = NULL;
720 #ifdef _SUN_SDK_
722 #ifdef HAVE_RPC_GSS_MECH_TO_OID
723 #include <rpc/rpcsec_gss.h>
724 #endif /* HAVE_RPC_GSS_MECH_TO_OID */
726 static int
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 */
733 *oid = &kerb_v5;
734 #endif /* HAVE_RPC_GSS_MECH_TO_OID */
735 return (SASL_OK);
738 static int
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);
748 return SASL_FAIL;
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);
756 return SASL_FAIL;
758 return SASL_OK;
760 #endif /* _SUN_SDK_ */
762 static void gssapi_common_mech_dispose(void *conn_context,
763 const sasl_utils_t *utils)
765 #ifdef _SUN_SDK_
766 if (conn_context == NULL)
767 return;
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 *****************************/
784 static int
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)),
789 void **conn_context)
791 context_t *text;
793 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
794 if (LOCK_MUTEX(&global_mutex) < 0)
795 return (SASL_FAIL);
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 */
801 if (text == NULL) {
802 #ifndef _SUN_SDK_
803 MEMERROR(params->utils);
804 #endif /* !_SUN_SDK_ */
805 return SASL_NOMEM;
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;
816 return SASL_OK;
819 static int
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;
832 #ifdef _SUN_SDK_
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;
837 int ret;
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;
844 if(!serverout) {
845 PARAMERROR(text->utils);
846 return SASL_BADPARAM;
849 *serverout = NULL;
850 *serveroutlen = 0;
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);
861 return SASL_NOMEM;
863 #ifdef _SUN_SDK_
864 snprintf(name_token.value, name_token.length + 1,
865 "%s@%s", params->service, params->serverFQDN);
866 #else
867 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
868 #endif /* _SUN_SDK_ */
870 maj_stat = gss_import_name (&min_stat,
871 &name_token,
872 GSS_C_NT_HOSTBASED_SERVICE,
873 &text->server_name);
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);
881 return SASL_FAIL;
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;
889 #ifdef _SUN_SDK_
890 if (text->mech_oid != GSS_C_NULL_OID) {
891 ret = add_mech_to_set(text, &desired_mechs);
892 if (ret != SASL_OK)
893 return (ret);
895 #endif /* _SUN_SDK_ */
897 maj_stat = gss_acquire_cred(&min_stat,
898 text->server_name,
899 GSS_C_INDEFINITE,
900 #ifdef _SUN_SDK_
901 desired_mechs,
902 #else
903 GSS_C_NO_OID_SET,
904 #endif /* _SUN_SDK_ */
905 GSS_C_ACCEPT,
906 &text->server_creds,
907 NULL,
908 NULL);
910 #ifdef _SUN_SDK_
911 if (desired_mechs != GSS_C_NULL_OID_SET) {
912 OM_uint32 min_stat2;
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);
920 return SASL_FAIL;
924 if (clientinlen) {
925 real_input_token.value = (void *)clientin;
926 real_input_token.length = clientinlen;
929 maj_stat =
930 gss_accept_sec_context(&min_stat,
931 &(text->gss_ctx),
932 text->server_creds,
933 input_token,
934 GSS_C_NO_CHANNEL_BINDINGS,
935 &text->client_name,
936 NULL,
937 output_token,
938 NULL,
939 NULL,
940 NULL);
942 if (GSS_ERROR(maj_stat)) {
943 #ifdef _SUN_SDK_
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);
951 #else
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);
959 return SASL_BADAUTH;
962 if (serveroutlen)
963 *serveroutlen = output_token->length;
964 if (output_token->value) {
965 if (serverout) {
966 ret = _plug_buf_alloc(text->utils, &(text->out_buf),
967 &(text->out_buf_len), *serveroutlen);
968 if(ret != SASL_OK) {
969 gss_release_buffer(&min_stat, output_token);
970 return ret;
972 memcpy(text->out_buf, output_token->value, *serveroutlen);
973 *serverout = text->out_buf;
976 gss_release_buffer(&min_stat, output_token);
977 } else {
978 /* No output token, send an empty string */
979 *serverout = GSSAPI_BLANK_STRING;
980 #ifndef _SUN_SDK_
981 serveroutlen = 0;
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;
996 #ifndef _SUN_SDK_
997 gss_buffer_desc name_without_realm;
998 gss_name_t without = NULL;
999 int equal;
1000 #endif /* !_SUN_SDK_ */
1002 name_token.value = NULL;
1003 #ifndef _SUN_SDK_
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,
1010 text->client_name,
1011 &name_token,
1012 NULL);
1014 if (GSS_ERROR(maj_stat)) {
1015 #ifndef _SUN_SDK_
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);
1022 #ifndef _SUN_SDK_
1023 if (without)
1024 gss_release_name(&min_stat, &without);
1025 #endif /* !_SUN_SDK_ */
1026 #ifdef _INTEGRATED_SOLARIS_
1027 SETERROR(text->utils, gettext("GSSAPI Failure"));
1028 #else
1029 SETERROR(text->utils, "GSSAPI Failure");
1030 #endif /* _INTEGRATED_SOLARIS_ */
1031 sasl_gss_free_context_contents(text);
1032 return SASL_BADAUTH;
1035 #ifndef _SUN_SDK_
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
1042 * function! */
1043 name_without_realm.value = malloc(strlen(name_token.value)+1);
1044 if (name_without_realm.value == NULL) {
1045 MEMERROR(text->utils);
1046 return SASL_NOMEM;
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
1061 GSS_C_NT_USER_NAME,
1062 #else
1063 GSS_C_NULL_OID,
1064 #endif
1065 &without);
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);
1071 if (without)
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,
1079 text->client_name,
1080 without,
1081 &equal);
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);
1087 if (without)
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);
1095 } else {
1096 equal = 0;
1099 if (equal) {
1100 text->authid = strdup(name_without_realm.value);
1102 if (text->authid == NULL) {
1103 MEMERROR(params->utils);
1104 return SASL_NOMEM;
1106 } else {
1107 text->authid = strdup(name_token.value);
1109 if (text->authid == NULL) {
1110 MEMERROR(params->utils);
1111 return SASL_NOMEM;
1114 #else
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);
1124 #ifdef _SUN_SDK_
1125 if (ret != SASL_OK)
1126 return (ret);
1127 #else
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.,
1134 we support */
1135 if (params->props.max_ssf < params->external_ssf) {
1136 text->limitssf = 0;
1137 } else {
1138 text->limitssf = params->props.max_ssf - params->external_ssf;
1140 if (params->props.min_ssf < params->external_ssf) {
1141 text->requiressf = 0;
1142 } else {
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;
1151 } else {
1152 sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
1153 sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
1154 sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
1156 sasldata[0] = 0;
1157 if(text->requiressf != 0 && !params->props.maxbufsize) {
1158 #ifdef _SUN_SDK_
1159 params->utils->log(params->utils->conn, SASL_LOG_ERR,
1160 "GSSAPI needs a security layer but one is forbidden");
1161 #else
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) {
1173 sasldata[0] |= 2;
1175 if (text->requiressf <= 56 && text->limitssf >= 56
1176 && params->props.maxbufsize) {
1177 sasldata[0] |= 4;
1180 real_input_token.value = (void *)sasldata;
1181 real_input_token.length = 4;
1183 maj_stat = gss_wrap(&min_stat,
1184 text->gss_ctx,
1185 0, /* Just integrity checking here */
1186 GSS_C_QOP_DEFAULT,
1187 input_token,
1188 NULL,
1189 output_token);
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);
1196 return SASL_FAIL;
1200 if (serveroutlen)
1201 *serveroutlen = output_token->length;
1202 if (output_token->value) {
1203 if (serverout) {
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);
1208 return ret;
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: {
1224 int layerchoice;
1226 real_input_token.value = (void *)clientin;
1227 real_input_token.length = clientinlen;
1229 maj_stat = gss_unwrap(&min_stat,
1230 text->gss_ctx,
1231 input_token,
1232 output_token,
1233 NULL,
1234 NULL);
1236 if (GSS_ERROR(maj_stat)) {
1237 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1238 sasl_gss_free_context_contents(text);
1239 return SASL_FAIL;
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;
1257 } else {
1258 /* not a supported encryption layer */
1259 #ifdef _SUN_SDK_
1260 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1261 "protocol violation: client requested invalid layer");
1262 #else
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);
1271 return SASL_FAIL;
1274 if (output_token->length > 4) {
1275 int ret;
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);
1284 return ret;
1287 ret = params->canon_user(params->utils->conn,
1288 text->authid,
1289 0, /* strlen(text->authid) */
1290 SASL_CU_AUTHID, oparams);
1291 if (ret != SASL_OK) {
1292 sasl_gss_free_context_contents(text);
1293 return ret;
1295 } else if(output_token->length == 4) {
1296 /* null authzid */
1297 int ret;
1299 ret = params->canon_user(params->utils->conn,
1300 text->authid,
1301 0, /* strlen(text->authid) */
1302 SASL_CU_AUTHZID | SASL_CU_AUTHID,
1303 oparams);
1305 if (ret != SASL_OK) {
1306 sasl_gss_free_context_contents(text);
1307 return ret;
1309 } else {
1310 #ifdef _SUN_SDK_
1311 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1312 "token too short");
1313 #else
1314 SETERROR(text->utils,
1315 "token too short");
1316 #endif /* _SUN_SDK_ */
1317 gss_release_buffer(&min_stat, output_token);
1318 sasl_gss_free_context_contents(text);
1319 return SASL_FAIL;
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);
1328 #ifdef _SUN_SDK_
1329 if (oparams->mech_ssf) {
1330 oparams->maxoutbuf -= 4; /* Allow for 4 byte tag */
1331 maj_stat = gss_wrap_size_limit(&min_stat,
1332 text->gss_ctx,
1333 oparams->mech_ssf > 1,
1334 GSS_C_QOP_DEFAULT,
1335 oparams->maxoutbuf,
1336 &max_input_size);
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);
1341 return (SASL_FAIL);
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;
1350 else {
1351 oparams->maxoutbuf = 0;
1354 #else
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;
1367 return SASL_OK;
1370 default:
1371 #ifdef _SUN_SDK_
1372 params->utils->log(text->utils->conn, SASL_LOG_ERR,
1373 "Invalid GSSAPI server step %d", text->state);
1374 #else
1375 params->utils->log(NULL, SASL_LOG_ERR,
1376 "Invalid GSSAPI server step %d\n", text->state);
1377 #endif /* _SUN_SDK_ */
1378 return SASL_FAIL;
1381 #ifndef _SUN_SDK_
1382 return SASL_FAIL; /* should never get here */
1383 #endif /* !_SUN_SDK_ */
1386 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1387 static int
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)
1396 int ret;
1398 if (LOCK_MUTEX(&global_mutex) < 0)
1399 return (SASL_FAIL);
1401 ret = gssapi_server_mech_step(conn_context, params, clientin, clientinlen,
1402 serverout, serveroutlen, oparams);
1404 UNLOCK_MUTEX(&global_mutex);
1405 return (ret);
1407 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1409 static sasl_server_plug_t gssapi_server_plugins[] =
1412 "GSSAPI", /* mech_name */
1413 56, /* max_ssf */
1414 SASL_SEC_NOPLAINTEXT
1415 | SASL_SEC_NOACTIVE
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 */
1424 #else
1425 &gssapi_server_mech_step, /* mech_step */
1426 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1427 &gssapi_common_mech_dispose, /* mech_dispose */
1428 NULL, /* mech_free */
1429 NULL, /* setpass */
1430 NULL, /* user_query */
1431 NULL, /* idle */
1432 NULL, /* mech_avail */
1433 NULL /* spare */
1437 int gssapiv2_server_plug_init(
1438 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1439 const sasl_utils_t *utils __attribute__((unused)),
1440 #else
1441 const sasl_utils_t *utils,
1442 #endif
1443 int maxversion,
1444 int *out_version,
1445 sasl_server_plug_t **pluglist,
1446 int *plugcount)
1448 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1449 const char *keytab = NULL;
1450 char keytab_path[1024];
1451 unsigned int rl;
1452 #endif
1454 if (maxversion < SASL_SERVER_PLUG_VERSION) {
1455 return SASL_BADVERS;
1458 #ifndef _SUN_SDK_
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",
1470 keytab, errno);
1471 return SASL_FAIL;
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);
1484 #endif
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;
1497 *plugcount = 1;
1499 return SASL_OK;
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)
1508 context_t *text;
1509 #ifdef _SUN_SDK_
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)
1516 return (SASL_FAIL);
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 */
1522 if (text == NULL) {
1523 #ifndef _SUN_SDK_
1524 MEMERROR(params->utils);
1525 #endif /* !_SUN_SDK_ */
1526 return SASL_NOMEM;
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;
1534 #ifdef _SUN_SDK_
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;
1543 return SASL_OK;
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;
1559 #ifdef _SUN_SDK_
1560 OM_uint32 max_input_size;
1561 #endif /* _SUN_SDK_ */
1562 gss_buffer_desc name_token;
1563 int ret;
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;
1571 *clientout = NULL;
1572 *clientoutlen = 0;
1574 switch (text->state) {
1576 case SASL_GSSAPI_STATE_AUTHNEG:
1577 /* try to get the userid */
1578 #ifdef _SUN_SDK_
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,
1587 prompt_need);
1589 if ((auth_result != SASL_OK) &&
1590 (auth_result != SASL_INTERACT)) {
1591 sasl_gss_free_context_contents(text);
1592 return auth_result;
1595 if (text->user == NULL) {
1596 user_result = _plug_get_userid(params->utils, &text->user,
1597 prompt_need);
1599 if ((user_result != SASL_OK) &&
1600 (user_result != SASL_INTERACT)) {
1601 sasl_gss_free_context_contents(text);
1602 return user_result;
1605 #else
1606 if (text->user == NULL) {
1607 int user_result = SASL_OK;
1609 user_result = _plug_get_userid(params->utils, &text->user,
1610 prompt_need);
1612 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
1613 sasl_gss_free_context_contents(text);
1614 return user_result;
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 */
1625 #ifdef _SUN_SDK_
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,
1631 prompt_need,
1632 user_result == SASL_INTERACT ?
1633 convert_prompt(params->utils, &text->h,
1634 gettext("Please enter your authorization name"))
1635 : NULL, NULL,
1636 auth_result == SASL_INTERACT ?
1637 convert_prompt(params->utils, &text->h,
1638 gettext("Please enter your authentication name"))
1639 : NULL, NULL,
1640 NULL, NULL,
1641 NULL, NULL, NULL,
1642 NULL, NULL, NULL);
1643 #else
1644 int result = _plug_make_prompts(params->utils, prompt_need,
1645 user_result == SASL_INTERACT ?
1646 "Please enter your authorization name"
1647 : NULL, NULL,
1648 auth_result == SASL_INTERACT ?
1649 "Please enter your authentication name"
1650 : NULL, NULL,
1651 NULL, NULL,
1652 NULL, NULL, NULL,
1653 NULL, NULL, NULL);
1654 #endif /* _INTEGRATED_SOLARIS_ */
1656 if (result != SASL_OK) return result;
1658 return SASL_INTERACT;
1660 #else
1661 if (user_result == SASL_INTERACT) {
1662 /* make the prompt list */
1663 int result =
1664 _plug_make_prompts(params->utils, prompt_need,
1665 user_result == SASL_INTERACT ?
1666 "Please enter your authorization name" : NULL, NULL,
1667 NULL, NULL,
1668 NULL, NULL,
1669 NULL, NULL, NULL,
1670 NULL, 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);
1683 return SASL_NOMEM;
1685 if (params->serverFQDN == NULL
1686 || strlen(params->serverFQDN) == 0) {
1687 #ifdef _SUN_SDK_
1688 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1689 "GSSAPI Failure: no serverFQDN");
1690 #else
1691 SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1692 #endif /* _SUN_SDK_ */
1693 return SASL_FAIL;
1696 #ifdef _SUN_SDK_
1697 snprintf(name_token.value, name_token.length + 1,
1698 "%s@%s", params->service, params->serverFQDN);
1699 #else
1700 sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1701 #endif /* _SUN_SDK_ */
1703 maj_stat = gss_import_name (&min_stat,
1704 &name_token,
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);
1714 return SASL_FAIL;
1718 if (serverinlen == 0)
1719 input_token = GSS_C_NO_BUFFER;
1721 if (serverinlen) {
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;
1745 #ifdef _SUN_SDK_
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,
1754 &name_token,
1755 #ifdef HAVE_GSS_C_NT_USER_NAME
1756 GSS_C_NT_USER_NAME,
1757 #else
1758 GSS_C_NULL_OID,
1759 #endif
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);
1764 return SASL_FAIL;
1767 if (text->mech_oid != GSS_C_NULL_OID) {
1768 ret = add_mech_to_set(text, &desired_mechs);
1769 if (ret != SASL_OK)
1770 return (ret);
1773 maj_stat = gss_acquire_cred(&min_stat,
1774 text->client_name,
1775 GSS_C_INDEFINITE,
1776 desired_mechs,
1777 GSS_C_INITIATE,
1778 &text->client_creds,
1779 NULL,
1780 NULL);
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);
1790 return SASL_FAIL;
1793 #endif /* _SUN_SDK_ */
1795 maj_stat = gss_init_sec_context(&min_stat,
1796 #ifdef _SUN_SDK_
1797 text->client_creds,
1798 #else
1799 GSS_C_NO_CREDENTIAL,
1800 #endif /* _SUN_SDK_ */
1801 &text->gss_ctx,
1802 text->server_name,
1803 #ifdef _SUN_SDK_
1804 text->mech_oid,
1805 #else
1806 GSS_C_NO_OID,
1807 #endif /* _SUN_SDK_ */
1808 req_flags,
1810 GSS_C_NO_CHANNEL_BINDINGS,
1811 input_token,
1812 NULL,
1813 output_token,
1814 &out_req_flags,
1815 NULL);
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);
1822 return SASL_FAIL;
1825 *clientoutlen = output_token->length;
1827 if (output_token->value) {
1828 if (clientout) {
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);
1833 return ret;
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,
1844 text->gss_ctx,
1845 &text->client_name,
1846 NULL, /* targ_name */
1847 NULL, /* lifetime */
1848 NULL, /* mech */
1849 NULL, /* flags */
1850 NULL, /* local init */
1851 NULL); /* open */
1853 if (GSS_ERROR(maj_stat)) {
1854 sasl_gss_seterror(text->utils, maj_stat, min_stat);
1855 sasl_gss_free_context_contents(text);
1856 return SASL_FAIL;
1859 name_token.length = 0;
1860 maj_stat = gss_display_name(&min_stat,
1861 text->client_name,
1862 &name_token,
1863 NULL);
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"));
1870 #else
1871 SETERROR(text->utils, "GSSAPI Failure");
1872 #endif /* _INTEGRATED_SOLARIS_ */
1873 sasl_gss_free_context_contents(text);
1874 return SASL_FAIL;
1877 if (text->user && text->user[0]) {
1878 ret = params->canon_user(params->utils->conn,
1879 text->user, 0,
1880 SASL_CU_AUTHZID, oparams);
1881 if (ret == SASL_OK)
1882 ret = params->canon_user(params->utils->conn,
1883 name_token.value, 0,
1884 SASL_CU_AUTHID, oparams);
1885 } else {
1886 ret = params->canon_user(params->utils->conn,
1887 name_token.value, 0,
1888 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1889 oparams);
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,
1911 text->gss_ctx,
1912 input_token,
1913 output_token,
1914 NULL,
1915 NULL);
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);
1922 return SASL_FAIL;
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;
1935 } else {
1936 allowed = 0;
1938 if (secprops->min_ssf >= external) {
1939 need = secprops->min_ssf - external;
1940 } else {
1941 /* good to go */
1942 need = 0;
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)) {
1950 /* encryption */
1951 oparams->encode = &gssapi_privacy_encode;
1952 oparams->decode = &gssapi_decode;
1953 oparams->mech_ssf = 56;
1954 mychoice = 4;
1955 } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1956 /* integrity */
1957 oparams->encode = &gssapi_integrity_encode;
1958 oparams->decode = &gssapi_decode;
1959 oparams->mech_ssf = 1;
1960 mychoice = 2;
1961 #ifdef _SUN_SDK_
1962 } else if (need == 0 && (serverhas & 1)) {
1963 #else
1964 } else if (need <= 0 && (serverhas & 1)) {
1965 #endif /* _SUN_SDK_ */
1966 /* no layer */
1967 oparams->encode = NULL;
1968 oparams->decode = NULL;
1969 oparams->mech_ssf = 0;
1970 mychoice = 1;
1971 } else {
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);
1982 #ifdef _SUN_SDK_
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,
1986 text->gss_ctx,
1987 oparams->mech_ssf > 1,
1988 GSS_C_QOP_DEFAULT,
1989 oparams->maxoutbuf,
1990 &max_input_size);
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);
1995 return (SASL_FAIL);
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;
2005 else {
2006 oparams->maxoutbuf = 0;
2009 #else
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);
2024 else
2025 alen = 0;
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);
2032 return SASL_NOMEM;
2035 if (alen)
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;
2045 } else {
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,
2056 text->gss_ctx,
2057 0, /* Just integrity checking here */
2058 GSS_C_QOP_DEFAULT,
2059 input_token,
2060 NULL,
2061 output_token);
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);
2071 return SASL_FAIL;
2074 if (clientoutlen)
2075 *clientoutlen = output_token->length;
2076 if (output_token->value) {
2077 if (clientout) {
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);
2082 return ret;
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;
2095 return SASL_OK;
2098 default:
2099 #ifdef _SUN_SDK_
2100 params->utils->log(params->utils->conn, SASL_LOG_ERR,
2101 "Invalid GSSAPI client step %d", text->state);
2102 #else
2103 params->utils->log(NULL, SASL_LOG_ERR,
2104 "Invalid GSSAPI client step %d\n", text->state);
2105 #endif /* _SUN_SDK_ */
2106 return SASL_FAIL;
2109 #ifndef _SUN_SDK_
2110 return SASL_FAIL; /* should never get here */
2111 #endif /* !_SUN_SDK_ */
2114 #ifdef _SUN_SDK_
2115 static const unsigned long gssapi_required_prompts[] = {
2116 #else
2117 static const long gssapi_required_prompts[] = {
2118 #endif /* _SUN_SDK_ */
2119 SASL_CB_LIST_END
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)
2132 int ret;
2134 if (LOCK_MUTEX(&global_mutex) < 0)
2135 return (SASL_FAIL);
2137 ret = gssapi_client_mech_step(conn_context, params, serverin, serverinlen,
2138 prompt_need, clientout, clientoutlen, oparams);
2140 UNLOCK_MUTEX(&global_mutex);
2141 return (ret);
2143 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
2145 static sasl_client_plug_t gssapi_client_plugins[] =
2148 "GSSAPI", /* mech_name */
2149 56, /* max_ssf */
2150 SASL_SEC_NOPLAINTEXT
2151 | SASL_SEC_NOACTIVE
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 */
2161 #else
2162 &gssapi_client_mech_step, /* mech_step */
2163 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
2164 &gssapi_common_mech_dispose, /* mech_dispose */
2165 NULL, /* mech_free */
2166 NULL, /* idle */
2167 NULL, /* spare */
2168 NULL /* spare */
2172 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
2173 int maxversion,
2174 int *out_version,
2175 sasl_client_plug_t **pluglist,
2176 int *plugcount)
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;
2193 *plugcount = 1;
2195 return SASL_OK;