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