xref: /titanic_41/usr/src/lib/sasl_plugins/gssapi/gssapi.c (revision 1e49577a7fcde812700ded04431b49d67cc57d6d)
1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /* GSSAPI SASL plugin
9  * Leif Johansson
10  * Rob Siemborski (SASL v2 Conversion)
11  * $Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $
12  */
13 /*
14  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  *
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  *
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in
25  *    the documentation and/or other materials provided with the
26  *    distribution.
27  *
28  * 3. The name "Carnegie Mellon University" must not be used to
29  *    endorse or promote products derived from this software without
30  *    prior written permission. For permission or any other legal
31  *    details, please contact
32  *      Office of Technology Transfer
33  *      Carnegie Mellon University
34  *      5000 Forbes Avenue
35  *      Pittsburgh, PA  15213-3890
36  *      (412) 268-4387, fax: (412) 268-7395
37  *      tech-transfer@andrew.cmu.edu
38  *
39  * 4. Redistributions of any form whatsoever must retain the following
40  *    acknowledgment:
41  *    "This product includes software developed by Computing Services
42  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
43  *
44  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
45  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
47  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51  */
52 
53 #include <config.h>
54 
55 #ifdef HAVE_GSSAPI_H
56 #include <gssapi.h>
57 #else
58 #include <gssapi/gssapi.h>
59 #endif
60 
61 #ifdef WIN32
62 #  include <winsock.h>
63 
64 #  ifndef R_OK
65 #    define R_OK 04
66 #  endif
67 /* we also need io.h for access() prototype */
68 #  include <io.h>
69 #else
70 #  include <sys/param.h>
71 #  include <sys/socket.h>
72 #  include <netinet/in.h>
73 #  include <arpa/inet.h>
74 #  include <netdb.h>
75 #endif /* WIN32 */
76 #include <fcntl.h>
77 #include <stdio.h>
78 #include <sasl.h>
79 #include <saslutil.h>
80 #include <saslplug.h>
81 
82 #include "plugin_common.h"
83 
84 #ifdef HAVE_UNISTD_H
85 #include <unistd.h>
86 #endif
87 
88 #include <errno.h>
89 
90 #ifdef WIN32
91 /* This must be after sasl.h */
92 # include "saslgssapi.h"
93 #endif /* WIN32 */
94 
95 /*****************************  Common Section  *****************************/
96 
97 #ifndef _SUN_SDK_
98 static const char plugin_id[] = "$Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $";
99 #endif /* !_SUN_SDK_ */
100 
101 static const char * GSSAPI_BLANK_STRING = "";
102 
103 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
104 extern gss_OID gss_nt_service_name;
105 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
106 #endif
107 
108 #ifdef _SUN_SDK_
109 static int
110 get_oid(const sasl_utils_t *utils, gss_OID *oid);
111 #ifdef GSSAPI_PROTECT
112 DEFINE_STATIC_MUTEX(global_mutex);
113 #endif /* GSSAPI_PROTECT */
114 #endif /* _SUN_SDK_ */
115 
116 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
117  * inspired by the kerberos mechanism and the gssapi_server and
118  * gssapi_client from the heimdal distribution by Assar Westerlund
119  * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>.
120  * See the configure.in file for details on dependencies.
121  * Heimdal can be obtained from http://www.pdc.kth.se/heimdal
122  *
123  * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
124  */
125 
126 typedef struct context {
127     int state;
128 
129     gss_ctx_id_t gss_ctx;
130     gss_name_t   client_name;
131     gss_name_t   server_name;
132     gss_cred_id_t server_creds;
133     sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
134 					server */
135 #ifdef _SUN_SDK_
136     gss_cred_id_t client_creds;
137     gss_OID	mech_oid;
138     int		use_authid;
139 #endif /* _SUN_SDK_ */
140     const sasl_utils_t *utils;
141 
142     /* layers buffering */
143     char *buffer;
144 #ifdef _SUN_SDK_
145     unsigned bufsize;
146 #else
147     int bufsize;
148 #endif /* _SUN_SDK_ */
149     char sizebuf[4];
150 #ifdef _SUN_SDK_
151     unsigned cursize;
152     unsigned size;
153 #else
154     int cursize;
155     int size;
156 #endif /* _SUN_SDK_ */
157     unsigned needsize;
158 
159     char *encode_buf;                /* For encoding/decoding mem management */
160     char *decode_buf;
161     char *decode_once_buf;
162     unsigned encode_buf_len;
163     unsigned decode_buf_len;
164     unsigned decode_once_buf_len;
165     buffer_info_t *enc_in_buf;
166 
167     char *out_buf;                   /* per-step mem management */
168     unsigned out_buf_len;
169 
170     char *authid; /* hold the authid between steps - server */
171     const char *user;   /* hold the userid between steps - client */
172 #ifdef _SUN_SDK_
173     const char *client_authid;
174 #endif /* _SUN_SDK_ */
175 #ifdef _INTEGRATED_SOLARIS_
176     void *h;
177 #endif /* _INTEGRATED_SOLARIS_ */
178 } context_t;
179 
180 enum {
181     SASL_GSSAPI_STATE_AUTHNEG = 1,
182     SASL_GSSAPI_STATE_SSFCAP = 2,
183     SASL_GSSAPI_STATE_SSFREQ = 3,
184     SASL_GSSAPI_STATE_AUTHENTICATED = 4
185 };
186 
187 #ifdef _SUN_SDK_
188 /* sasl_gss_log only logs gss_display_status() error string */
189 #define sasl_gss_log(x,y,z) sasl_gss_seterror_(text,y,z,1)
190 #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(text,y,z,0)
191 static void
192 sasl_gss_seterror_(const context_t *text, OM_uint32 maj, OM_uint32 min,
193 	int logonly)
194 #else
195 static void
196 sasl_gss_seterror(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min)
197 #endif /* _SUN_SDK_ */
198 {
199     OM_uint32 maj_stat, min_stat;
200     gss_buffer_desc msg;
201     OM_uint32 msg_ctx;
202     int ret;
203     char *out = NULL;
204 #ifdef _SUN_SDK_
205     unsigned len, curlen = 0;
206     const sasl_utils_t *utils = text->utils;
207     char *prefix = dgettext(TEXT_DOMAIN, "GSSAPI Error: ");
208 #else
209     size_t len, curlen = 0;
210     const char prefix[] = "GSSAPI Error: ";
211 #endif /* _SUN_SDK_ */
212 
213     if(!utils) return;
214 
215     len = sizeof(prefix);
216     ret = _plug_buf_alloc(utils, &out, &curlen, 256);
217     if(ret != SASL_OK) return;
218 
219     strcpy(out, prefix);
220 
221     msg_ctx = 0;
222     while (1) {
223 	maj_stat = gss_display_status(&min_stat, maj,
224 #ifdef _SUN_SDK_
225 				      GSS_C_GSS_CODE, text->mech_oid,
226 #else
227 				      GSS_C_GSS_CODE, GSS_C_NULL_OID,
228 #endif /* _SUN_SDK_ */
229 				      &msg_ctx, &msg);
230 	if(GSS_ERROR(maj_stat)) {
231 #ifdef _SUN_SDK_
232 	    if (logonly) {
233 		utils->log(text->utils->conn, SASL_LOG_FAIL,
234 		    "GSSAPI Failure: (could not get major error message)");
235 	    } else {
236 #endif /* _SUN_SDK_ */
237 #ifdef _INTEGRATED_SOLARIS_
238 		utils->seterror(utils->conn, 0,
239 				gettext("GSSAPI Failure "
240 				"(could not get major error message)"));
241 #ifdef _SUN_SDK_
242 	    }
243 #endif /* _SUN_SDK_ */
244 #else
245 	    utils->seterror(utils->conn, 0,
246 			    "GSSAPI Failure "
247 			    "(could not get major error message)");
248 #ifdef _SUN_SDK_
249 	    }
250 #endif /* _SUN_SDK_ */
251 #endif /* _INTEGRATED_SOLARIS_ */
252 	    utils->free(out);
253 	    return;
254 	}
255 
256 	len += len + msg.length;
257 	ret = _plug_buf_alloc(utils, &out, &curlen, len);
258 
259 	if(ret != SASL_OK) {
260 	    utils->free(out);
261 	    return;
262 	}
263 
264 	strcat(out, msg.value);
265 
266 	gss_release_buffer(&min_stat, &msg);
267 
268 	if (!msg_ctx)
269 	    break;
270     }
271 
272     /* Now get the minor status */
273 
274     len += 2;
275     ret = _plug_buf_alloc(utils, &out, &curlen, len);
276     if(ret != SASL_OK) {
277 	utils->free(out);
278 	return;
279     }
280 
281     strcat(out, " (");
282 
283     msg_ctx = 0;
284     while (1) {
285 	maj_stat = gss_display_status(&min_stat, min,
286 #ifdef _SUN_SDK_
287 				      GSS_C_MECH_CODE, text->mech_oid,
288 #else
289 				      GSS_C_MECH_CODE, GSS_C_NULL_OID,
290 #endif /* _SUN_SDK_ */
291 				      &msg_ctx, &msg);
292 	if(GSS_ERROR(maj_stat)) {
293 #ifdef _SUN_SDK_
294 	    if (logonly) {
295 		utils->log(text->utils->conn, SASL_LOG_FAIL,
296 		    "GSSAPI Failure: (could not get minor error message)");
297 	    } else {
298 #endif /* _SUN_SDK_ */
299 #ifdef _INTEGRATED_SOLARIS_
300 		utils->seterror(utils->conn, 0,
301 				gettext("GSSAPI Failure "
302 				"(could not get minor error message)"));
303 #ifdef _SUN_SDK_
304 	    }
305 #endif /* _SUN_SDK_ */
306 #else
307 	    utils->seterror(utils->conn, 0,
308 			    "GSSAPI Failure "
309 			    "(could not get minor error message)");
310 #ifdef _SUN_SDK_
311 	    }
312 #endif /* _SUN_SDK_ */
313 #endif /* _INTEGRATED_SOLARIS_ */
314 	    utils->free(out);
315 	    return;
316 	}
317 
318 	len += len + msg.length;
319 	ret = _plug_buf_alloc(utils, &out, &curlen, len);
320 
321 	if(ret != SASL_OK) {
322 	    utils->free(out);
323 	    return;
324 	}
325 
326 	strcat(out, msg.value);
327 
328 	gss_release_buffer(&min_stat, &msg);
329 
330 	if (!msg_ctx)
331 	    break;
332     }
333 
334     len += 1;
335     ret = _plug_buf_alloc(utils, &out, &curlen, len);
336     if(ret != SASL_OK) {
337 	utils->free(out);
338 	return;
339     }
340 
341     strcat(out, ")");
342 
343 #ifdef _SUN_SDK_
344     if (logonly) {
345 	utils->log(text->utils->conn, SASL_LOG_FAIL, out);
346     } else {
347 	utils->seterror(utils->conn, 0, out);
348     }
349 #else
350     utils->seterror(utils->conn, 0, out);
351 #endif /* _SUN_SDK_ */
352     utils->free(out);
353 }
354 
355 static int
356 sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
357 		const char **output, unsigned *outputlen, int privacy)
358 {
359     context_t *text = (context_t *)context;
360     OM_uint32 maj_stat, min_stat;
361     gss_buffer_t input_token, output_token;
362     gss_buffer_desc real_input_token, real_output_token;
363     int ret;
364     struct buffer_info *inblob, bufinfo;
365 
366     if(!output) return SASL_BADPARAM;
367 
368     if(numiov > 1) {
369 	ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
370 	if(ret != SASL_OK) return ret;
371 	inblob = text->enc_in_buf;
372     } else {
373 	bufinfo.data = invec[0].iov_base;
374 	bufinfo.curlen = invec[0].iov_len;
375 	inblob = &bufinfo;
376     }
377 
378     if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
379 
380     input_token = &real_input_token;
381 
382     real_input_token.value  = inblob->data;
383     real_input_token.length = inblob->curlen;
384 
385     output_token = &real_output_token;
386     output_token->value = NULL;
387     output_token->length = 0;
388 
389 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
390     if (LOCK_MUTEX(&global_mutex) < 0)
391 	return (SASL_FAIL);
392 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
393     maj_stat = gss_wrap (&min_stat,
394 			 text->gss_ctx,
395 			 privacy,
396 			 GSS_C_QOP_DEFAULT,
397 			 input_token,
398 			 NULL,
399 			 output_token);
400 
401     if (GSS_ERROR(maj_stat))
402 	{
403 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
404 	    if (output_token->value)
405 		gss_release_buffer(&min_stat, output_token);
406 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
407 	    UNLOCK_MUTEX(&global_mutex);
408 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
409 	    return SASL_FAIL;
410 	}
411 
412     if (output_token->value && output) {
413 	int len;
414 
415 	ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
416 			      &(text->encode_buf_len), output_token->length + 4);
417 
418 	if (ret != SASL_OK) {
419 	    gss_release_buffer(&min_stat, output_token);
420 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
421 	    UNLOCK_MUTEX(&global_mutex);
422 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
423 	    return ret;
424 	}
425 
426 	len = htonl(output_token->length);
427 	memcpy(text->encode_buf, &len, 4);
428 	memcpy(text->encode_buf + 4, output_token->value, output_token->length);
429     }
430 
431     if (outputlen) {
432 	*outputlen = output_token->length + 4;
433     }
434 
435     *output = text->encode_buf;
436 
437     if (output_token->value)
438 	gss_release_buffer(&min_stat, output_token);
439 
440 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
441     UNLOCK_MUTEX(&global_mutex);
442 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
443 
444     return SASL_OK;
445 }
446 
447 static int gssapi_privacy_encode(void *context, const struct iovec *invec,
448 				 unsigned numiov, const char **output,
449 				 unsigned *outputlen)
450 {
451     return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
452 }
453 
454 static int gssapi_integrity_encode(void *context, const struct iovec *invec,
455 				   unsigned numiov, const char **output,
456 				   unsigned *outputlen)
457 {
458     return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
459 }
460 
461 #define myMIN(a,b) (((a) < (b)) ? (a) : (b))
462 
463 static int gssapi_decode_once(void *context,
464 			      const char **input, unsigned *inputlen,
465 			      char **output, unsigned *outputlen)
466 {
467     context_t *text = (context_t *) context;
468     OM_uint32 maj_stat, min_stat;
469     gss_buffer_t input_token, output_token;
470     gss_buffer_desc real_input_token, real_output_token;
471     int result;
472     unsigned diff;
473 
474     if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
475 #ifdef _INTEGRATED_SOLARIS_
476 	SETERROR(text->utils, gettext("GSSAPI Failure"));
477 #else
478 	SETERROR(text->utils, "GSSAPI Failure");
479 #endif /* _INTEGRATED_SOLARIS_ */
480 	return SASL_NOTDONE;
481     }
482 
483     /* first we need to extract a packet */
484     if (text->needsize > 0) {
485 	/* how long is it? */
486 	int tocopy = myMIN(text->needsize, *inputlen);
487 
488 	memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
489 	text->needsize -= tocopy;
490 	*input += tocopy;
491 	*inputlen -= tocopy;
492 
493 	if (text->needsize == 0) {
494 	    /* got the entire size */
495 	    memcpy(&text->size, text->sizebuf, 4);
496 	    text->size = ntohl(text->size);
497 	    text->cursize = 0;
498 
499 #ifdef _SUN_SDK_
500 	    if (text->size > 0xFFFFFF) {
501 		text->utils->log(text->utils->conn, SASL_LOG_ERR,
502 				 "Illegal size in sasl_gss_decode_once");
503 #else
504 	    if (text->size > 0xFFFFFF || text->size <= 0) {
505 		SETERROR(text->utils, "Illegal size in sasl_gss_decode_once");
506 #endif /* _SUN_SDK_ */
507 		return SASL_FAIL;
508 	    }
509 
510 	    if (text->bufsize < text->size + 5) {
511 		result = _plug_buf_alloc(text->utils, &text->buffer,
512 					 &(text->bufsize), text->size+5);
513 		if(result != SASL_OK) return result;
514 	    }
515 	}
516 	if (*inputlen == 0) {
517 	    /* need more data ! */
518 	    *outputlen = 0;
519 	    *output = NULL;
520 
521 	    return SASL_OK;
522 	}
523     }
524 
525     diff = text->size - text->cursize;
526 
527     if (*inputlen < diff) {
528 	/* ok, let's queue it up; not enough data */
529 	memcpy(text->buffer + text->cursize, *input, *inputlen);
530 	text->cursize += *inputlen;
531 	*inputlen = 0;
532 	*outputlen = 0;
533 	*output = NULL;
534 	return SASL_OK;
535     } else {
536 	memcpy(text->buffer + text->cursize, *input, diff);
537 	*input += diff;
538 	*inputlen -= diff;
539     }
540 
541     input_token = &real_input_token;
542     real_input_token.value = text->buffer;
543     real_input_token.length = text->size;
544 
545     output_token = &real_output_token;
546     output_token->value = NULL;
547     output_token->length = 0;
548 
549 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
550     if (LOCK_MUTEX(&global_mutex) < 0)
551 	return (SASL_FAIL);
552 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
553 
554     maj_stat = gss_unwrap (&min_stat,
555 			   text->gss_ctx,
556 			   input_token,
557 			   output_token,
558 			   NULL,
559 			   NULL);
560 
561     if (GSS_ERROR(maj_stat))
562 	{
563 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
564 	    if (output_token->value)
565 		gss_release_buffer(&min_stat, output_token);
566 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
567 	    UNLOCK_MUTEX(&global_mutex);
568 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
569 	    return SASL_FAIL;
570 	}
571 
572     if (outputlen)
573 	*outputlen = output_token->length;
574 
575     if (output_token->value) {
576 	if (output) {
577 	    result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
578 				     &text->decode_once_buf_len,
579 				     *outputlen);
580 	    if(result != SASL_OK) {
581 		gss_release_buffer(&min_stat, output_token);
582 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
583 	    UNLOCK_MUTEX(&global_mutex);
584 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
585 		return result;
586 	    }
587 	    *output = text->decode_once_buf;
588 	    memcpy(*output, output_token->value, *outputlen);
589 	}
590 	gss_release_buffer(&min_stat, output_token);
591     }
592 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
593 	    UNLOCK_MUTEX(&global_mutex);
594 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
595 
596     /* reset for the next packet */
597 #ifndef _SUN_SDK_
598     text->size = -1;
599 #endif /* !_SUN_SDK_ */
600     text->needsize = 4;
601 
602     return SASL_OK;
603 }
604 
605 static int gssapi_decode(void *context,
606 			 const char *input, unsigned inputlen,
607 			 const char **output, unsigned *outputlen)
608 {
609     context_t *text = (context_t *) context;
610     int ret;
611 
612     ret = _plug_decode(text->utils, context, input, inputlen,
613 		       &text->decode_buf, &text->decode_buf_len, outputlen,
614 		       gssapi_decode_once);
615 
616     *output = text->decode_buf;
617 
618     return ret;
619 }
620 
621 static context_t *gss_new_context(const sasl_utils_t *utils)
622 {
623     context_t *ret;
624 
625     ret = utils->malloc(sizeof(context_t));
626     if(!ret) return NULL;
627 
628     memset(ret,0,sizeof(context_t));
629     ret->utils = utils;
630 #ifdef _SUN_SDK_
631     ret->gss_ctx = GSS_C_NO_CONTEXT;
632     ret->client_name = GSS_C_NO_NAME;
633     ret->server_name = GSS_C_NO_NAME;
634     ret->server_creds = GSS_C_NO_CREDENTIAL;
635     ret->client_creds = GSS_C_NO_CREDENTIAL;
636     if (get_oid(utils, &ret->mech_oid) != SASL_OK) {
637 	utils->free(ret);
638 	return (NULL);
639     }
640 #endif /* _SUN_SDK_ */
641 
642     ret->needsize = 4;
643 
644     return ret;
645 }
646 
647 static void sasl_gss_free_context_contents(context_t *text)
648 {
649     OM_uint32 maj_stat, min_stat;
650 
651     if (!text) return;
652 
653     if (text->gss_ctx != GSS_C_NO_CONTEXT) {
654 	maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
655 	text->gss_ctx = GSS_C_NO_CONTEXT;
656     }
657 
658     if (text->client_name != GSS_C_NO_NAME) {
659 	maj_stat = gss_release_name(&min_stat,&text->client_name);
660 	text->client_name = GSS_C_NO_NAME;
661     }
662 
663     if (text->server_name != GSS_C_NO_NAME) {
664 	maj_stat = gss_release_name(&min_stat,&text->server_name);
665 	text->server_name = GSS_C_NO_NAME;
666     }
667 
668     if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
669 	maj_stat = gss_release_cred(&min_stat, &text->server_creds);
670 	text->server_creds = GSS_C_NO_CREDENTIAL;
671     }
672 
673 #ifdef _SUN_SDK_
674     if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
675 	maj_stat = gss_release_cred(&min_stat, &text->client_creds);
676 	text->client_creds = GSS_C_NO_CREDENTIAL;
677     }
678 
679     /*
680      * Note that the oid returned by rpc_gss_mech_to_oid should not
681      * be released
682      */
683 #endif /* _SUN_SDK_ */
684 
685     if (text->out_buf) {
686 	text->utils->free(text->out_buf);
687 	text->out_buf = NULL;
688     }
689 
690     if (text->encode_buf) {
691 	text->utils->free(text->encode_buf);
692 	text->encode_buf = NULL;
693     }
694 
695     if (text->decode_buf) {
696 	text->utils->free(text->decode_buf);
697 	text->decode_buf = NULL;
698     }
699 
700     if (text->decode_once_buf) {
701 	text->utils->free(text->decode_once_buf);
702 	text->decode_once_buf = NULL;
703     }
704 
705     if (text->enc_in_buf) {
706 	if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
707 	text->utils->free(text->enc_in_buf);
708 	text->enc_in_buf = NULL;
709     }
710 
711     if (text->buffer) {
712 	text->utils->free(text->buffer);
713 	text->buffer = NULL;
714     }
715 
716     if (text->authid) { /* works for both client and server */
717 	text->utils->free(text->authid);
718 	text->authid = NULL;
719     }
720 }
721 
722 #ifdef _SUN_SDK_
723 
724 #ifdef HAVE_RPC_GSS_MECH_TO_OID
725 #include <rpc/rpcsec_gss.h>
726 #endif /* HAVE_RPC_GSS_MECH_TO_OID */
727 
728 static int
729 get_oid(const sasl_utils_t *utils, gss_OID *oid)
730 {
731 #ifdef HAVE_RPC_GSS_MECH_TO_OID
732     static gss_OID_desc kerb_v5 =
733 	{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
734 	/* 1.2.840.113554.1.2.2 */
735     *oid = &kerb_v5;
736 #endif /* HAVE_RPC_GSS_MECH_TO_OID */
737     return (SASL_OK);
738 }
739 
740 static int
741 add_mech_to_set(context_t *text, gss_OID_set *desired_mechs)
742 {
743     OM_uint32 maj_stat, min_stat;
744 
745     maj_stat = gss_create_empty_oid_set(&min_stat, desired_mechs);
746 
747     if (GSS_ERROR(maj_stat)) {
748 	sasl_gss_seterror(text->utils, maj_stat, min_stat);
749 	sasl_gss_free_context_contents(text);
750 	return SASL_FAIL;
751     }
752 
753     maj_stat = gss_add_oid_set_member(&min_stat, text->mech_oid, desired_mechs);
754     if (GSS_ERROR(maj_stat)) {
755 	sasl_gss_seterror(text->utils, maj_stat, min_stat);
756 	sasl_gss_free_context_contents(text);
757 	(void) gss_release_oid_set(&min_stat, desired_mechs);
758 	return SASL_FAIL;
759     }
760     return SASL_OK;
761 }
762 #endif /* _SUN_SDK_ */
763 
764 static void gssapi_common_mech_dispose(void *conn_context,
765 				       const sasl_utils_t *utils)
766 {
767 #ifdef _SUN_SDK_
768     if (conn_context == NULL)
769 	return;
770 #ifdef _INTEGRATED_SOLARIS_
771     convert_prompt(utils, &((context_t *)conn_context)->h, NULL);
772 #endif /* _INTEGRATED_SOLARIS_ */
773 #endif /* _SUN_SDK_ */
774 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
775     (void) LOCK_MUTEX(&global_mutex);
776 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
777     sasl_gss_free_context_contents((context_t *)(conn_context));
778 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
779     UNLOCK_MUTEX(&global_mutex);
780 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
781     utils->free(conn_context);
782 }
783 
784 /*****************************  Server Section  *****************************/
785 
786 static int
787 gssapi_server_mech_new(void *glob_context __attribute__((unused)),
788 		       sasl_server_params_t *params,
789 		       const char *challenge __attribute__((unused)),
790 		       unsigned challen __attribute__((unused)),
791 		       void **conn_context)
792 {
793     context_t *text;
794 
795 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
796     if (LOCK_MUTEX(&global_mutex) < 0)
797 	return (SASL_FAIL);
798 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
799     text = gss_new_context(params->utils);
800 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
801     UNLOCK_MUTEX(&global_mutex);
802 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
803     if (text == NULL) {
804 #ifndef _SUN_SDK_
805 	MEMERROR(params->utils);
806 #endif /* !_SUN_SDK_ */
807 	return SASL_NOMEM;
808     }
809 
810     text->gss_ctx = GSS_C_NO_CONTEXT;
811     text->client_name = GSS_C_NO_NAME;
812     text->server_name = GSS_C_NO_NAME;
813     text->server_creds = GSS_C_NO_CREDENTIAL;
814     text->state = SASL_GSSAPI_STATE_AUTHNEG;
815 
816     *conn_context = text;
817 
818     return SASL_OK;
819 }
820 
821 static int
822 gssapi_server_mech_step(void *conn_context,
823 			sasl_server_params_t *params,
824 			const char *clientin,
825 			unsigned clientinlen,
826 			const char **serverout,
827 			unsigned *serveroutlen,
828 			sasl_out_params_t *oparams)
829 {
830     context_t *text = (context_t *)conn_context;
831     gss_buffer_t input_token, output_token;
832     gss_buffer_desc real_input_token, real_output_token;
833     OM_uint32 maj_stat, min_stat;
834 #ifdef _SUN_SDK_
835     OM_uint32 max_input_size;
836     gss_OID_set desired_mechs = GSS_C_NULL_OID_SET;
837 #endif /* _SUN_SDK_ */
838     gss_buffer_desc name_token;
839     int ret;
840 
841     input_token = &real_input_token;
842     output_token = &real_output_token;
843     output_token->value = NULL; output_token->length = 0;
844     input_token->value = NULL; input_token->length = 0;
845 
846     if(!serverout) {
847 	PARAMERROR(text->utils);
848 	return SASL_BADPARAM;
849     }
850 
851     *serverout = NULL;
852     *serveroutlen = 0;
853 
854     switch (text->state) {
855 
856     case SASL_GSSAPI_STATE_AUTHNEG:
857 	if (text->server_name == GSS_C_NO_NAME) { /* only once */
858 	    name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
859 	    name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
860 	    if (name_token.value == NULL) {
861 		MEMERROR(text->utils);
862 		sasl_gss_free_context_contents(text);
863 		return SASL_NOMEM;
864 	    }
865 #ifdef _SUN_SDK_
866 	    snprintf(name_token.value, name_token.length + 1,
867 		"%s@%s", params->service, params->serverFQDN);
868 #else
869 	    sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
870 #endif /* _SUN_SDK_ */
871 
872 	    maj_stat = gss_import_name (&min_stat,
873 					&name_token,
874 					GSS_C_NT_HOSTBASED_SERVICE,
875 					&text->server_name);
876 
877 	    params->utils->free(name_token.value);
878 	    name_token.value = NULL;
879 
880 	    if (GSS_ERROR(maj_stat)) {
881 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
882 		sasl_gss_free_context_contents(text);
883 		return SASL_FAIL;
884 	    }
885 
886 	    if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
887 		maj_stat = gss_release_cred(&min_stat, &text->server_creds);
888 		text->server_creds = GSS_C_NO_CREDENTIAL;
889 	    }
890 
891 #ifdef _SUN_SDK_
892 	    if (text->mech_oid != GSS_C_NULL_OID) {
893 		ret = add_mech_to_set(text, &desired_mechs);
894 		if (ret != SASL_OK)
895 		    return (ret);
896 	    }
897 #endif /* _SUN_SDK_ */
898 
899 	    maj_stat = gss_acquire_cred(&min_stat,
900 					text->server_name,
901 					GSS_C_INDEFINITE,
902 #ifdef _SUN_SDK_
903 					desired_mechs,
904 #else
905 					GSS_C_NO_OID_SET,
906 #endif /* _SUN_SDK_ */
907 					GSS_C_ACCEPT,
908 					&text->server_creds,
909 					NULL,
910 					NULL);
911 
912 #ifdef _SUN_SDK_
913 	    if (desired_mechs != GSS_C_NULL_OID_SET) {
914 		OM_uint32 min_stat2;
915 		(void) gss_release_oid_set(&min_stat2, &desired_mechs);
916 	    }
917 #endif /* _SUN_SDK_ */
918 
919 	    if (GSS_ERROR(maj_stat)) {
920 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
921 		sasl_gss_free_context_contents(text);
922 		return SASL_FAIL;
923 	    }
924 	}
925 
926 	if (clientinlen) {
927 	    real_input_token.value = (void *)clientin;
928 	    real_input_token.length = clientinlen;
929 	}
930 
931 	maj_stat =
932 	    gss_accept_sec_context(&min_stat,
933 				   &(text->gss_ctx),
934 				   text->server_creds,
935 				   input_token,
936 				   GSS_C_NO_CHANNEL_BINDINGS,
937 				   &text->client_name,
938 				   NULL,
939 				   output_token,
940 				   NULL,
941 				   NULL,
942 				   NULL);
943 
944 	if (GSS_ERROR(maj_stat)) {
945 #ifdef _SUN_SDK_
946 	    /* log the local error info, set a more generic error */
947 	    sasl_gss_log(text->utils, maj_stat, min_stat);
948 	    text->utils->seterror(text->utils->conn, SASL_NOLOG,
949 		    gettext("GSSAPI Failure: accept security context error"));
950 	    if (output_token->value) {
951 		gss_release_buffer(&min_stat, output_token);
952 	    }
953 #else
954 	    if (output_token->value) {
955 		gss_release_buffer(&min_stat, output_token);
956 	    }
957 	    text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
958 	    text->utils->log(NULL, SASL_LOG_DEBUG, "GSSAPI Failure: gss_accept_sec_context");
959 #endif /* _SUN_SDK_ */
960 	    sasl_gss_free_context_contents(text);
961 	    return SASL_BADAUTH;
962 	}
963 
964 	if (serveroutlen)
965 	    *serveroutlen = output_token->length;
966 	if (output_token->value) {
967 	    if (serverout) {
968 		ret = _plug_buf_alloc(text->utils, &(text->out_buf),
969 				      &(text->out_buf_len), *serveroutlen);
970 		if(ret != SASL_OK) {
971 		    gss_release_buffer(&min_stat, output_token);
972 		    return ret;
973 		}
974 		memcpy(text->out_buf, output_token->value, *serveroutlen);
975 		*serverout = text->out_buf;
976 	    }
977 
978 	    gss_release_buffer(&min_stat, output_token);
979 	} else {
980 	    /* No output token, send an empty string */
981 	    *serverout = GSSAPI_BLANK_STRING;
982 #ifndef _SUN_SDK_
983 	    serveroutlen = 0;
984 #endif /* !_SUN_SDK_ */
985 	}
986 
987 
988 	if (maj_stat == GSS_S_COMPLETE) {
989 	    /* Switch to ssf negotiation */
990 	    text->state = SASL_GSSAPI_STATE_SSFCAP;
991 	}
992 
993 	return SASL_CONTINUE;
994 
995     case SASL_GSSAPI_STATE_SSFCAP: {
996 	unsigned char sasldata[4];
997 	gss_buffer_desc name_token;
998 #ifndef _SUN_SDK_
999 	gss_buffer_desc name_without_realm;
1000 	gss_name_t without = NULL;
1001 	int equal;
1002 #endif /* !_SUN_SDK_ */
1003 
1004 	name_token.value = NULL;
1005 #ifndef _SUN_SDK_
1006 	name_without_realm.value = NULL;
1007 #endif /* !_SUN_SDK_ */
1008 
1009 	/* We ignore whatever the client sent us at this stage */
1010 
1011 	maj_stat = gss_display_name (&min_stat,
1012 				     text->client_name,
1013 				     &name_token,
1014 				     NULL);
1015 
1016 	if (GSS_ERROR(maj_stat)) {
1017 #ifndef _SUN_SDK_
1018 	    if (name_without_realm.value)
1019 		params->utils->free(name_without_realm.value);
1020 #endif /* !_SUN_SDK_ */
1021 
1022 	    if (name_token.value)
1023 		gss_release_buffer(&min_stat, &name_token);
1024 #ifndef _SUN_SDK_
1025 	    if (without)
1026 		gss_release_name(&min_stat, &without);
1027 #endif /* !_SUN_SDK_ */
1028 #ifdef _INTEGRATED_SOLARIS_
1029 	    SETERROR(text->utils, gettext("GSSAPI Failure"));
1030 #else
1031 	    SETERROR(text->utils, "GSSAPI Failure");
1032 #endif /* _INTEGRATED_SOLARIS_ */
1033 	    sasl_gss_free_context_contents(text);
1034 	    return SASL_BADAUTH;
1035 	}
1036 
1037 #ifndef _SUN_SDK_
1038 	/* If the id contains a realm get the identifier for the user
1039 	   without the realm and see if it's the same id (i.e.
1040 	   tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
1041 	   to return the id (i.e. just "tmartin" */
1042 	if (strchr((char *) name_token.value, (int) '@') != NULL) {
1043 	    /* NOTE: libc malloc, as it is freed below by a gssapi internal
1044 	     *       function! */
1045 	    name_without_realm.value = malloc(strlen(name_token.value)+1);
1046 	    if (name_without_realm.value == NULL) {
1047 		MEMERROR(text->utils);
1048 		return SASL_NOMEM;
1049 	    }
1050 
1051 	    strcpy(name_without_realm.value, name_token.value);
1052 
1053 	    /* cut off string at '@' */
1054 	    (strchr(name_without_realm.value,'@'))[0] = '\0';
1055 
1056 	    name_without_realm.length = strlen( (char *) name_without_realm.value );
1057 
1058 	    maj_stat = gss_import_name (&min_stat,
1059 					&name_without_realm,
1060 	    /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
1061 	       so use GSS_C_NT_USER_NAME instead if available.  */
1062 #ifdef HAVE_GSS_C_NT_USER_NAME
1063 					GSS_C_NT_USER_NAME,
1064 #else
1065 					GSS_C_NULL_OID,
1066 #endif
1067 					&without);
1068 
1069 	    if (GSS_ERROR(maj_stat)) {
1070 		params->utils->free(name_without_realm.value);
1071 		if (name_token.value)
1072 		    gss_release_buffer(&min_stat, &name_token);
1073 		if (without)
1074 		    gss_release_name(&min_stat, &without);
1075 		SETERROR(text->utils, "GSSAPI Failure");
1076 		sasl_gss_free_context_contents(text);
1077 		return SASL_BADAUTH;
1078 	    }
1079 
1080 	    maj_stat = gss_compare_name(&min_stat,
1081 					text->client_name,
1082 					without,
1083 					&equal);
1084 
1085 	    if (GSS_ERROR(maj_stat)) {
1086 		params->utils->free(name_without_realm.value);
1087 		if (name_token.value)
1088 		    gss_release_buffer(&min_stat, &name_token);
1089 		if (without)
1090 		    gss_release_name(&min_stat, &without);
1091 		SETERROR(text->utils, "GSSAPI Failure");
1092 		sasl_gss_free_context_contents(text);
1093 		return SASL_BADAUTH;
1094 	    }
1095 
1096 	    gss_release_name(&min_stat,&without);
1097 	} else {
1098 	    equal = 0;
1099 	}
1100 
1101 	if (equal) {
1102 	    text->authid = strdup(name_without_realm.value);
1103 
1104 	    if (text->authid == NULL) {
1105 		MEMERROR(params->utils);
1106 		return SASL_NOMEM;
1107 	    }
1108 	} else {
1109 	    text->authid = strdup(name_token.value);
1110 
1111 	    if (text->authid == NULL) {
1112 		MEMERROR(params->utils);
1113 		return SASL_NOMEM;
1114 	    }
1115 	}
1116 #else
1117 	{
1118 	    ret = _plug_strdup(params->utils, name_token.value,
1119 		&text->authid, NULL);
1120 	}
1121 #endif /* _SUN_SDK_ */
1122 
1123 	if (name_token.value)
1124 	    gss_release_buffer(&min_stat, &name_token);
1125 
1126 #ifdef _SUN_SDK_
1127 	if (ret != SASL_OK)
1128 	    return (ret);
1129 #else
1130 	if (name_without_realm.value)
1131 	    params->utils->free(name_without_realm.value);
1132 #endif /* _SUN_SDK_ */
1133 
1134 
1135 	/* we have to decide what sort of encryption/integrity/etc.,
1136 	   we support */
1137 	if (params->props.max_ssf < params->external_ssf) {
1138 	    text->limitssf = 0;
1139 	} else {
1140 	    text->limitssf = params->props.max_ssf - params->external_ssf;
1141 	}
1142 	if (params->props.min_ssf < params->external_ssf) {
1143 	    text->requiressf = 0;
1144 	} else {
1145 	    text->requiressf = params->props.min_ssf - params->external_ssf;
1146 	}
1147 
1148 	/* build up our security properties token */
1149         if (params->props.maxbufsize > 0xFFFFFF) {
1150             /* make sure maxbufsize isn't too large */
1151             /* maxbufsize = 0xFFFFFF */
1152             sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
1153         } else {
1154             sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
1155             sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
1156             sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
1157         }
1158 	sasldata[0] = 0;
1159 	if(text->requiressf != 0 && !params->props.maxbufsize) {
1160 #ifdef _SUN_SDK_
1161 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
1162 		"GSSAPI needs a security layer but one is forbidden");
1163 #else
1164 	    params->utils->seterror(params->utils->conn, 0,
1165 				    "GSSAPI needs a security layer but one is forbidden");
1166 #endif /* _SUN_SDK_ */
1167 	    return SASL_TOOWEAK;
1168 	}
1169 
1170 	if (text->requiressf == 0) {
1171 	    sasldata[0] |= 1; /* authentication */
1172 	}
1173 	if (text->requiressf <= 1 && text->limitssf >= 1
1174 	    && params->props.maxbufsize) {
1175 	    sasldata[0] |= 2;
1176 	}
1177 	if (text->requiressf <= 56 && text->limitssf >= 56
1178 	    && params->props.maxbufsize) {
1179 	    sasldata[0] |= 4;
1180 	}
1181 
1182 	real_input_token.value = (void *)sasldata;
1183 	real_input_token.length = 4;
1184 
1185 	maj_stat = gss_wrap(&min_stat,
1186 			    text->gss_ctx,
1187 			    0, /* Just integrity checking here */
1188 			    GSS_C_QOP_DEFAULT,
1189 			    input_token,
1190 			    NULL,
1191 			    output_token);
1192 
1193 	if (GSS_ERROR(maj_stat)) {
1194 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
1195 	    if (output_token->value)
1196 		gss_release_buffer(&min_stat, output_token);
1197 	    sasl_gss_free_context_contents(text);
1198 	    return SASL_FAIL;
1199 	}
1200 
1201 
1202 	if (serveroutlen)
1203 	    *serveroutlen = output_token->length;
1204 	if (output_token->value) {
1205 	    if (serverout) {
1206 		ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1207 				      &(text->out_buf_len), *serveroutlen);
1208 		if(ret != SASL_OK) {
1209 		    gss_release_buffer(&min_stat, output_token);
1210 		    return ret;
1211 		}
1212 		memcpy(text->out_buf, output_token->value, *serveroutlen);
1213 		*serverout = text->out_buf;
1214 	    }
1215 
1216 	    gss_release_buffer(&min_stat, output_token);
1217 	}
1218 
1219 	/* Wait for ssf request and authid */
1220 	text->state = SASL_GSSAPI_STATE_SSFREQ;
1221 
1222 	return SASL_CONTINUE;
1223     }
1224 
1225     case SASL_GSSAPI_STATE_SSFREQ: {
1226 	int layerchoice;
1227 
1228 	real_input_token.value = (void *)clientin;
1229 	real_input_token.length = clientinlen;
1230 
1231 	maj_stat = gss_unwrap(&min_stat,
1232 			      text->gss_ctx,
1233 			      input_token,
1234 			      output_token,
1235 			      NULL,
1236 			      NULL);
1237 
1238 	if (GSS_ERROR(maj_stat)) {
1239 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
1240 	    sasl_gss_free_context_contents(text);
1241 	    return SASL_FAIL;
1242 	}
1243 
1244 	layerchoice = (int)(((char *)(output_token->value))[0]);
1245 	if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
1246 	    oparams->encode = NULL;
1247 	    oparams->decode = NULL;
1248 	    oparams->mech_ssf = 0;
1249 	} else if (layerchoice == 2 && text->requiressf <= 1 &&
1250 		   text->limitssf >= 1) { /* integrity */
1251 	    oparams->encode=&gssapi_integrity_encode;
1252 	    oparams->decode=&gssapi_decode;
1253 	    oparams->mech_ssf=1;
1254 	} else if (layerchoice == 4 && text->requiressf <= 56 &&
1255 		   text->limitssf >= 56) { /* privacy */
1256 	    oparams->encode = &gssapi_privacy_encode;
1257 	    oparams->decode = &gssapi_decode;
1258 	    oparams->mech_ssf = 56;
1259 	} else {
1260 	    /* not a supported encryption layer */
1261 #ifdef _SUN_SDK_
1262 	    text->utils->log(text->utils->conn, SASL_LOG_ERR,
1263 		"protocol violation: client requested invalid layer");
1264 #else
1265 	    SETERROR(text->utils,
1266 		     "protocol violation: client requested invalid layer");
1267 #endif /* _SUN_SDK_ */
1268 	    /* Mark that we attempted negotiation */
1269 	    oparams->mech_ssf = 2;
1270 	    if (output_token->value)
1271 		gss_release_buffer(&min_stat, output_token);
1272 	    sasl_gss_free_context_contents(text);
1273 	    return SASL_FAIL;
1274 	}
1275 
1276 	if (output_token->length > 4) {
1277 	    int ret;
1278 
1279 	    ret = params->canon_user(params->utils->conn,
1280 				     ((char *) output_token->value) + 4,
1281 				     (output_token->length - 4) * sizeof(char),
1282 				     SASL_CU_AUTHZID, oparams);
1283 
1284 	    if (ret != SASL_OK) {
1285 		sasl_gss_free_context_contents(text);
1286 		return ret;
1287 	    }
1288 
1289 	    ret = params->canon_user(params->utils->conn,
1290 				     text->authid,
1291 				     0, /* strlen(text->authid) */
1292 				     SASL_CU_AUTHID, oparams);
1293 	    if (ret != SASL_OK) {
1294 		sasl_gss_free_context_contents(text);
1295 		return ret;
1296 	    }
1297 	} else if(output_token->length == 4) {
1298 	    /* null authzid */
1299 	    int ret;
1300 
1301 	    ret = params->canon_user(params->utils->conn,
1302 				     text->authid,
1303 				     0, /* strlen(text->authid) */
1304 				     SASL_CU_AUTHZID | SASL_CU_AUTHID,
1305 				     oparams);
1306 
1307 	    if (ret != SASL_OK) {
1308 		sasl_gss_free_context_contents(text);
1309 		return ret;
1310 	    }
1311 	} else {
1312 #ifdef _SUN_SDK_
1313 	    text->utils->log(text->utils->conn, SASL_LOG_ERR,
1314 	    		     "token too short");
1315 #else
1316 	    SETERROR(text->utils,
1317 		     "token too short");
1318 #endif /* _SUN_SDK_ */
1319 	    gss_release_buffer(&min_stat, output_token);
1320 	    sasl_gss_free_context_contents(text);
1321 	    return SASL_FAIL;
1322 	}
1323 
1324 	/* No matter what, set the rest of the oparams */
1325         oparams->maxoutbuf =
1326 	    (((unsigned char *) output_token->value)[1] << 16) |
1327             (((unsigned char *) output_token->value)[2] << 8) |
1328             (((unsigned char *) output_token->value)[3] << 0);
1329 
1330 #ifdef _SUN_SDK_
1331 	if (oparams->mech_ssf) {
1332 	    oparams->maxoutbuf -= 4;	/* Allow for 4 byte tag */
1333 	    maj_stat = gss_wrap_size_limit(&min_stat,
1334 					text->gss_ctx,
1335 					oparams->mech_ssf > 1,
1336 					GSS_C_QOP_DEFAULT,
1337 					oparams->maxoutbuf,
1338 					&max_input_size);
1339 	    if (GSS_ERROR(maj_stat)) {
1340 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
1341 		(void) gss_release_buffer(&min_stat, output_token);
1342 		sasl_gss_free_context_contents(text);
1343 		return (SASL_FAIL);
1344 	    }
1345 
1346 	    /*
1347 	     * gss_wrap_size_limit will return very big sizes for
1348 	     * small input values
1349 	     */
1350 	    if (max_input_size < oparams->maxoutbuf)
1351  		oparams->maxoutbuf = max_input_size;
1352 	    else {
1353 		oparams->maxoutbuf = 0;
1354 	    }
1355 	}
1356 #else
1357 	if (oparams->mech_ssf) {
1358 	    /* xxx this is probably too big */
1359 	    oparams->maxoutbuf -= 50;
1360 	}
1361 #endif /* _SUN_SDK_ */
1362 
1363 	gss_release_buffer(&min_stat, output_token);
1364 
1365 	text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
1366 
1367 	oparams->doneflag = 1;
1368 
1369 	return SASL_OK;
1370     }
1371 
1372     default:
1373 #ifdef _SUN_SDK_
1374 	params->utils->log(text->utils->conn, SASL_LOG_ERR,
1375 			   "Invalid GSSAPI server step %d", text->state);
1376 #else
1377 	params->utils->log(NULL, SASL_LOG_ERR,
1378 			   "Invalid GSSAPI server step %d\n", text->state);
1379 #endif /* _SUN_SDK_ */
1380 	return SASL_FAIL;
1381     }
1382 
1383 #ifndef _SUN_SDK_
1384     return SASL_FAIL; /* should never get here */
1385 #endif /* !_SUN_SDK_ */
1386 }
1387 
1388 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1389 static int
1390 _gssapi_server_mech_step(void *conn_context,
1391 			sasl_server_params_t *params,
1392 			const char *clientin,
1393 			unsigned clientinlen,
1394 			const char **serverout,
1395 			unsigned *serveroutlen,
1396 			sasl_out_params_t *oparams)
1397 {
1398     int ret;
1399 
1400     if (LOCK_MUTEX(&global_mutex) < 0)
1401 	return (SASL_FAIL);
1402 
1403     ret = gssapi_server_mech_step(conn_context, params, clientin, clientinlen,
1404 	serverout, serveroutlen, oparams);
1405 
1406     UNLOCK_MUTEX(&global_mutex);
1407     return (ret);
1408 }
1409 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1410 
1411 static sasl_server_plug_t gssapi_server_plugins[] =
1412 {
1413     {
1414 	"GSSAPI",			/* mech_name */
1415 	56,				/* max_ssf */
1416 	SASL_SEC_NOPLAINTEXT
1417 	| SASL_SEC_NOACTIVE
1418 	| SASL_SEC_NOANONYMOUS
1419 	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
1420 	SASL_FEAT_WANT_CLIENT_FIRST
1421 	| SASL_FEAT_ALLOWS_PROXY,	/* features */
1422 	NULL,				/* glob_context */
1423 	&gssapi_server_mech_new,	/* mech_new */
1424 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1425 	&_gssapi_server_mech_step,	/* mech_step */
1426 #else
1427 	&gssapi_server_mech_step,	/* mech_step */
1428 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1429 	&gssapi_common_mech_dispose,	/* mech_dispose */
1430 	NULL,				/* mech_free */
1431 	NULL,				/* setpass */
1432 	NULL,				/* user_query */
1433 	NULL,				/* idle */
1434 	NULL,				/* mech_avail */
1435 	NULL				/* spare */
1436     }
1437 };
1438 
1439 int gssapiv2_server_plug_init(
1440 #ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1441     const sasl_utils_t *utils __attribute__((unused)),
1442 #else
1443     const sasl_utils_t *utils,
1444 #endif
1445     int maxversion,
1446     int *out_version,
1447     sasl_server_plug_t **pluglist,
1448     int *plugcount)
1449 {
1450 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1451     const char *keytab = NULL;
1452     char keytab_path[1024];
1453     unsigned int rl;
1454 #endif
1455 
1456     if (maxversion < SASL_SERVER_PLUG_VERSION) {
1457 	return SASL_BADVERS;
1458     }
1459 
1460 #ifndef _SUN_SDK_
1461 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
1462     /* unfortunately, we don't check for readability of keytab if it's
1463        the standard one, since we don't know where it is */
1464 
1465     /* FIXME: This code is broken */
1466 
1467     utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
1468     if (keytab != NULL) {
1469 	if (access(keytab, R_OK) != 0) {
1470 	    utils->log(NULL, SASL_LOG_ERR,
1471 		       "Could not find keytab file: %s: %m",
1472 		       keytab, errno);
1473 	    return SASL_FAIL;
1474 	}
1475 
1476 	if(strlen(keytab) > 1024) {
1477 	    utils->log(NULL, SASL_LOG_ERR,
1478 		       "path to keytab is > 1024 characters");
1479 	    return SASL_BUFOVER;
1480 	}
1481 
1482 	strncpy(keytab_path, keytab, 1024);
1483 
1484 	gsskrb5_register_acceptor_identity(keytab_path);
1485     }
1486 #endif
1487 #endif /* !_SUN_SDK_ */
1488 
1489     /* EXPORT DELETE START */
1490     /* CRYPT DELETE START */
1491 #ifdef _INTEGRATED_SOLARIS_
1492     /*
1493      * Let libsasl know that we are a "Sun" plugin so that privacy
1494      * and integrity will be allowed.
1495      */
1496     REG_PLUG("GSSAPI", gssapi_server_plugins);
1497 #endif /* _INTEGRATED_SOLARIS_ */
1498     /* CRYPT DELETE END */
1499     /* EXPORT DELETE END */
1500 
1501     *out_version = SASL_SERVER_PLUG_VERSION;
1502     *pluglist = gssapi_server_plugins;
1503     *plugcount = 1;
1504 
1505     return SASL_OK;
1506 }
1507 
1508 /*****************************  Client Section  *****************************/
1509 
1510 static int gssapi_client_mech_new(void *glob_context __attribute__((unused)),
1511 				  sasl_client_params_t *params,
1512 				  void **conn_context)
1513 {
1514     context_t *text;
1515 #ifdef _SUN_SDK_
1516     const char *use_authid = NULL;
1517 #endif /* _SUN_SDK_ */
1518 
1519     /* holds state are in */
1520 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1521     if (LOCK_MUTEX(&global_mutex) < 0)
1522 	return (SASL_FAIL);
1523 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1524     text = gss_new_context(params->utils);
1525 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
1526     UNLOCK_MUTEX(&global_mutex);
1527 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
1528     if (text == NULL) {
1529 #ifndef _SUN_SDK_
1530 	MEMERROR(params->utils);
1531 #endif /* !_SUN_SDK_ */
1532 	return SASL_NOMEM;
1533     }
1534 
1535     text->state = SASL_GSSAPI_STATE_AUTHNEG;
1536     text->gss_ctx = GSS_C_NO_CONTEXT;
1537     text->client_name = GSS_C_NO_NAME;
1538     text->server_creds = GSS_C_NO_CREDENTIAL;
1539 
1540 #ifdef _SUN_SDK_
1541     params->utils->getopt(params->utils->getopt_context,
1542 			  "GSSAPI", "use_authid", &use_authid, NULL);
1543     text->use_authid = (use_authid != NULL) &&
1544 	(*use_authid == 'y' || *use_authid == 'Y' || *use_authid == '1');
1545 #endif /* _SUN_SDK_ */
1546 
1547     *conn_context = text;
1548 
1549     return SASL_OK;
1550 }
1551 
1552 static int gssapi_client_mech_step(void *conn_context,
1553 				   sasl_client_params_t *params,
1554 				   const char *serverin,
1555 				   unsigned serverinlen,
1556 				   sasl_interact_t **prompt_need,
1557 				   const char **clientout,
1558 				   unsigned *clientoutlen,
1559 				   sasl_out_params_t *oparams)
1560 {
1561     context_t *text = (context_t *)conn_context;
1562     gss_buffer_t input_token, output_token;
1563     gss_buffer_desc real_input_token, real_output_token;
1564     OM_uint32 maj_stat, min_stat;
1565 #ifdef _SUN_SDK_
1566     OM_uint32 max_input_size;
1567 #endif /* _SUN_SDK_ */
1568     gss_buffer_desc name_token;
1569     int ret;
1570     OM_uint32 req_flags, out_req_flags;
1571     input_token = &real_input_token;
1572     output_token = &real_output_token;
1573     output_token->value = NULL;
1574     input_token->value = NULL;
1575     input_token->length = 0;
1576 
1577     *clientout = NULL;
1578     *clientoutlen = 0;
1579 
1580     switch (text->state) {
1581 
1582     case SASL_GSSAPI_STATE_AUTHNEG:
1583 	/* try to get the userid */
1584 #ifdef _SUN_SDK_
1585 	if (text->user == NULL ||
1586 		(text->use_authid && text->client_authid == NULL)) {
1587 	    int auth_result = SASL_OK;
1588 	    int user_result = SASL_OK;
1589 
1590 	    if (text->use_authid && text->client_authid == NULL) {
1591 		auth_result = _plug_get_authid(params->utils,
1592 					       &text->client_authid,
1593 					       prompt_need);
1594 
1595 		if ((auth_result != SASL_OK) &&
1596 			(auth_result != SASL_INTERACT)) {
1597 		    sasl_gss_free_context_contents(text);
1598 		    return auth_result;
1599 		}
1600 	    }
1601 	    if (text->user == NULL) {
1602 		user_result = _plug_get_userid(params->utils, &text->user,
1603 					       prompt_need);
1604 
1605 		if ((user_result != SASL_OK) &&
1606 			(user_result != SASL_INTERACT)) {
1607 		    sasl_gss_free_context_contents(text);
1608 		    return user_result;
1609 		}
1610 	    }
1611 #else
1612 	if (text->user == NULL) {
1613 	    int user_result = SASL_OK;
1614 
1615 	    user_result = _plug_get_userid(params->utils, &text->user,
1616 					   prompt_need);
1617 
1618 	    if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
1619 		sasl_gss_free_context_contents(text);
1620 		return user_result;
1621 	    }
1622 #endif /* _SUN_SDK_ */
1623 
1624 	    /* free prompts we got */
1625 	    if (prompt_need && *prompt_need) {
1626 		params->utils->free(*prompt_need);
1627 		*prompt_need = NULL;
1628 	    }
1629 
1630 	    /* if there are prompts not filled in */
1631 #ifdef _SUN_SDK_
1632 	    if ((user_result == SASL_INTERACT) ||
1633 			(auth_result == SASL_INTERACT)) {
1634 		/* make the prompt list */
1635 #ifdef _INTEGRATED_SOLARIS_
1636 		int result = _plug_make_prompts(params->utils, &text->h,
1637 			   prompt_need,
1638 			   user_result == SASL_INTERACT ?
1639 			   convert_prompt(params->utils, &text->h,
1640 			    gettext("Please enter your authorization name"))
1641 				: NULL, NULL,
1642 			   auth_result == SASL_INTERACT ?
1643 			   convert_prompt(params->utils, &text->h,
1644 			    gettext("Please enter your authentication name"))
1645 				: NULL, NULL,
1646 			   NULL, NULL,
1647 			   NULL, NULL, NULL,
1648 			   NULL, NULL, NULL);
1649 #else
1650 		int result = _plug_make_prompts(params->utils, prompt_need,
1651 			   user_result == SASL_INTERACT ?
1652 			   	"Please enter your authorization name"
1653 				: NULL, NULL,
1654 			   auth_result == SASL_INTERACT ?
1655 			   	"Please enter your authentication name"
1656 				: NULL, NULL,
1657 			   NULL, NULL,
1658 			   NULL, NULL, NULL,
1659 			   NULL, NULL, NULL);
1660 #endif /* _INTEGRATED_SOLARIS_ */
1661 
1662 		if (result != SASL_OK) return result;
1663 
1664 		return SASL_INTERACT;
1665 	    }
1666 #else
1667 	    if (user_result == SASL_INTERACT) {
1668 		/* make the prompt list */
1669 		int result =
1670 		    _plug_make_prompts(params->utils, prompt_need,
1671 				       user_result == SASL_INTERACT ?
1672 				       "Please enter your authorization name" : NULL, NULL,
1673 				       NULL, NULL,
1674 				       NULL, NULL,
1675 				       NULL, NULL, NULL,
1676 				       NULL, NULL, NULL);
1677 		if (result != SASL_OK) return result;
1678 
1679 		return SASL_INTERACT;
1680 	    }
1681 #endif /* _SUN_SDK_ */
1682 	}
1683 
1684 	if (text->server_name == GSS_C_NO_NAME) { /* only once */
1685 	    name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
1686 	    name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
1687 	    if (name_token.value == NULL) {
1688 		sasl_gss_free_context_contents(text);
1689 		return SASL_NOMEM;
1690 	    }
1691 	    if (params->serverFQDN == NULL
1692 		|| strlen(params->serverFQDN) == 0) {
1693 #ifdef _SUN_SDK_
1694 		text->utils->log(text->utils->conn, SASL_LOG_ERR,
1695 				 "GSSAPI Failure: no serverFQDN");
1696 #else
1697 		SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
1698 #endif /* _SUN_SDK_ */
1699 		return SASL_FAIL;
1700 	    }
1701 
1702 #ifdef _SUN_SDK_
1703 	    snprintf(name_token.value, name_token.length + 1,
1704 		"%s@%s", params->service, params->serverFQDN);
1705 #else
1706 	    sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
1707 #endif /* _SUN_SDK_ */
1708 
1709 	    maj_stat = gss_import_name (&min_stat,
1710 					&name_token,
1711 					GSS_C_NT_HOSTBASED_SERVICE,
1712 					&text->server_name);
1713 
1714 	    params->utils->free(name_token.value);
1715 	    name_token.value = NULL;
1716 
1717 	    if (GSS_ERROR(maj_stat)) {
1718 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
1719 		sasl_gss_free_context_contents(text);
1720 		return SASL_FAIL;
1721 	    }
1722 	}
1723 
1724 	if (serverinlen == 0)
1725 	    input_token = GSS_C_NO_BUFFER;
1726 
1727 	if (serverinlen) {
1728 	    real_input_token.value = (void *)serverin;
1729 	    real_input_token.length = serverinlen;
1730 	}
1731 	else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
1732 	    /* This can't happen under GSSAPI: we have a non-null context
1733 	     * and no input from the server.  However, thanks to Imap,
1734 	     * which discards our first output, this happens all the time.
1735 	     * Throw away the context and try again. */
1736 	    maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
1737 	    text->gss_ctx = GSS_C_NO_CONTEXT;
1738 	}
1739 
1740 	/* Setup req_flags properly */
1741 	req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
1742 	if(params->props.max_ssf > params->external_ssf) {
1743 	    /* We are requesting a security layer */
1744 	    req_flags |= GSS_C_INTEG_FLAG;
1745 	    if(params->props.max_ssf - params->external_ssf > 56) {
1746 		/* We want to try for privacy */
1747 		req_flags |= GSS_C_CONF_FLAG;
1748 	    }
1749 	}
1750 
1751 #ifdef _SUN_SDK_
1752 	if (text->use_authid && text->client_creds == GSS_C_NO_CREDENTIAL) {
1753 	    gss_OID_set desired_mechs = GSS_C_NULL_OID_SET;
1754 	    gss_buffer_desc name_token;
1755 
1756 	    name_token.length = strlen(text->client_authid);
1757 	    name_token.value = (char *)text->client_authid;
1758 
1759 	    maj_stat = gss_import_name (&min_stat,
1760 					&name_token,
1761 #ifdef HAVE_GSS_C_NT_USER_NAME
1762 					GSS_C_NT_USER_NAME,
1763 #else
1764 					GSS_C_NULL_OID,
1765 #endif
1766 					&text->client_name);
1767 	    if (GSS_ERROR(maj_stat)) {
1768 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
1769 		sasl_gss_free_context_contents(text);
1770 		return SASL_FAIL;
1771 	    }
1772 
1773 	    if (text->mech_oid != GSS_C_NULL_OID) {
1774 		ret = add_mech_to_set(text, &desired_mechs);
1775 		if (ret != SASL_OK)
1776 		    return (ret);
1777 	    }
1778 
1779 	    maj_stat = gss_acquire_cred(&min_stat,
1780 					text->client_name,
1781 					GSS_C_INDEFINITE,
1782 					desired_mechs,
1783 					GSS_C_INITIATE,
1784 					&text->client_creds,
1785 					NULL,
1786 					NULL);
1787 
1788 	    if (desired_mechs != GSS_C_NULL_OID_SET) {
1789 		OM_uint32 min_stat2;
1790 		(void) gss_release_oid_set(&min_stat2, &desired_mechs);
1791 	    }
1792 
1793 	    if (GSS_ERROR(maj_stat)) {
1794 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
1795 		sasl_gss_free_context_contents(text);
1796 		return SASL_FAIL;
1797 	    }
1798 	}
1799 #endif /* _SUN_SDK_ */
1800 
1801 	maj_stat = gss_init_sec_context(&min_stat,
1802 #ifdef _SUN_SDK_
1803 					text->client_creds,
1804 #else
1805 					GSS_C_NO_CREDENTIAL,
1806 #endif /* _SUN_SDK_ */
1807 					&text->gss_ctx,
1808 					text->server_name,
1809 #ifdef _SUN_SDK_
1810 					text->mech_oid,
1811 #else
1812 					GSS_C_NO_OID,
1813 #endif /* _SUN_SDK_ */
1814 					req_flags,
1815 					0,
1816 					GSS_C_NO_CHANNEL_BINDINGS,
1817 					input_token,
1818 					NULL,
1819 					output_token,
1820 					&out_req_flags,
1821 					NULL);
1822 
1823 	if (GSS_ERROR(maj_stat)) {
1824 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
1825 	    if (output_token->value)
1826 		gss_release_buffer(&min_stat, output_token);
1827 	    sasl_gss_free_context_contents(text);
1828 	    return SASL_FAIL;
1829 	}
1830 
1831 	*clientoutlen = output_token->length;
1832 
1833 	if (output_token->value) {
1834 	    if (clientout) {
1835 		ret = _plug_buf_alloc(text->utils, &(text->out_buf),
1836 				      &(text->out_buf_len), *clientoutlen);
1837 		if(ret != SASL_OK) {
1838 		    gss_release_buffer(&min_stat, output_token);
1839 		    return ret;
1840 		}
1841 		memcpy(text->out_buf, output_token->value, *clientoutlen);
1842 		*clientout = text->out_buf;
1843 	    }
1844 
1845 	    gss_release_buffer(&min_stat, output_token);
1846 	}
1847 
1848 	if (maj_stat == GSS_S_COMPLETE) {
1849 	    maj_stat = gss_inquire_context(&min_stat,
1850 					   text->gss_ctx,
1851 					   &text->client_name,
1852 					   NULL,       /* targ_name */
1853 					   NULL,       /* lifetime */
1854 					   NULL,       /* mech */
1855 					   NULL,       /* flags */
1856 					   NULL,       /* local init */
1857 					   NULL);      /* open */
1858 
1859 	    if (GSS_ERROR(maj_stat)) {
1860 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
1861 		sasl_gss_free_context_contents(text);
1862 		return SASL_FAIL;
1863 	    }
1864 
1865 	    name_token.length = 0;
1866 	    maj_stat = gss_display_name(&min_stat,
1867 					text->client_name,
1868 					&name_token,
1869 					NULL);
1870 
1871 	    if (GSS_ERROR(maj_stat)) {
1872 		if (name_token.value)
1873 		    gss_release_buffer(&min_stat, &name_token);
1874 #ifdef _INTEGRATED_SOLARIS_
1875 		SETERROR(text->utils, gettext("GSSAPI Failure"));
1876 #else
1877 		SETERROR(text->utils, "GSSAPI Failure");
1878 #endif /* _INTEGRATED_SOLARIS_ */
1879 		sasl_gss_free_context_contents(text);
1880 		return SASL_FAIL;
1881 	    }
1882 
1883 	    if (text->user && text->user[0]) {
1884 		ret = params->canon_user(params->utils->conn,
1885 					 text->user, 0,
1886 					 SASL_CU_AUTHZID, oparams);
1887 		if (ret == SASL_OK)
1888 		    ret = params->canon_user(params->utils->conn,
1889 					     name_token.value, 0,
1890 					     SASL_CU_AUTHID, oparams);
1891 	    } else {
1892 		ret = params->canon_user(params->utils->conn,
1893 					 name_token.value, 0,
1894 					 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1895 					 oparams);
1896 	    }
1897 	    gss_release_buffer(&min_stat, &name_token);
1898 
1899 	    if (ret != SASL_OK) return ret;
1900 
1901 	    /* Switch to ssf negotiation */
1902 	    text->state = SASL_GSSAPI_STATE_SSFCAP;
1903 	}
1904 
1905 	return SASL_CONTINUE;
1906 
1907     case SASL_GSSAPI_STATE_SSFCAP: {
1908 	sasl_security_properties_t *secprops = &(params->props);
1909 	unsigned int alen, external = params->external_ssf;
1910 	sasl_ssf_t need, allowed;
1911 	char serverhas, mychoice;
1912 
1913 	real_input_token.value = (void *) serverin;
1914 	real_input_token.length = serverinlen;
1915 
1916 	maj_stat = gss_unwrap(&min_stat,
1917 			      text->gss_ctx,
1918 			      input_token,
1919 			      output_token,
1920 			      NULL,
1921 			      NULL);
1922 
1923 	if (GSS_ERROR(maj_stat)) {
1924 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
1925 	    sasl_gss_free_context_contents(text);
1926 	    if (output_token->value)
1927 		gss_release_buffer(&min_stat, output_token);
1928 	    return SASL_FAIL;
1929 	}
1930 
1931 	/* taken from kerberos.c */
1932 	if (secprops->min_ssf > (56 + external)) {
1933 	    return SASL_TOOWEAK;
1934 	} else if (secprops->min_ssf > secprops->max_ssf) {
1935 	    return SASL_BADPARAM;
1936 	}
1937 
1938 	/* need bits of layer -- sasl_ssf_t is unsigned so be careful */
1939 	if (secprops->max_ssf >= external) {
1940 	    allowed = secprops->max_ssf - external;
1941 	} else {
1942 	    allowed = 0;
1943 	}
1944 	if (secprops->min_ssf >= external) {
1945 	    need = secprops->min_ssf - external;
1946 	} else {
1947 	    /* good to go */
1948 	    need = 0;
1949 	}
1950 
1951 	/* bit mask of server support */
1952 	serverhas = ((char *)output_token->value)[0];
1953 
1954 	/* if client didn't set use strongest layer available */
1955 	if (allowed >= 56 && need <= 56 && (serverhas & 4)) {
1956 	    /* encryption */
1957 	    oparams->encode = &gssapi_privacy_encode;
1958 	    oparams->decode = &gssapi_decode;
1959 	    oparams->mech_ssf = 56;
1960 	    mychoice = 4;
1961 	} else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
1962 	    /* integrity */
1963 	    oparams->encode = &gssapi_integrity_encode;
1964 	    oparams->decode = &gssapi_decode;
1965 	    oparams->mech_ssf = 1;
1966 	    mychoice = 2;
1967 #ifdef _SUN_SDK_
1968 	} else if (need == 0 && (serverhas & 1)) {
1969 #else
1970 	} else if (need <= 0 && (serverhas & 1)) {
1971 #endif /* _SUN_SDK_ */
1972 	    /* no layer */
1973 	    oparams->encode = NULL;
1974 	    oparams->decode = NULL;
1975 	    oparams->mech_ssf = 0;
1976 	    mychoice = 1;
1977 	} else {
1978 	    /* there's no appropriate layering for us! */
1979 	    sasl_gss_free_context_contents(text);
1980 	    return SASL_TOOWEAK;
1981 	}
1982 
1983         oparams->maxoutbuf =
1984 	    (((unsigned char *) output_token->value)[1] << 16) |
1985             (((unsigned char *) output_token->value)[2] << 8) |
1986             (((unsigned char *) output_token->value)[3] << 0);
1987 
1988 #ifdef _SUN_SDK_
1989 	if (oparams->mech_ssf > 0) {
1990 	    oparams->maxoutbuf -= 4;	/* Space for 4 byte length header */
1991 	    maj_stat = gss_wrap_size_limit(&min_stat,
1992 					text->gss_ctx,
1993 					oparams->mech_ssf > 1,
1994 					GSS_C_QOP_DEFAULT,
1995 					oparams->maxoutbuf,
1996 					&max_input_size);
1997 	    if (GSS_ERROR(maj_stat)) {
1998 		sasl_gss_seterror(text->utils, maj_stat, min_stat);
1999 		(void) gss_release_buffer(&min_stat, output_token);
2000 		sasl_gss_free_context_contents(text);
2001 		return (SASL_FAIL);
2002 	    }
2003 
2004 	/*
2005 	 * This is a workaround for a Solaris bug where
2006 	 * gss_wrap_size_limit may return very big sizes for
2007 	 * small input values
2008 	 */
2009 	    if (max_input_size < oparams->maxoutbuf)
2010  		oparams->maxoutbuf = max_input_size;
2011 	    else {
2012 		oparams->maxoutbuf = 0;
2013 	    }
2014 	}
2015 #else
2016 	if(oparams->mech_ssf) {
2017 	    /* xxx probably too large */
2018 	    oparams->maxoutbuf -= 50;
2019 	}
2020 #endif /* _SUN_SDK_ */
2021 
2022 	gss_release_buffer(&min_stat, output_token);
2023 
2024 	/* oparams->user is always set, due to canon_user requirements.
2025 	 * Make sure the client actually requested it though, by checking
2026 	 * if our context was set.
2027 	 */
2028 	if (text->user && text->user[0])
2029 	    alen = strlen(oparams->user);
2030 	else
2031 	    alen = 0;
2032 
2033 	input_token->length = 4 + alen;
2034 	input_token->value =
2035 	    (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
2036 	if (input_token->value == NULL) {
2037 	    sasl_gss_free_context_contents(text);
2038 	    return SASL_NOMEM;
2039 	}
2040 
2041 	if (alen)
2042 	    memcpy((char *)input_token->value+4,oparams->user,alen);
2043 
2044 	/* build up our security properties token */
2045         if (params->props.maxbufsize > 0xFFFFFF) {
2046             /* make sure maxbufsize isn't too large */
2047             /* maxbufsize = 0xFFFFFF */
2048             ((unsigned char *)input_token->value)[1] = 0xFF;
2049             ((unsigned char *)input_token->value)[2] = 0xFF;
2050             ((unsigned char *)input_token->value)[3] = 0xFF;
2051         } else {
2052             ((unsigned char *)input_token->value)[1] =
2053                 (params->props.maxbufsize >> 16) & 0xFF;
2054             ((unsigned char *)input_token->value)[2] =
2055                 (params->props.maxbufsize >> 8) & 0xFF;
2056             ((unsigned char *)input_token->value)[3] =
2057                 (params->props.maxbufsize >> 0) & 0xFF;
2058         }
2059 	((unsigned char *)input_token->value)[0] = mychoice;
2060 
2061 	maj_stat = gss_wrap (&min_stat,
2062 			     text->gss_ctx,
2063 			     0, /* Just integrity checking here */
2064 			     GSS_C_QOP_DEFAULT,
2065 			     input_token,
2066 			     NULL,
2067 			     output_token);
2068 
2069 	params->utils->free(input_token->value);
2070 	input_token->value = NULL;
2071 
2072 	if (GSS_ERROR(maj_stat)) {
2073 	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
2074 	    if (output_token->value)
2075 		gss_release_buffer(&min_stat, output_token);
2076 	    sasl_gss_free_context_contents(text);
2077 	    return SASL_FAIL;
2078 	}
2079 
2080 	if (clientoutlen)
2081 	    *clientoutlen = output_token->length;
2082 	if (output_token->value) {
2083 	    if (clientout) {
2084 		ret = _plug_buf_alloc(text->utils, &(text->out_buf),
2085 				      &(text->out_buf_len), *clientoutlen);
2086 		if (ret != SASL_OK) {
2087 		    gss_release_buffer(&min_stat, output_token);
2088 		    return ret;
2089 		}
2090 		memcpy(text->out_buf, output_token->value, *clientoutlen);
2091 		*clientout = text->out_buf;
2092 	    }
2093 
2094 	    gss_release_buffer(&min_stat, output_token);
2095 	}
2096 
2097 	text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
2098 
2099 	oparams->doneflag = 1;
2100 
2101 	return SASL_OK;
2102     }
2103 
2104     default:
2105 #ifdef _SUN_SDK_
2106 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
2107 			   "Invalid GSSAPI client step %d", text->state);
2108 #else
2109 	params->utils->log(NULL, SASL_LOG_ERR,
2110 			   "Invalid GSSAPI client step %d\n", text->state);
2111 #endif /* _SUN_SDK_ */
2112 	return SASL_FAIL;
2113     }
2114 
2115 #ifndef _SUN_SDK_
2116     return SASL_FAIL; /* should never get here */
2117 #endif /* !_SUN_SDK_ */
2118 }
2119 
2120 #ifdef _SUN_SDK_
2121 static const unsigned long gssapi_required_prompts[] = {
2122 #else
2123 static const long gssapi_required_prompts[] = {
2124 #endif /* _SUN_SDK_ */
2125     SASL_CB_LIST_END
2126 };
2127 
2128 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
2129 static int _gssapi_client_mech_step(void *conn_context,
2130 				   sasl_client_params_t *params,
2131 				   const char *serverin,
2132 				   unsigned serverinlen,
2133 				   sasl_interact_t **prompt_need,
2134 				   const char **clientout,
2135 				   unsigned *clientoutlen,
2136 				   sasl_out_params_t *oparams)
2137 {
2138     int ret;
2139 
2140     if (LOCK_MUTEX(&global_mutex) < 0)
2141 	return (SASL_FAIL);
2142 
2143     ret = gssapi_client_mech_step(conn_context, params, serverin, serverinlen,
2144 	prompt_need, clientout, clientoutlen, oparams);
2145 
2146     UNLOCK_MUTEX(&global_mutex);
2147     return (ret);
2148 }
2149 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
2150 
2151 static sasl_client_plug_t gssapi_client_plugins[] =
2152 {
2153     {
2154 	"GSSAPI",			/* mech_name */
2155 	56,				/* max_ssf */
2156 	SASL_SEC_NOPLAINTEXT
2157 	| SASL_SEC_NOACTIVE
2158 	| SASL_SEC_NOANONYMOUS
2159 	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
2160 	SASL_FEAT_WANT_CLIENT_FIRST
2161 	| SASL_FEAT_ALLOWS_PROXY,	/* features */
2162 	gssapi_required_prompts,	/* required_prompts */
2163 	NULL,				/* glob_context */
2164 	&gssapi_client_mech_new,	/* mech_new */
2165 #if defined _SUN_SDK_ && defined GSSAPI_PROTECT
2166 	&_gssapi_client_mech_step,	/* mech_step */
2167 #else
2168 	&gssapi_client_mech_step,	/* mech_step */
2169 #endif /* _SUN_SDK_ && GSSAPI_PROTECT */
2170 	&gssapi_common_mech_dispose,	/* mech_dispose */
2171 	NULL,				/* mech_free */
2172 	NULL,				/* idle */
2173 	NULL,				/* spare */
2174 	NULL				/* spare */
2175     }
2176 };
2177 
2178 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
2179 			      int maxversion,
2180 			      int *out_version,
2181 			      sasl_client_plug_t **pluglist,
2182 			      int *plugcount)
2183 {
2184     if (maxversion < SASL_CLIENT_PLUG_VERSION) {
2185 	SETERROR(utils, "Version mismatch in GSSAPI");
2186 	return SASL_BADVERS;
2187     }
2188 
2189     /* EXPORT DELETE START */
2190     /* CRYPT DELETE START */
2191 #ifdef _INTEGRATED_SOLARIS_
2192     /*
2193      * Let libsasl know that we are a "Sun" plugin so that privacy
2194      * and integrity will be allowed.
2195      */
2196     REG_PLUG("GSSAPI", gssapi_client_plugins);
2197 #endif /* _INTEGRATED_SOLARIS_ */
2198     /* CRYPT DELETE END */
2199     /* EXPORT DELETE END */
2200 
2201     *out_version = SASL_CLIENT_PLUG_VERSION;
2202     *pluglist = gssapi_client_plugins;
2203     *plugcount = 1;
2204 
2205     return SASL_OK;
2206 }
2207