diff options
Diffstat (limited to 'src/lib/gssapi/generic')
-rw-r--r-- | src/lib/gssapi/generic/Makefile.in | 10 | ||||
-rw-r--r-- | src/lib/gssapi/generic/deps | 8 | ||||
-rw-r--r-- | src/lib/gssapi/generic/t_seqstate.c | 15 | ||||
-rw-r--r-- | src/lib/gssapi/generic/util_ordering.c | 259 | ||||
-rw-r--r-- | src/lib/gssapi/generic/util_seqstate.c | 163 |
5 files changed, 184 insertions, 271 deletions
diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in index 04049a655..530a0a96e 100644 --- a/src/lib/gssapi/generic/Makefile.in +++ b/src/lib/gssapi/generic/Makefile.in @@ -66,8 +66,8 @@ SRCS = \ $(srcdir)/util_buffer.c \ $(srcdir)/util_buffer_set.c \ $(srcdir)/util_errmap.c \ - $(srcdir)/util_ordering.c \ $(srcdir)/util_set.c \ + $(srcdir)/util_seqstate.c \ $(srcdir)/util_token.c \ gssapi_err_generic.c @@ -83,8 +83,8 @@ OBJS = \ $(OUTPRE)util_buffer.$(OBJEXT) \ $(OUTPRE)util_buffer_set.$(OBJEXT) \ $(OUTPRE)util_errmap.$(OBJEXT) \ - $(OUTPRE)util_ordering.$(OBJEXT) \ $(OUTPRE)util_set.$(OBJEXT) \ + $(OUTPRE)util_seqstate.$(OBJEXT) \ $(OUTPRE)util_token.$(OBJEXT) \ $(OUTPRE)gssapi_err_generic.$(OBJEXT) @@ -98,8 +98,8 @@ STLIBOBJS = \ util_buffer.o \ util_buffer_set.o \ util_errmap.o \ - util_ordering.o \ util_set.o \ + util_seqstate.o \ util_token.o \ gssapi_err_generic.o @@ -146,8 +146,8 @@ clean-windows:: $(RM) $(HDRS) maptest.h -if exist $(EHDRDIR)\nul rmdir $(EHDRDIR) -t_seqstate: t_seqstate.o util_ordering.o - $(CC_LINK) $(ALL_CFLAGS) -o $@ t_seqstate.o util_ordering.o +t_seqstate: t_seqstate.o util_seqstate.o + $(CC_LINK) $(ALL_CFLAGS) -o $@ t_seqstate.o util_seqstate.o check-unix:: t_seqstate $(RUN_SETUP) $(VALGRIND) ./t_seqstate diff --git a/src/lib/gssapi/generic/deps b/src/lib/gssapi/generic/deps index 41a967bca..5b80e7f38 100644 --- a/src/lib/gssapi/generic/deps +++ b/src/lib/gssapi/generic/deps @@ -64,20 +64,20 @@ util_errmap.so util_errmap.po $(OUTPRE)util_errmap.$(OBJEXT): \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/krb5.h \ errmap.h gssapiP_generic.h gssapi_err_generic.h gssapi_ext.h \ gssapi_generic.h util_errmap.c -util_ordering.so util_ordering.po $(OUTPRE)util_ordering.$(OBJEXT): \ +util_set.so util_set.po $(OUTPRE)util_set.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \ - util_ordering.c -util_set.so util_set.po $(OUTPRE)util_set.$(OBJEXT): \ + util_set.c +util_seqstate.so util_seqstate.po $(OUTPRE)util_seqstate.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \ - util_set.c + util_seqstate.c util_token.so util_token.po $(OUTPRE)util_token.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \ diff --git a/src/lib/gssapi/generic/t_seqstate.c b/src/lib/gssapi/generic/t_seqstate.c index c7250b9ad..8f44fcf3e 100644 --- a/src/lib/gssapi/generic/t_seqstate.c +++ b/src/lib/gssapi/generic/t_seqstate.c @@ -115,11 +115,10 @@ struct test { 3, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, GAP } } }, - /* Replay without the replay flag set. Current code reports a replay - * anyway. */ + /* Replay without the replay flag set. */ { 250, NO_REPLAY, DO_SEQUENCE, BOTH, - 2, { { 250, NOERR }, { 250, REPLAY } } + 2, { { 250, NOERR }, { 250, UNSEQ } } }, /* Basic replay detection with and without sequence checking. */ @@ -152,6 +151,16 @@ struct test { { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ }, { UINT32_MAX - 2, REPLAY }, { UINT32_MAX - 6, GAP } } }, + + /* Old token edge cases. The current code can detect replays up to 64 + * numbers behind the expected sequence number (1164 in this case). */ + { + 1000, DO_REPLAY, NO_SEQUENCE, BOTH, + 10, { { 1163, NOERR }, { 1100, NOERR }, { 1100, REPLAY }, + { 1163, REPLAY }, { 1099, OLD }, { 1100, REPLAY }, + { 1150, NOERR }, { 1150, REPLAY }, { 1000, OLD }, + { 999, NOERR } } + }, }; int diff --git a/src/lib/gssapi/generic/util_ordering.c b/src/lib/gssapi/generic/util_ordering.c deleted file mode 100644 index d6feed10d..000000000 --- a/src/lib/gssapi/generic/util_ordering.c +++ /dev/null @@ -1,259 +0,0 @@ -/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - * Copyright 1993 by OpenVision Technologies, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appears in all copies and - * that both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of OpenVision not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. OpenVision makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * $Id$ - */ - -/* - * functions to check sequence numbers for replay and sequencing - */ - -#include "gssapiP_generic.h" -#include <string.h> - -#define QUEUE_LENGTH 20 - -typedef struct g_seqnum_state_st { - int do_replay; - int do_sequence; - int start; - int length; - uint64_t firstnum; - /* Stored as deltas from firstnum. This way, the high bit won't - overflow unless we've actually gone through 2**n messages, or - gotten something *way* out of sequence. */ - uint64_t elem[QUEUE_LENGTH]; - /* All ones for 64-bit sequence numbers; 32 ones for 32-bit - sequence numbers. */ - uint64_t mask; -} queue; - -/* rep invariant: - * - the queue is a circular queue. The first element (q->elem[q->start]) - * is the oldest. The last element is the newest. - */ - -#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0])) -#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)]) - -static void -queue_insert(queue *q, int after, uint64_t seqnum) -{ - /* insert. this is not the fastest way, but it's easy, and it's - optimized for insert at end, which is the common case */ - int i; - - /* common case: at end, after == q->start+q->length-1 */ - - /* move all the elements (after,last] up one slot */ - - for (i=q->start+q->length-1; i>after; i--) - QELEM(q,i+1) = QELEM(q,i); - - /* fill in slot after+1 */ - - QELEM(q,after+1) = seqnum; - - /* Either increase the length by one, or move the starting point up - one (deleting the first element, which got bashed above), as - appropriate. */ - - if (q->length == QSIZE(q)) { - q->start++; - if (q->start == QSIZE(q)) - q->start = 0; - } else { - q->length++; - } -} - -long -g_seqstate_init(g_seqnum_state *state_out, uint64_t seqnum, - int do_replay, int do_sequence, int wide_nums) -{ - queue *q; - - if ((q = (queue *) malloc(sizeof(queue))) == NULL) - return(ENOMEM); - - /* This stops valgrind from complaining about writing uninitialized - data if the caller exports the context and writes it to a file. - We don't actually use those bytes at all, but valgrind still - complains. */ - memset(q, 0xfe, sizeof(*q)); - - q->do_replay = do_replay; - q->do_sequence = do_sequence; - q->mask = wide_nums ? ~(uint64_t)0 : 0xffffffffUL; - - q->start = 0; - q->length = 1; - q->firstnum = seqnum; - q->elem[q->start] = ((uint64_t)0 - 1) & q->mask; - - *state_out = q; - return(0); -} - -OM_uint32 -g_seqstate_check(g_seqnum_state q, uint64_t seqnum) -{ - int i; - uint64_t expected; - - if (!q->do_replay && !q->do_sequence) - return(GSS_S_COMPLETE); - - /* All checks are done relative to the initial sequence number, to - avoid (or at least put off) the pain of wrapping. */ - seqnum -= q->firstnum; - /* If we're only doing 32-bit values, adjust for that again. - - Note that this will probably be the wrong thing to if we get - 2**32 messages sent with 32-bit sequence numbers. */ - seqnum &= q->mask; - - /* rule 1: expected sequence number */ - - expected = (QELEM(q,q->start+q->length-1)+1) & q->mask; - if (seqnum == expected) { - queue_insert(q, q->start+q->length-1, seqnum); - return(GSS_S_COMPLETE); - } - - /* rule 2: > expected sequence number */ - - if ((seqnum > expected)) { - queue_insert(q, q->start+q->length-1, seqnum); - if (q->do_replay && !q->do_sequence) - return(GSS_S_COMPLETE); - else - return(GSS_S_GAP_TOKEN); - } - - /* rule 3: seqnum < seqnum(first) */ - - if ((seqnum < QELEM(q,q->start)) && - /* Is top bit of whatever width we're using set? - - We used to check for greater than or equal to firstnum, but - (1) we've since switched to compute values relative to - firstnum, so the lowest we can have is 0, and (2) the effect - of the original scheme was highly dependent on whether - firstnum was close to either side of 0. (Consider - firstnum==0xFFFFFFFE and we miss three packets; the next - packet is *new* but would look old.) - - This check should give us 2**31 or 2**63 messages "new", and - just as many "old". That's not quite right either. */ - (seqnum & (1 + (q->mask >> 1))) - ) { - if (q->do_replay && !q->do_sequence) - return(GSS_S_OLD_TOKEN); - else - return(GSS_S_UNSEQ_TOKEN); - } - - /* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */ - - else { - if (seqnum == QELEM(q,q->start+q->length-1)) - return(GSS_S_DUPLICATE_TOKEN); - - for (i=q->start; i<q->start+q->length-1; i++) { - if (seqnum == QELEM(q,i)) - return(GSS_S_DUPLICATE_TOKEN); - if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) { - queue_insert(q, i, seqnum); - if (q->do_replay && !q->do_sequence) - return(GSS_S_COMPLETE); - else - return(GSS_S_UNSEQ_TOKEN); - } - } - /* - * Exception: if first token arrived out-of-order. - * In that case first two elements in queue are 0xFFFFFFFF and some k, - * where k > seqnum. We need to insert seqnum before k. - * We check this after the for-loop, because this should be rare. - */ - if ((QELEM(q, q->start) == (((uint64_t)0 - 1) & q->mask)) && - ((QELEM(q, q->start + 1) > seqnum))) { - queue_insert(q, q->start, seqnum); - if (q->do_replay && !q->do_sequence) - return(GSS_S_COMPLETE); - else - return(GSS_S_UNSEQ_TOKEN); - - } - } - - /* this should never happen */ - return(GSS_S_FAILURE); -} - -void -g_seqstate_free(g_seqnum_state q) -{ - free(q); -} - -/* - * These support functions are for the serialization routines - */ -void -g_seqstate_size(g_seqnum_state q, size_t *sizep) -{ - *sizep += sizeof(*q); -} - -long -g_seqstate_externalize(g_seqnum_state q, unsigned char **buf, - size_t *lenremain) -{ - if (*lenremain < sizeof(*q)) - return ENOMEM; - memcpy(*buf, q, sizeof(*q)); - *buf += sizeof(*q); - *lenremain -= sizeof(*q); - - return 0; -} - -long -g_seqstate_internalize(g_seqnum_state *state_out, unsigned char **buf, - size_t *lenremain) -{ - queue *q; - - if (*lenremain < sizeof(*q)) - return EINVAL; - if ((q = malloc(sizeof(*q))) == 0) - return ENOMEM; - memcpy(q, *buf, sizeof(*q)); - *buf += sizeof(*q); - *lenremain -= sizeof(*q); - *state_out = q; - return 0; -} diff --git a/src/lib/gssapi/generic/util_seqstate.c b/src/lib/gssapi/generic/util_seqstate.c new file mode 100644 index 000000000..a0bc2cc1c --- /dev/null +++ b/src/lib/gssapi/generic/util_seqstate.c @@ -0,0 +1,163 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/gssapi/generic/util_seqstate.c - sequence number checking */ +/* + * Copyright (C) 2014 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gssapiP_generic.h" +#include <string.h> + +struct g_seqnum_state_st { + /* Flags to indicate whether we are supposed to check for replays or + * enforce strict sequencing. */ + int do_replay; + int do_sequence; + + /* UINT32_MAX for 32-bit sequence numbers, UINT64_MAX for 64-bit. Mask + * against this after arithmetic to stay within the correct range. */ + uint64_t seqmask; + + /* The initial sequence number for this context. This value will be + * subtracted from all received sequence numbers to simplify wraparound. */ + uint64_t base; + + /* The expected next sequence number (one more than the highest previously + * seen sequence number), relative to base. */ + uint64_t next; + + /* + * A bitmap for the 64 sequence numbers prior to next. If the 1<<(i-1) bit + * is set, then we have seen seqnum next-i relative to base. The least + * significant bit is always set if we have received any sequence numbers, + * and indicates the highest sequence number we have seen (next-1). When + * we advance next, we shift recvmap to the left. + */ + uint64_t recvmap; +}; + +long +g_seqstate_init(g_seqnum_state *state_out, uint64_t seqnum, int do_replay, + int do_sequence, int wide) +{ + g_seqnum_state state; + + *state_out = NULL; + state = malloc(sizeof(*state)); + if (state == NULL) + return ENOMEM; + state->do_replay = do_replay; + state->do_sequence = do_sequence; + state->seqmask = wide ? UINT64_MAX : UINT32_MAX; + state->base = seqnum; + state->next = state->recvmap = 0; + *state_out = state; + return 0; +} + +OM_uint32 +g_seqstate_check(g_seqnum_state state, uint64_t seqnum) +{ + uint64_t rel_seqnum, offset, bit; + + if (!state->do_replay && !state->do_sequence) + return GSS_S_COMPLETE; + + /* Use the difference from the base seqnum, to simplify wraparound. */ + rel_seqnum = (seqnum - state->base) & state->seqmask; + + if (rel_seqnum >= state->next) { + /* seqnum is the expected sequence number or in the future. Update the + * received bitmap and expected next sequence number. */ + offset = rel_seqnum - state->next; + state->recvmap = (state->recvmap << (offset + 1)) | 1; + state->next = (rel_seqnum + 1) & state->seqmask; + + return (offset > 0 && state->do_sequence) ? GSS_S_GAP_TOKEN : + GSS_S_COMPLETE; + } + + /* seqnum is in the past. Check if it's too old for replay detection. */ + offset = state->next - rel_seqnum; + if (offset > 64) + return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_OLD_TOKEN; + + /* Check for replay and mark as received. */ + bit = (uint64_t)1 << (offset - 1); + if (state->do_replay && (state->recvmap & bit)) + return GSS_S_DUPLICATE_TOKEN; + state->recvmap |= bit; + + return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_COMPLETE; +} + +void +g_seqstate_free(g_seqnum_state state) +{ + free(state); +} + +/* + * These support functions are for the serialization routines + */ +void +g_seqstate_size(g_seqnum_state state, size_t *sizep) +{ + *sizep += sizeof(*state); +} + +long +g_seqstate_externalize(g_seqnum_state state, unsigned char **buf, + size_t *lenremain) +{ + if (*lenremain < sizeof(*state)) + return ENOMEM; + memcpy(*buf, state, sizeof(*state)); + *buf += sizeof(*state); + *lenremain -= sizeof(*state); + return 0; +} + +long +g_seqstate_internalize(g_seqnum_state *state_out, unsigned char **buf, + size_t *lenremain) +{ + g_seqnum_state state; + + *state_out = NULL; + if (*lenremain < sizeof(*state)) + return EINVAL; + state = malloc(sizeof(*state)); + if (state == NULL) + return ENOMEM; + memcpy(state, *buf, sizeof(*state)); + *buf += sizeof(*state); + *lenremain -= sizeof(*state); + *state_out = state; + return 0; +} |