fixed a bunch of compiler warnings, pgp end certificate listing
[strongswan.git] / src / 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$
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 #ifdef NOT_YET
73 /*
74 * Allocator cache:
75 * Because of the single-threaded nature of pluto/spdb.c,
76 * alloc()/free() is exercised many times with very small
77 * lifetime objects.
78 * Just caching last object (currently it will select the
79 * largest) will avoid this allocation mas^Wperturbations
80 *
81 */
82 struct db_ops_alloc_cache {
83 void *ptr;
84 int size;
85 };
86 #endif
87
88 #ifndef NO_DB_OPS_STATS
89 /*
90 * stats: do account for allocations
91 * displayed in db_ops_show_status()
92 */
93 struct db_ops_stats {
94 int st_curr_cnt; /* current number of allocations */
95 int st_total_cnt; /* total allocations so far */
96 size_t st_maxsz; /* max. size requested */
97 };
98 #define DB_OPS_ZERO { 0, 0, 0};
99 #define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
100 #define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
101 #define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz
102 static struct db_ops_stats db_context_st = DB_OPS_ZERO;
103 static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
104 static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
105 static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st)
106 {
107 void *ptr = malloc(size);
108 if (ptr)
109 {
110 st->st_curr_cnt++;
111 st->st_total_cnt++;
112 if (size > st->st_maxsz) st->st_maxsz=size;
113 }
114 return ptr;
115 }
116 #define ALLOC_BYTES_ST(z,st) malloc_bytes_st(z, &st);
117 #define PFREE_ST(p,st) do { st.st_curr_cnt--; free(p); } while (0);
118
119 #else
120
121 #define ALLOC_BYTES_ST(z,n) malloc(z);
122 #define PFREE_ST(p,n) free(p);
123
124 #endif /* NO_DB_OPS_STATS */
125 /* Initialize db object
126 * max_trans and max_attrs can be 0, will be dynamically expanded
127 * as a result of "add" operations
128 */
129 int
130 db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs)
131 {
132 ctx->trans0 = NULL;
133 ctx->attrs0 = NULL;
134
135 if (max_trans > 0) { /* quite silly if not */
136 ctx->trans0 = ALLOC_BYTES_ST ( sizeof(struct db_trans) * max_trans,
137 db_trans_st);
138 memset(ctx->trans0, '\0', sizeof(struct db_trans) * max_trans);
139 }
140
141 if (max_attrs > 0) { /* quite silly if not */
142 ctx->attrs0 = ALLOC_BYTES_ST (sizeof(struct db_attr) * max_attrs,
143 db_attrs_st);
144 memset(ctx->attrs0, '\0', sizeof(struct db_attr) * max_attrs);
145 }
146
147 ctx->max_trans = max_trans;
148 ctx->max_attrs = max_attrs;
149 ctx->trans_cur = ctx->trans0;
150 ctx->attrs_cur = ctx->attrs0;
151 ctx->prop.protoid = protoid;
152 ctx->prop.trans = ctx->trans0;
153 ctx->prop.trans_cnt = 0;
154 return 0;
155 }
156
157 /* Expand storage for transforms by number delta_trans */
158 static int
159 db_trans_expand(struct db_context *ctx, int delta_trans)
160 {
161 int ret = -1;
162 struct db_trans *new_trans, *old_trans;
163 int max_trans = ctx->max_trans + delta_trans;
164 int offset;
165
166 old_trans = ctx->trans0;
167 new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
168 db_trans_st);
169 if (!new_trans)
170 goto out;
171 memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
172
173 /* update trans0 (obviously) */
174 ctx->trans0 = ctx->prop.trans = new_trans;
175 /* update trans_cur (by offset) */
176 offset = (char *)(new_trans) - (char *)(old_trans);
177
178 {
179 char *cctx = (char *)(ctx->trans_cur);
180
181 cctx += offset;
182 ctx->trans_cur = (struct db_trans *)cctx;
183 }
184 /* update elem count */
185 ctx->max_trans = max_trans;
186 PFREE_ST(old_trans, db_trans_st);
187 ret = 0;
188 out:
189 return ret;
190 }
191 /*
192 * Expand storage for attributes by delta_attrs number AND
193 * rewrite trans->attr pointers
194 */
195 static int
196 db_attrs_expand(struct db_context *ctx, int delta_attrs)
197 {
198 int ret = -1;
199 struct db_attr *new_attrs, *old_attrs;
200 struct db_trans *t;
201 int ti;
202 int max_attrs = ctx->max_attrs + delta_attrs;
203 int offset;
204
205 old_attrs = ctx->attrs0;
206 new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs,
207 db_attrs_st);
208 if (!new_attrs)
209 goto out;
210
211 memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
212
213 /* update attrs0 and attrs_cur (obviously) */
214 offset = (char *)(new_attrs) - (char *)(old_attrs);
215
216 {
217 char *actx = (char *)(ctx->attrs0);
218
219 actx += offset;
220 ctx->attrs0 = (struct db_attr *)actx;
221
222 actx = (char *)ctx->attrs_cur;
223 actx += offset;
224 ctx->attrs_cur = (struct db_attr *)actx;
225 }
226
227 /* for each transform, rewrite attrs pointer by offsetting it */
228 for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
229 char *actx = (char *)(t->attrs);
230
231 actx += offset;
232 t->attrs = (struct db_attr *)actx;
233 }
234 /* update elem count */
235 ctx->max_attrs = max_attrs;
236 PFREE_ST(old_attrs, db_attrs_st);
237 ret = 0;
238 out:
239 return ret;
240 }
241 /* Allocate a new db object */
242 struct db_context *
243 db_prop_new(u_int8_t protoid, int max_trans, int max_attrs)
244 {
245 struct db_context *ctx;
246 ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), db_context_st);
247 if (!ctx) goto out;
248
249 if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
250 PFREE_ST(ctx, db_context_st);
251 ctx=NULL;
252 }
253 out:
254 return ctx;
255 }
256 /* Free a db object */
257 void
258 db_destroy(struct db_context *ctx)
259 {
260 if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st);
261 if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st);
262 PFREE_ST(ctx, db_context_st);
263 }
264 /* Start a new transform, expand trans0 is needed */
265 int
266 db_trans_add(struct db_context *ctx, u_int8_t transid)
267 {
268 /* skip incrementing current trans pointer the 1st time*/
269 if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
270 ctx->trans_cur++;
271 /*
272 * Strategy: if more space is needed, expand by
273 * <current_size>/2 + 1
274 *
275 * This happens to produce a "reasonable" sequence
276 * after few allocations, eg.:
277 * 0,1,2,4,8,13,20,31,47
278 */
279 if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
280 /* XXX:jjo if fails should shout and flag it */
281 if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
282 return -1;
283 }
284 ctx->trans_cur->transid = transid;
285 ctx->trans_cur->attrs=ctx->attrs_cur;
286 ctx->trans_cur->attr_cnt = 0;
287 ctx->prop.trans_cnt++;
288 return 0;
289 }
290 /* Add attr copy to current transform, expanding attrs0 if needed */
291 int
292 db_attr_add(struct db_context *ctx, const struct db_attr *a)
293 {
294 /*
295 * Strategy: if more space is needed, expand by
296 * <current_size>/2 + 1
297 */
298 if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
299 /* XXX:jjo if fails should shout and flag it */
300 if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
301 return -1;
302 }
303 *ctx->attrs_cur++=*a;
304 ctx->trans_cur->attr_cnt++;
305 return 0;
306 }
307 /* Add attr copy (by value) to current transform,
308 * expanding attrs0 if needed, just calls db_attr_add().
309 */
310 int
311 db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val)
312 {
313 struct db_attr attr;
314 attr.type = type;
315 attr.val = val;
316 return db_attr_add (ctx, &attr);
317 }
318 #ifndef NO_DB_OPS_STATS
319 int
320 db_ops_show_status(void)
321 {
322 whack_log(RC_COMMENT, "stats " __FILE__ ": "
323 DB_OPS_STATS_DESC " :"
324 DB_OPS_STATS_STR("context")
325 DB_OPS_STATS_STR("trans")
326 DB_OPS_STATS_STR("attrs"),
327 DB_OPS_STATS_F(db_context_st),
328 DB_OPS_STATS_F(db_trans_st),
329 DB_OPS_STATS_F(db_attrs_st)
330 );
331 return 0;
332 }
333 #endif /* NO_DB_OPS_STATS */
334 /*
335 * From below to end just testing stuff ....
336 */
337 #ifdef TEST
338 static void db_prop_print(struct db_prop *p)
339 {
340 struct db_trans *t;
341 struct db_attr *a;
342 int ti, ai;
343 enum_names *n, *n_at, *n_av;
344 printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
345 for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
346 switch( t->transid) {
347 case PROTO_ISAKMP:
348 n=&isakmp_transformid_names;break;
349 case PROTO_IPSEC_ESP:
350 n=&esp_transformid_names;break;
351 default:
352 continue;
353 }
354 printf(" transid=\"%s\"\n",
355 enum_name(n, t->transid));
356 for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
357 int i;
358 switch( t->transid) {
359 case PROTO_ISAKMP:
360 n_at=&oakley_attr_names;
361 i=a->type|ISAKMP_ATTR_AF_TV;
362 n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
363 break;
364 case PROTO_IPSEC_ESP:
365 n_at=&ipsec_attr_names;
366 i=a->type|ISAKMP_ATTR_AF_TV;
367 n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
368 break;
369 default:
370 continue;
371 }
372 printf(" type=\"%s\" value=\"%s\"\n",
373 enum_name(n_at, i),
374 enum_name(n_av, a->val));
375 }
376 }
377
378 }
379 static void db_print(struct db_context *ctx)
380 {
381 printf("trans_cur diff=%d, attrs_cur diff=%d\n",
382 ctx->trans_cur - ctx->trans0,
383 ctx->attrs_cur - ctx->attrs0);
384 db_prop_print(&ctx->prop);
385 }
386
387 void
388 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
389 void abort(void);
390 void
391 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
392 {
393 fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
394 abort(); /* exiting correctly doesn't always work */
395 }
396 int main(void) {
397 struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
398 db_trans_add(ctx, KEY_IKE);
399 db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
400 db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
401 db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
402 db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
403 db_trans_add(ctx, KEY_IKE);
404 db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
405 db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
406 db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
407 db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);
408 db_trans_add(ctx, ESP_3DES);
409 db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
410 db_print(ctx);
411 db_destroy(ctx);
412 return 0;
413 }
414 #endif