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
sasl_gss_seterror_(const context_t * text,OM_uint32 maj,OM_uint32 min,int logonly)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
sasl_gss_encode(void * context,const struct iovec * invec,unsigned numiov,const char ** output,unsigned * outputlen,int privacy)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
gssapi_privacy_encode(void * context,const struct iovec * invec,unsigned numiov,const char ** output,unsigned * outputlen)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
gssapi_integrity_encode(void * context,const struct iovec * invec,unsigned numiov,const char ** output,unsigned * outputlen)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
gssapi_decode_once(void * context,const char ** input,unsigned * inputlen,char ** output,unsigned * outputlen)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