iprop-log.c revision 1.2
1/* $NetBSD: iprop-log.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2005 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "iprop.h" 37#include <krb5/sl.h> 38#include <krb5/parse_time.h> 39#include "iprop-commands.h" 40 41__RCSID("$NetBSD: iprop-log.c,v 1.2 2017/01/28 21:31:49 christos Exp $"); 42 43static krb5_context context; 44 45static kadm5_server_context * 46get_kadmin_context(const char *config_file, char *realm) 47{ 48 kadm5_config_params conf; 49 krb5_error_code ret; 50 void *kadm_handle; 51 char *file = NULL; 52 char **files; 53 int aret; 54 55 if (config_file == NULL) { 56 aret = asprintf(&file, "%s/kdc.conf", hdb_db_dir(context)); 57 if (aret == -1 || file == NULL) 58 errx(1, "out of memory"); 59 config_file = file; 60 } 61 62 ret = krb5_prepend_config_files_default(config_file, &files); 63 free(file); 64 if (ret) 65 krb5_err(context, 1, ret, "getting configuration files"); 66 67 ret = krb5_set_config_files(context, files); 68 krb5_free_config_files(files); 69 if (ret) 70 krb5_err(context, 1, ret, "reading configuration files"); 71 72 memset(&conf, 0, sizeof(conf)); 73 if(realm) { 74 conf.mask |= KADM5_CONFIG_REALM; 75 conf.realm = realm; 76 } 77 78 ret = kadm5_init_with_password_ctx (context, 79 KADM5_ADMIN_SERVICE, 80 NULL, 81 KADM5_ADMIN_SERVICE, 82 &conf, 0, 0, 83 &kadm_handle); 84 if (ret) 85 krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 86 87 return (kadm5_server_context *)kadm_handle; 88} 89 90/* 91 * dump log 92 */ 93 94static const char *op_names[] = { 95 "get", 96 "delete", 97 "create", 98 "rename", 99 "chpass", 100 "modify", 101 "randkey", 102 "get_privs", 103 "get_princs", 104 "chpass_with_key", 105 "nop" 106}; 107 108static kadm5_ret_t 109print_entry(kadm5_server_context *server_context, 110 uint32_t ver, 111 time_t timestamp, 112 enum kadm_ops op, 113 uint32_t len, 114 krb5_storage *sp, 115 void *ctx) 116{ 117 char t[256]; 118 const char *entry_kind = ctx; 119 int32_t mask; 120 int32_t nop_time; 121 uint32_t nop_ver; 122 hdb_entry ent; 123 krb5_principal source; 124 char *name1, *name2; 125 krb5_data data; 126 krb5_context scontext = server_context->context; 127 krb5_error_code ret; 128 129 krb5_data_zero(&data); 130 131 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); 132 133 if((int)op < (int)kadm_get || (int)op > (int)kadm_nop) { 134 printf("unknown op: %d\n", op); 135 return 0; 136 } 137 138 printf ("%s%s: ver = %u, timestamp = %s, len = %u\n", 139 entry_kind, op_names[op], ver, t, len); 140 switch(op) { 141 case kadm_delete: 142 krb5_ret_principal(sp, &source); 143 krb5_unparse_name(scontext, source, &name1); 144 printf(" %s\n", name1); 145 free(name1); 146 krb5_free_principal(scontext, source); 147 break; 148 case kadm_rename: 149 ret = krb5_data_alloc(&data, len); 150 if (ret) 151 krb5_err (scontext, 1, ret, "kadm_rename: data alloc: %d", len); 152 krb5_ret_principal(sp, &source); 153 krb5_storage_read(sp, data.data, data.length); 154 hdb_value2entry(scontext, &data, &ent); 155 krb5_unparse_name(scontext, source, &name1); 156 krb5_unparse_name(scontext, ent.principal, &name2); 157 printf(" %s -> %s\n", name1, name2); 158 free(name1); 159 free(name2); 160 krb5_free_principal(scontext, source); 161 free_hdb_entry(&ent); 162 break; 163 case kadm_create: 164 ret = krb5_data_alloc(&data, len); 165 if (ret) 166 krb5_err (scontext, 1, ret, "kadm_create: data alloc: %d", len); 167 krb5_storage_read(sp, data.data, data.length); 168 ret = hdb_value2entry(scontext, &data, &ent); 169 if(ret) 170 abort(); 171 mask = ~0; 172 goto foo; 173 case kadm_modify: 174 ret = krb5_data_alloc(&data, len); 175 if (ret) 176 krb5_err (scontext, 1, ret, "kadm_modify: data alloc: %d", len); 177 krb5_ret_int32(sp, &mask); 178 krb5_storage_read(sp, data.data, data.length); 179 ret = hdb_value2entry(scontext, &data, &ent); 180 if(ret) 181 abort(); 182 foo: 183 if(ent.principal /* mask & KADM5_PRINCIPAL */) { 184 krb5_unparse_name(scontext, ent.principal, &name1); 185 printf(" principal = %s\n", name1); 186 free(name1); 187 } 188 if(mask & KADM5_PRINC_EXPIRE_TIME) { 189 if(ent.valid_end == NULL) { 190 strlcpy(t, "never", sizeof(t)); 191 } else { 192 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", 193 localtime(ent.valid_end)); 194 } 195 printf(" expires = %s\n", t); 196 } 197 if(mask & KADM5_PW_EXPIRATION) { 198 if(ent.pw_end == NULL) { 199 strlcpy(t, "never", sizeof(t)); 200 } else { 201 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", 202 localtime(ent.pw_end)); 203 } 204 printf(" password exp = %s\n", t); 205 } 206 if(mask & KADM5_LAST_PWD_CHANGE) { 207 } 208 if(mask & KADM5_ATTRIBUTES) { 209 unparse_flags(HDBFlags2int(ent.flags), 210 asn1_HDBFlags_units(), t, sizeof(t)); 211 printf(" attributes = %s\n", t); 212 } 213 if(mask & KADM5_MAX_LIFE) { 214 if(ent.max_life == NULL) 215 strlcpy(t, "for ever", sizeof(t)); 216 else 217 unparse_time(*ent.max_life, t, sizeof(t)); 218 printf(" max life = %s\n", t); 219 } 220 if(mask & KADM5_MAX_RLIFE) { 221 if(ent.max_renew == NULL) 222 strlcpy(t, "for ever", sizeof(t)); 223 else 224 unparse_time(*ent.max_renew, t, sizeof(t)); 225 printf(" max rlife = %s\n", t); 226 } 227 if(mask & KADM5_MOD_TIME) { 228 printf(" mod time\n"); 229 } 230 if(mask & KADM5_MOD_NAME) { 231 printf(" mod name\n"); 232 } 233 if(mask & KADM5_KVNO) { 234 printf(" kvno = %d\n", ent.kvno); 235 } 236 if(mask & KADM5_MKVNO) { 237 printf(" mkvno\n"); 238 } 239 if(mask & KADM5_AUX_ATTRIBUTES) { 240 printf(" aux attributes\n"); 241 } 242 if(mask & KADM5_POLICY) { 243 printf(" policy\n"); 244 } 245 if(mask & KADM5_POLICY_CLR) { 246 printf(" mod time\n"); 247 } 248 if(mask & KADM5_LAST_SUCCESS) { 249 printf(" last success\n"); 250 } 251 if(mask & KADM5_LAST_FAILED) { 252 printf(" last failed\n"); 253 } 254 if(mask & KADM5_FAIL_AUTH_COUNT) { 255 printf(" fail auth count\n"); 256 } 257 if(mask & KADM5_KEY_DATA) { 258 printf(" key data\n"); 259 } 260 if(mask & KADM5_TL_DATA) { 261 printf(" tl data\n"); 262 } 263 free_hdb_entry(&ent); 264 break; 265 case kadm_nop : 266 if (len == 16) { 267 uint64_t off; 268 krb5_ret_uint64(sp, &off); 269 printf("uberblock offset %llu ", (unsigned long long)off); 270 } else { 271 printf("nop"); 272 } 273 if (len == 16 || len == 8) { 274 krb5_ret_int32(sp, &nop_time); 275 krb5_ret_uint32(sp, &nop_ver); 276 277 timestamp = nop_time; 278 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); 279 printf("timestamp %s version %u", t, nop_ver); 280 } 281 printf("\n"); 282 break; 283 default: 284 abort(); 285 } 286 krb5_data_free(&data); 287 288 return 0; 289} 290 291int 292iprop_dump(struct dump_options *opt, int argc, char **argv) 293{ 294 kadm5_server_context *server_context; 295 krb5_error_code ret; 296 enum kadm_iter_opts iter_opts_1st = 0; 297 enum kadm_iter_opts iter_opts_2nd = 0; 298 char *desc_1st = ""; 299 char *desc_2nd = ""; 300 301 server_context = get_kadmin_context(opt->config_file_string, 302 opt->realm_string); 303 304 if (argc > 0) { 305 free(server_context->log_context.log_file); 306 server_context->log_context.log_file = strdup(argv[0]); 307 if (server_context->log_context.log_file == NULL) 308 krb5_err(context, 1, errno, "strdup"); 309 } 310 311 if (opt->reverse_flag) { 312 iter_opts_1st = kadm_backward | kadm_unconfirmed; 313 iter_opts_2nd = kadm_backward | kadm_confirmed; 314 desc_1st = "unconfirmed "; 315 } else { 316 iter_opts_1st = kadm_forward | kadm_confirmed; 317 iter_opts_2nd = kadm_forward | kadm_unconfirmed; 318 desc_2nd = "unconfirmed"; 319 } 320 321 if (opt->no_lock_flag) { 322 ret = kadm5_log_init_sharedlock(server_context, LOCK_NB); 323 if (ret == EAGAIN || ret == EWOULDBLOCK) { 324 warnx("Not locking the iprop log"); 325 ret = kadm5_log_init_nolock(server_context); 326 if (ret) 327 krb5_err(context, 1, ret, "kadm5_log_init_nolock"); 328 } 329 } else { 330 warnx("If this command appears to block, try the --no-lock option"); 331 ret = kadm5_log_init_sharedlock(server_context, 0); 332 if (ret) 333 krb5_err(context, 1, ret, "kadm5_log_init_sharedlock"); 334 } 335 336 ret = kadm5_log_foreach(server_context, iter_opts_1st, 337 NULL, print_entry, desc_1st); 338 if (ret) 339 krb5_warn(context, ret, "kadm5_log_foreach"); 340 341 ret = kadm5_log_foreach(server_context, iter_opts_2nd, 342 NULL, print_entry, desc_2nd); 343 if (ret) 344 krb5_warn(context, ret, "kadm5_log_foreach"); 345 346 ret = kadm5_log_end (server_context); 347 if (ret) 348 krb5_warn(context, ret, "kadm5_log_end"); 349 350 kadm5_destroy(server_context); 351 return 0; 352} 353 354int 355iprop_truncate(struct truncate_options *opt, int argc, char **argv) 356{ 357 kadm5_server_context *server_context; 358 krb5_error_code ret; 359 360 server_context = get_kadmin_context(opt->config_file_string, 361 opt->realm_string); 362 363 if (argc > 0) { 364 free(server_context->log_context.log_file); 365 server_context->log_context.log_file = strdup(argv[0]); 366 if (server_context->log_context.log_file == NULL) 367 krb5_err(context, 1, errno, "strdup"); 368 } 369 370 if (opt->keep_entries_integer < 0 && 371 opt->max_bytes_integer < 0) { 372 opt->keep_entries_integer = 100; 373 opt->max_bytes_integer = 0; 374 } 375 if (opt->keep_entries_integer < 0) 376 opt->keep_entries_integer = 0; 377 if (opt->max_bytes_integer < 0) 378 opt->max_bytes_integer = 0; 379 380 if (opt->reset_flag) { 381 /* First recover unconfirmed records */ 382 ret = kadm5_log_init(server_context); 383 if (ret == 0) 384 ret = kadm5_log_reinit(server_context, 0); 385 } else { 386 ret = kadm5_log_init(server_context); 387 if (ret) 388 krb5_err(context, 1, ret, "kadm5_log_init"); 389 ret = kadm5_log_truncate(server_context, opt->keep_entries_integer, 390 opt->max_bytes_integer); 391 } 392 if (ret) 393 krb5_err(context, 1, ret, "kadm5_log_truncate"); 394 395 kadm5_log_signal_master(server_context); 396 397 kadm5_destroy(server_context); 398 return 0; 399} 400 401int 402last_version(struct last_version_options *opt, int argc, char **argv) 403{ 404 kadm5_server_context *server_context; 405 char *alt_argv[2] = { NULL, NULL }; 406 krb5_error_code ret; 407 uint32_t version; 408 size_t i; 409 410 server_context = get_kadmin_context(opt->config_file_string, 411 opt->realm_string); 412 413 if (argc == 0) { 414 alt_argv[0] = strdup(server_context->log_context.log_file); 415 if (alt_argv[0] == NULL) 416 krb5_err(context, 1, errno, "strdup"); 417 argv = alt_argv; 418 argc = 1; 419 } 420 421 for (i = 0; i < argc; i++) { 422 free(server_context->log_context.log_file); 423 server_context->log_context.log_file = strdup(argv[i]); 424 if (server_context->log_context.log_file == NULL) 425 krb5_err(context, 1, errno, "strdup"); 426 427 if (opt->no_lock_flag) { 428 ret = kadm5_log_init_sharedlock(server_context, LOCK_NB); 429 if (ret == EAGAIN || ret == EWOULDBLOCK) { 430 warnx("Not locking the iprop log"); 431 ret = kadm5_log_init_nolock(server_context); 432 if (ret) 433 krb5_err(context, 1, ret, "kadm5_log_init_nolock"); 434 } 435 } else { 436 warnx("If this command appears to block, try the " 437 "--no-lock option"); 438 ret = kadm5_log_init_sharedlock(server_context, 0); 439 if (ret) 440 krb5_err(context, 1, ret, "kadm5_log_init_sharedlock"); 441 } 442 443 ret = kadm5_log_get_version (server_context, &version); 444 if (ret) 445 krb5_err (context, 1, ret, "kadm5_log_get_version"); 446 447 ret = kadm5_log_end (server_context); 448 if (ret) 449 krb5_warn(context, ret, "kadm5_log_end"); 450 451 printf("version: %lu\n", (unsigned long)version); 452 } 453 454 kadm5_destroy(server_context); 455 free(alt_argv[0]); 456 return 0; 457} 458 459int 460signal_master(struct signal_options *opt, int argc, char **argv) 461{ 462 kadm5_server_context *server_context; 463 464 server_context = get_kadmin_context(opt->config_file_string, 465 opt->realm_string); 466 467 kadm5_log_signal_master(server_context); 468 469 kadm5_destroy(server_context); 470 return 0; 471} 472 473/* 474 * Replay log 475 */ 476 477int start_version = -1; 478int end_version = -1; 479 480static kadm5_ret_t 481apply_entry(kadm5_server_context *server_context, 482 uint32_t ver, 483 time_t timestamp, 484 enum kadm_ops op, 485 uint32_t len, 486 krb5_storage *sp, 487 void *ctx) 488{ 489 struct replay_options *opt = ctx; 490 krb5_error_code ret; 491 492 if((opt->start_version_integer != -1 && ver < (uint32_t)opt->start_version_integer) || 493 (opt->end_version_integer != -1 && ver > (uint32_t)opt->end_version_integer)) { 494 /* XXX skip this entry */ 495 return 0; 496 } 497 printf ("ver %u... ", ver); 498 fflush (stdout); 499 500 ret = kadm5_log_replay(server_context, op, ver, len, sp); 501 if (ret) 502 krb5_warn (server_context->context, ret, "kadm5_log_replay"); 503 504 printf ("done\n"); 505 506 return 0; 507} 508 509int 510iprop_replay(struct replay_options *opt, int argc, char **argv) 511{ 512 kadm5_server_context *server_context; 513 krb5_error_code ret; 514 515 server_context = get_kadmin_context(opt->config_file_string, 516 opt->realm_string); 517 518 if (argc > 0) { 519 free(server_context->log_context.log_file); 520 server_context->log_context.log_file = strdup(argv[0]); 521 if (server_context->log_context.log_file == NULL) 522 krb5_err(context, 1, errno, "strdup"); 523 } 524 525 ret = server_context->db->hdb_open(context, 526 server_context->db, 527 O_RDWR | O_CREAT, 0600); 528 if (ret) 529 krb5_err (context, 1, ret, "db->open"); 530 531 ret = kadm5_log_init (server_context); 532 if (ret) 533 krb5_err (context, 1, ret, "kadm5_log_init"); 534 535 ret = kadm5_log_foreach(server_context, 536 kadm_forward | kadm_confirmed | kadm_unconfirmed, 537 NULL, apply_entry, opt); 538 if(ret) 539 krb5_warn(context, ret, "kadm5_log_foreach"); 540 ret = kadm5_log_end (server_context); 541 if (ret) 542 krb5_warn(context, ret, "kadm5_log_end"); 543 ret = server_context->db->hdb_close (context, server_context->db); 544 if (ret) 545 krb5_err (context, 1, ret, "db->close"); 546 547 kadm5_destroy(server_context); 548 return 0; 549} 550 551static int help_flag; 552static int version_flag; 553 554static struct getargs args[] = { 555 { "version", 0, arg_flag, &version_flag, 556 NULL, NULL 557 }, 558 { "help", 'h', arg_flag, &help_flag, 559 NULL, NULL 560 } 561}; 562 563static int num_args = sizeof(args) / sizeof(args[0]); 564 565int 566help(void *opt, int argc, char **argv) 567{ 568 if(argc == 0) { 569 sl_help(commands, 1, argv - 1 /* XXX */); 570 } else { 571 SL_cmd *c = sl_match (commands, argv[0], 0); 572 if(c == NULL) { 573 fprintf (stderr, "No such command: %s. " 574 "Try \"help\" for a list of commands\n", 575 argv[0]); 576 } else { 577 if(c->func) { 578 static char shelp[] = "--help"; 579 char *fake[3]; 580 fake[0] = argv[0]; 581 fake[1] = shelp; 582 fake[2] = NULL; 583 (*c->func)(2, fake); 584 fprintf(stderr, "\n"); 585 } 586 if(c->help && *c->help) 587 fprintf (stderr, "%s\n", c->help); 588 if((++c)->name && c->func == NULL) { 589 int f = 0; 590 fprintf (stderr, "Synonyms:"); 591 while (c->name && c->func == NULL) { 592 fprintf (stderr, "%s%s", f ? ", " : " ", (c++)->name); 593 f = 1; 594 } 595 fprintf (stderr, "\n"); 596 } 597 } 598 } 599 return 0; 600} 601 602static void 603usage(int status) 604{ 605 arg_printusage(args, num_args, NULL, "command"); 606 exit(status); 607} 608 609int 610main(int argc, char **argv) 611{ 612 int optidx = 0; 613 krb5_error_code ret; 614 615 setprogname(argv[0]); 616 617 if(getarg(args, num_args, argc, argv, &optidx)) 618 usage(1); 619 if(help_flag) 620 usage(0); 621 if(version_flag) { 622 print_version(NULL); 623 exit(0); 624 } 625 argc -= optidx; 626 argv += optidx; 627 if(argc == 0) 628 usage(1); 629 630 ret = krb5_init_context(&context); 631 if (ret) 632 errx(1, "krb5_init_context failed with: %d\n", ret); 633 634 ret = sl_command(commands, argc, argv); 635 if(ret == -1) 636 warnx ("unrecognized command: %s", argv[0]); 637 return ret; 638} 639