Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: sequence.c,v 1.2 2017/01/28 21:31:46 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2003 - 2006 Kungliga Tekniska Hgskolan
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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