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