1178825Sdfr/*
2233294Sstas * Copyright (c) 2003 - 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36178825Sdfr#define DEFAULT_JITTER_WINDOW 20
37178825Sdfr
38178825Sdfrstruct gss_msg_order {
39178825Sdfr    OM_uint32 flags;
40178825Sdfr    OM_uint32 start;
41178825Sdfr    OM_uint32 length;
42178825Sdfr    OM_uint32 jitter_window;
43178825Sdfr    OM_uint32 first_seq;
44178825Sdfr    OM_uint32 elem[1];
45178825Sdfr};
46178825Sdfr
47178825Sdfr
48178825Sdfr/*
49178825Sdfr *
50178825Sdfr */
51178825Sdfr
52178825Sdfrstatic OM_uint32
53178825Sdfrmsg_order_alloc(OM_uint32 *minor_status,
54178825Sdfr		struct gss_msg_order **o,
55178825Sdfr		OM_uint32 jitter_window)
56178825Sdfr{
57178825Sdfr    size_t len;
58233294Sstas
59178825Sdfr    len = jitter_window * sizeof((*o)->elem[0]);
60178825Sdfr    len += sizeof(**o);
61178825Sdfr    len -= sizeof((*o)->elem[0]);
62233294Sstas
63178825Sdfr    *o = calloc(1, len);
64178825Sdfr    if (*o == NULL) {
65178825Sdfr	*minor_status = ENOMEM;
66178825Sdfr	return GSS_S_FAILURE;
67233294Sstas    }
68233294Sstas
69178825Sdfr    *minor_status = 0;
70233294Sstas    return GSS_S_COMPLETE;
71178825Sdfr}
72178825Sdfr
73178825Sdfr/*
74178825Sdfr *
75178825Sdfr */
76178825Sdfr
77178825SdfrOM_uint32
78178825Sdfr_gssapi_msg_order_create(OM_uint32 *minor_status,
79233294Sstas			 struct gss_msg_order **o,
80233294Sstas			 OM_uint32 flags,
81233294Sstas			 OM_uint32 seq_num,
82178825Sdfr			 OM_uint32 jitter_window,
83178825Sdfr			 int use_64)
84178825Sdfr{
85178825Sdfr    OM_uint32 ret;
86178825Sdfr
87178825Sdfr    if (jitter_window == 0)
88178825Sdfr	jitter_window = DEFAULT_JITTER_WINDOW;
89178825Sdfr
90178825Sdfr    ret = msg_order_alloc(minor_status, o, jitter_window);
91178825Sdfr    if(ret != GSS_S_COMPLETE)
92178825Sdfr        return ret;
93178825Sdfr
94178825Sdfr    (*o)->flags = flags;
95178825Sdfr    (*o)->length = 0;
96178825Sdfr    (*o)->first_seq = seq_num;
97178825Sdfr    (*o)->jitter_window = jitter_window;
98178825Sdfr    (*o)->elem[0] = seq_num - 1;
99178825Sdfr
100178825Sdfr    *minor_status = 0;
101178825Sdfr    return GSS_S_COMPLETE;
102178825Sdfr}
103178825Sdfr
104178825SdfrOM_uint32
105178825Sdfr_gssapi_msg_order_destroy(struct gss_msg_order **m)
106178825Sdfr{
107178825Sdfr    free(*m);
108178825Sdfr    *m = NULL;
109178825Sdfr    return GSS_S_COMPLETE;
110178825Sdfr}
111178825Sdfr
112178825Sdfrstatic void
113178825Sdfrelem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val)
114178825Sdfr{
115178825Sdfr    o->elem[slot % o->jitter_window] = val;
116178825Sdfr}
117178825Sdfr
118178825Sdfrstatic void
119233294Sstaselem_insert(struct gss_msg_order *o,
120178825Sdfr	    unsigned int after_slot,
121178825Sdfr	    OM_uint32 seq_num)
122178825Sdfr{
123178825Sdfr    assert(o->jitter_window > after_slot);
124178825Sdfr
125178825Sdfr    if (o->length > after_slot)
126178825Sdfr	memmove(&o->elem[after_slot + 1], &o->elem[after_slot],
127178825Sdfr		(o->length - after_slot - 1) * sizeof(o->elem[0]));
128178825Sdfr
129178825Sdfr    elem_set(o, after_slot, seq_num);
130178825Sdfr
131178825Sdfr    if (o->length < o->jitter_window)
132178825Sdfr	o->length++;
133178825Sdfr}
134178825Sdfr
135178825Sdfr/* rule 1: expected sequence number */
136178825Sdfr/* rule 2: > expected sequence number */
137178825Sdfr/* rule 3: seqnum < seqnum(first) */
138178825Sdfr/* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
139178825Sdfr
140178825SdfrOM_uint32
141178825Sdfr_gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num)
142178825Sdfr{
143178825Sdfr    OM_uint32 r;
144233294Sstas    size_t i;
145178825Sdfr
146178825Sdfr    if (o == NULL)
147178825Sdfr	return GSS_S_COMPLETE;
148178825Sdfr
149178825Sdfr    if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0)
150178825Sdfr	return GSS_S_COMPLETE;
151178825Sdfr
152178825Sdfr    /* check if the packet is the next in order */
153178825Sdfr    if (o->elem[0] == seq_num - 1) {
154178825Sdfr	elem_insert(o, 0, seq_num);
155178825Sdfr	return GSS_S_COMPLETE;
156178825Sdfr    }
157178825Sdfr
158178825Sdfr    r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG;
159178825Sdfr
160233294Sstas    /* sequence number larger then largest sequence number
161178825Sdfr     * or smaller then the first sequence number */
162178825Sdfr    if (seq_num > o->elem[0]
163178825Sdfr	|| seq_num < o->first_seq
164233294Sstas	|| o->length == 0)
165178825Sdfr    {
166178825Sdfr	elem_insert(o, 0, seq_num);
167178825Sdfr	if (r) {
168178825Sdfr	    return GSS_S_COMPLETE;
169178825Sdfr	} else {
170178825Sdfr	    return GSS_S_GAP_TOKEN;
171178825Sdfr	}
172178825Sdfr    }
173178825Sdfr
174178825Sdfr    assert(o->length > 0);
175178825Sdfr
176178825Sdfr    /* sequence number smaller the first sequence number */
177178825Sdfr    if (seq_num < o->elem[o->length - 1]) {
178178825Sdfr	if (r)
179178825Sdfr	    return(GSS_S_OLD_TOKEN);
180178825Sdfr	else
181178825Sdfr	    return(GSS_S_UNSEQ_TOKEN);
182178825Sdfr    }
183178825Sdfr
184178825Sdfr    if (seq_num == o->elem[o->length - 1]) {
185178825Sdfr	return GSS_S_DUPLICATE_TOKEN;
186178825Sdfr    }
187178825Sdfr
188178825Sdfr    for (i = 0; i < o->length - 1; i++) {
189178825Sdfr	if (o->elem[i] == seq_num)
190178825Sdfr	    return GSS_S_DUPLICATE_TOKEN;
191178825Sdfr	if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) {
192178825Sdfr	    elem_insert(o, i, seq_num);
193178825Sdfr	    if (r)
194178825Sdfr		return GSS_S_COMPLETE;
195178825Sdfr	    else
196178825Sdfr		return GSS_S_UNSEQ_TOKEN;
197178825Sdfr	}
198178825Sdfr    }
199178825Sdfr
200178825Sdfr    return GSS_S_FAILURE;
201178825Sdfr}
202178825Sdfr
203178825SdfrOM_uint32
204178825Sdfr_gssapi_msg_order_f(OM_uint32 flags)
205178825Sdfr{
206178825Sdfr    return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG);
207178825Sdfr}
208178825Sdfr
209178825Sdfr/*
210178825Sdfr * Translate `o` into inter-process format and export in to `sp'.
211178825Sdfr */
212178825Sdfr
213178825Sdfrkrb5_error_code
214178825Sdfr_gssapi_msg_order_export(krb5_storage *sp, struct gss_msg_order *o)
215178825Sdfr{
216178825Sdfr    krb5_error_code kret;
217178825Sdfr    OM_uint32 i;
218233294Sstas
219178825Sdfr    kret = krb5_store_int32(sp, o->flags);
220178825Sdfr    if (kret)
221178825Sdfr        return kret;
222178825Sdfr    kret = krb5_store_int32(sp, o->start);
223178825Sdfr    if (kret)
224178825Sdfr        return kret;
225178825Sdfr    kret = krb5_store_int32(sp, o->length);
226178825Sdfr    if (kret)
227178825Sdfr        return kret;
228178825Sdfr    kret = krb5_store_int32(sp, o->jitter_window);
229178825Sdfr    if (kret)
230178825Sdfr        return kret;
231178825Sdfr    kret = krb5_store_int32(sp, o->first_seq);
232178825Sdfr    if (kret)
233178825Sdfr        return kret;
234233294Sstas
235178825Sdfr    for (i = 0; i < o->jitter_window; i++) {
236178825Sdfr        kret = krb5_store_int32(sp, o->elem[i]);
237178825Sdfr	if (kret)
238178825Sdfr	    return kret;
239178825Sdfr    }
240233294Sstas
241178825Sdfr    return 0;
242178825Sdfr}
243178825Sdfr
244178825SdfrOM_uint32
245178825Sdfr_gssapi_msg_order_import(OM_uint32 *minor_status,
246233294Sstas			 krb5_storage *sp,
247178825Sdfr			 struct gss_msg_order **o)
248178825Sdfr{
249178825Sdfr    OM_uint32 ret;
250178825Sdfr    krb5_error_code kret;
251178825Sdfr    int32_t i, flags, start, length, jitter_window, first_seq;
252233294Sstas
253178825Sdfr    kret = krb5_ret_int32(sp, &flags);
254178825Sdfr    if (kret)
255178825Sdfr	goto failed;
256233294Sstas    kret = krb5_ret_int32(sp, &start);
257178825Sdfr    if (kret)
258178825Sdfr	goto failed;
259233294Sstas    kret = krb5_ret_int32(sp, &length);
260178825Sdfr    if (kret)
261178825Sdfr	goto failed;
262233294Sstas    kret = krb5_ret_int32(sp, &jitter_window);
263178825Sdfr    if (kret)
264178825Sdfr	goto failed;
265233294Sstas    kret = krb5_ret_int32(sp, &first_seq);
266178825Sdfr    if (kret)
267178825Sdfr	goto failed;
268233294Sstas
269178825Sdfr    ret = msg_order_alloc(minor_status, o, jitter_window);
270178825Sdfr    if (ret != GSS_S_COMPLETE)
271178825Sdfr        return ret;
272233294Sstas
273178825Sdfr    (*o)->flags = flags;
274178825Sdfr    (*o)->start = start;
275178825Sdfr    (*o)->length = length;
276178825Sdfr    (*o)->jitter_window = jitter_window;
277178825Sdfr    (*o)->first_seq = first_seq;
278233294Sstas
279178825Sdfr    for( i = 0; i < jitter_window; i++ ) {
280178825Sdfr        kret = krb5_ret_int32(sp, (int32_t*)&((*o)->elem[i]));
281178825Sdfr	if (kret)
282178825Sdfr	    goto failed;
283178825Sdfr    }
284178825Sdfr
285178825Sdfr    *minor_status = 0;
286178825Sdfr    return GSS_S_COMPLETE;
287178825Sdfr
288178825Sdfrfailed:
289178825Sdfr    _gssapi_msg_order_destroy(o);
290178825Sdfr    *minor_status = kret;
291178825Sdfr    return GSS_S_FAILURE;
292178825Sdfr}
293