#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>
#ifndef HAVE_NETINET6_IPSEC
#include <netinet/ipsec.h>
#else
#include <netinet6/ipsec.h>
#endif
#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"
static char *format = "%b %d %T %Y";
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));
int
backupsa_to_file(satype, mode, src, dst, spi, reqid, wsize,
keymat, e_type, e_keylen, a_type, a_keylen, flags,
l_alloc, l_bytes, l_addtime, l_usetime, seq)
u_int satype, mode, wsize;
struct sockaddr *src, *dst;
u_int32_t spi, reqid;
caddr_t keymat;
u_int e_type, e_keylen, a_type, a_keylen, flags;
u_int32_t l_alloc;
u_int64_t l_bytes, l_addtime, l_usetime;
u_int32_t seq;
{
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(src, sysdep_sa_len(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(dst, sysdep_sa_len(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",
satype, (unsigned long)ntohl(spi), mode, reqid, wsize,
e_type, e_keylen, a_type, a_keylen, flags,
l_alloc, (unsigned long long)l_bytes,
(unsigned long long)l_addtime, (unsigned long long)l_usetime,
seq);
if (l < 0 || l >= len)
goto err;
p += l;
len -= l;
if (len < 0)
goto err;
k = val2str(keymat, e_keylen + a_keylen);
l = snprintf(p, len, " %s", k);
if (l < 0 || l >= len)
goto err;
racoon_free(k);
p += l;
len -= l;
if (len < 0)
goto err;
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;
u_int satype, mode;
struct sockaddr *src, *dst;
u_int32_t spi, reqid;
caddr_t keymat;
size_t keymatlen;
u_int wsize, e_type, e_keylen, a_type, a_keylen, flags;
u_int32_t l_alloc;
u_int64_t l_bytes, l_addtime, l_usetime;
u_int32_t seq;
int line;
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++) {
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);
continue;
}
created = mktime(&tm);
p++;
for (q = p; *q != '\0' && !isspace((int)*q); q++)
;
*q = '\0';
src = str2saddr(p, NULL);
if (src == NULL)
goto err;
p = q + 1;
for (q = p; *q != '\0' && !isspace((int)*q); q++)
;
*q = '\0';
dst = str2saddr(p, NULL);
if (dst == NULL) {
racoon_free(src);
goto err;
}
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 err; \
p = q + 1; \
} while (0);
GETNEXTNUM(satype, strtoul);
GETNEXTNUM(spi, strtoul);
spi = ntohl(spi);
GETNEXTNUM(mode, strtoul);
GETNEXTNUM(reqid, strtoul);
GETNEXTNUM(wsize, strtoul);
GETNEXTNUM(e_type, strtoul);
GETNEXTNUM(e_keylen, strtoul);
GETNEXTNUM(a_type, strtoul);
GETNEXTNUM(a_keylen, strtoul);
GETNEXTNUM(flags, strtoul);
GETNEXTNUM(l_alloc, strtoul);
GETNEXTNUM(l_bytes, strtouq);
GETNEXTNUM(l_addtime, strtouq);
GETNEXTNUM(l_usetime, strtouq);
GETNEXTNUM(seq, strtoul);
#undef GETNEXTNUM
keymat = str2val(p, 16, &keymatlen);
if (keymat == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
"illegal format(keymat) line#%d in %s: %s\n",
line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf);
racoon_free(src);
racoon_free(dst);
continue;
}
if (created + l_addtime < current) {
plog(LLV_DEBUG, LOCATION, NULL,
"ignore this line#%d in %s due to expiration\n",
line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
racoon_free(src);
racoon_free(dst);
racoon_free(keymat);
continue;
}
l_addtime -= current - created;
#ifdef __APPLE__
if (pfkey_send_add(
lcconf->sock_pfkey,
satype,
mode,
src,
dst,
spi,
reqid,
wsize,
keymat,
e_type, e_keylen, a_type, a_keylen, flags,
0, l_bytes, l_addtime, 0, seq, 0) < 0) {
plog(LLV_ERROR, LOCATION, NULL,
"restore SA filed line#%d in %s: %s\n",
line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror());
}
#else
if (pfkey_send_add(
lcconf->sock_pfkey,
satype,
mode,
src,
dst,
spi,
reqid,
wsize,
keymat,
e_type, e_keylen, a_type, a_keylen, flags,
0, l_bytes, l_addtime, 0, seq) < 0) {
plog(LLV_ERROR, LOCATION, NULL,
"restore SA filed line#%d in %s: %s\n",
line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror());
}
#endif
racoon_free(src);
racoon_free(dst);
racoon_free(keymat);
}
fclose(fp);
return 0;
}
int
backupsa_clean()
{
FILE *fp;
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;
}
static char *
str2tmx(char *p, struct tm *tm)
{
int i, len;
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;
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;
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;
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;
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;
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