OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / pluto / db_ops.c
1 /* 
2  * Dynamic db (proposal, transforms, attributes) handling.
3  * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
4  * 
5  * $Id: db_ops.c,v 1.3 2006-03-23 01:19:17 steveb Exp $
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2 of the License, or (at your
10  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * for more details.
16  */
17
18 /* 
19  * The stratedy is to have (full contained) struct db_prop in db_context
20  * pointing to ONE dynamically sizable transform vector (trans0).
21  * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
22  * in a "serialized" way (attributes storage is used in linear sequence for 
23  * subsecuent transforms).
24  *
25  * Resizing for both trans0 and attrs0 is supported:
26  * - For trans0: quite simple, just allocate and copy trans. vector content
27  *               also update trans_cur (by offset)
28  * - For attrs0: after allocating and copying attrs, I must rewrite each
29  *               trans->attrs present in trans0; to achieve this, calculate
30  *               attrs pointer offset (new minus old) and iterate over 
31  *               each transform "adding" this difference.
32  *               also update attrs_cur (by offset)
33  *
34  * db_context structure:
35  *      +---------------------+
36  *      |  prop               |
37  *      |    .protoid         |
38  *      |    .trans           | --+
39  *      |    .trans_cnt       |   |
40  *      +---------------------+ <-+
41  *      |  trans0             | ----> { trans#1 | ... | trans#i | ...   }
42  *      +---------------------+                       ^
43  *      |  trans_cur          | ----------------------' current transf.
44  *      +---------------------+
45  *      |  attrs0             | ----> { attr#1 | ... | attr#j | ...  }
46  *      +---------------------+                      ^
47  *      |  attrs_cur          | ---------------------' current attr.
48  *      +---------------------+
49  *      | max_trans,max_attrs |  max_trans/attrs: number of elem. of each vector
50  *      +---------------------+
51  *
52  * See testing examples at end for interface usage.
53  */
54 #include <stdio.h>
55 #include <unistd.h>
56 #include <string.h>
57 #include <malloc.h>
58 #include <sys/types.h>
59
60 #include <freeswan.h>
61
62 #include "constants.h"
63 #include "defs.h"
64 #include "state.h"
65 #include "packet.h"
66 #include "spdb.h"
67 #include "db_ops.h"
68 #include "log.h"
69 #include "whack.h"
70
71 #include <assert.h>
72
73 #ifndef NO_PLUTO
74 #else
75 #define passert(x) assert(x)
76 extern int debug;       /* eg: spi.c */
77 #define DBG(cond, action)   { if (debug) { action ; } }
78 #define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
79 #define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
80 void * alloc_bytes(size_t size, const char *name) {
81         void *p=malloc(size);
82         if (p == NULL)
83                 fprintf(stderr, "unable to malloc %lu bytes for %s",
84                         (unsigned long) size, name);
85         memset(p, '\0', size);
86         return p;
87 }
88 #define pfreeany(ptr) free(ptr)
89
90 #endif
91
92 #ifdef NOT_YET
93 /*
94  *      Allocator cache:
95  *      Because of the single-threaded nature of pluto/spdb.c, 
96  *      alloc()/free() is exercised many times with very small
97  *      lifetime objects.
98  *      Just caching last object (currently it will select the
99  *      largest) will avoid this allocation mas^Wperturbations
100  *
101  */
102 struct db_ops_alloc_cache {
103         void *ptr;
104         int size;
105 };
106 #endif
107
108 #ifndef NO_DB_OPS_STATS
109 /*      
110  *      stats: do account for allocations       
111  *      displayed in db_ops_show_status() 
112  */
113 struct db_ops_stats {
114         int st_curr_cnt;        /* current number of allocations */
115         int st_total_cnt;       /* total allocations so far */
116         size_t st_maxsz;        /* max. size requested */
117 };
118 #define DB_OPS_ZERO { 0, 0, 0};
119 #define DB_OPS_STATS_DESC   "{curr_cnt, total_cnt, maxsz}"
120 #define DB_OPS_STATS_STR(name)  name "={%d,%d,%d} "
121 #define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (st).st_maxsz
122 static struct db_ops_stats db_context_st = DB_OPS_ZERO;
123 static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
124 static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
125 static __inline__ void * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st) 
126 {
127         void *ptr = alloc_bytes(size, str);
128         if (ptr)  {
129                 st->st_curr_cnt++;
130                 st->st_total_cnt++;
131                 if (size > st->st_maxsz) st->st_maxsz=size;
132         }       
133         return ptr;
134 }
135 #define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
136 #define PFREE_ST(p,st)         do { st.st_curr_cnt--; pfree(p);  } while (0);
137
138 #else
139
140 #define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
141 #define PFREE_ST(p,n)         pfree(p);
142
143 #endif /* NO_DB_OPS_STATS */
144 /*      Initialize db object
145  *      max_trans and max_attrs can be 0, will be dynamically expanded
146  *      as a result of "add" operations
147  */
148 int
149 db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) 
150 {
151         int ret=-1;
152
153         ctx->trans0 = NULL;
154         ctx->attrs0 = NULL;
155
156         if (max_trans > 0) { /* quite silly if not */
157                 ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, 
158                         "db_context->trans", db_trans_st);
159                 if (!ctx->trans0) goto out;
160         }
161
162         if (max_attrs > 0) { /* quite silly if not */
163                 ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs,
164                                 "db_context->attrs", db_attrs_st);
165                 if (!ctx->attrs0) goto out;
166         }
167         ret = 0;
168 out:
169         if (ret < 0 && ctx->trans0) {
170                 PFREE_ST(ctx->trans0, db_trans_st);
171                 ctx->trans0 = NULL;
172         }
173         ctx->max_trans = max_trans;
174         ctx->max_attrs = max_attrs;
175         ctx->trans_cur = ctx->trans0;
176         ctx->attrs_cur = ctx->attrs0;
177         ctx->prop.protoid = protoid;
178         ctx->prop.trans = ctx->trans0;
179         ctx->prop.trans_cnt = 0;
180         return ret;
181 }
182
183 #define INCR_POINTER(PT, OFF)  PT = (void *)((char *)PT + OFF)
184
185 /*      Expand storage for transforms by number delta_trans */
186 static int
187 db_trans_expand(struct db_context *ctx, int delta_trans)
188 {
189         int ret = -1;
190         struct db_trans *new_trans, *old_trans;
191         int max_trans = ctx->max_trans + delta_trans;
192         int offset;
193
194         old_trans = ctx->trans0;
195         new_trans = alloc_bytes ( sizeof (struct db_trans) * max_trans, 
196                         "db_context->trans (expand)");
197         if (!new_trans)
198                 goto out;
199         memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
200         
201         /* update trans0 (obviously) */
202         ctx->trans0 = ctx->prop.trans = new_trans;
203         /* update trans_cur (by offset) */
204         offset = (char *)(new_trans) - (char *)(old_trans);
205         INCR_POINTER(ctx->trans_cur, offset);
206         /* update elem count */
207         ctx->max_trans = max_trans;
208         pfree(old_trans);
209         ret = 0;
210 out:
211         return ret;
212 }
213
214 /*      
215  *      Expand storage for attributes by delta_attrs number AND
216  *      rewrite trans->attr pointers
217  */
218 static int
219 db_attrs_expand(struct db_context *ctx, int delta_attrs)
220 {
221         int ret = -1;
222         struct db_attr *new_attrs, *old_attrs;
223         struct db_trans *t;
224         int ti;
225         int max_attrs = ctx->max_attrs + delta_attrs;
226         int offset;
227
228         old_attrs = ctx->attrs0;
229         new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, 
230                         "db_context->attrs (expand)", db_attrs_st);
231         if (!new_attrs)
232                 goto out;
233
234         memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
235         
236         /* update attrs0 and attrs_cur (obviously) */
237         offset = (char *)(new_attrs) - (char *)(old_attrs);
238         INCR_POINTER(ctx->attrs0, offset);
239         INCR_POINTER(ctx->attrs_cur, offset);
240         /* for each transform, rewrite attrs pointer by offsetting it */
241         for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
242                 INCR_POINTER(t->attrs, offset);
243         }
244         /* update elem count */
245         ctx->max_attrs = max_attrs;
246         PFREE_ST(old_attrs, db_attrs_st);
247         ret = 0;
248 out:
249         return ret;
250 }
251 /*      Allocate a new db object */
252 struct db_context * 
253 db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) 
254 {
255         struct db_context *ctx;
256         ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), "db_context", db_context_st);
257         if (!ctx) goto out;
258         
259         if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
260                 PFREE_ST(ctx, db_context_st);
261                 ctx=NULL;
262         }
263 out:
264         return ctx;
265 }
266 /*      Free a db object */
267 void
268 db_destroy(struct db_context *ctx)
269 {
270         PFREE_ST(ctx->trans0, db_trans_st);
271         PFREE_ST(ctx->attrs0, db_attrs_st);
272         PFREE_ST(ctx, db_context_st);
273 }
274 /*      Start a new transform, expand trans0 is needed */
275 int
276 db_trans_add(struct db_context *ctx, u_int8_t transid)
277 {
278         /*      skip incrementing current trans pointer the 1st time*/
279         if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
280                 ctx->trans_cur++;
281         /*      
282          *      Strategy: if more space is needed, expand by 
283          *                <current_size>/2 + 1
284          *
285          *      This happens to produce a "reasonable" sequence
286          *      after few allocations, eg.:
287          *      0,1,2,4,8,13,20,31,47
288          */
289         if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
290                 /* XXX:jjo if fails should shout and flag it */
291                 if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
292                         return -1;
293         }
294         ctx->trans_cur->transid = transid;
295         ctx->trans_cur->attrs=ctx->attrs_cur;
296         ctx->trans_cur->attr_cnt = 0;
297         ctx->prop.trans_cnt++;
298         return 0;
299 }
300 /*      Add attr copy to current transform, expanding attrs0 if needed */
301 int
302 db_attr_add(struct db_context *ctx, const struct db_attr *a) 
303 {
304         /*      
305          *      Strategy: if more space is needed, expand by 
306          *                <current_size>/2 + 1
307          */
308         if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
309                 /* XXX:jjo if fails should shout and flag it */
310                 if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
311                         return -1;
312         }
313         *ctx->attrs_cur++=*a;
314         ctx->trans_cur->attr_cnt++;
315         return 0;
316 }
317 /*      Add attr copy (by value) to current transform, 
318  *      expanding attrs0 if needed, just calls db_attr_add().
319  */
320 int
321 db_attr_add_values(struct db_context *ctx,  u_int16_t type, u_int16_t val)
322 {
323         struct db_attr attr;
324         attr.type = type;
325         attr.val = val;
326         return db_attr_add (ctx, &attr);
327 }
328 /* 
329  * From below to end just testing stuff ....
330  */
331 #ifndef NO_DB_OPS_STATS
332 int
333 db_ops_show_status(void)
334 {
335         whack_log(RC_COMMENT, "stats : " 
336                         DB_OPS_STATS_DESC " :"
337                         DB_OPS_STATS_STR("context")
338                         DB_OPS_STATS_STR("trans")
339                         DB_OPS_STATS_STR("attrs"),
340                         DB_OPS_STATS_F(db_context_st),
341                         DB_OPS_STATS_F(db_trans_st),
342                         DB_OPS_STATS_F(db_attrs_st)
343                         );
344         return 0;
345 }
346 #endif /* NO_DB_OPS_STATS */
347 #ifdef TEST
348 static void db_prop_print(struct db_prop *p)
349 {
350         struct db_trans *t;
351         struct db_attr *a;
352         int ti, ai;
353         enum_names *n, *n_at, *n_av;
354         printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
355         for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
356                 switch( t->transid) {
357                         case PROTO_ISAKMP:
358                                 n=&isakmp_transformid_names;break;
359                         case PROTO_IPSEC_ESP:
360                                 n=&esp_transformid_names;break;
361                         default:
362                                 continue;
363                 }
364                 printf("  transid=\"%s\"\n", 
365                         enum_name(n, t->transid));
366                 for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
367                         int i;
368                         switch( t->transid) {
369                                 case PROTO_ISAKMP:
370                                         n_at=&oakley_attr_names;
371                                         i=a->type|ISAKMP_ATTR_AF_TV;
372                                         n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
373                                         break;
374                                 case PROTO_IPSEC_ESP:
375                                         n_at=&ipsec_attr_names;
376                                         i=a->type|ISAKMP_ATTR_AF_TV;
377                                         n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
378                                         break;
379                                 default:
380                                         continue;
381                         }
382                         printf("    type=\"%s\" value=\"%s\"\n", 
383                                 enum_name(n_at, i),
384                                 enum_name(n_av, a->val));
385                 }
386         }
387
388 }
389 static void db_print(struct db_context *ctx) 
390 {
391         printf("trans_cur diff=%d, attrs_cur diff=%d\n", 
392                         ctx->trans_cur - ctx->trans0,
393                         ctx->attrs_cur - ctx->attrs0);
394         db_prop_print(&ctx->prop);
395 }
396
397 void
398 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
399 void abort(void);
400 void
401 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
402 {
403     fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
404     abort();    /* exiting correctly doesn't always work */
405 }
406 int main(void) {
407         struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
408         db_trans_add(ctx, KEY_IKE);
409         db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_DES_CBC);
410         db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
411         db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
412         db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
413         db_trans_add(ctx, KEY_IKE);
414         db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
415         db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
416         db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
417         db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
418         db_trans_add(ctx, KEY_IKE);
419         db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
420         db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
421         db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
422         db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);       
423         db_trans_add(ctx, ESP_3DES);
424         db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
425         db_trans_add(ctx, ESP_DES);
426         db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
427         db_print(ctx);
428         db_destroy(ctx);
429         return 0;
430 }
431 #endif