1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 #include "k5-int.h"
8 #include "auth_con.h"
9
10 static krb5_boolean chk_heimdal_seqnum(krb5_ui_4, krb5_ui_4);
11
12 /*ARGSUSED*/
13 static krb5_error_code
actx_copy_addr(krb5_context context,const krb5_address * inad,krb5_address ** outad)14 actx_copy_addr(krb5_context context, const krb5_address *inad, krb5_address **outad)
15 {
16 krb5_address *tmpad;
17
18 if (!(tmpad = (krb5_address *)malloc(sizeof(*tmpad))))
19 return ENOMEM;
20 *tmpad = *inad;
21 if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
22 krb5_xfree(tmpad);
23 return ENOMEM;
24 }
25 /* Solaris Kerberos */
26 (void) memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
27 *outad = tmpad;
28 return 0;
29 }
30
31 krb5_error_code KRB5_CALLCONV
krb5_auth_con_init(krb5_context context,krb5_auth_context * auth_context)32 krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context)
33 {
34 *auth_context =
35 (krb5_auth_context)MALLOC(sizeof(struct _krb5_auth_context));
36 if (!*auth_context)
37 return ENOMEM;
38
39 /* Solaris Kerberos */
40 (void) memset(*auth_context, 0, sizeof(struct _krb5_auth_context));
41
42 /* Default flags, do time not seq */
43 (*auth_context)->auth_context_flags =
44 KRB5_AUTH_CONTEXT_DO_TIME | KRB5_AUTH_CONN_INITIALIZED;
45
46 (*auth_context)->req_cksumtype = context->default_ap_req_sumtype;
47 (*auth_context)->safe_cksumtype = context->default_safe_sumtype;
48 (*auth_context) -> checksum_func = NULL;
49 (*auth_context)->checksum_func_data = NULL;
50 (*auth_context)->magic = KV5M_AUTH_CONTEXT;
51 return 0;
52 }
53
54 krb5_error_code KRB5_CALLCONV
krb5_auth_con_free(krb5_context context,krb5_auth_context auth_context)55 krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
56 {
57 if (auth_context->local_addr)
58 krb5_free_address(context, auth_context->local_addr);
59 if (auth_context->remote_addr)
60 krb5_free_address(context, auth_context->remote_addr);
61 if (auth_context->local_port)
62 krb5_free_address(context, auth_context->local_port);
63 if (auth_context->remote_port)
64 krb5_free_address(context, auth_context->remote_port);
65 if (auth_context->authentp)
66 krb5_free_authenticator(context, auth_context->authentp);
67 if (auth_context->keyblock)
68 krb5_free_keyblock(context, auth_context->keyblock);
69 if (auth_context->send_subkey)
70 krb5_free_keyblock(context, auth_context->send_subkey);
71 if (auth_context->recv_subkey)
72 krb5_free_keyblock(context, auth_context->recv_subkey);
73 /* Solaris Kerberos */
74 if (auth_context->rcache)
75 (void) krb5_rc_close(context, auth_context->rcache);
76 if (auth_context->permitted_etypes)
77 krb5_xfree(auth_context->permitted_etypes);
78 free(auth_context);
79 return 0;
80 }
81
82 krb5_error_code
krb5_auth_con_setaddrs(krb5_context context,krb5_auth_context auth_context,krb5_address * local_addr,krb5_address * remote_addr)83 krb5_auth_con_setaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address *local_addr, krb5_address *remote_addr)
84 {
85 krb5_error_code retval;
86
87 /* Free old addresses */
88 if (auth_context->local_addr)
89 (void) krb5_free_address(context, auth_context->local_addr);
90 if (auth_context->remote_addr)
91 (void) krb5_free_address(context, auth_context->remote_addr);
92
93 retval = 0;
94 if (local_addr)
95 retval = actx_copy_addr(context,
96 local_addr,
97 &auth_context->local_addr);
98 else
99 auth_context->local_addr = NULL;
100
101 if (!retval && remote_addr)
102 retval = actx_copy_addr(context,
103 remote_addr,
104 &auth_context->remote_addr);
105 else
106 auth_context->remote_addr = NULL;
107
108 return retval;
109 }
110
111 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getaddrs(krb5_context context,krb5_auth_context auth_context,krb5_address ** local_addr,krb5_address ** remote_addr)112 krb5_auth_con_getaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address **local_addr, krb5_address **remote_addr)
113 {
114 krb5_error_code retval;
115
116 retval = 0;
117 if (local_addr && auth_context->local_addr) {
118 retval = actx_copy_addr(context,
119 auth_context->local_addr,
120 local_addr);
121 }
122 if (!retval && (remote_addr) && auth_context->remote_addr) {
123 retval = actx_copy_addr(context,
124 auth_context->remote_addr,
125 remote_addr);
126 }
127 return retval;
128 }
129
130 krb5_error_code KRB5_CALLCONV
krb5_auth_con_setports(krb5_context context,krb5_auth_context auth_context,krb5_address * local_port,krb5_address * remote_port)131 krb5_auth_con_setports(krb5_context context, krb5_auth_context auth_context, krb5_address *local_port, krb5_address *remote_port)
132 {
133 krb5_error_code retval;
134
135 /* Free old addresses */
136 if (auth_context->local_port)
137 (void) krb5_free_address(context, auth_context->local_port);
138 if (auth_context->remote_port)
139 (void) krb5_free_address(context, auth_context->remote_port);
140
141 retval = 0;
142 if (local_port)
143 retval = actx_copy_addr(context,
144 local_port,
145 &auth_context->local_port);
146 else
147 auth_context->local_port = NULL;
148
149 if (!retval && remote_port)
150 retval = actx_copy_addr(context,
151 remote_port,
152 &auth_context->remote_port);
153 else
154 auth_context->remote_port = NULL;
155
156 return retval;
157 }
158
159
160 /*
161 * This function overloads the keyblock field. It is only useful prior to
162 * a krb5_rd_req_decode() call for user to user authentication where the
163 * server has the key and needs to use it to decrypt the incoming request.
164 * Once decrypted this key is no longer necessary and is then overwritten
165 * with the session key sent by the client.
166 */
167 krb5_error_code KRB5_CALLCONV
krb5_auth_con_setuseruserkey(krb5_context context,krb5_auth_context auth_context,krb5_keyblock * keyblock)168 krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock)
169 {
170 if (auth_context->keyblock)
171 krb5_free_keyblock(context, auth_context->keyblock);
172 return(krb5_copy_keyblock(context, keyblock, &(auth_context->keyblock)));
173 }
174
175 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getkey(krb5_context context,krb5_auth_context auth_context,krb5_keyblock ** keyblock)176 krb5_auth_con_getkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
177 {
178 if (auth_context->keyblock)
179 return krb5_copy_keyblock(context, auth_context->keyblock, keyblock);
180 *keyblock = NULL;
181 return 0;
182 }
183
184 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getlocalsubkey(krb5_context context,krb5_auth_context auth_context,krb5_keyblock ** keyblock)185 krb5_auth_con_getlocalsubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
186 {
187 return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
188 }
189
190 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getremotesubkey(krb5_context context,krb5_auth_context auth_context,krb5_keyblock ** keyblock)191 krb5_auth_con_getremotesubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
192 {
193 return krb5_auth_con_getrecvsubkey(context, auth_context, keyblock);
194 }
195
196 krb5_error_code KRB5_CALLCONV
krb5_auth_con_setsendsubkey(krb5_context ctx,krb5_auth_context ac,krb5_keyblock * keyblock)197 krb5_auth_con_setsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
198 {
199 if (ac->send_subkey != NULL)
200 krb5_free_keyblock(ctx, ac->send_subkey);
201 ac->send_subkey = NULL;
202 if (keyblock !=NULL)
203 return krb5_copy_keyblock(ctx, keyblock, &ac->send_subkey);
204 else
205 return 0;
206 }
207
208 krb5_error_code KRB5_CALLCONV
krb5_auth_con_setrecvsubkey(krb5_context ctx,krb5_auth_context ac,krb5_keyblock * keyblock)209 krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
210 {
211 if (ac->recv_subkey != NULL)
212 krb5_free_keyblock(ctx, ac->recv_subkey);
213 ac->recv_subkey = NULL;
214 if (keyblock != NULL)
215 return krb5_copy_keyblock(ctx, keyblock, &ac->recv_subkey);
216 else
217 return 0;
218 }
219
220 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getsendsubkey(krb5_context ctx,krb5_auth_context ac,krb5_keyblock ** keyblock)221 krb5_auth_con_getsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
222 {
223 if (ac->send_subkey != NULL)
224 return krb5_copy_keyblock(ctx, ac->send_subkey, keyblock);
225 *keyblock = NULL;
226 return 0;
227 }
228
229 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getrecvsubkey(krb5_context ctx,krb5_auth_context ac,krb5_keyblock ** keyblock)230 krb5_auth_con_getrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
231 {
232 if (ac->recv_subkey != NULL)
233 return krb5_copy_keyblock(ctx, ac->recv_subkey, keyblock);
234 *keyblock = NULL;
235 return 0;
236 }
237
238 /*ARGSUSED*/
239 krb5_error_code KRB5_CALLCONV
krb5_auth_con_set_req_cksumtype(krb5_context context,krb5_auth_context auth_context,krb5_cksumtype cksumtype)240 krb5_auth_con_set_req_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
241 {
242 auth_context->req_cksumtype = cksumtype;
243 return 0;
244 }
245
246 /*ARGSUSED*/
247 krb5_error_code
krb5_auth_con_set_safe_cksumtype(krb5_context context,krb5_auth_context auth_context,krb5_cksumtype cksumtype)248 krb5_auth_con_set_safe_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
249 {
250 auth_context->safe_cksumtype = cksumtype;
251 return 0;
252 }
253
254 /*ARGSUSED*/
255 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getlocalseqnumber(krb5_context context,krb5_auth_context auth_context,krb5_int32 * seqnumber)256 krb5_auth_con_getlocalseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
257 {
258 *seqnumber = auth_context->local_seq_number;
259 return 0;
260 }
261
262 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getauthenticator(krb5_context context,krb5_auth_context auth_context,krb5_authenticator ** authenticator)263 krb5_auth_con_getauthenticator(krb5_context context, krb5_auth_context auth_context, krb5_authenticator **authenticator)
264 {
265 return (krb5_copy_authenticator(context, auth_context->authentp,
266 authenticator));
267 }
268
269 /*ARGSUSED*/
270 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getremoteseqnumber(krb5_context context,krb5_auth_context auth_context,krb5_int32 * seqnumber)271 krb5_auth_con_getremoteseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
272 {
273 *seqnumber = auth_context->remote_seq_number;
274 return 0;
275 }
276
277 krb5_error_code KRB5_CALLCONV
krb5_auth_con_initivector(krb5_context context,krb5_auth_context auth_context)278 krb5_auth_con_initivector(krb5_context context, krb5_auth_context auth_context)
279 {
280 krb5_error_code ret;
281
282 if (auth_context->keyblock) {
283 size_t blocksize;
284
285 if ((ret = krb5_c_block_size(context, auth_context->keyblock->enctype,
286 &blocksize)))
287 return(ret);
288 if ((auth_context->i_vector = (krb5_pointer)malloc(blocksize))) {
289 memset(auth_context->i_vector, 0, blocksize);
290 return 0;
291 }
292 return ENOMEM;
293 }
294 return EINVAL; /* XXX need an error for no keyblock */
295 }
296
297 /*ARGSUSED*/
298 krb5_error_code
krb5_auth_con_setivector(krb5_context context,krb5_auth_context auth_context,krb5_pointer ivector)299 krb5_auth_con_setivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer ivector)
300 {
301 auth_context->i_vector = ivector;
302 return 0;
303 }
304
305 /*ARGSUSED*/
306 krb5_error_code
krb5_auth_con_getivector(krb5_context context,krb5_auth_context auth_context,krb5_pointer * ivector)307 krb5_auth_con_getivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer *ivector)
308 {
309 *ivector = auth_context->i_vector;
310 return 0;
311 }
312
313 /*ARGSUSED*/
314 krb5_error_code KRB5_CALLCONV
krb5_auth_con_setflags(krb5_context context,krb5_auth_context auth_context,krb5_int32 flags)315 krb5_auth_con_setflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 flags)
316 {
317 auth_context->auth_context_flags = flags;
318 return 0;
319 }
320
321 /*ARGSUSED*/
322 krb5_error_code KRB5_CALLCONV
krb5_auth_con_getflags(krb5_context context,krb5_auth_context auth_context,krb5_int32 * flags)323 krb5_auth_con_getflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 *flags)
324 {
325 *flags = auth_context->auth_context_flags;
326 return 0;
327 }
328
329 /*ARGSUSED*/
330 krb5_error_code KRB5_CALLCONV
krb5_auth_con_setrcache(krb5_context context,krb5_auth_context auth_context,krb5_rcache rcache)331 krb5_auth_con_setrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache rcache)
332 {
333 auth_context->rcache = rcache;
334 return 0;
335 }
336
337 /*ARGSUSED*/
338 krb5_error_code
krb5_auth_con_getrcache(krb5_context context,krb5_auth_context auth_context,krb5_rcache * rcache)339 krb5_auth_con_getrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache *rcache)
340 {
341 *rcache = auth_context->rcache;
342 return 0;
343 }
344
345 /*ARGSUSED*/
346 krb5_error_code
krb5_auth_con_setpermetypes(krb5_context context,krb5_auth_context auth_context,const krb5_enctype * permetypes)347 krb5_auth_con_setpermetypes(krb5_context context, krb5_auth_context auth_context, const krb5_enctype *permetypes)
348 {
349 krb5_enctype * newpe;
350 int i;
351
352 for (i=0; permetypes[i]; i++)
353 ;
354 i++; /* include the zero */
355
356 if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
357 == NULL)
358 return(ENOMEM);
359
360 if (auth_context->permitted_etypes)
361 krb5_xfree(auth_context->permitted_etypes);
362
363 auth_context->permitted_etypes = newpe;
364
365 /* Solaris Kerberos */
366 (void) memcpy(newpe, permetypes, i*sizeof(krb5_enctype));
367
368 return 0;
369 }
370
371 /*ARGSUSED*/
372 krb5_error_code
krb5_auth_con_getpermetypes(krb5_context context,krb5_auth_context auth_context,krb5_enctype ** permetypes)373 krb5_auth_con_getpermetypes(krb5_context context, krb5_auth_context auth_context, krb5_enctype **permetypes)
374 {
375 krb5_enctype * newpe;
376 int i;
377
378 if (! auth_context->permitted_etypes) {
379 *permetypes = NULL;
380 return(0);
381 }
382
383 for (i=0; auth_context->permitted_etypes[i]; i++)
384 ;
385 i++; /* include the zero */
386
387 if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
388 == NULL)
389 return(ENOMEM);
390
391 *permetypes = newpe;
392
393 memcpy(newpe, auth_context->permitted_etypes, i*sizeof(krb5_enctype));
394
395 return(0);
396 }
397
398 krb5_error_code KRB5_CALLCONV
krb5_auth_con_set_checksum_func(krb5_context context,krb5_auth_context auth_context,krb5_mk_req_checksum_func func,void * data)399 krb5_auth_con_set_checksum_func( krb5_context context,
400 krb5_auth_context auth_context,
401 krb5_mk_req_checksum_func func,
402 void *data)
403 {
404 auth_context->checksum_func = func;
405 auth_context->checksum_func_data = data;
406 return 0;
407 }
408
409 krb5_error_code KRB5_CALLCONV
krb5_auth_con_get_checksum_func(krb5_context context,krb5_auth_context auth_context,krb5_mk_req_checksum_func * func,void ** data)410 krb5_auth_con_get_checksum_func( krb5_context context,
411 krb5_auth_context auth_context,
412 krb5_mk_req_checksum_func *func,
413 void **data)
414 {
415 *func = auth_context->checksum_func;
416 *data = auth_context->checksum_func_data;
417 return 0;
418 }
419
420 /*
421 * krb5int_auth_con_chkseqnum
422 *
423 * We use a somewhat complex heuristic for validating received
424 * sequence numbers. We must accommodate both our older
425 * implementation, which sends negative sequence numbers, and the
426 * broken Heimdal implementation (at least as of 0.5.2), which
427 * violates X.690 BER for integer encodings. The requirement of
428 * handling negative sequence numbers removes one of easier means of
429 * detecting a Heimdal implementation, so we resort to this mess
430 * here.
431 *
432 * X.690 BER (and consequently DER, which are the required encoding
433 * rules in RFC1510) encode all integer types as signed integers.
434 * This means that the MSB being set on the first octet of the
435 * contents of the encoding indicates a negative value. Heimdal does
436 * not prepend the required zero octet to unsigned integer encodings
437 * which would otherwise have the MSB of the first octet of their
438 * encodings set.
439 *
440 * Our ASN.1 library implements a special decoder for sequence
441 * numbers, accepting both negative and positive 32-bit numbers but
442 * mapping them both into the space of positive unsigned 32-bit
443 * numbers in the obvious bit-pattern-preserving way. This maintains
444 * compatibility with our older implementations. This also means that
445 * encodings emitted by Heimdal are ambiguous.
446 *
447 * Heimdal counter value received uint32 value
448 *
449 * 0x00000080 0xFFFFFF80
450 * 0x000000FF 0xFFFFFFFF
451 * 0x00008000 0xFFFF8000
452 * 0x0000FFFF 0xFFFFFFFF
453 * 0x00800000 0xFF800000
454 * 0x00FFFFFF 0xFFFFFFFF
455 * 0xFF800000 0xFF800000
456 * 0xFFFFFFFF 0xFFFFFFFF
457 *
458 * We use two auth_context flags, SANE_SEQ and HEIMDAL_SEQ, which are
459 * only set after we can unambiguously determine the sanity of the
460 * sending implementation. Once one of these flags is set, we accept
461 * only the sequence numbers appropriate to the remote implementation
462 * type. We can make the determination in two different ways. The
463 * first is to note the receipt of a "negative" sequence number when a
464 * "positive" one was expected. The second is to note the receipt of
465 * a sequence number that wraps through "zero" in a weird way. The
466 * latter corresponds to the receipt of an initial sequence number in
467 * the ambiguous range.
468 *
469 * There are 2^7 + 2^15 + 2^23 + 2^23 = 16810112 total ambiguous
470 * initial Heimdal counter values, but we receive them as one of 2^23
471 * possible values. There is a ~1/256 chance of a Heimdal
472 * implementation sending an intial sequence number in the ambiguous
473 * range.
474 *
475 * We have to do special treatment when receiving sequence numbers
476 * between 0xFF800000..0xFFFFFFFF, or when wrapping through zero
477 * weirdly (due to ambiguous initial sequence number). If we are
478 * expecting a value corresponding to an ambiguous Heimdal counter
479 * value, and we receive an exact match, we can mark the remote end as
480 * sane.
481 */
482 krb5_boolean
krb5int_auth_con_chkseqnum(krb5_context ctx,krb5_auth_context ac,krb5_ui_4 in_seq)483 krb5int_auth_con_chkseqnum(
484 krb5_context ctx,
485 krb5_auth_context ac,
486 krb5_ui_4 in_seq)
487 {
488 krb5_ui_4 exp_seq;
489
490 exp_seq = ac->remote_seq_number;
491
492 /*
493 * If sender is known to be sane, accept _only_ exact matches.
494 */
495 if (ac->auth_context_flags & KRB5_AUTH_CONN_SANE_SEQ)
496 return in_seq == exp_seq;
497
498 /*
499 * If sender is not known to be sane, first check the ambiguous
500 * range of received values, 0xFF800000..0xFFFFFFFF.
501 */
502 if ((in_seq & 0xFF800000) == 0xFF800000) {
503 /*
504 * If expected sequence number is in the range
505 * 0xFF800000..0xFFFFFFFF, then we can't make any
506 * determinations about the sanity of the sending
507 * implementation.
508 */
509 if ((exp_seq & 0xFF800000) == 0xFF800000 && in_seq == exp_seq)
510 return 1;
511 /*
512 * If sender is not known for certain to be a broken Heimdal
513 * implementation, check for exact match.
514 */
515 if (!(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)
516 && in_seq == exp_seq)
517 return 1;
518 /*
519 * Now apply hairy algorithm for matching sequence numbers
520 * sent by broken Heimdal implementations. If it matches, we
521 * know for certain it's a broken Heimdal sender.
522 */
523 if (chk_heimdal_seqnum(exp_seq, in_seq)) {
524 ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
525 return 1;
526 }
527 return 0;
528 }
529
530 /*
531 * Received value not in the ambiguous range? If the _expected_
532 * value is in the range of ambiguous Hemidal counter values, and
533 * it matches the received value, sender is known to be sane.
534 */
535 if (in_seq == exp_seq) {
536 if (( exp_seq & 0xFFFFFF80) == 0x00000080
537 || (exp_seq & 0xFFFF8000) == 0x00008000
538 || (exp_seq & 0xFF800000) == 0x00800000)
539 ac->auth_context_flags |= KRB5_AUTH_CONN_SANE_SEQ;
540 return 1;
541 }
542
543 /*
544 * Magic wraparound for the case where the intial sequence number
545 * is in the ambiguous range. This means that the sender's
546 * counter is at a different count than ours, so we correct ours,
547 * and mark the sender as being a broken Heimdal implementation.
548 */
549 if (exp_seq == 0
550 && !(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)) {
551 switch (in_seq) {
552 case 0x100:
553 case 0x10000:
554 case 0x1000000:
555 ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
556 exp_seq = in_seq;
557 return 1;
558 default:
559 return 0;
560 }
561 }
562 return 0;
563 }
564
565 static krb5_boolean
chk_heimdal_seqnum(krb5_ui_4 exp_seq,krb5_ui_4 in_seq)566 chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
567 {
568 if (( exp_seq & 0xFF800000) == 0x00800000
569 && (in_seq & 0xFF800000) == 0xFF800000
570 && (in_seq & 0x00FFFFFF) == exp_seq)
571 return 1;
572 else if (( exp_seq & 0xFFFF8000) == 0x00008000
573 && (in_seq & 0xFFFF8000) == 0xFFFF8000
574 && (in_seq & 0x0000FFFF) == exp_seq)
575 return 1;
576 else if (( exp_seq & 0xFFFFFF80) == 0x00000080
577 && (in_seq & 0xFFFFFF80) == 0xFFFFFF80
578 && (in_seq & 0x000000FF) == exp_seq)
579 return 1;
580 else
581 return 0;
582 }
583