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