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