1 /* $NetBSD: backupsa.c,v 1.13 2025/03/08 16:39:08 christos 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 */ 80 #define FORMAT "%b %d %T %Y" /* time format */ 81 static const char *strmon[12] = { 82 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 83 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 84 }; 85 86 static char *str2tmx(char *, struct tm *); 87 static int str2num(char *, int); 88 89 /* 90 * output the sa parameter. 91 */ 92 int 93 backupsa_to_file(struct pfkey_send_sa_args *sa_args) 94 { 95 char buf[1024]; 96 struct tm *tm; 97 time_t t; 98 char *p, *k; 99 int i, l, len; 100 FILE *fp; 101 102 p = buf; 103 len = sizeof(buf); 104 105 t = time(NULL); 106 tm = localtime(&t); 107 l = strftime(p, len, FORMAT, tm); 108 p += l; 109 len -= l; 110 if (len < 0) 111 goto err; 112 113 l = snprintf(p, len, "%%"); 114 if (l < 0 || l >= len) 115 goto err; 116 p += l; 117 len -= l; 118 if (len < 0) 119 goto err; 120 121 i = getnameinfo(sa_args->src, sysdep_sa_len(sa_args->src), p, len, NULL, 0, NIFLAGS); 122 if (i != 0) 123 goto err; 124 l = strlen(p); 125 p += l; 126 len -= l; 127 if (len < 0) 128 goto err; 129 130 l = snprintf(p, len, " "); 131 if (l < 0 || l >= len) 132 goto err; 133 p += l; 134 len -= l; 135 if (len < 0) 136 goto err; 137 138 i = getnameinfo(sa_args->dst, sysdep_sa_len(sa_args->dst), p, len, NULL, 0, NIFLAGS); 139 if (i != 0) 140 goto err; 141 l = strlen(p); 142 p += l; 143 len -= l; 144 if (len < 0) 145 goto err; 146 147 l = snprintf(p, len, 148 " %u %lu %u %u %u " 149 "%u %u %u %u %u " 150 "%u %llu %llu %llu %u", 151 sa_args->satype, (unsigned long)ntohl(sa_args->spi), 152 sa_args->mode, sa_args->reqid, sa_args->wsize, sa_args->e_type, 153 sa_args->e_keylen, sa_args->a_type, sa_args->a_keylen, 154 sa_args->flags, sa_args->l_alloc, 155 (unsigned long long)sa_args->l_bytes, 156 (unsigned long long)sa_args->l_addtime, 157 (unsigned long long)sa_args->l_usetime, sa_args->seq); 158 159 if (l < 0 || l >= len) 160 goto err; 161 p += l; 162 len -= l; 163 if (len < 0) 164 goto err; 165 166 k = val2str(sa_args->keymat, sa_args->e_keylen + sa_args->a_keylen); 167 l = snprintf(p, len, " %s", k); 168 racoon_free(k); 169 if (l < 0 || l >= len) 170 goto err; 171 p += l; 172 len -= l; 173 if (len < 0) 174 goto err; 175 176 /* open the file and write the SA parameter */ 177 if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) != 0 || 178 (fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "a")) == NULL) { 179 plog(LLV_ERROR, LOCATION, NULL, 180 "failed to open the backup file %s.\n", 181 lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); 182 return -1; 183 } 184 fprintf(fp, "%s\n", buf); 185 fclose(fp); 186 187 return 0; 188 189 err: 190 plog(LLV_ERROR, LOCATION, NULL, 191 "SA cannot be saved to a file.\n"); 192 return -1; 193 } 194 195 int 196 backupsa_from_file(void) 197 { 198 FILE *fp; 199 char buf[512]; 200 struct tm tm; 201 time_t created, current; 202 char *p, *q; 203 size_t keymatlen; 204 int line; 205 struct pfkey_send_sa_args sa_args; 206 207 memset(&sa_args, 0, sizeof(sa_args)); 208 209 if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) == 0) 210 fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "r"); 211 else 212 fp = NULL; 213 if (fp == NULL) { 214 plog(LLV_ERROR, LOCATION, NULL, 215 "failed to open the backup file %s.\n", 216 lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); 217 return -1; 218 } 219 220 current = time(NULL); 221 222 for(line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) { 223 /* comment line */ 224 if (buf[0] == '#') 225 continue; 226 227 memset(&tm, 0, sizeof(tm)); 228 p = str2tmx(buf, &tm); 229 if (*p != '%') { 230 plog(LLV_ERROR, LOCATION, NULL, 231 "illegal format line#%d in %s: %s\n", 232 line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 233 buf); 234 goto next; 235 } 236 created = mktime(&tm); 237 p++; 238 239 for (q = p; *q != '\0' && !isspace((unsigned char)*q); q++) 240 ; 241 *q = '\0'; 242 if ((sa_args.src = str2saddr(p, NULL)) == NULL) 243 goto next; 244 p = q + 1; 245 246 for (q = p; *q != '\0' && !isspace((unsigned char)*q); q++) 247 ; 248 *q = '\0'; 249 if ((sa_args.dst = str2saddr(p, NULL)) == NULL) 250 goto next; 251 p = q + 1; 252 253 #define GETNEXTNUM(value, function) \ 254 do { \ 255 char *y; \ 256 for (q = p; *q != '\0' && !isspace((unsigned char )*q); q++) \ 257 ; \ 258 *q = '\0'; \ 259 (value) = function(p, &y, 10); \ 260 if ((value) == 0 && *y != '\0') \ 261 goto next; \ 262 p = q + 1; \ 263 } while (/*CONSTCOND*/0) 264 265 GETNEXTNUM(sa_args.satype, strtoul); 266 GETNEXTNUM(sa_args.spi, strtoul); 267 sa_args.spi = ntohl(sa_args.spi); 268 GETNEXTNUM(sa_args.mode, strtoul); 269 GETNEXTNUM(sa_args.reqid, strtoul); 270 GETNEXTNUM(sa_args.wsize, strtoul); 271 GETNEXTNUM(sa_args.e_type, strtoul); 272 GETNEXTNUM(sa_args.e_keylen, strtoul); 273 GETNEXTNUM(sa_args.a_type, strtoul); 274 GETNEXTNUM(sa_args.a_keylen, strtoul); 275 GETNEXTNUM(sa_args.flags, strtoul); 276 GETNEXTNUM(sa_args.l_alloc, strtoul); 277 GETNEXTNUM(sa_args.l_bytes, strtouq); 278 GETNEXTNUM(sa_args.l_addtime, strtouq); 279 GETNEXTNUM(sa_args.l_usetime, strtouq); 280 GETNEXTNUM(sa_args.seq, strtoul); 281 282 #undef GETNEXTNUM 283 284 sa_args.keymat = str2val(p, 16, &keymatlen); 285 if (sa_args.keymat == NULL) { 286 plog(LLV_ERROR, LOCATION, NULL, 287 "illegal format(keymat) line#%d in %s: %s\n", 288 line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 289 buf); 290 goto next; 291 } 292 293 if (created + sa_args.l_addtime < current) { 294 plog(LLV_DEBUG, LOCATION, NULL, 295 "ignore this line#%d in %s due to expiration\n", 296 line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); 297 goto next; 298 } 299 sa_args.l_addtime -= current - created; 300 301 if (pfkey_send_add2(&sa_args) < 0) { 302 plog(LLV_ERROR, LOCATION, NULL, 303 "restore SA failed line#%d in %s: %s\n", 304 line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 305 ipsec_strerror()); 306 } 307 308 next: 309 if (sa_args.src != NULL) { 310 racoon_free(sa_args.src); 311 sa_args.src = NULL; 312 } 313 if (sa_args.dst != NULL) { 314 racoon_free(sa_args.dst); 315 sa_args.dst = NULL; 316 } 317 if (sa_args.keymat != NULL) { 318 racoon_free(sa_args.keymat); 319 sa_args.keymat = NULL; 320 } 321 } 322 323 fclose(fp); 324 325 /* 326 * There is a possibility that an abnormal system down will happen 327 * again before new negotiation will be started. so racoon clears 328 * the backup file here. it's ok that old SAs are remained in the 329 * file. any old SA will not be installed because racoon checks the 330 * lifetime and compare with current time. 331 */ 332 333 return 0; 334 } 335 336 int 337 backupsa_clean(void) 338 { 339 FILE *fp; 340 341 /* simply return if the file is not defined. */ 342 if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) 343 return 0; 344 345 fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "w+"); 346 if (fp == NULL) { 347 plog(LLV_ERROR, LOCATION, NULL, 348 "failed to clean the backup file %s.\n", 349 lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); 350 return -1; 351 } 352 fclose(fp); 353 return 0; 354 } 355 356 /* 357 * convert fixed string into the tm structure. 358 * The fixed string is like 'Nov 24 18:22:48 1986'. 359 */ 360 static char * 361 str2tmx(char *p, struct tm *tm) 362 { 363 int len; 364 size_t i; 365 366 /* Month */ 367 for (i = 0; i < sizeof(strmon)/sizeof(strmon[0]); i++) { 368 if (strncasecmp(p, strmon[i], strlen(strmon[i])) == 0) { 369 tm->tm_mon = i; 370 break; 371 } 372 } 373 if (i == sizeof(strmon)/sizeof(strmon[0])) 374 return 0; 375 p += strlen(strmon[i]); 376 if (*p++ != ' ') 377 return 0; 378 379 /* Day */ 380 len = 2; 381 tm->tm_mday = str2num(p, len); 382 if (tm->tm_mday == -1 || tm->tm_mday > 31) 383 return 0; 384 p += len; 385 if (*p++ != ' ') 386 return 0; 387 388 /* Hour */ 389 len = 2; 390 tm->tm_hour = str2num(p, len); 391 if (tm->tm_hour == -1 || tm->tm_hour > 24) 392 return 0; 393 p += len; 394 if (*p++ != ':') 395 return 0; 396 397 /* Min */ 398 len = 2; 399 tm->tm_min = str2num(p, len); 400 if (tm->tm_min == -1 || tm->tm_min > 60) 401 return 0; 402 p += len; 403 if (*p++ != ':') 404 return 0; 405 406 /* Sec */ 407 len = 2; 408 tm->tm_sec = str2num(p, len); 409 if (tm->tm_sec == -1 || tm->tm_sec > 60) 410 return 0; 411 p += len; 412 if (*p++ != ' ') 413 return 0; 414 415 /* Year */ 416 len = 4; 417 tm->tm_year = str2num(p, len); 418 if (tm->tm_year == -1 || tm->tm_year < 1900) 419 return 0; 420 tm->tm_year -= 1900; 421 p += len; 422 423 return p; 424 } 425 426 static int 427 str2num(char *p, int len) 428 { 429 int res, i; 430 431 res = 0; 432 for (i = len; i > 0; i--) { 433 if (!isdigit((unsigned char)*p)) 434 return -1; 435 res *= 10; 436 res += *p - '0'; 437 p++; 438 } 439 440 return res; 441 } 442 443 #ifdef TEST 444 #include <stdio.h> 445 int 446 main(void) 447 { 448 struct tm tm; 449 time_t t; 450 char *buf = "Nov 24 18:22:48 1986 "; 451 const char *p; 452 453 memset(&tm, 0, sizeof(tm)); 454 p = str2tmx(buf, &tm); 455 printf("[%x]\n", *p); 456 t = mktime(&tm); 457 if (t == -1) 458 printf("mktime failed."); 459 if ((p = ctime(&t)) == NULL) 460 p = "?"; 461 printf("[%s]\n", p); 462 463 exit(0); 464 } 465 #endif 466