summaryrefslogtreecommitdiffstats
path: root/src/lib/gssapi/generic
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/generic')
-rw-r--r--src/lib/gssapi/generic/Makefile.in10
-rw-r--r--src/lib/gssapi/generic/deps8
-rw-r--r--src/lib/gssapi/generic/t_seqstate.c15
-rw-r--r--src/lib/gssapi/generic/util_ordering.c259
-rw-r--r--src/lib/gssapi/generic/util_seqstate.c163
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;
+}