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