/* $NetBSD: backupsa.c,v 1.8.4.1 2007/08/01 11:52:19 vanhu Exp $ */ /* $KAME: backupsa.c,v 1.16 2001/12/31 20:13:40 thorpej Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <netinet/in.h> #include PATH_IPSEC_H #if TIME_WITH_SYS_TIME # include <sys/time.h> # include <time.h> #else # if HAVE_SYS_TIME_H # include <sys/time.h> # else # include <time.h> # endif #endif #include "var.h" #include "misc.h" #include "vmbuf.h" #include "str2val.h" #include "plog.h" #include "debug.h" #include "localconf.h" #include "sockmisc.h" #include "safefile.h" #include "backupsa.h" #include "libpfkey.h" /* * (time string)%(sa parameter) * (time string) := ex. Nov 24 18:22:48 1986 * (sa parameter) := * src dst satype spi mode reqid wsize \ * e_type e_keylen a_type a_keylen flags \ * l_alloc l_bytes l_addtime l_usetime seq keymat */ static char *format = "%b %d %T %Y"; /* time format */ static char *strmon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *str2tmx __P((char *, struct tm *)); static int str2num __P((char *, int)); /* * output the sa parameter. */ int backupsa_to_file(sa_args) struct pfkey_send_sa_args *sa_args; { char buf[1024]; struct tm *tm; time_t t; char *p, *k; int len, l, i; FILE *fp; p = buf; len = sizeof(buf); t = time(NULL); tm = localtime(&t); l = strftime(p, len, format, tm); p += l; len -= l; if (len < 0) goto err; l = snprintf(p, len, "%%"); if (l < 0 || l >= len) goto err; p += l; len -= l; if (len < 0) goto err; i = getnameinfo(sa_args->src, sysdep_sa_len(sa_args->src), p, len, NULL, 0, NIFLAGS); if (i != 0) goto err; l = strlen(p); p += l; len -= l; if (len < 0) goto err; l = snprintf(p, len, " "); if (l < 0 || l >= len) goto err; p += l; len -= l; if (len < 0) goto err; i = getnameinfo(sa_args->dst, sysdep_sa_len(sa_args->dst), p, len, NULL, 0, NIFLAGS); if (i != 0) goto err; l = strlen(p); p += l; len -= l; if (len < 0) goto err; l = snprintf(p, len, " %u %lu %u %u %u " "%u %u %u %u %u " "%u %llu %llu %llu %u", sa_args->satype, (unsigned long)ntohl(sa_args->spi), sa_args->mode, sa_args->reqid, sa_args->wsize, sa_args->e_type, sa_args->e_keylen, sa_args->a_type, sa_args->a_keylen, sa_args->flags, sa_args->l_alloc, (unsigned long long)sa_args->l_bytes, (unsigned long long)sa_args->l_addtime, (unsigned long long)sa_args->l_usetime, sa_args->seq); if (l < 0 || l >= len) goto err; p += l; len -= l; if (len < 0) goto err; k = val2str(sa_args->keymat, sa_args->e_keylen + sa_args->a_keylen); l = snprintf(p, len, " %s", k); racoon_free(k); if (l < 0 || l >= len) goto err; p += l; len -= l; if (len < 0) goto err; /* open the file and write the SA parameter */ if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) != 0 || (fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "a")) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to open the backup file %s.\n", lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); return -1; } fprintf(fp, "%s\n", buf); fclose(fp); return 0; err: plog(LLV_ERROR, LOCATION, NULL, "SA cannot be saved to a file.\n"); return -1; } int backupsa_from_file() { FILE *fp; char buf[512]; struct tm tm; time_t created, current; char *p, *q; size_t keymatlen; int line; struct pfkey_send_sa_args sa_args; memset(&sa_args, 0, sizeof(sa_args)); if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) == 0) fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "r"); else fp = NULL; if (fp == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to open the backup file %s.\n", lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); return -1; } current = time(NULL); for(line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) { /* comment line */ if (buf[0] == '#') continue; memset(&tm, 0, sizeof(tm)); p = str2tmx(buf, &tm); if (*p != '%') { err: plog(LLV_ERROR, LOCATION, NULL, "illegal format line#%d in %s: %s\n", line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf); goto next; } created = mktime(&tm); p++; for (q = p; *q != '\0' && !isspace((int)*q); q++) ; *q = '\0'; if ((sa_args.src = str2saddr(p, NULL)) == NULL) goto next; p = q + 1; for (q = p; *q != '\0' && !isspace((int)*q); q++) ; *q = '\0'; if ((sa_args.dst = str2saddr(p, NULL)) == NULL) goto next; p = q + 1; #define GETNEXTNUM(value, function) \ do { \ char *y; \ for (q = p; *q != '\0' && !isspace((int)*q); q++) \ ; \ *q = '\0'; \ (value) = function(p, &y, 10); \ if ((value) == 0 && *y != '\0') \ goto next; \ p = q + 1; \ } while (/*CONSTCOND*/0); GETNEXTNUM(sa_args.satype, strtoul); GETNEXTNUM(sa_args.spi, strtoul); sa_args.spi = ntohl(sa_args.spi); GETNEXTNUM(sa_args.mode, strtoul); GETNEXTNUM(sa_args.reqid, strtoul); GETNEXTNUM(sa_args.wsize, strtoul); GETNEXTNUM(sa_args.e_type, strtoul); GETNEXTNUM(sa_args.e_keylen, strtoul); GETNEXTNUM(sa_args.a_type, strtoul); GETNEXTNUM(sa_args.a_keylen, strtoul); GETNEXTNUM(sa_args.flags, strtoul); GETNEXTNUM(sa_args.l_alloc, strtoul); GETNEXTNUM(sa_args.l_bytes, strtouq); GETNEXTNUM(sa_args.l_addtime, strtouq); GETNEXTNUM(sa_args.l_usetime, strtouq); GETNEXTNUM(sa_args.seq, strtoul); #undef GETNEXTNUM sa_args.keymat = str2val(p, 16, &keymatlen); if (sa_args.keymat == NULL) { plog(LLV_ERROR, LOCATION, NULL, "illegal format(keymat) line#%d in %s: %s\n", line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf); goto next; } if (created + sa_args.l_addtime < current) { plog(LLV_DEBUG, LOCATION, NULL, "ignore this line#%d in %s due to expiration\n", line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); goto next; } sa_args.l_addtime -= current - created; if (pfkey_send_add2(&sa_args) < 0) { plog(LLV_ERROR, LOCATION, NULL, "restore SA failed line#%d in %s: %s\n", line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror()); } next: if (sa_args.src != NULL) { racoon_free(sa_args.src); sa_args.src = NULL; } if (sa_args.dst != NULL) { racoon_free(sa_args.dst); sa_args.dst = NULL; } if (sa_args.keymat != NULL) { racoon_free(sa_args.keymat); sa_args.keymat = NULL; } } fclose(fp); /* * There is a possibility that an abnormal system down will happen * again before new negotiation will be started. so racoon clears * the backup file here. it's ok that old SAs are remained in the * file. any old SA will not be installed because racoon checks the * lifetime and compare with current time. */ return 0; } int backupsa_clean() { FILE *fp; /* simply return if the file is not defined. */ if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) return 0; fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "w+"); if (fp == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to clean the backup file %s.\n", lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); return -1; } fclose(fp); return 0; } /* * convert fixed string into the tm structure. * The fixed string is like 'Nov 24 18:22:48 1986'. * static char *format = "%b %d %T %Y"; */ static char * str2tmx(char *p, struct tm *tm) { int i, len; /* Month */ for (i = 0; i < sizeof(strmon)/sizeof(strmon[0]); i++) { if (strncasecmp(p, strmon[i], strlen(strmon[i])) == 0) { tm->tm_mon = i; break; } } if (i == sizeof(strmon)/sizeof(strmon[0])) return 0; p += strlen(strmon[i]); if (*p++ != ' ') return 0; /* Day */ len = 2; tm->tm_mday = str2num(p, len); if (tm->tm_mday == -1 || tm->tm_mday > 31) return 0; p += len; if (*p++ != ' ') return 0; /* Hour */ len = 2; tm->tm_hour = str2num(p, len); if (tm->tm_hour == -1 || tm->tm_hour > 24) return 0; p += len; if (*p++ != ':') return 0; /* Min */ len = 2; tm->tm_min = str2num(p, len); if (tm->tm_min == -1 || tm->tm_min > 60) return 0; p += len; if (*p++ != ':') return 0; /* Sec */ len = 2; tm->tm_sec = str2num(p, len); if (tm->tm_sec == -1 || tm->tm_sec > 60) return 0; p += len; if (*p++ != ' ') return 0; /* Year */ len = 4; tm->tm_year = str2num(p, len); if (tm->tm_year == -1 || tm->tm_year < 1900) return 0; tm->tm_year -= 1900; p += len; return p; } static int str2num(p, len) char *p; int len; { int res, i; res = 0; for (i = len; i > 0; i--) { if (!isdigit((int)*p)) return -1; res *= 10; res += *p - '0'; p++; } return res; } #ifdef TEST #include <stdio.h> int main() { struct tm tm; time_t t; char *buf = "Nov 24 18:22:48 1986 "; char *p; memset(&tm, 0, sizeof(tm)); p = str2tmx(buf, &tm); printf("[%x]\n", *p); t = mktime(&tm); if (t == -1) printf("mktime failed."); p = ctime(&t); printf("[%s]\n", p); exit(0); } #endif