1/* $NetBSD: iprop-log.c,v 1.1.1.1 2011/04/13 18:15:29 elric 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.1.1.1 2011/04/13 18:15:29 elric 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 **files; 52 53 if (config_file == NULL) { 54 char *file; 55 asprintf(&file, "%s/kdc.conf", hdb_db_dir(context)); 56 if (file == NULL) 57 errx(1, "out of memory"); 58 config_file = file; 59 } 60 61 ret = krb5_prepend_config_files_default(config_file, &files); 62 if (ret) 63 krb5_err(context, 1, ret, "getting configuration files"); 64 65 ret = krb5_set_config_files(context, files); 66 krb5_free_config_files(files); 67 if (ret) 68 krb5_err(context, 1, ret, "reading configuration files"); 69 70 memset(&conf, 0, sizeof(conf)); 71 if(realm) { 72 conf.mask |= KADM5_CONFIG_REALM; 73 conf.realm = realm; 74 } 75 76 ret = kadm5_init_with_password_ctx (context, 77 KADM5_ADMIN_SERVICE, 78 NULL, 79 KADM5_ADMIN_SERVICE, 80 &conf, 0, 0, 81 &kadm_handle); 82 if (ret) 83 krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 84 85 return (kadm5_server_context *)kadm_handle; 86} 87 88/* 89 * dump log 90 */ 91 92static const char *op_names[] = { 93 "get", 94 "delete", 95 "create", 96 "rename", 97 "chpass", 98 "modify", 99 "randkey", 100 "get_privs", 101 "get_princs", 102 "chpass_with_key", 103 "nop" 104}; 105 106static void 107print_entry(kadm5_server_context *server_context, 108 uint32_t ver, 109 time_t timestamp, 110 enum kadm_ops op, 111 uint32_t len, 112 krb5_storage *sp, 113 void *ctx) 114{ 115 char t[256]; 116 int32_t mask; 117 hdb_entry ent; 118 krb5_principal source; 119 char *name1, *name2; 120 krb5_data data; 121 krb5_context scontext = server_context->context; 122 123 off_t end = krb5_storage_seek(sp, 0, SEEK_CUR) + len; 124 125 krb5_error_code ret; 126 127 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); 128 129 if(op < kadm_get || op > kadm_nop) { 130 printf("unknown op: %d\n", op); 131 krb5_storage_seek(sp, end, SEEK_SET); 132 return; 133 } 134 135 printf ("%s: ver = %u, timestamp = %s, len = %u\n", 136 op_names[op], ver, t, len); 137 switch(op) { 138 case kadm_delete: 139 krb5_ret_principal(sp, &source); 140 krb5_unparse_name(scontext, source, &name1); 141 printf(" %s\n", name1); 142 free(name1); 143 krb5_free_principal(scontext, source); 144 break; 145 case kadm_rename: 146 ret = krb5_data_alloc(&data, len); 147 if (ret) 148 krb5_err (scontext, 1, ret, "kadm_rename: data alloc: %d", len); 149 krb5_ret_principal(sp, &source); 150 krb5_storage_read(sp, data.data, data.length); 151 hdb_value2entry(scontext, &data, &ent); 152 krb5_unparse_name(scontext, source, &name1); 153 krb5_unparse_name(scontext, ent.principal, &name2); 154 printf(" %s -> %s\n", name1, name2); 155 free(name1); 156 free(name2); 157 krb5_free_principal(scontext, source); 158 free_hdb_entry(&ent); 159 break; 160 case kadm_create: 161 ret = krb5_data_alloc(&data, len); 162 if (ret) 163 krb5_err (scontext, 1, ret, "kadm_create: data alloc: %d", len); 164 krb5_storage_read(sp, data.data, data.length); 165 ret = hdb_value2entry(scontext, &data, &ent); 166 if(ret) 167 abort(); 168 mask = ~0; 169 goto foo; 170 case kadm_modify: 171 ret = krb5_data_alloc(&data, len); 172 if (ret) 173 krb5_err (scontext, 1, ret, "kadm_modify: data alloc: %d", len); 174 krb5_ret_int32(sp, &mask); 175 krb5_storage_read(sp, data.data, data.length); 176 ret = hdb_value2entry(scontext, &data, &ent); 177 if(ret) 178 abort(); 179 foo: 180 if(ent.principal /* mask & KADM5_PRINCIPAL */) { 181 krb5_unparse_name(scontext, ent.principal, &name1); 182 printf(" principal = %s\n", name1); 183 free(name1); 184 } 185 if(mask & KADM5_PRINC_EXPIRE_TIME) { 186 if(ent.valid_end == NULL) { 187 strlcpy(t, "never", sizeof(t)); 188 } else { 189 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", 190 localtime(ent.valid_end)); 191 } 192 printf(" expires = %s\n", t); 193 } 194 if(mask & KADM5_PW_EXPIRATION) { 195 if(ent.pw_end == NULL) { 196 strlcpy(t, "never", sizeof(t)); 197 } else { 198 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", 199 localtime(ent.pw_end)); 200 } 201 printf(" password exp = %s\n", t); 202 } 203 if(mask & KADM5_LAST_PWD_CHANGE) { 204 } 205 if(mask & KADM5_ATTRIBUTES) { 206 unparse_flags(HDBFlags2int(ent.flags), 207 asn1_HDBFlags_units(), t, sizeof(t)); 208 printf(" attributes = %s\n", t); 209 } 210 if(mask & KADM5_MAX_LIFE) { 211 if(ent.max_life == NULL) 212 strlcpy(t, "for ever", sizeof(t)); 213 else 214 unparse_time(*ent.max_life, t, sizeof(t)); 215 printf(" max life = %s\n", t); 216 } 217 if(mask & KADM5_MAX_RLIFE) { 218 if(ent.max_renew == NULL) 219 strlcpy(t, "for ever", sizeof(t)); 220 else 221 unparse_time(*ent.max_renew, t, sizeof(t)); 222 printf(" max rlife = %s\n", t); 223 } 224 if(mask & KADM5_MOD_TIME) { 225 printf(" mod time\n"); 226 } 227 if(mask & KADM5_MOD_NAME) { 228 printf(" mod name\n"); 229 } 230 if(mask & KADM5_KVNO) { 231 printf(" kvno = %d\n", ent.kvno); 232 } 233 if(mask & KADM5_MKVNO) { 234 printf(" mkvno\n"); 235 } 236 if(mask & KADM5_AUX_ATTRIBUTES) { 237 printf(" aux attributes\n"); 238 } 239 if(mask & KADM5_POLICY) { 240 printf(" policy\n"); 241 } 242 if(mask & KADM5_POLICY_CLR) { 243 printf(" mod time\n"); 244 } 245 if(mask & KADM5_LAST_SUCCESS) { 246 printf(" last success\n"); 247 } 248 if(mask & KADM5_LAST_FAILED) { 249 printf(" last failed\n"); 250 } 251 if(mask & KADM5_FAIL_AUTH_COUNT) { 252 printf(" fail auth count\n"); 253 } 254 if(mask & KADM5_KEY_DATA) { 255 printf(" key data\n"); 256 } 257 if(mask & KADM5_TL_DATA) { 258 printf(" tl data\n"); 259 } 260 free_hdb_entry(&ent); 261 break; 262 case kadm_nop : 263 break; 264 default: 265 abort(); 266 } 267 krb5_storage_seek(sp, end, SEEK_SET); 268} 269 270int 271iprop_dump(struct dump_options *opt, int argc, char **argv) 272{ 273 kadm5_server_context *server_context; 274 krb5_error_code ret; 275 276 server_context = get_kadmin_context(opt->config_file_string, 277 opt->realm_string); 278 279 ret = kadm5_log_init (server_context); 280 if (ret) 281 krb5_err (context, 1, ret, "kadm5_log_init"); 282 283 ret = kadm5_log_foreach (server_context, print_entry, NULL); 284 if(ret) 285 krb5_warn(context, ret, "kadm5_log_foreach"); 286 287 ret = kadm5_log_end (server_context); 288 if (ret) 289 krb5_warn(context, ret, "kadm5_log_end"); 290 return 0; 291} 292 293int 294iprop_truncate(struct truncate_options *opt, int argc, char **argv) 295{ 296 kadm5_server_context *server_context; 297 krb5_error_code ret; 298 299 server_context = get_kadmin_context(opt->config_file_string, 300 opt->realm_string); 301 302 ret = kadm5_log_truncate (server_context); 303 if (ret) 304 krb5_err (context, 1, ret, "kadm5_log_truncate"); 305 306 return 0; 307} 308 309int 310last_version(struct last_version_options *opt, int argc, char **argv) 311{ 312 kadm5_server_context *server_context; 313 krb5_error_code ret; 314 uint32_t version; 315 316 server_context = get_kadmin_context(opt->config_file_string, 317 opt->realm_string); 318 319 ret = kadm5_log_init (server_context); 320 if (ret) 321 krb5_err (context, 1, ret, "kadm5_log_init"); 322 323 ret = kadm5_log_get_version (server_context, &version); 324 if (ret) 325 krb5_err (context, 1, ret, "kadm5_log_get_version"); 326 327 ret = kadm5_log_end (server_context); 328 if (ret) 329 krb5_warn(context, ret, "kadm5_log_end"); 330 331 printf("version: %lu\n", (unsigned long)version); 332 333 return 0; 334} 335 336/* 337 * Replay log 338 */ 339 340int start_version = -1; 341int end_version = -1; 342 343static void 344apply_entry(kadm5_server_context *server_context, 345 uint32_t ver, 346 time_t timestamp, 347 enum kadm_ops op, 348 uint32_t len, 349 krb5_storage *sp, 350 void *ctx) 351{ 352 struct replay_options *opt = ctx; 353 krb5_error_code ret; 354 355 if((opt->start_version_integer != -1 && ver < opt->start_version_integer) || 356 (opt->end_version_integer != -1 && ver > opt->end_version_integer)) { 357 /* XXX skip this entry */ 358 krb5_storage_seek(sp, len, SEEK_CUR); 359 return; 360 } 361 printf ("ver %u... ", ver); 362 fflush (stdout); 363 364 ret = kadm5_log_replay (server_context, 365 op, ver, len, sp); 366 if (ret) 367 krb5_warn (server_context->context, ret, "kadm5_log_replay"); 368 369 printf ("done\n"); 370} 371 372int 373iprop_replay(struct replay_options *opt, int argc, char **argv) 374{ 375 kadm5_server_context *server_context; 376 krb5_error_code ret; 377 378 server_context = get_kadmin_context(opt->config_file_string, 379 opt->realm_string); 380 381 ret = server_context->db->hdb_open(context, 382 server_context->db, 383 O_RDWR | O_CREAT, 0600); 384 if (ret) 385 krb5_err (context, 1, ret, "db->open"); 386 387 ret = kadm5_log_init (server_context); 388 if (ret) 389 krb5_err (context, 1, ret, "kadm5_log_init"); 390 391 ret = kadm5_log_foreach (server_context, apply_entry, opt); 392 if(ret) 393 krb5_warn(context, ret, "kadm5_log_foreach"); 394 ret = kadm5_log_end (server_context); 395 if (ret) 396 krb5_warn(context, ret, "kadm5_log_end"); 397 ret = server_context->db->hdb_close (context, server_context->db); 398 if (ret) 399 krb5_err (context, 1, ret, "db->close"); 400 401 return 0; 402} 403 404static int help_flag; 405static int version_flag; 406 407static struct getargs args[] = { 408 { "version", 0, arg_flag, &version_flag, 409 NULL, NULL 410 }, 411 { "help", 'h', arg_flag, &help_flag, 412 NULL, NULL 413 } 414}; 415 416static int num_args = sizeof(args) / sizeof(args[0]); 417 418int 419help(void *opt, int argc, char **argv) 420{ 421 if(argc == 0) { 422 sl_help(commands, 1, argv - 1 /* XXX */); 423 } else { 424 SL_cmd *c = sl_match (commands, argv[0], 0); 425 if(c == NULL) { 426 fprintf (stderr, "No such command: %s. " 427 "Try \"help\" for a list of commands\n", 428 argv[0]); 429 } else { 430 if(c->func) { 431 char *fake[] = { NULL, "--help", NULL }; 432 fake[0] = argv[0]; 433 (*c->func)(2, fake); 434 fprintf(stderr, "\n"); 435 } 436 if(c->help && *c->help) 437 fprintf (stderr, "%s\n", c->help); 438 if((++c)->name && c->func == NULL) { 439 int f = 0; 440 fprintf (stderr, "Synonyms:"); 441 while (c->name && c->func == NULL) { 442 fprintf (stderr, "%s%s", f ? ", " : " ", (c++)->name); 443 f = 1; 444 } 445 fprintf (stderr, "\n"); 446 } 447 } 448 } 449 return 0; 450} 451 452static void 453usage(int status) 454{ 455 arg_printusage(args, num_args, NULL, "command"); 456 exit(status); 457} 458 459int 460main(int argc, char **argv) 461{ 462 int optidx = 0; 463 krb5_error_code ret; 464 465 setprogname(argv[0]); 466 467 if(getarg(args, num_args, argc, argv, &optidx)) 468 usage(1); 469 if(help_flag) 470 usage(0); 471 if(version_flag) { 472 print_version(NULL); 473 exit(0); 474 } 475 argc -= optidx; 476 argv += optidx; 477 if(argc == 0) 478 usage(1); 479 480 ret = krb5_init_context(&context); 481 if (ret) 482 errx(1, "krb5_init_context failed with: %d\n", ret); 483 484 ret = sl_command(commands, argc, argv); 485 if(ret == -1) 486 warnx ("unrecognized command: %s", argv[0]); 487 return ret; 488} 489