1 /* 2 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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 "kadmin_locl.h" 35 #include "kadmin-commands.h" 36 #include <kadm5/private.h> 37 38 struct entry { 39 char *principal; 40 char *key; 41 char *max_life; 42 char *max_renew; 43 char *created; 44 char *modified; 45 char *valid_start; 46 char *valid_end; 47 char *pw_end; 48 char *flags; 49 char *generation; 50 char *extensions; 51 }; 52 53 static char * 54 skip_next(char *p) 55 { 56 while(*p && !isspace((unsigned char)*p)) 57 p++; 58 *p++ = 0; 59 while(*p && isspace((unsigned char)*p)) 60 p++; 61 return p; 62 } 63 64 /* 65 * Parse the time in `s', returning: 66 * -1 if error parsing 67 * 0 if none present 68 * 1 if parsed ok 69 */ 70 71 static int 72 parse_time_string(time_t *t, const char *s) 73 { 74 int year, month, date, hour, minute, second; 75 struct tm tm; 76 77 if(strcmp(s, "-") == 0) 78 return 0; 79 if(sscanf(s, "%04d%02d%02d%02d%02d%02d", 80 &year, &month, &date, &hour, &minute, &second) != 6) 81 return -1; 82 tm.tm_year = year - 1900; 83 tm.tm_mon = month - 1; 84 tm.tm_mday = date; 85 tm.tm_hour = hour; 86 tm.tm_min = minute; 87 tm.tm_sec = second; 88 tm.tm_isdst = 0; 89 *t = timegm(&tm); 90 return 1; 91 } 92 93 /* 94 * parse time, allocating space in *t if it's there 95 */ 96 97 static int 98 parse_time_string_alloc (time_t **t, const char *s) 99 { 100 time_t tmp; 101 int ret; 102 103 *t = NULL; 104 ret = parse_time_string (&tmp, s); 105 if (ret == 1) { 106 *t = malloc (sizeof (**t)); 107 if (*t == NULL) 108 krb5_errx (context, 1, "malloc: out of memory"); 109 **t = tmp; 110 } 111 return ret; 112 } 113 114 /* 115 * see parse_time_string for calling convention 116 */ 117 118 static int 119 parse_integer(unsigned int *u, const char *s) 120 { 121 if(strcmp(s, "-") == 0) 122 return 0; 123 if (sscanf(s, "%u", u) != 1) 124 return -1; 125 return 1; 126 } 127 128 static int 129 parse_integer_alloc (unsigned int **u, const char *s) 130 { 131 unsigned int tmp; 132 int ret; 133 134 *u = NULL; 135 ret = parse_integer (&tmp, s); 136 if (ret == 1) { 137 *u = malloc (sizeof (**u)); 138 if (*u == NULL) 139 krb5_errx (context, 1, "malloc: out of memory"); 140 **u = tmp; 141 } 142 return ret; 143 } 144 145 /* 146 * Parse dumped keys in `str' and store them in `ent' 147 * return -1 if parsing failed 148 */ 149 150 static int 151 parse_keys(hdb_entry *ent, char *str) 152 { 153 krb5_error_code ret; 154 int tmp; 155 char *p; 156 size_t i; 157 158 p = strsep(&str, ":"); 159 if (sscanf(p, "%d", &tmp) != 1) 160 return 1; 161 ent->kvno = tmp; 162 p = strsep(&str, ":"); 163 while(p){ 164 Key *key; 165 key = realloc(ent->keys.val, 166 (ent->keys.len + 1) * sizeof(*ent->keys.val)); 167 if(key == NULL) 168 krb5_errx (context, 1, "realloc: out of memory"); 169 ent->keys.val = key; 170 key = ent->keys.val + ent->keys.len; 171 ent->keys.len++; 172 memset(key, 0, sizeof(*key)); 173 if(sscanf(p, "%d", &tmp) == 1) { 174 key->mkvno = malloc(sizeof(*key->mkvno)); 175 *key->mkvno = tmp; 176 } else 177 key->mkvno = NULL; 178 p = strsep(&str, ":"); 179 if (sscanf(p, "%d", &tmp) != 1) 180 return 1; 181 key->key.keytype = tmp; 182 p = strsep(&str, ":"); 183 ret = krb5_data_alloc(&key->key.keyvalue, (strlen(p) - 1) / 2 + 1); 184 if (ret) 185 krb5_err (context, 1, ret, "krb5_data_alloc"); 186 for(i = 0; i < strlen(p); i += 2) { 187 if(sscanf(p + i, "%02x", &tmp) != 1) 188 return 1; 189 ((u_char*)key->key.keyvalue.data)[i / 2] = tmp; 190 } 191 p = strsep(&str, ":"); 192 if(strcmp(p, "-") != 0){ 193 unsigned type; 194 size_t p_len; 195 196 if(sscanf(p, "%u/", &type) != 1) 197 return 1; 198 p = strchr(p, '/'); 199 if(p == NULL) 200 return 1; 201 p++; 202 p_len = strlen(p); 203 204 key->salt = calloc(1, sizeof(*key->salt)); 205 if (key->salt == NULL) 206 krb5_errx (context, 1, "malloc: out of memory"); 207 key->salt->type = type; 208 209 if (p_len) { 210 if(*p == '\"') { 211 ret = krb5_data_copy(&key->salt->salt, p + 1, p_len - 2); 212 if (ret) 213 krb5_err (context, 1, ret, "krb5_data_copy"); 214 } else { 215 ret = krb5_data_alloc(&key->salt->salt, 216 (p_len - 1) / 2 + 1); 217 if (ret) 218 krb5_err (context, 1, ret, "krb5_data_alloc"); 219 for(i = 0; i < p_len; i += 2){ 220 if (sscanf(p + i, "%02x", &tmp) != 1) 221 return 1; 222 ((u_char*)key->salt->salt.data)[i / 2] = tmp; 223 } 224 } 225 } else 226 krb5_data_zero (&key->salt->salt); 227 } 228 p = strsep(&str, ":"); 229 } 230 return 0; 231 } 232 233 /* 234 * see parse_time_string for calling convention 235 */ 236 237 static int 238 parse_event(Event *ev, char *s) 239 { 240 krb5_error_code ret; 241 char *p; 242 243 if(strcmp(s, "-") == 0) 244 return 0; 245 memset(ev, 0, sizeof(*ev)); 246 p = strsep(&s, ":"); 247 if(parse_time_string(&ev->time, p) != 1) 248 return -1; 249 p = strsep(&s, ":"); 250 ret = krb5_parse_name(context, p, &ev->principal); 251 if (ret) 252 return -1; 253 return 1; 254 } 255 256 static int 257 parse_event_alloc (Event **ev, char *s) 258 { 259 Event tmp; 260 int ret; 261 262 *ev = NULL; 263 ret = parse_event (&tmp, s); 264 if (ret == 1) { 265 *ev = malloc (sizeof (**ev)); 266 if (*ev == NULL) 267 krb5_errx (context, 1, "malloc: out of memory"); 268 **ev = tmp; 269 } 270 return ret; 271 } 272 273 static int 274 parse_hdbflags2int(HDBFlags *f, const char *s) 275 { 276 int ret; 277 unsigned int tmp; 278 279 ret = parse_integer (&tmp, s); 280 if (ret == 1) 281 *f = int2HDBFlags (tmp); 282 return ret; 283 } 284 285 static int 286 parse_generation(char *str, GENERATION **gen) 287 { 288 char *p; 289 int v; 290 291 if(strcmp(str, "-") == 0 || *str == '\0') { 292 *gen = NULL; 293 return 0; 294 } 295 *gen = calloc(1, sizeof(**gen)); 296 297 p = strsep(&str, ":"); 298 if(parse_time_string(&(*gen)->time, p) != 1) 299 return -1; 300 p = strsep(&str, ":"); 301 if(sscanf(p, "%d", &v) != 1) 302 return -1; 303 (*gen)->usec = v; 304 p = strsep(&str, ":"); 305 if(sscanf(p, "%d", &v) != 1) 306 return -1; 307 (*gen)->gen = v - 1; /* XXX gets bumped in _hdb_store */ 308 return 0; 309 } 310 311 static int 312 parse_extensions(char *str, HDB_extensions **e) 313 { 314 char *p; 315 int ret; 316 317 if(strcmp(str, "-") == 0 || *str == '\0') { 318 *e = NULL; 319 return 0; 320 } 321 *e = calloc(1, sizeof(**e)); 322 323 p = strsep(&str, ":"); 324 325 while (p) { 326 HDB_extension ext; 327 ssize_t len; 328 void *d; 329 330 len = strlen(p); 331 d = malloc(len); 332 333 len = hex_decode(p, d, len); 334 if (len < 0) { 335 free(d); 336 return -1; 337 } 338 339 ret = decode_HDB_extension(d, len, &ext, NULL); 340 free(d); 341 if (ret) 342 return -1; 343 d = realloc((*e)->val, ((*e)->len + 1) * sizeof((*e)->val[0])); 344 if (d == NULL) 345 abort(); 346 (*e)->val = d; 347 (*e)->val[(*e)->len] = ext; 348 (*e)->len++; 349 350 p = strsep(&str, ":"); 351 } 352 353 return 0; 354 } 355 356 357 /* 358 * Parse the dump file in `filename' and create the database (merging 359 * iff merge) 360 */ 361 362 static int 363 doit(const char *filename, int mergep) 364 { 365 krb5_error_code ret; 366 FILE *f; 367 char s[8192]; /* XXX should fix this properly */ 368 char *p; 369 int line; 370 int flags = O_RDWR; 371 struct entry e; 372 hdb_entry_ex ent; 373 HDB *db = _kadm5_s_get_db(kadm_handle); 374 375 f = fopen(filename, "r"); 376 if(f == NULL){ 377 krb5_warn(context, errno, "fopen(%s)", filename); 378 return 1; 379 } 380 ret = kadm5_log_truncate (kadm_handle); 381 if (ret) { 382 fclose (f); 383 krb5_warn(context, ret, "kadm5_log_truncate"); 384 return 1; 385 } 386 387 if(!mergep) 388 flags |= O_CREAT | O_TRUNC; 389 ret = db->hdb_open(context, db, flags, 0600); 390 if(ret){ 391 krb5_warn(context, ret, "hdb_open"); 392 fclose(f); 393 return 1; 394 } 395 line = 0; 396 ret = 0; 397 while(fgets(s, sizeof(s), f) != NULL) { 398 line++; 399 400 p = s; 401 while (isspace((unsigned char)*p)) 402 p++; 403 404 e.principal = p; 405 for(p = s; *p; p++){ 406 if(*p == '\\') 407 p++; 408 else if(isspace((unsigned char)*p)) { 409 *p = 0; 410 break; 411 } 412 } 413 p = skip_next(p); 414 415 e.key = p; 416 p = skip_next(p); 417 418 e.created = p; 419 p = skip_next(p); 420 421 e.modified = p; 422 p = skip_next(p); 423 424 e.valid_start = p; 425 p = skip_next(p); 426 427 e.valid_end = p; 428 p = skip_next(p); 429 430 e.pw_end = p; 431 p = skip_next(p); 432 433 e.max_life = p; 434 p = skip_next(p); 435 436 e.max_renew = p; 437 p = skip_next(p); 438 439 e.flags = p; 440 p = skip_next(p); 441 442 e.generation = p; 443 p = skip_next(p); 444 445 e.extensions = p; 446 skip_next(p); 447 448 memset(&ent, 0, sizeof(ent)); 449 ret = krb5_parse_name(context, e.principal, &ent.entry.principal); 450 if(ret) { 451 const char *msg = krb5_get_error_message(context, ret); 452 fprintf(stderr, "%s:%d:%s (%s)\n", 453 filename, line, msg, e.principal); 454 krb5_free_error_message(context, msg); 455 continue; 456 } 457 458 if (parse_keys(&ent.entry, e.key)) { 459 fprintf (stderr, "%s:%d:error parsing keys (%s)\n", 460 filename, line, e.key); 461 hdb_free_entry (context, &ent); 462 continue; 463 } 464 465 if (parse_event(&ent.entry.created_by, e.created) == -1) { 466 fprintf (stderr, "%s:%d:error parsing created event (%s)\n", 467 filename, line, e.created); 468 hdb_free_entry (context, &ent); 469 continue; 470 } 471 if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) { 472 fprintf (stderr, "%s:%d:error parsing event (%s)\n", 473 filename, line, e.modified); 474 hdb_free_entry (context, &ent); 475 continue; 476 } 477 if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) { 478 fprintf (stderr, "%s:%d:error parsing time (%s)\n", 479 filename, line, e.valid_start); 480 hdb_free_entry (context, &ent); 481 continue; 482 } 483 if (parse_time_string_alloc (&ent.entry.valid_end, e.valid_end) == -1) { 484 fprintf (stderr, "%s:%d:error parsing time (%s)\n", 485 filename, line, e.valid_end); 486 hdb_free_entry (context, &ent); 487 continue; 488 } 489 if (parse_time_string_alloc (&ent.entry.pw_end, e.pw_end) == -1) { 490 fprintf (stderr, "%s:%d:error parsing time (%s)\n", 491 filename, line, e.pw_end); 492 hdb_free_entry (context, &ent); 493 continue; 494 } 495 496 if (parse_integer_alloc (&ent.entry.max_life, e.max_life) == -1) { 497 fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", 498 filename, line, e.max_life); 499 hdb_free_entry (context, &ent); 500 continue; 501 502 } 503 if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) { 504 fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", 505 filename, line, e.max_renew); 506 hdb_free_entry (context, &ent); 507 continue; 508 } 509 510 if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) { 511 fprintf (stderr, "%s:%d:error parsing flags (%s)\n", 512 filename, line, e.flags); 513 hdb_free_entry (context, &ent); 514 continue; 515 } 516 517 if(parse_generation(e.generation, &ent.entry.generation) == -1) { 518 fprintf (stderr, "%s:%d:error parsing generation (%s)\n", 519 filename, line, e.generation); 520 hdb_free_entry (context, &ent); 521 continue; 522 } 523 524 if(parse_extensions(e.extensions, &ent.entry.extensions) == -1) { 525 fprintf (stderr, "%s:%d:error parsing extension (%s)\n", 526 filename, line, e.extensions); 527 hdb_free_entry (context, &ent); 528 continue; 529 } 530 531 ret = db->hdb_store(context, db, HDB_F_REPLACE, &ent); 532 hdb_free_entry (context, &ent); 533 if (ret) { 534 krb5_warn(context, ret, "db_store"); 535 break; 536 } 537 } 538 db->hdb_close(context, db); 539 fclose(f); 540 return ret != 0; 541 } 542 543 544 extern int local_flag; 545 546 static int 547 loadit(int mergep, const char *name, int argc, char **argv) 548 { 549 if(!local_flag) { 550 krb5_warnx(context, "%s is only available in local (-l) mode", name); 551 return 0; 552 } 553 554 return doit(argv[0], mergep); 555 } 556 557 int 558 load(void *opt, int argc, char **argv) 559 { 560 return loadit(0, "load", argc, argv); 561 } 562 563 int 564 merge(void *opt, int argc, char **argv) 565 { 566 return loadit(1, "merge", argc, argv); 567 } 568