00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 #ifdef GSSAPI
00129
00130
00131
00132
00133
00134
00135
00136
00137 #include <config.h>
00138
00139 #include <stdlib.h>
00140 #include <errno.h>
00141
00142 #include <isc/buffer.h>
00143 #include <isc/dir.h>
00144 #include <isc/entropy.h>
00145 #include <isc/lex.h>
00146 #include <isc/mem.h>
00147 #include <isc/once.h>
00148 #include <isc/random.h>
00149 #include <isc/string.h>
00150 #include <isc/time.h>
00151 #include <isc/util.h>
00152
00153 #include <dns/fixedname.h>
00154 #include <dns/name.h>
00155 #include <dns/rdata.h>
00156 #include <dns/rdataclass.h>
00157 #include <dns/result.h>
00158 #include <dns/types.h>
00159 #include <dns/keyvalues.h>
00160 #include <dns/log.h>
00161
00162 #include <dst/gssapi.h>
00163 #include <dst/result.h>
00164
00165 #include "dst_internal.h"
00166
00167
00168
00169
00170 #include "spnego.h"
00171
00172
00173
00174
00175 #ifndef ERROR_TABLE_BASE_asn1
00176
00177 typedef enum asn1_error_number {
00178 ASN1_BAD_TIMEFORMAT = 1859794432,
00179 ASN1_MISSING_FIELD = 1859794433,
00180 ASN1_MISPLACED_FIELD = 1859794434,
00181 ASN1_TYPE_MISMATCH = 1859794435,
00182 ASN1_OVERFLOW = 1859794436,
00183 ASN1_OVERRUN = 1859794437,
00184 ASN1_BAD_ID = 1859794438,
00185 ASN1_BAD_LENGTH = 1859794439,
00186 ASN1_BAD_FORMAT = 1859794440,
00187 ASN1_PARSE_ERROR = 1859794441
00188 } asn1_error_number;
00189
00190 #define ERROR_TABLE_BASE_asn1 1859794432
00191 #endif
00192
00193 #define __asn1_common_definitions__
00194
00195 typedef struct octet_string {
00196 size_t length;
00197 void *data;
00198 } octet_string;
00199
00200 typedef char *general_string;
00201
00202 typedef char *utf8_string;
00203
00204 typedef struct oid {
00205 size_t length;
00206 unsigned *components;
00207 } oid;
00208
00209
00210
00211 typedef enum {
00212 ASN1_C_UNIV = 0, ASN1_C_APPL = 1,
00213 ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3
00214 } Der_class;
00215
00216 typedef enum {
00217 PRIM = 0, CONS = 1
00218 } Der_type;
00219
00220
00221
00222 enum {
00223 UT_Boolean = 1,
00224 UT_Integer = 2,
00225 UT_BitString = 3,
00226 UT_OctetString = 4,
00227 UT_Null = 5,
00228 UT_OID = 6,
00229 UT_Enumerated = 10,
00230 UT_Sequence = 16,
00231 UT_Set = 17,
00232 UT_PrintableString = 19,
00233 UT_IA5String = 22,
00234 UT_UTCTime = 23,
00235 UT_GeneralizedTime = 24,
00236 UT_VisibleString = 26,
00237 UT_GeneralString = 27
00238 };
00239
00240 #define ASN1_INDEFINITE 0xdce0deed
00241
00242 static int
00243 der_get_length(const unsigned char *p, size_t len,
00244 size_t * val, size_t * size);
00245
00246 static int
00247 der_get_octet_string(const unsigned char *p, size_t len,
00248 octet_string * data, size_t * size);
00249 static int
00250 der_get_oid(const unsigned char *p, size_t len,
00251 oid * data, size_t * size);
00252 static int
00253 der_get_tag(const unsigned char *p, size_t len,
00254 Der_class * class, Der_type * type,
00255 int *tag, size_t * size);
00256
00257 static int
00258 der_match_tag(const unsigned char *p, size_t len,
00259 Der_class class, Der_type type,
00260 int tag, size_t * size);
00261 static int
00262 der_match_tag_and_length(const unsigned char *p, size_t len,
00263 Der_class class, Der_type type, int tag,
00264 size_t * length_ret, size_t * size);
00265
00266 static int
00267 decode_oid(const unsigned char *p, size_t len,
00268 oid * k, size_t * size);
00269
00270 static int
00271 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size);
00272
00273 static int
00274 decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *);
00275
00276 static int
00277 der_put_int(unsigned char *p, size_t len, int val, size_t *);
00278
00279 static int
00280 der_put_length(unsigned char *p, size_t len, size_t val, size_t *);
00281
00282 static int
00283 der_put_octet_string(unsigned char *p, size_t len,
00284 const octet_string * data, size_t *);
00285 static int
00286 der_put_oid(unsigned char *p, size_t len,
00287 const oid * data, size_t * size);
00288 static int
00289 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
00290 int tag, size_t *);
00291 static int
00292 der_put_length_and_tag(unsigned char *, size_t, size_t,
00293 Der_class, Der_type, int, size_t *);
00294
00295 static int
00296 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *);
00297
00298 static int
00299 encode_octet_string(unsigned char *p, size_t len,
00300 const octet_string * k, size_t *);
00301 static int
00302 encode_oid(unsigned char *p, size_t len,
00303 const oid * k, size_t *);
00304
00305 static void
00306 free_octet_string(octet_string * k);
00307
00308 static void
00309 free_oid (oid * k);
00310
00311 static size_t
00312 length_len(size_t len);
00313
00314 static int
00315 fix_dce(size_t reallen, size_t * len);
00316
00317
00318
00319
00320
00321 #include "spnego_asn1.c"
00322
00323 static unsigned char gss_krb5_mech_oid_bytes[] = {
00324 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
00325 };
00326
00327 static gss_OID_desc gss_krb5_mech_oid_desc = {
00328 sizeof(gss_krb5_mech_oid_bytes),
00329 gss_krb5_mech_oid_bytes
00330 };
00331
00332 static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc;
00333
00334 static unsigned char gss_mskrb5_mech_oid_bytes[] = {
00335 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
00336 };
00337
00338 static gss_OID_desc gss_mskrb5_mech_oid_desc = {
00339 sizeof(gss_mskrb5_mech_oid_bytes),
00340 gss_mskrb5_mech_oid_bytes
00341 };
00342
00343 static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc;
00344
00345 static unsigned char gss_spnego_mech_oid_bytes[] = {
00346 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
00347 };
00348
00349 static gss_OID_desc gss_spnego_mech_oid_desc = {
00350 sizeof(gss_spnego_mech_oid_bytes),
00351 gss_spnego_mech_oid_bytes
00352 };
00353
00354 static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc;
00355
00356
00357
00358 static OM_uint32
00359 gssapi_spnego_encapsulate(OM_uint32 *,
00360 unsigned char *,
00361 size_t,
00362 gss_buffer_t,
00363 const gss_OID);
00364
00365 static OM_uint32
00366 gssapi_spnego_decapsulate(OM_uint32 *,
00367 gss_buffer_t,
00368 unsigned char **,
00369 size_t *,
00370 const gss_OID);
00371
00372
00373
00374 static int
00375 cmp_gss_type(gss_buffer_t token, gss_OID gssoid)
00376 {
00377 unsigned char *p;
00378 size_t len;
00379
00380 if (token->length == 0U)
00381 return (GSS_S_DEFECTIVE_TOKEN);
00382
00383 p = token->value;
00384 if (*p++ != 0x60)
00385 return (GSS_S_DEFECTIVE_TOKEN);
00386 len = *p++;
00387 if (len & 0x80) {
00388 if ((len & 0x7f) > 4U)
00389 return (GSS_S_DEFECTIVE_TOKEN);
00390 p += len & 0x7f;
00391 }
00392 if (*p++ != 0x06)
00393 return (GSS_S_DEFECTIVE_TOKEN);
00394
00395 if (((OM_uint32) *p++) != gssoid->length)
00396 return (GSS_S_DEFECTIVE_TOKEN);
00397
00398 return (memcmp(p, gssoid->elements, gssoid->length));
00399 }
00400
00401
00402
00403
00404
00405
00406
00407 static OM_uint32
00408 code_NegTokenArg(OM_uint32 * minor_status,
00409 const NegTokenResp * resp,
00410 unsigned char **outbuf,
00411 size_t * outbuf_size)
00412 {
00413 OM_uint32 ret;
00414 u_char *buf;
00415 size_t buf_size, buf_len = 0;
00416
00417 buf_size = 1024;
00418 buf = malloc(buf_size);
00419 if (buf == NULL) {
00420 *minor_status = ENOMEM;
00421 return (GSS_S_FAILURE);
00422 }
00423 do {
00424 ret = encode_NegTokenResp(buf + buf_size - 1,
00425 buf_size,
00426 resp, &buf_len);
00427 if (ret == 0) {
00428 size_t tmp;
00429
00430 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
00431 buf_size - buf_len,
00432 buf_len,
00433 ASN1_C_CONTEXT,
00434 CONS,
00435 1,
00436 &tmp);
00437 if (ret == 0)
00438 buf_len += tmp;
00439 }
00440 if (ret) {
00441 if (ret == ASN1_OVERFLOW) {
00442 u_char *tmp;
00443
00444 buf_size *= 2;
00445 tmp = realloc(buf, buf_size);
00446 if (tmp == NULL) {
00447 *minor_status = ENOMEM;
00448 free(buf);
00449 return (GSS_S_FAILURE);
00450 }
00451 buf = tmp;
00452 } else {
00453 *minor_status = ret;
00454 free(buf);
00455 return (GSS_S_FAILURE);
00456 }
00457 }
00458 } while (ret == ASN1_OVERFLOW);
00459
00460 *outbuf = malloc(buf_len);
00461 if (*outbuf == NULL) {
00462 *minor_status = ENOMEM;
00463 free(buf);
00464 return (GSS_S_FAILURE);
00465 }
00466 memmove(*outbuf, buf + buf_size - buf_len, buf_len);
00467 *outbuf_size = buf_len;
00468
00469 free(buf);
00470
00471 return (GSS_S_COMPLETE);
00472 }
00473
00474 static OM_uint32
00475 send_reject(OM_uint32 * minor_status,
00476 gss_buffer_t output_token)
00477 {
00478 NegTokenResp resp;
00479 OM_uint32 ret;
00480
00481 resp.negState = malloc(sizeof(*resp.negState));
00482 if (resp.negState == NULL) {
00483 *minor_status = ENOMEM;
00484 return (GSS_S_FAILURE);
00485 }
00486 *(resp.negState) = reject;
00487
00488 resp.supportedMech = NULL;
00489 resp.responseToken = NULL;
00490 resp.mechListMIC = NULL;
00491
00492 ret = code_NegTokenArg(minor_status, &resp,
00493 (unsigned char **)&output_token->value,
00494 &output_token->length);
00495 free_NegTokenResp(&resp);
00496 if (ret)
00497 return (ret);
00498
00499 return (GSS_S_BAD_MECH);
00500 }
00501
00502 static OM_uint32
00503 send_accept(OM_uint32 * minor_status,
00504 gss_buffer_t output_token,
00505 gss_buffer_t mech_token,
00506 const gss_OID pref)
00507 {
00508 NegTokenResp resp;
00509 OM_uint32 ret;
00510
00511 memset(&resp, 0, sizeof(resp));
00512 resp.negState = malloc(sizeof(*resp.negState));
00513 if (resp.negState == NULL) {
00514 *minor_status = ENOMEM;
00515 return (GSS_S_FAILURE);
00516 }
00517 *(resp.negState) = accept_completed;
00518
00519 resp.supportedMech = malloc(sizeof(*resp.supportedMech));
00520 if (resp.supportedMech == NULL) {
00521 free_NegTokenResp(&resp);
00522 *minor_status = ENOMEM;
00523 return (GSS_S_FAILURE);
00524 }
00525 ret = der_get_oid(pref->elements,
00526 pref->length,
00527 resp.supportedMech,
00528 NULL);
00529 if (ret) {
00530 free_NegTokenResp(&resp);
00531 *minor_status = ENOMEM;
00532 return (GSS_S_FAILURE);
00533 }
00534 if (mech_token != NULL && mech_token->length != 0U) {
00535 resp.responseToken = malloc(sizeof(*resp.responseToken));
00536 if (resp.responseToken == NULL) {
00537 free_NegTokenResp(&resp);
00538 *minor_status = ENOMEM;
00539 return (GSS_S_FAILURE);
00540 }
00541 resp.responseToken->length = mech_token->length;
00542 resp.responseToken->data = mech_token->value;
00543 }
00544
00545 ret = code_NegTokenArg(minor_status, &resp,
00546 (unsigned char **)&output_token->value,
00547 &output_token->length);
00548 if (resp.responseToken != NULL) {
00549 free(resp.responseToken);
00550 resp.responseToken = NULL;
00551 }
00552 free_NegTokenResp(&resp);
00553 if (ret)
00554 return (ret);
00555
00556 return (GSS_S_COMPLETE);
00557 }
00558
00559 OM_uint32
00560 gss_accept_sec_context_spnego(OM_uint32 *minor_status,
00561 gss_ctx_id_t *context_handle,
00562 const gss_cred_id_t acceptor_cred_handle,
00563 const gss_buffer_t input_token_buffer,
00564 const gss_channel_bindings_t input_chan_bindings,
00565 gss_name_t *src_name,
00566 gss_OID *mech_type,
00567 gss_buffer_t output_token,
00568 OM_uint32 *ret_flags,
00569 OM_uint32 *time_rec,
00570 gss_cred_id_t *delegated_cred_handle)
00571 {
00572 NegTokenInit init_token;
00573 OM_uint32 major_status;
00574 OM_uint32 minor_status2;
00575 gss_buffer_desc ibuf, obuf;
00576 gss_buffer_t ot = NULL;
00577 gss_OID pref = GSS_KRB5_MECH;
00578 unsigned char *buf;
00579 size_t buf_size;
00580 size_t len, taglen, ni_len;
00581 int found = 0;
00582 int ret;
00583 unsigned i;
00584
00585
00586
00587
00588
00589
00590 if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH))
00591 return (gss_accept_sec_context(minor_status,
00592 context_handle,
00593 acceptor_cred_handle,
00594 input_token_buffer,
00595 input_chan_bindings,
00596 src_name,
00597 mech_type,
00598 output_token,
00599 ret_flags,
00600 time_rec,
00601 delegated_cred_handle));
00602
00603
00604
00605
00606
00607 memset(&init_token, 0, sizeof(init_token));
00608
00609 ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
00610 &buf, &buf_size, GSS_SPNEGO_MECH);
00611 if (ret)
00612 return (ret);
00613
00614 ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS,
00615 0, &len, &taglen);
00616 if (ret)
00617 return (ret);
00618
00619 ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
00620 if (ret) {
00621 *minor_status = EINVAL;
00622 return (GSS_S_DEFECTIVE_TOKEN);
00623 }
00624
00625 for (i = 0; !found && i < init_token.mechTypes.len; ++i) {
00626 unsigned char mechbuf[17];
00627 size_t mech_len;
00628
00629 ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1,
00630 sizeof(mechbuf),
00631 &init_token.mechTypes.val[i],
00632 &mech_len);
00633 if (ret) {
00634 free_NegTokenInit(&init_token);
00635 return (GSS_S_DEFECTIVE_TOKEN);
00636 }
00637 if (mech_len == GSS_KRB5_MECH->length &&
00638 memcmp(GSS_KRB5_MECH->elements,
00639 mechbuf + sizeof(mechbuf) - mech_len,
00640 mech_len) == 0) {
00641 found = 1;
00642 break;
00643 }
00644 if (mech_len == GSS_MSKRB5_MECH->length &&
00645 memcmp(GSS_MSKRB5_MECH->elements,
00646 mechbuf + sizeof(mechbuf) - mech_len,
00647 mech_len) == 0) {
00648 found = 1;
00649 if (i == 0)
00650 pref = GSS_MSKRB5_MECH;
00651 break;
00652 }
00653 }
00654
00655 if (!found) {
00656 free_NegTokenInit(&init_token);
00657 return (send_reject(minor_status, output_token));
00658 }
00659
00660 if (i == 0 && init_token.mechToken != NULL) {
00661 ibuf.length = init_token.mechToken->length;
00662 ibuf.value = init_token.mechToken->data;
00663
00664 major_status = gss_accept_sec_context(minor_status,
00665 context_handle,
00666 acceptor_cred_handle,
00667 &ibuf,
00668 input_chan_bindings,
00669 src_name,
00670 mech_type,
00671 &obuf,
00672 ret_flags,
00673 time_rec,
00674 delegated_cred_handle);
00675 if (GSS_ERROR(major_status)) {
00676 free_NegTokenInit(&init_token);
00677 send_reject(&minor_status2, output_token);
00678 return (major_status);
00679 }
00680 ot = &obuf;
00681 }
00682 ret = send_accept(&minor_status2, output_token, ot, pref);
00683 free_NegTokenInit(&init_token);
00684 if (ot != NULL && ot->length != 0U)
00685 gss_release_buffer(&minor_status2, ot);
00686
00687 return (ret);
00688 }
00689
00690
00691
00692 static OM_uint32
00693 gssapi_verify_mech_header(u_char ** str,
00694 size_t total_len,
00695 const gss_OID mech)
00696 {
00697 size_t len, len_len, mech_len, foo;
00698 int e;
00699 u_char *p = *str;
00700
00701 if (total_len < 1U)
00702 return (GSS_S_DEFECTIVE_TOKEN);
00703 if (*p++ != 0x60)
00704 return (GSS_S_DEFECTIVE_TOKEN);
00705 e = der_get_length(p, total_len - 1, &len, &len_len);
00706 if (e || 1 + len_len + len != total_len)
00707 return (GSS_S_DEFECTIVE_TOKEN);
00708 p += len_len;
00709 if (*p++ != 0x06)
00710 return (GSS_S_DEFECTIVE_TOKEN);
00711 e = der_get_length(p, total_len - 1 - len_len - 1,
00712 &mech_len, &foo);
00713 if (e)
00714 return (GSS_S_DEFECTIVE_TOKEN);
00715 p += foo;
00716 if (mech_len != mech->length)
00717 return (GSS_S_BAD_MECH);
00718 if (memcmp(p, mech->elements, mech->length) != 0)
00719 return (GSS_S_BAD_MECH);
00720 p += mech_len;
00721 *str = p;
00722 return (GSS_S_COMPLETE);
00723 }
00724
00725
00726
00727
00728
00729
00730 static OM_uint32
00731 gssapi_spnego_decapsulate(OM_uint32 *minor_status,
00732 gss_buffer_t input_token_buffer,
00733 unsigned char **buf,
00734 size_t *buf_len,
00735 const gss_OID mech)
00736 {
00737 u_char *p;
00738 OM_uint32 ret;
00739
00740 p = input_token_buffer->value;
00741 ret = gssapi_verify_mech_header(&p,
00742 input_token_buffer->length,
00743 mech);
00744 if (ret) {
00745 *minor_status = ret;
00746 return (GSS_S_FAILURE);
00747 }
00748 *buf_len = input_token_buffer->length -
00749 (p - (u_char *) input_token_buffer->value);
00750 *buf = p;
00751 return (GSS_S_COMPLETE);
00752 }
00753
00754
00755
00756 static void
00757 free_octet_string(octet_string *k)
00758 {
00759 free(k->data);
00760 k->data = NULL;
00761 }
00762
00763 static void
00764 free_oid(oid *k)
00765 {
00766 free(k->components);
00767 k->components = NULL;
00768 }
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779 static int
00780 der_get_unsigned(const unsigned char *p, size_t len,
00781 unsigned *ret, size_t *size)
00782 {
00783 unsigned val = 0;
00784 size_t oldlen = len;
00785
00786 while (len--)
00787 val = val * 256 + *p++;
00788 *ret = val;
00789 if (size)
00790 *size = oldlen;
00791 return (0);
00792 }
00793
00794 static int
00795 der_get_int(const unsigned char *p, size_t len,
00796 int *ret, size_t *size)
00797 {
00798 int val = 0;
00799 size_t oldlen = len;
00800
00801 if (len > 0U) {
00802 val = (signed char)*p++;
00803 while (--len)
00804 val = val * 256 + *p++;
00805 }
00806 *ret = val;
00807 if (size)
00808 *size = oldlen;
00809 return (0);
00810 }
00811
00812 static int
00813 der_get_length(const unsigned char *p, size_t len,
00814 size_t *val, size_t *size)
00815 {
00816 size_t v;
00817
00818 if (len <= 0U)
00819 return (ASN1_OVERRUN);
00820 --len;
00821 v = *p++;
00822 if (v < 128U) {
00823 *val = v;
00824 if (size)
00825 *size = 1;
00826 } else {
00827 int e;
00828 size_t l;
00829 unsigned tmp;
00830
00831 if (v == 0x80U) {
00832 *val = ASN1_INDEFINITE;
00833 if (size)
00834 *size = 1;
00835 return (0);
00836 }
00837 v &= 0x7F;
00838 if (len < v)
00839 return (ASN1_OVERRUN);
00840 e = der_get_unsigned(p, v, &tmp, &l);
00841 if (e)
00842 return (e);
00843 *val = tmp;
00844 if (size)
00845 *size = l + 1;
00846 }
00847 return (0);
00848 }
00849
00850 static int
00851 der_get_octet_string(const unsigned char *p, size_t len,
00852 octet_string *data, size_t *size)
00853 {
00854 data->length = len;
00855 if (len != 0U) {
00856 data->data = malloc(len);
00857 if (data->data == NULL)
00858 return (ENOMEM);
00859 memmove(data->data, p, len);
00860 } else
00861 data->data = NULL;
00862 if (size)
00863 *size = len;
00864 return (0);
00865 }
00866
00867 static int
00868 der_get_oid(const unsigned char *p, size_t len,
00869 oid *data, size_t *size)
00870 {
00871 int n;
00872 size_t oldlen = len;
00873
00874 data->components = NULL;
00875 data->length = 0;
00876 if (len < 1U)
00877 return (ASN1_OVERRUN);
00878
00879 data->components = malloc(len * sizeof(*data->components));
00880 if (data->components == NULL && len != 0U)
00881 return (ENOMEM);
00882 data->components[0] = (*p) / 40;
00883 data->components[1] = (*p) % 40;
00884 --len;
00885 ++p;
00886 for (n = 2; len > 0U; ++n) {
00887 unsigned u = 0;
00888
00889 do {
00890 --len;
00891 u = u * 128 + (*p++ % 128);
00892 } while (len > 0U && p[-1] & 0x80);
00893 data->components[n] = u;
00894 }
00895 if (p[-1] & 0x80) {
00896 free_oid(data);
00897 return (ASN1_OVERRUN);
00898 }
00899 data->length = n;
00900 if (size)
00901 *size = oldlen;
00902 return (0);
00903 }
00904
00905 static int
00906 der_get_tag(const unsigned char *p, size_t len,
00907 Der_class *class, Der_type *type,
00908 int *tag, size_t *size)
00909 {
00910 if (len < 1U)
00911 return (ASN1_OVERRUN);
00912 *class = (Der_class) (((*p) >> 6) & 0x03);
00913 *type = (Der_type) (((*p) >> 5) & 0x01);
00914 *tag = (*p) & 0x1F;
00915 if (size)
00916 *size = 1;
00917 return (0);
00918 }
00919
00920 static int
00921 der_match_tag(const unsigned char *p, size_t len,
00922 Der_class class, Der_type type,
00923 int tag, size_t *size)
00924 {
00925 size_t l;
00926 Der_class thisclass;
00927 Der_type thistype;
00928 int thistag;
00929 int e;
00930
00931 e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l);
00932 if (e)
00933 return (e);
00934 if (class != thisclass || type != thistype)
00935 return (ASN1_BAD_ID);
00936 if (tag > thistag)
00937 return (ASN1_MISPLACED_FIELD);
00938 if (tag < thistag)
00939 return (ASN1_MISSING_FIELD);
00940 if (size)
00941 *size = l;
00942 return (0);
00943 }
00944
00945 static int
00946 der_match_tag_and_length(const unsigned char *p, size_t len,
00947 Der_class class, Der_type type, int tag,
00948 size_t *length_ret, size_t *size)
00949 {
00950 size_t l, ret = 0;
00951 int e;
00952
00953 e = der_match_tag(p, len, class, type, tag, &l);
00954 if (e)
00955 return (e);
00956 p += l;
00957 len -= l;
00958 ret += l;
00959 e = der_get_length(p, len, length_ret, &l);
00960 if (e)
00961 return (e);
00962
00963 len -= l;
00964 POST(len);
00965 ret += l;
00966 if (size)
00967 *size = ret;
00968 return (0);
00969 }
00970
00971 static int
00972 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size)
00973 {
00974 size_t ret = 0;
00975 size_t l, reallen;
00976 int e;
00977
00978 e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
00979 if (e)
00980 return (e);
00981 p += l;
00982 len -= l;
00983 ret += l;
00984 e = der_get_length(p, len, &reallen, &l);
00985 if (e)
00986 return (e);
00987 p += l;
00988 len -= l;
00989 ret += l;
00990 e = der_get_int(p, reallen, num, &l);
00991 if (e)
00992 return (e);
00993 p += l;
00994 len -= l;
00995 POST(p); POST(len);
00996 ret += l;
00997 if (size)
00998 *size = ret;
00999 return (0);
01000 }
01001
01002 static int
01003 decode_octet_string(const unsigned char *p, size_t len,
01004 octet_string *k, size_t *size)
01005 {
01006 size_t ret = 0;
01007 size_t l;
01008 int e;
01009 size_t slen;
01010
01011 k->data = NULL;
01012 k->length = 0;
01013
01014 e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
01015 if (e)
01016 return (e);
01017 p += l;
01018 len -= l;
01019 ret += l;
01020
01021 e = der_get_length(p, len, &slen, &l);
01022 if (e)
01023 return (e);
01024 p += l;
01025 len -= l;
01026 ret += l;
01027 if (len < slen)
01028 return (ASN1_OVERRUN);
01029
01030 e = der_get_octet_string(p, slen, k, &l);
01031 if (e)
01032 return (e);
01033 p += l;
01034 len -= l;
01035 POST(p); POST(len);
01036 ret += l;
01037 if (size)
01038 *size = ret;
01039 return (0);
01040 }
01041
01042 static int
01043 decode_oid(const unsigned char *p, size_t len,
01044 oid *k, size_t *size)
01045 {
01046 size_t ret = 0;
01047 size_t l;
01048 int e;
01049 size_t slen;
01050
01051 e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l);
01052 if (e)
01053 return (e);
01054 p += l;
01055 len -= l;
01056 ret += l;
01057
01058 e = der_get_length(p, len, &slen, &l);
01059 if (e)
01060 return (e);
01061 p += l;
01062 len -= l;
01063 ret += l;
01064 if (len < slen)
01065 return (ASN1_OVERRUN);
01066
01067 e = der_get_oid(p, slen, k, &l);
01068 if (e)
01069 return (e);
01070 p += l;
01071 len -= l;
01072 POST(p); POST(len);
01073 ret += l;
01074 if (size)
01075 *size = ret;
01076 return (0);
01077 }
01078
01079 static int
01080 fix_dce(size_t reallen, size_t *len)
01081 {
01082 if (reallen == ASN1_INDEFINITE)
01083 return (1);
01084 if (*len < reallen)
01085 return (-1);
01086 *len = reallen;
01087 return (0);
01088 }
01089
01090
01091
01092 static size_t
01093 len_unsigned(unsigned val)
01094 {
01095 size_t ret = 0;
01096
01097 do {
01098 ++ret;
01099 val /= 256;
01100 } while (val);
01101 return (ret);
01102 }
01103
01104 static size_t
01105 length_len(size_t len)
01106 {
01107 if (len < 128U)
01108 return (1);
01109 else
01110 return (len_unsigned((unsigned int)len) + 1);
01111 }
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123 static int
01124 der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size)
01125 {
01126 unsigned char *base = p;
01127
01128 if (val) {
01129 while (len > 0U && val) {
01130 *p-- = val % 256;
01131 val /= 256;
01132 --len;
01133 }
01134 if (val != 0)
01135 return (ASN1_OVERFLOW);
01136 else {
01137 *size = base - p;
01138 return (0);
01139 }
01140 } else if (len < 1U)
01141 return (ASN1_OVERFLOW);
01142 else {
01143 *p = 0;
01144 *size = 1;
01145 return (0);
01146 }
01147 }
01148
01149 static int
01150 der_put_int(unsigned char *p, size_t len, int val, size_t *size)
01151 {
01152 unsigned char *base = p;
01153
01154 if (val >= 0) {
01155 do {
01156 if (len < 1U)
01157 return (ASN1_OVERFLOW);
01158 *p-- = val % 256;
01159 len--;
01160 val /= 256;
01161 } while (val);
01162 if (p[1] >= 128) {
01163 if (len < 1U)
01164 return (ASN1_OVERFLOW);
01165 *p-- = 0;
01166 len--;
01167 }
01168 } else {
01169 val = ~val;
01170 do {
01171 if (len < 1U)
01172 return (ASN1_OVERFLOW);
01173 *p-- = ~(val % 256);
01174 len--;
01175 val /= 256;
01176 } while (val);
01177 if (p[1] < 128) {
01178 if (len < 1U)
01179 return (ASN1_OVERFLOW);
01180 *p-- = 0xff;
01181 len--;
01182 }
01183 }
01184 *size = base - p;
01185 return (0);
01186 }
01187
01188 static int
01189 der_put_length(unsigned char *p, size_t len, size_t val, size_t *size)
01190 {
01191 if (len < 1U)
01192 return (ASN1_OVERFLOW);
01193 if (val < 128U) {
01194 *p = (unsigned char)val;
01195 *size = 1;
01196 return (0);
01197 } else {
01198 size_t l;
01199 int e;
01200
01201 e = der_put_unsigned(p, len - 1, (unsigned int)val, &l);
01202 if (e)
01203 return (e);
01204 p -= l;
01205 *p = 0x80 | (unsigned char)l;
01206 *size = l + 1;
01207 return (0);
01208 }
01209 }
01210
01211 static int
01212 der_put_octet_string(unsigned char *p, size_t len,
01213 const octet_string *data, size_t *size)
01214 {
01215 if (len < data->length)
01216 return (ASN1_OVERFLOW);
01217 p -= data->length;
01218 len -= data->length;
01219 POST(len);
01220 memmove(p + 1, data->data, data->length);
01221 *size = data->length;
01222 return (0);
01223 }
01224
01225 static int
01226 der_put_oid(unsigned char *p, size_t len,
01227 const oid *data, size_t *size)
01228 {
01229 unsigned char *base = p;
01230 size_t n;
01231
01232 for (n = data->length; n >= 3u; --n) {
01233 unsigned u = data->components[n - 1];
01234
01235 if (len < 1U)
01236 return (ASN1_OVERFLOW);
01237 *p-- = u % 128;
01238 u /= 128;
01239 --len;
01240 while (u > 0) {
01241 if (len < 1U)
01242 return (ASN1_OVERFLOW);
01243 *p-- = 128 + u % 128;
01244 u /= 128;
01245 --len;
01246 }
01247 }
01248 if (len < 1U)
01249 return (ASN1_OVERFLOW);
01250 *p-- = 40 * data->components[0] + data->components[1];
01251 *size = base - p;
01252 return (0);
01253 }
01254
01255 static int
01256 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
01257 int tag, size_t *size)
01258 {
01259 if (len < 1U)
01260 return (ASN1_OVERFLOW);
01261 *p = (class << 6) | (type << 5) | tag;
01262 *size = 1;
01263 return (0);
01264 }
01265
01266 static int
01267 der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val,
01268 Der_class class, Der_type type, int tag, size_t *size)
01269 {
01270 size_t ret = 0;
01271 size_t l;
01272 int e;
01273
01274 e = der_put_length(p, len, len_val, &l);
01275 if (e)
01276 return (e);
01277 p -= l;
01278 len -= l;
01279 ret += l;
01280 e = der_put_tag(p, len, class, type, tag, &l);
01281 if (e)
01282 return (e);
01283 p -= l;
01284 len -= l;
01285 POST(p); POST(len);
01286 ret += l;
01287 *size = ret;
01288 return (0);
01289 }
01290
01291 static int
01292 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size)
01293 {
01294 unsigned num = *(const unsigned *)data;
01295 size_t ret = 0;
01296 size_t l;
01297 int e;
01298
01299 e = der_put_int(p, len, num, &l);
01300 if (e)
01301 return (e);
01302 p -= l;
01303 len -= l;
01304 ret += l;
01305 e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
01306 if (e)
01307 return (e);
01308 p -= l;
01309 len -= l;
01310 POST(p); POST(len);
01311 ret += l;
01312 *size = ret;
01313 return (0);
01314 }
01315
01316 static int
01317 encode_octet_string(unsigned char *p, size_t len,
01318 const octet_string *k, size_t *size)
01319 {
01320 size_t ret = 0;
01321 size_t l;
01322 int e;
01323
01324 e = der_put_octet_string(p, len, k, &l);
01325 if (e)
01326 return (e);
01327 p -= l;
01328 len -= l;
01329 ret += l;
01330 e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
01331 if (e)
01332 return (e);
01333 p -= l;
01334 len -= l;
01335 POST(p); POST(len);
01336 ret += l;
01337 *size = ret;
01338 return (0);
01339 }
01340
01341 static int
01342 encode_oid(unsigned char *p, size_t len,
01343 const oid *k, size_t *size)
01344 {
01345 size_t ret = 0;
01346 size_t l;
01347 int e;
01348
01349 e = der_put_oid(p, len, k, &l);
01350 if (e)
01351 return (e);
01352 p -= l;
01353 len -= l;
01354 ret += l;
01355 e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l);
01356 if (e)
01357 return (e);
01358 p -= l;
01359 len -= l;
01360 POST(p); POST(len);
01361 ret += l;
01362 *size = ret;
01363 return (0);
01364 }
01365
01366
01367
01368
01369 static void
01370 gssapi_encap_length(size_t data_len,
01371 size_t *len,
01372 size_t *total_len,
01373 const gss_OID mech)
01374 {
01375 size_t len_len;
01376
01377 *len = 1 + 1 + mech->length + data_len;
01378
01379 len_len = length_len(*len);
01380
01381 *total_len = 1 + len_len + *len;
01382 }
01383
01384 static u_char *
01385 gssapi_mech_make_header(u_char *p,
01386 size_t len,
01387 const gss_OID mech)
01388 {
01389 int e;
01390 size_t len_len, foo;
01391
01392 *p++ = 0x60;
01393 len_len = length_len(len);
01394 e = der_put_length(p + len_len - 1, len_len, len, &foo);
01395 if (e || foo != len_len)
01396 return (NULL);
01397 p += len_len;
01398 *p++ = 0x06;
01399 *p++ = mech->length;
01400 memmove(p, mech->elements, mech->length);
01401 p += mech->length;
01402 return (p);
01403 }
01404
01405
01406
01407
01408
01409 static OM_uint32
01410 gssapi_spnego_encapsulate(OM_uint32 * minor_status,
01411 unsigned char *buf,
01412 size_t buf_size,
01413 gss_buffer_t output_token,
01414 const gss_OID mech)
01415 {
01416 size_t len, outer_len;
01417 u_char *p;
01418
01419 gssapi_encap_length(buf_size, &len, &outer_len, mech);
01420
01421 output_token->length = outer_len;
01422 output_token->value = malloc(outer_len);
01423 if (output_token->value == NULL) {
01424 *minor_status = ENOMEM;
01425 return (GSS_S_FAILURE);
01426 }
01427 p = gssapi_mech_make_header(output_token->value, len, mech);
01428 if (p == NULL) {
01429 if (output_token->length != 0U)
01430 gss_release_buffer(minor_status, output_token);
01431 return (GSS_S_FAILURE);
01432 }
01433 memmove(p, buf, buf_size);
01434 return (GSS_S_COMPLETE);
01435 }
01436
01437
01438
01439
01440
01441
01442
01443 static int
01444 add_mech(MechTypeList * mech_list, gss_OID mech)
01445 {
01446 MechType *tmp;
01447 int ret;
01448
01449 tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
01450 if (tmp == NULL)
01451 return (ENOMEM);
01452 mech_list->val = tmp;
01453
01454 ret = der_get_oid(mech->elements, mech->length,
01455 &mech_list->val[mech_list->len], NULL);
01456 if (ret)
01457 return (ret);
01458
01459 mech_list->len++;
01460 return (0);
01461 }
01462
01463
01464
01465
01466
01467
01468 static ssize_t
01469 gssapi_krb5_get_mech(const u_char *ptr,
01470 size_t total_len,
01471 const u_char **mech_ret)
01472 {
01473 size_t len, len_len, mech_len, foo;
01474 const u_char *p = ptr;
01475 int e;
01476
01477 if (total_len < 1U)
01478 return (-1);
01479 if (*p++ != 0x60)
01480 return (-1);
01481 e = der_get_length (p, total_len - 1, &len, &len_len);
01482 if (e || 1 + len_len + len != total_len)
01483 return (-1);
01484 p += len_len;
01485 if (*p++ != 0x06)
01486 return (-1);
01487 e = der_get_length (p, total_len - 1 - len_len - 1,
01488 &mech_len, &foo);
01489 if (e)
01490 return (-1);
01491 p += foo;
01492 *mech_ret = p;
01493 return (mech_len);
01494 }
01495
01496 static OM_uint32
01497 spnego_initial(OM_uint32 *minor_status,
01498 const gss_cred_id_t initiator_cred_handle,
01499 gss_ctx_id_t *context_handle,
01500 const gss_name_t target_name,
01501 const gss_OID mech_type,
01502 OM_uint32 req_flags,
01503 OM_uint32 time_req,
01504 const gss_channel_bindings_t input_chan_bindings,
01505 const gss_buffer_t input_token,
01506 gss_OID *actual_mech_type,
01507 gss_buffer_t output_token,
01508 OM_uint32 *ret_flags,
01509 OM_uint32 *time_rec)
01510 {
01511 NegTokenInit token_init;
01512 OM_uint32 major_status, minor_status2;
01513 gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
01514 unsigned char *buf = NULL;
01515 size_t buf_size;
01516 size_t len;
01517 int ret;
01518
01519 (void)mech_type;
01520
01521 memset(&token_init, 0, sizeof(token_init));
01522
01523 ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH);
01524 if (ret) {
01525 *minor_status = ret;
01526 ret = GSS_S_FAILURE;
01527 goto end;
01528 }
01529
01530 major_status = gss_init_sec_context(minor_status,
01531 initiator_cred_handle,
01532 context_handle,
01533 target_name,
01534 GSS_KRB5_MECH,
01535 req_flags,
01536 time_req,
01537 input_chan_bindings,
01538 input_token,
01539 actual_mech_type,
01540 &krb5_output_token,
01541 ret_flags,
01542 time_rec);
01543 if (GSS_ERROR(major_status)) {
01544 ret = major_status;
01545 goto end;
01546 }
01547 if (krb5_output_token.length > 0U) {
01548 token_init.mechToken = malloc(sizeof(*token_init.mechToken));
01549 if (token_init.mechToken == NULL) {
01550 *minor_status = ENOMEM;
01551 ret = GSS_S_FAILURE;
01552 goto end;
01553 }
01554 token_init.mechToken->data = krb5_output_token.value;
01555 token_init.mechToken->length = krb5_output_token.length;
01556 }
01557
01558
01559
01560
01561
01562 buf_size = 1024;
01563 buf = malloc(buf_size);
01564 if (buf == NULL) {
01565 *minor_status = ENOMEM;
01566 ret = GSS_S_FAILURE;
01567 goto end;
01568 }
01569
01570 do {
01571 ret = encode_NegTokenInit(buf + buf_size - 1,
01572 buf_size,
01573 &token_init, &len);
01574 if (ret == 0) {
01575 size_t tmp;
01576
01577 ret = der_put_length_and_tag(buf + buf_size - len - 1,
01578 buf_size - len,
01579 len,
01580 ASN1_C_CONTEXT,
01581 CONS,
01582 0,
01583 &tmp);
01584 if (ret == 0)
01585 len += tmp;
01586 }
01587 if (ret) {
01588 if (ret == ASN1_OVERFLOW) {
01589 u_char *tmp;
01590
01591 buf_size *= 2;
01592 tmp = realloc(buf, buf_size);
01593 if (tmp == NULL) {
01594 *minor_status = ENOMEM;
01595 ret = GSS_S_FAILURE;
01596 goto end;
01597 }
01598 buf = tmp;
01599 } else {
01600 *minor_status = ret;
01601 ret = GSS_S_FAILURE;
01602 goto end;
01603 }
01604 }
01605 } while (ret == ASN1_OVERFLOW);
01606
01607 ret = gssapi_spnego_encapsulate(minor_status,
01608 buf + buf_size - len, len,
01609 output_token, GSS_SPNEGO_MECH);
01610 if (ret == GSS_S_COMPLETE)
01611 ret = major_status;
01612
01613 end:
01614 if (token_init.mechToken != NULL) {
01615 free(token_init.mechToken);
01616 token_init.mechToken = NULL;
01617 }
01618 free_NegTokenInit(&token_init);
01619 if (krb5_output_token.length != 0U)
01620 gss_release_buffer(&minor_status2, &krb5_output_token);
01621 if (buf)
01622 free(buf);
01623
01624 return (ret);
01625 }
01626
01627 static OM_uint32
01628 spnego_reply(OM_uint32 *minor_status,
01629 const gss_cred_id_t initiator_cred_handle,
01630 gss_ctx_id_t *context_handle,
01631 const gss_name_t target_name,
01632 const gss_OID mech_type,
01633 OM_uint32 req_flags,
01634 OM_uint32 time_req,
01635 const gss_channel_bindings_t input_chan_bindings,
01636 const gss_buffer_t input_token,
01637 gss_OID *actual_mech_type,
01638 gss_buffer_t output_token,
01639 OM_uint32 *ret_flags,
01640 OM_uint32 *time_rec)
01641 {
01642 OM_uint32 ret;
01643 NegTokenResp resp;
01644 unsigned char *buf;
01645 size_t buf_size;
01646 u_char oidbuf[17];
01647 size_t oidlen;
01648 gss_buffer_desc sub_token;
01649 ssize_t mech_len;
01650 const u_char *p;
01651 size_t len, taglen;
01652
01653 (void)mech_type;
01654
01655 output_token->length = 0;
01656 output_token->value = NULL;
01657
01658
01659
01660
01661
01662
01663 mech_len = gssapi_krb5_get_mech(input_token->value,
01664 input_token->length,
01665 &p);
01666
01667 if (mech_len < 0) {
01668 buf = input_token->value;
01669 buf_size = input_token->length;
01670 } else if ((size_t)mech_len == GSS_KRB5_MECH->length &&
01671 memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0)
01672 return (gss_init_sec_context(minor_status,
01673 initiator_cred_handle,
01674 context_handle,
01675 target_name,
01676 GSS_KRB5_MECH,
01677 req_flags,
01678 time_req,
01679 input_chan_bindings,
01680 input_token,
01681 actual_mech_type,
01682 output_token,
01683 ret_flags,
01684 time_rec));
01685 else if ((size_t)mech_len == GSS_SPNEGO_MECH->length &&
01686 memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) {
01687 ret = gssapi_spnego_decapsulate(minor_status,
01688 input_token,
01689 &buf,
01690 &buf_size,
01691 GSS_SPNEGO_MECH);
01692 if (ret)
01693 return (ret);
01694 } else
01695 return (GSS_S_BAD_MECH);
01696
01697 ret = der_match_tag_and_length(buf, buf_size,
01698 ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
01699 if (ret)
01700 return (ret);
01701
01702 if(len > buf_size - taglen)
01703 return (ASN1_OVERRUN);
01704
01705 ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL);
01706 if (ret) {
01707 free_NegTokenResp(&resp);
01708 *minor_status = ENOMEM;
01709 return (GSS_S_FAILURE);
01710 }
01711
01712 if (resp.negState == NULL ||
01713 *(resp.negState) == reject ||
01714 resp.supportedMech == NULL) {
01715 free_NegTokenResp(&resp);
01716 return (GSS_S_BAD_MECH);
01717 }
01718
01719 ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
01720 sizeof(oidbuf),
01721 resp.supportedMech,
01722 &oidlen);
01723 if (ret || oidlen != GSS_KRB5_MECH->length ||
01724 memcmp(oidbuf + sizeof(oidbuf) - oidlen,
01725 GSS_KRB5_MECH->elements,
01726 oidlen) != 0) {
01727 free_NegTokenResp(&resp);
01728 return GSS_S_BAD_MECH;
01729 }
01730
01731 if (resp.responseToken != NULL) {
01732 sub_token.length = resp.responseToken->length;
01733 sub_token.value = resp.responseToken->data;
01734 } else {
01735 sub_token.length = 0;
01736 sub_token.value = NULL;
01737 }
01738
01739 ret = gss_init_sec_context(minor_status,
01740 initiator_cred_handle,
01741 context_handle,
01742 target_name,
01743 GSS_KRB5_MECH,
01744 req_flags,
01745 time_req,
01746 input_chan_bindings,
01747 &sub_token,
01748 actual_mech_type,
01749 output_token,
01750 ret_flags,
01751 time_rec);
01752 if (ret) {
01753 free_NegTokenResp(&resp);
01754 return (ret);
01755 }
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765 free_NegTokenResp(&resp);
01766 return (ret);
01767 }
01768
01769
01770
01771 OM_uint32
01772 gss_init_sec_context_spnego(OM_uint32 *minor_status,
01773 const gss_cred_id_t initiator_cred_handle,
01774 gss_ctx_id_t *context_handle,
01775 const gss_name_t target_name,
01776 const gss_OID mech_type,
01777 OM_uint32 req_flags,
01778 OM_uint32 time_req,
01779 const gss_channel_bindings_t input_chan_bindings,
01780 const gss_buffer_t input_token,
01781 gss_OID *actual_mech_type,
01782 gss_buffer_t output_token,
01783 OM_uint32 *ret_flags,
01784 OM_uint32 *time_rec)
01785 {
01786
01787
01788
01789
01790 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0U)
01791 return (spnego_initial(minor_status,
01792 initiator_cred_handle,
01793 context_handle,
01794 target_name,
01795 mech_type,
01796 req_flags,
01797 time_req,
01798 input_chan_bindings,
01799 input_token,
01800 actual_mech_type,
01801 output_token,
01802 ret_flags,
01803 time_rec));
01804 else
01805 return (spnego_reply(minor_status,
01806 initiator_cred_handle,
01807 context_handle,
01808 target_name,
01809 mech_type,
01810 req_flags,
01811 time_req,
01812 input_chan_bindings,
01813 input_token,
01814 actual_mech_type,
01815 output_token,
01816 ret_flags,
01817 time_rec));
01818 }
01819
01820 #endif