1 /*	$NetBSD: sequence.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "gsskrb5_locl.h"
37 
38 #define DEFAULT_JITTER_WINDOW 20
39 
40 struct gss_msg_order {
41     OM_uint32 flags;
42     OM_uint32 start;
43     OM_uint32 length;
44     OM_uint32 jitter_window;
45     OM_uint32 first_seq;
46     OM_uint32 elem[1];
47 };
48 
49 
50 /*
51  *
52  */
53 
54 static OM_uint32
msg_order_alloc(OM_uint32 * minor_status,struct gss_msg_order ** o,OM_uint32 jitter_window)55 msg_order_alloc(OM_uint32 *minor_status,
56 		struct gss_msg_order **o,
57 		OM_uint32 jitter_window)
58 {
59     size_t len;
60 
61     len = jitter_window * sizeof((*o)->elem[0]);
62     len += sizeof(**o);
63     len -= sizeof((*o)->elem[0]);
64 
65     *o = calloc(1, len);
66     if (*o == NULL) {
67 	*minor_status = ENOMEM;
68 	return GSS_S_FAILURE;
69     }
70 
71     *minor_status = 0;
72     return GSS_S_COMPLETE;
73 }
74 
75 /*
76  *
77  */
78 
79 OM_uint32
_gssapi_msg_order_create(OM_uint32 * minor_status,struct gss_msg_order ** o,OM_uint32 flags,OM_uint32 seq_num,OM_uint32 jitter_window,int use_64)80 _gssapi_msg_order_create(OM_uint32 *minor_status,
81 			 struct gss_msg_order **o,
82 			 OM_uint32 flags,
83 			 OM_uint32 seq_num,
84 			 OM_uint32 jitter_window,
85 			 int use_64)
86 {
87     OM_uint32 ret;
88 
89     if (jitter_window == 0)
90 	jitter_window = DEFAULT_JITTER_WINDOW;
91 
92     ret = msg_order_alloc(minor_status, o, jitter_window);
93     if(ret != GSS_S_COMPLETE)
94         return ret;
95 
96     (*o)->flags = flags;
97     (*o)->length = 0;
98     (*o)->first_seq = seq_num;
99     (*o)->jitter_window = jitter_window;
100     (*o)->elem[0] = seq_num - 1;
101 
102     *minor_status = 0;
103     return GSS_S_COMPLETE;
104 }
105 
106 OM_uint32
_gssapi_msg_order_destroy(struct gss_msg_order ** m)107 _gssapi_msg_order_destroy(struct gss_msg_order **m)
108 {
109     free(*m);
110     *m = NULL;
111     return GSS_S_COMPLETE;
112 }
113 
114 static void
elem_set(struct gss_msg_order * o,unsigned int slot,OM_uint32 val)115 elem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val)
116 {
117     o->elem[slot % o->jitter_window] = val;
118 }
119 
120 static void
elem_insert(struct gss_msg_order * o,unsigned int after_slot,OM_uint32 seq_num)121 elem_insert(struct gss_msg_order *o,
122 	    unsigned int after_slot,
123 	    OM_uint32 seq_num)
124 {
125     assert(o->jitter_window > after_slot);
126 
127     if (o->length > after_slot)
128 	memmove(&o->elem[after_slot + 1], &o->elem[after_slot],
129 		(o->length - after_slot - 1) * sizeof(o->elem[0]));
130 
131     elem_set(o, after_slot, seq_num);
132 
133     if (o->length < o->jitter_window)
134 	o->length++;
135 }
136 
137 /* rule 1: expected sequence number */
138 /* rule 2: > expected sequence number */
139 /* rule 3: seqnum < seqnum(first) */
140 /* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
141 
142 OM_uint32
_gssapi_msg_order_check(struct gss_msg_order * o,OM_uint32 seq_num)143 _gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num)
144 {
145     OM_uint32 r;
146     size_t i;
147 
148     if (o == NULL)
149 	return GSS_S_COMPLETE;
150 
151     if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0)
152 	return GSS_S_COMPLETE;
153 
154     /* check if the packet is the next in order */
155     if (o->elem[0] == seq_num - 1) {
156 	elem_insert(o, 0, seq_num);
157 	return GSS_S_COMPLETE;
158     }
159 
160     r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG;
161 
162     /* sequence number larger then largest sequence number
163      * or smaller then the first sequence number */
164     if (seq_num > o->elem[0]
165 	|| seq_num < o->first_seq
166 	|| o->length == 0)
167     {
168 	elem_insert(o, 0, seq_num);
169 	if (r) {
170 	    return GSS_S_COMPLETE;
171 	} else {
172 	    return GSS_S_GAP_TOKEN;
173 	}
174     }
175 
176     assert(o->length > 0);
177 
178     /* sequence number smaller the first sequence number */
179     if (seq_num < o->elem[o->length - 1]) {
180 	if (r)
181 	    return(GSS_S_OLD_TOKEN);
182 	else
183 	    return(GSS_S_UNSEQ_TOKEN);
184     }
185 
186     if (seq_num == o->elem[o->length - 1]) {
187 	return GSS_S_DUPLICATE_TOKEN;
188     }
189 
190     for (i = 0; i < o->length - 1; i++) {
191 	if (o->elem[i] == seq_num)
192 	    return GSS_S_DUPLICATE_TOKEN;
193 	if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) {
194 	    elem_insert(o, i, seq_num);
195 	    if (r)
196 		return GSS_S_COMPLETE;
197 	    else
198 		return GSS_S_UNSEQ_TOKEN;
199 	}
200     }
201 
202     return GSS_S_FAILURE;
203 }
204 
205 OM_uint32
_gssapi_msg_order_f(OM_uint32 flags)206 _gssapi_msg_order_f(OM_uint32 flags)
207 {
208     return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG);
209 }
210 
211 /*
212  * Translate `o` into inter-process format and export in to `sp'.
213  */
214 
215 krb5_error_code
_gssapi_msg_order_export(krb5_storage * sp,struct gss_msg_order * o)216 _gssapi_msg_order_export(krb5_storage *sp, struct gss_msg_order *o)
217 {
218     krb5_error_code kret;
219     OM_uint32 i;
220 
221     kret = krb5_store_int32(sp, o->flags);
222     if (kret)
223         return kret;
224     kret = krb5_store_int32(sp, o->start);
225     if (kret)
226         return kret;
227     kret = krb5_store_int32(sp, o->length);
228     if (kret)
229         return kret;
230     kret = krb5_store_int32(sp, o->jitter_window);
231     if (kret)
232         return kret;
233     kret = krb5_store_int32(sp, o->first_seq);
234     if (kret)
235         return kret;
236 
237     for (i = 0; i < o->jitter_window; i++) {
238         kret = krb5_store_int32(sp, o->elem[i]);
239 	if (kret)
240 	    return kret;
241     }
242 
243     return 0;
244 }
245 
246 OM_uint32
_gssapi_msg_order_import(OM_uint32 * minor_status,krb5_storage * sp,struct gss_msg_order ** o)247 _gssapi_msg_order_import(OM_uint32 *minor_status,
248 			 krb5_storage *sp,
249 			 struct gss_msg_order **o)
250 {
251     OM_uint32 ret;
252     krb5_error_code kret;
253     int32_t i, flags, start, length, jitter_window, first_seq;
254 
255     kret = krb5_ret_int32(sp, &flags);
256     if (kret)
257 	goto failed;
258     kret = krb5_ret_int32(sp, &start);
259     if (kret)
260 	goto failed;
261     kret = krb5_ret_int32(sp, &length);
262     if (kret)
263 	goto failed;
264     kret = krb5_ret_int32(sp, &jitter_window);
265     if (kret)
266 	goto failed;
267     kret = krb5_ret_int32(sp, &first_seq);
268     if (kret)
269 	goto failed;
270 
271     ret = msg_order_alloc(minor_status, o, jitter_window);
272     if (ret != GSS_S_COMPLETE)
273         return ret;
274 
275     (*o)->flags = flags;
276     (*o)->start = start;
277     (*o)->length = length;
278     (*o)->jitter_window = jitter_window;
279     (*o)->first_seq = first_seq;
280 
281     for( i = 0; i < jitter_window; i++ ) {
282         kret = krb5_ret_int32(sp, (int32_t*)&((*o)->elem[i]));
283 	if (kret)
284 	    goto failed;
285     }
286 
287     *minor_status = 0;
288     return GSS_S_COMPLETE;
289 
290 failed:
291     _gssapi_msg_order_destroy(o);
292     *minor_status = kret;
293     return GSS_S_FAILURE;
294 }
295