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