1/*	$KAME: backupsa.c,v 1.16 2001/12/31 20:13:40 thorpej Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/param.h>
34#include <sys/socket.h>
35
36#include <stdlib.h>
37#include <stdio.h>
38#include <string.h>
39#include <ctype.h>
40
41#include <netinet/in.h>
42#ifdef IPV6_INRIA_VERSION
43#include <netinet/ipsec.h>
44#else
45#include <netinet6/ipsec.h>
46#endif
47
48#if TIME_WITH_SYS_TIME
49# include <sys/time.h>
50# include <time.h>
51#else
52# if HAVE_SYS_TIME_H
53#  include <sys/time.h>
54# else
55#  include <time.h>
56# endif
57#endif
58
59#include "var.h"
60#include "misc.h"
61#include "vmbuf.h"
62#include "str2val.h"
63#include "plog.h"
64#include "debug.h"
65
66#include "localconf.h"
67#include "sockmisc.h"
68#include "safefile.h"
69#include "backupsa.h"
70#include "libpfkey.h"
71
72/*
73 * (time string)%(sa parameter)
74 * (time string) := ex. Nov 24 18:22:48 1986
75 * (sa parameter) :=
76 *    src dst satype spi mode reqid wsize \
77 *    e_type e_keylen a_type a_keylen flags \
78 *    l_alloc l_bytes l_addtime l_usetime seq keymat
79 */
80static char *format = "%b %d %T %Y";	/* time format */
81static char *strmon[12] = {
82        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
83        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
84};
85
86static char *str2tmx __P((char *, struct tm *));
87static int str2num __P((char *, int));
88
89/*
90 * output the sa parameter.
91 */
92int
93backupsa_to_file(satype, mode, src, dst, spi, reqid, wsize,
94                keymat, e_type, e_keylen, a_type, a_keylen, flags,
95                l_alloc, l_bytes, l_addtime, l_usetime, seq)
96        u_int satype, mode, wsize;
97        struct sockaddr *src, *dst;
98        u_int32_t spi, reqid;
99        caddr_t keymat;
100        u_int e_type, e_keylen, a_type, a_keylen, flags;
101        u_int32_t l_alloc;
102        u_int64_t l_bytes, l_addtime, l_usetime;
103        u_int32_t seq;
104{
105	char buf[1024];
106	struct tm *tm;
107	time_t t;
108	char *p, *k;
109	int len, l, i;
110	FILE *fp;
111
112	p = buf;
113	len = sizeof(buf);
114
115	t = time(NULL);
116	tm = localtime(&t);
117	l = strftime(p, len, format, tm);
118	p += l;
119	len -= l;
120	if (len < 0)
121		goto err;
122
123	l = snprintf(p, len, "%%");
124	if (l < 0 || l >= len)
125		goto err;
126	p += l;
127	len -= l;
128	if (len < 0)
129		goto err;
130
131        i = getnameinfo(src, sysdep_sa_len(src), p, len, NULL, 0, NIFLAGS);
132	if (i != 0)
133		goto err;
134	l = strlen(p);
135	p += l;
136	len -= l;
137	if (len < 0)
138		goto err;
139
140	l = snprintf(p, len, " ");
141	if (l < 0 || l >= len)
142		goto err;
143	p += l;
144	len -= l;
145	if (len < 0)
146		goto err;
147
148        i = getnameinfo(dst, sysdep_sa_len(dst), p, len, NULL, 0, NIFLAGS);
149	if (i != 0)
150		goto err;
151	l = strlen(p);
152	p += l;
153	len -= l;
154	if (len < 0)
155		goto err;
156
157	l = snprintf(p, len,
158		" %u %lu %u %u %u "
159		"%u %u %u %u %u "
160		"%u %llu %llu %llu %u",
161		satype, (unsigned long)ntohl(spi), mode, reqid, wsize,
162		e_type, e_keylen, a_type, a_keylen, flags,
163		l_alloc, (unsigned long long)l_bytes,
164		(unsigned long long)l_addtime, (unsigned long long)l_usetime,
165		seq);
166	if (l < 0 || l >= len)
167		goto err;
168	p += l;
169	len -= l;
170	if (len < 0)
171		goto err;
172
173	k = val2str(keymat, e_keylen + a_keylen);
174	l = snprintf(p, len, " %s", k);
175	if (l < 0 || l >= len)
176		goto err;
177	racoon_free(k);
178	p += l;
179	len -= l;
180	if (len < 0)
181		goto err;
182
183	/* open the file and write the SA parameter */
184	if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) != 0 ||
185	    (fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "a")) == NULL) {
186		plog(LLV_ERROR, LOCATION, NULL,
187			"failed to open the backup file %s.\n",
188			lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
189		return -1;
190	}
191	fprintf(fp, "%s\n", buf);
192	fclose(fp);
193
194	return 0;
195
196err:
197	plog(LLV_ERROR, LOCATION, NULL,
198		"SA cannot be saved to a file.\n");
199	return -1;
200}
201
202int
203backupsa_from_file()
204{
205	FILE *fp;
206	char buf[512];
207	struct tm tm;
208	time_t created, current;
209	char *p, *q;
210        u_int satype, mode;
211        struct sockaddr *src, *dst;
212        u_int32_t spi, reqid;
213        caddr_t keymat;
214	size_t keymatlen;
215        u_int wsize, e_type, e_keylen, a_type, a_keylen, flags;
216        u_int32_t l_alloc;
217        u_int64_t l_bytes, l_addtime, l_usetime;
218        u_int32_t seq;
219	int line;
220
221	if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) == 0)
222		fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "r");
223	else
224		fp = NULL;
225	if (fp == NULL) {
226		plog(LLV_ERROR, LOCATION, NULL,
227			"failed to open the backup file %s.\n",
228			lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
229		return -1;
230	}
231
232	current = time(NULL);
233
234	for(line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) {
235		/* comment line */
236		if (buf[0] == '#')
237			continue;
238
239		memset(&tm, 0, sizeof(tm));
240		p = str2tmx(buf, &tm);
241		if (*p != '%') {
242	err:
243			plog(LLV_ERROR, LOCATION, NULL,
244				"illegal format line#%d in %s: %s\n",
245				line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf);
246			continue;
247		}
248		created = mktime(&tm);
249		p++;
250
251		for (q = p; *q != '\0' && !isspace(*q); q++)
252			;
253		*q = '\0';
254		src = str2saddr(p, NULL);
255		if (src == NULL)
256			goto err;
257		p = q + 1;
258
259		for (q = p; *q != '\0' && !isspace(*q); q++)
260			;
261		*q = '\0';
262		dst = str2saddr(p, NULL);
263		if (dst == NULL) {
264			racoon_free(src);
265			goto err;
266		}
267		p = q + 1;
268
269#define GETNEXTNUM(value, function) \
270do { \
271	char *y; \
272	for (q = p; *q != '\0' && !isspace(*q); q++) \
273		; \
274	*q = '\0'; \
275	(value) = function(p, &y, 10); \
276	if ((value) == 0 && *y != '\0') \
277		goto err; \
278	p = q + 1; \
279} while (0);
280
281		GETNEXTNUM(satype, strtoul);
282		GETNEXTNUM(spi, strtoul);
283		spi = ntohl(spi);
284		GETNEXTNUM(mode, strtoul);
285		GETNEXTNUM(reqid, strtoul);
286		GETNEXTNUM(wsize, strtoul);
287		GETNEXTNUM(e_type, strtoul);
288		GETNEXTNUM(e_keylen, strtoul);
289		GETNEXTNUM(a_type, strtoul);
290		GETNEXTNUM(a_keylen, strtoul);
291		GETNEXTNUM(flags, strtoul);
292		GETNEXTNUM(l_alloc, strtoul);
293		GETNEXTNUM(l_bytes, strtouq);
294		GETNEXTNUM(l_addtime, strtouq);
295		GETNEXTNUM(l_usetime, strtouq);
296		GETNEXTNUM(seq, strtoul);
297
298#undef GETNEXTNUM
299
300		keymat = str2val(p, 16, &keymatlen);
301		if (keymat == NULL) {
302			plog(LLV_ERROR, LOCATION, NULL,
303				"illegal format(keymat) line#%d in %s: %s\n",
304				line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf);
305			racoon_free(src);
306			racoon_free(dst);
307			continue;
308		}
309
310		if (created + l_addtime < current) {
311			plog(LLV_DEBUG, LOCATION, NULL,
312				"ignore this line#%d in %s due to expiration\n",
313				line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
314			racoon_free(src);
315			racoon_free(dst);
316			racoon_free(keymat);
317			continue;
318		}
319		l_addtime -= current - created;
320
321		if (pfkey_send_add(
322				lcconf->sock_pfkey,
323				satype,
324				mode,
325				src,
326				dst,
327				spi,
328				reqid,
329				wsize,
330				keymat,
331				e_type, e_keylen, a_type, a_keylen, flags,
332				0, l_bytes, l_addtime, 0, seq) < 0) {
333			plog(LLV_ERROR, LOCATION, NULL,
334				"restore SA filed line#%d in %s: %s\n",
335				line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror());
336		}
337		racoon_free(src);
338		racoon_free(dst);
339		racoon_free(keymat);
340	}
341
342	fclose(fp);
343
344	/*
345	 * There is a possibility that an abnormal system down will happen
346	 * again before new negotiation will be started.  so racoon clears
347	 * the backup file here.  it's ok that old SAs are remained in the
348	 * file.  any old SA will not be installed because racoon checks the
349	 * lifetime and compare with current time.
350	 */
351
352	return 0;
353}
354
355int
356backupsa_clean()
357{
358	FILE *fp;
359
360	/* simply return if the file is not defined. */
361	if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA])
362		return 0;
363
364	fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "w+");
365	if (fp == NULL) {
366		plog(LLV_ERROR, LOCATION, NULL,
367			"failed to clean the backup file %s.\n",
368			lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
369		return -1;
370	}
371	fclose(fp);
372	return 0;
373}
374
375/*
376 * convert fixed string into the tm structure.
377 * The fixed string is like 'Nov 24 18:22:48 1986'.
378 * static char *format = "%b %d %T %Y";
379 */
380static char *
381str2tmx(char *p, struct tm *tm)
382{
383	int i, len;
384
385	/* Month */
386        for (i = 0; i < sizeof(strmon)/sizeof(strmon[0]); i++) {
387		if (strncasecmp(p, strmon[i], strlen(strmon[i])) == 0) {
388			tm->tm_mon = i;
389			break;
390		}
391	}
392	if (i == sizeof(strmon)/sizeof(strmon[0]))
393		return 0;
394	p += strlen(strmon[i]);
395	if (*p++ != ' ')
396		return 0;
397
398	/* Day */
399	len = 2;
400	tm->tm_mday = str2num(p, len);
401	if (tm->tm_mday == -1 || tm->tm_mday > 31)
402		return 0;
403	p += len;
404	if (*p++ != ' ')
405		return 0;
406
407	/* Hour */
408	len = 2;
409	tm->tm_hour = str2num(p, len);
410	if (tm->tm_hour == -1 || tm->tm_hour > 24)
411		return 0;
412	p += len;
413	if (*p++ != ':')
414		return 0;
415
416	/* Min */
417	len = 2;
418	tm->tm_min = str2num(p, len);
419	if (tm->tm_min == -1 || tm->tm_min > 60)
420		return 0;
421	p += len;
422	if (*p++ != ':')
423		return 0;
424
425	/* Sec */
426	len = 2;
427	tm->tm_sec = str2num(p, len);
428	if (tm->tm_sec == -1 || tm->tm_sec > 60)
429		return 0;
430	p += len;
431	if (*p++ != ' ')
432		return 0;
433
434	/* Year */
435	len = 4;
436	tm->tm_year = str2num(p, len);
437	if (tm->tm_year == -1 || tm->tm_year < 1900)
438		return 0;
439	tm->tm_year -= 1900;
440	p += len;
441
442	return p;
443}
444
445static int
446str2num(p, len)
447	char *p;
448	int len;
449{
450	int res, i;
451
452	res = 0;
453        for (i = len; i > 0; i--) {
454		if (!isdigit(*p))
455			return -1;
456		res *= 10;
457		res += *p - '0';
458		p++;
459	}
460
461	return res;
462}
463
464#ifdef TEST
465#include <stdio.h>
466int
467main()
468{
469	struct tm tm;
470	time_t t;
471	char *buf = "Nov 24 18:22:48 1986 ";
472	char *p;
473
474	memset(&tm, 0, sizeof(tm));
475	p = str2tmx(buf, &tm);
476	printf("[%x]\n", *p);
477	t = mktime(&tm);
478	if (t == -1)
479		printf("mktime failed.");
480	p = ctime(&t);
481	printf("[%s]\n", p);
482
483	exit(0);
484}
485#endif
486