5864099d3f239c5828212fa5997a4d20de8ba303
[strongswan.git] / src / pluto / defs.c
1 /* misc. universal things
2 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
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 #include <stdlib.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <dirent.h>
21 #include <time.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include <freeswan.h>
26
27 #include "constants.h"
28 #include "defs.h"
29 #include "log.h"
30 #include "whack.h" /* for RC_LOG_SERIOUS */
31
32 const chunk_t empty_chunk = { NULL, 0 };
33
34 bool
35 all_zero(const unsigned char *m, size_t len)
36 {
37 size_t i;
38
39 for (i = 0; i != len; i++)
40 if (m[i] != '\0')
41 return FALSE;
42 return TRUE;
43 }
44
45 /* memory allocation
46 *
47 * LEAK_DETECTIVE puts a wrapper around each allocation and maintains
48 * a list of live ones. If a dead one is freed, an assertion MIGHT fail.
49 * If the live list is currupted, that will often be detected.
50 * In the end, report_leaks() is called, and the names of remaining
51 * live allocations are printed. At the moment, it is hoped, not that
52 * the list is empty, but that there will be no surprises.
53 *
54 * Accepted Leaks:
55 * - "struct iface" and "device name" (for "discovered" net interfaces)
56 * - "struct event in event_schedule()" (events not associated with states)
57 * - "Pluto lock name" (one only, needed until end -- why bother?)
58 */
59
60 #ifdef LEAK_DETECTIVE
61
62 /* this magic number is 3671129837 decimal (623837458 complemented) */
63 #define LEAK_MAGIC 0xDAD0FEEDul
64
65 union mhdr {
66 struct {
67 const char *name;
68 union mhdr *older, *newer;
69 unsigned long magic;
70 } i; /* info */
71 unsigned long junk; /* force maximal alignment */
72 };
73
74 static union mhdr *allocs = NULL;
75
76 void *alloc_bytes(size_t size, const char *name)
77 {
78 union mhdr *p = malloc(sizeof(union mhdr) + size);
79
80 if (p == NULL)
81 exit_log("unable to malloc %lu bytes for %s"
82 , (unsigned long) size, name);
83 p->i.name = name;
84 p->i.older = allocs;
85 if (allocs != NULL)
86 allocs->i.newer = p;
87 allocs = p;
88 p->i.newer = NULL;
89 p->i.magic = LEAK_MAGIC;
90
91 memset(p+1, '\0', size);
92 return p+1;
93 }
94
95 void *
96 clone_bytes(const void *orig, size_t size, const char *name)
97 {
98 void *p = alloc_bytes(size, name);
99
100 memcpy(p, orig, size);
101 return p;
102 }
103
104 void
105 pfree(void *ptr)
106 {
107 union mhdr *p;
108
109 passert(ptr != NULL);
110 p = ((union mhdr *)ptr) - 1;
111 passert(p->i.magic == LEAK_MAGIC);
112 if (p->i.older != NULL)
113 {
114 passert(p->i.older->i.newer == p);
115 p->i.older->i.newer = p->i.newer;
116 }
117 if (p->i.newer == NULL)
118 {
119 passert(p == allocs);
120 allocs = p->i.older;
121 }
122 else
123 {
124 passert(p->i.newer->i.older == p);
125 p->i.newer->i.older = p->i.older;
126 }
127 p->i.magic = ~LEAK_MAGIC;
128 free(p);
129 }
130
131 void
132 report_leaks(void)
133 {
134 union mhdr
135 *p = allocs,
136 *pprev = NULL;
137 unsigned long n = 0;
138
139 while (p != NULL)
140 {
141 passert(p->i.magic == LEAK_MAGIC);
142 passert(pprev == p->i.newer);
143 pprev = p;
144 p = p->i.older;
145 n++;
146 if (p == NULL || pprev->i.name != p->i.name)
147 {
148 if (n != 1)
149 plog("leak: %lu * %s", n, pprev->i.name);
150 else
151 plog("leak: %s", pprev->i.name);
152 n = 0;
153 }
154 }
155 }
156
157 #else /* !LEAK_DETECTIVE */
158
159 void *alloc_bytes(size_t size, const char *name)
160 {
161 void *p = malloc(size);
162
163 if (p == NULL)
164 exit_log("unable to malloc %lu bytes for %s"
165 , (unsigned long) size, name);
166 memset(p, '\0', size);
167 return p;
168 }
169
170 void *clone_bytes(const void *orig, size_t size, const char *name)
171 {
172 void *p = malloc(size);
173
174 if (p == NULL)
175 exit_log("unable to malloc %lu bytes for %s"
176 , (unsigned long) size, name);
177 memcpy(p, orig, size);
178 return p;
179 }
180 #endif /* !LEAK_DETECTIVE */
181
182 /* Note that there may be as many as six IDs that are temporary at
183 * one time before unsharing the two ends of a connection. So we need
184 * at least six temporary buffers for DER_ASN1_DN IDs.
185 * We rotate them. Be careful!
186 */
187 #define MAX_BUF 10
188
189 char*
190 temporary_cyclic_buffer(void)
191 {
192 static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */
193 static int counter = 0; /* cyclic counter */
194
195 if (++counter == MAX_BUF) counter = 0; /* next internal buffer */
196 return buf[counter]; /* assign temporary buffer */
197 }
198
199 /* concatenates two sub paths into a string with a maximum size of BUF_LEN
200 * use for temporary storage only
201 */
202 const char*
203 concatenate_paths(const char *a, const char *b)
204 {
205 char *c;
206
207 if (*b == '/' || *b == '.')
208 return b;
209
210 c = temporary_cyclic_buffer();
211 snprintf(c, BUF_LEN, "%s/%s", a, b);
212 return c;
213 }
214
215 /* compare two chunks, returns zero if a equals b
216 * negative/positive if a is earlier/later in the alphabet than b
217 */
218 int
219 cmp_chunk(chunk_t a, chunk_t b)
220 {
221 int cmp_len, len, cmp_value;
222
223 cmp_len = a.len - b.len;
224 len = (cmp_len < 0)? a.len : b.len;
225 cmp_value = memcmp(a.ptr, b.ptr, len);
226
227 return (cmp_value == 0)? cmp_len : cmp_value;
228 };
229
230 /* moves a chunk to a memory position, chunk is freed afterwards
231 * position pointer is advanced after the insertion point
232 */
233 void
234 mv_chunk(u_char **pos, chunk_t content)
235 {
236 if (content.len > 0)
237 {
238 chunkcpy(*pos, content);
239 freeanychunk(content);
240 }
241 }
242
243 /*
244 * write the binary contents of a chunk_t to a file
245 */
246 bool
247 write_chunk(const char *filename, const char *label, chunk_t ch
248 , mode_t mask, bool force)
249 {
250 mode_t oldmask;
251 FILE *fd;
252
253 if (!force)
254 {
255 fd = fopen(filename, "r");
256 if (fd)
257 {
258 fclose(fd);
259 plog(" %s file '%s' already exists", label, filename);
260 return FALSE;
261 }
262 }
263
264 /* set umask */
265 oldmask = umask(mask);
266
267 fd = fopen(filename, "w");
268
269 if (fd)
270 {
271 fwrite(ch.ptr, sizeof(u_char), ch.len, fd);
272 fclose(fd);
273 plog(" written %s file '%s' (%d bytes)", label, filename, (int)ch.len);
274 umask(oldmask);
275 return TRUE;
276 }
277 else
278 {
279 plog(" could not open %s file '%s' for writing", label, filename);
280 umask(oldmask);
281 return FALSE;
282 }
283 }
284
285 /* Names of the months */
286
287 static const char* months[] = {
288 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
289 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
290 };
291
292
293 /*
294 * Display a date either in local or UTC time
295 */
296 char*
297 timetoa(const time_t *time, bool utc)
298 {
299 static char buf[TIMETOA_BUF];
300
301 if (*time == UNDEFINED_TIME)
302 sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" ");
303 else
304 {
305 struct tm *t = (utc)? gmtime(time) : localtime(time);
306
307 sprintf(buf, "%s %02d %02d:%02d:%02d%s%04d",
308 months[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
309 (utc)?" UTC ":" ", t->tm_year + 1900
310 );
311 }
312 return buf;
313 }
314
315 /* checks if the expiration date has been reached and
316 * warns during the warning_interval of the imminent
317 * expiry. strict=TRUE declares a fatal error,
318 * strict=FALSE issues a warning upon expiry.
319 */
320 const char*
321 check_expiry(time_t expiration_date, int warning_interval, bool strict)
322 {
323 time_t now;
324 int time_left;
325
326 if (expiration_date == UNDEFINED_TIME)
327 return "ok (expires never)";
328
329 /* determine the current time */
330 time(&now);
331
332 time_left = (expiration_date - now);
333 if (time_left < 0)
334 return strict? "fatal (expired)" : "warning (expired)";
335
336 if (time_left > 86400*warning_interval)
337 return "ok";
338 {
339 static char buf[35]; /* temporary storage */
340 const char* unit = "second";
341
342 if (time_left > 172800)
343 {
344 time_left /= 86400;
345 unit = "day";
346 }
347 else if (time_left > 7200)
348 {
349 time_left /= 3600;
350 unit = "hour";
351 }
352 else if (time_left > 120)
353 {
354 time_left /= 60;
355 unit = "minute";
356 }
357 snprintf(buf, 35, "warning (expires in %d %s%s)", time_left,
358 unit, (time_left == 1)?"":"s");
359 return buf;
360 }
361 }
362
363
364 /*
365 * Filter eliminating the directory entries '.' and '..'
366 */
367 int
368 file_select(const struct dirent *entry)
369 {
370 return strcmp(entry->d_name, "." ) &&
371 strcmp(entry->d_name, "..");
372 }
373
374