1178825Sdfr/* 2233294Sstas * Copyright (c) 1997 - 2005 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "iprop.h" 35178825Sdfr#include <sl.h> 36178825Sdfr#include <parse_time.h> 37178825Sdfr#include "iprop-commands.h" 38178825Sdfr 39233294SstasRCSID("$Id$"); 40178825Sdfr 41178825Sdfrstatic krb5_context context; 42178825Sdfr 43178825Sdfrstatic kadm5_server_context * 44178825Sdfrget_kadmin_context(const char *config_file, char *realm) 45178825Sdfr{ 46178825Sdfr kadm5_config_params conf; 47178825Sdfr krb5_error_code ret; 48178825Sdfr void *kadm_handle; 49178825Sdfr char **files; 50178825Sdfr 51178825Sdfr if (config_file == NULL) { 52178825Sdfr char *file; 53178825Sdfr asprintf(&file, "%s/kdc.conf", hdb_db_dir(context)); 54178825Sdfr if (file == NULL) 55178825Sdfr errx(1, "out of memory"); 56178825Sdfr config_file = file; 57178825Sdfr } 58178825Sdfr 59178825Sdfr ret = krb5_prepend_config_files_default(config_file, &files); 60178825Sdfr if (ret) 61178825Sdfr krb5_err(context, 1, ret, "getting configuration files"); 62178825Sdfr 63178825Sdfr ret = krb5_set_config_files(context, files); 64178825Sdfr krb5_free_config_files(files); 65178825Sdfr if (ret) 66178825Sdfr krb5_err(context, 1, ret, "reading configuration files"); 67178825Sdfr 68178825Sdfr memset(&conf, 0, sizeof(conf)); 69178825Sdfr if(realm) { 70178825Sdfr conf.mask |= KADM5_CONFIG_REALM; 71178825Sdfr conf.realm = realm; 72178825Sdfr } 73178825Sdfr 74178825Sdfr ret = kadm5_init_with_password_ctx (context, 75178825Sdfr KADM5_ADMIN_SERVICE, 76178825Sdfr NULL, 77178825Sdfr KADM5_ADMIN_SERVICE, 78233294Sstas &conf, 0, 0, 79178825Sdfr &kadm_handle); 80178825Sdfr if (ret) 81178825Sdfr krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 82178825Sdfr 83178825Sdfr return (kadm5_server_context *)kadm_handle; 84178825Sdfr} 85178825Sdfr 86178825Sdfr/* 87178825Sdfr * dump log 88178825Sdfr */ 89178825Sdfr 90178825Sdfrstatic const char *op_names[] = { 91178825Sdfr "get", 92178825Sdfr "delete", 93178825Sdfr "create", 94178825Sdfr "rename", 95178825Sdfr "chpass", 96178825Sdfr "modify", 97178825Sdfr "randkey", 98178825Sdfr "get_privs", 99178825Sdfr "get_princs", 100178825Sdfr "chpass_with_key", 101178825Sdfr "nop" 102178825Sdfr}; 103178825Sdfr 104178825Sdfrstatic void 105178825Sdfrprint_entry(kadm5_server_context *server_context, 106178825Sdfr uint32_t ver, 107178825Sdfr time_t timestamp, 108178825Sdfr enum kadm_ops op, 109178825Sdfr uint32_t len, 110178825Sdfr krb5_storage *sp, 111178825Sdfr void *ctx) 112178825Sdfr{ 113178825Sdfr char t[256]; 114178825Sdfr int32_t mask; 115178825Sdfr hdb_entry ent; 116178825Sdfr krb5_principal source; 117178825Sdfr char *name1, *name2; 118178825Sdfr krb5_data data; 119178825Sdfr krb5_context scontext = server_context->context; 120178825Sdfr 121178825Sdfr off_t end = krb5_storage_seek(sp, 0, SEEK_CUR) + len; 122233294Sstas 123178825Sdfr krb5_error_code ret; 124178825Sdfr 125178825Sdfr strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); 126178825Sdfr 127233294Sstas if((int)op < (int)kadm_get || (int)op > (int)kadm_nop) { 128178825Sdfr printf("unknown op: %d\n", op); 129178825Sdfr krb5_storage_seek(sp, end, SEEK_SET); 130178825Sdfr return; 131178825Sdfr } 132178825Sdfr 133178825Sdfr printf ("%s: ver = %u, timestamp = %s, len = %u\n", 134178825Sdfr op_names[op], ver, t, len); 135178825Sdfr switch(op) { 136178825Sdfr case kadm_delete: 137178825Sdfr krb5_ret_principal(sp, &source); 138178825Sdfr krb5_unparse_name(scontext, source, &name1); 139178825Sdfr printf(" %s\n", name1); 140178825Sdfr free(name1); 141178825Sdfr krb5_free_principal(scontext, source); 142178825Sdfr break; 143178825Sdfr case kadm_rename: 144178825Sdfr ret = krb5_data_alloc(&data, len); 145178825Sdfr if (ret) 146178825Sdfr krb5_err (scontext, 1, ret, "kadm_rename: data alloc: %d", len); 147178825Sdfr krb5_ret_principal(sp, &source); 148178825Sdfr krb5_storage_read(sp, data.data, data.length); 149178825Sdfr hdb_value2entry(scontext, &data, &ent); 150178825Sdfr krb5_unparse_name(scontext, source, &name1); 151178825Sdfr krb5_unparse_name(scontext, ent.principal, &name2); 152178825Sdfr printf(" %s -> %s\n", name1, name2); 153178825Sdfr free(name1); 154178825Sdfr free(name2); 155178825Sdfr krb5_free_principal(scontext, source); 156178825Sdfr free_hdb_entry(&ent); 157178825Sdfr break; 158178825Sdfr case kadm_create: 159178825Sdfr ret = krb5_data_alloc(&data, len); 160178825Sdfr if (ret) 161178825Sdfr krb5_err (scontext, 1, ret, "kadm_create: data alloc: %d", len); 162178825Sdfr krb5_storage_read(sp, data.data, data.length); 163178825Sdfr ret = hdb_value2entry(scontext, &data, &ent); 164178825Sdfr if(ret) 165178825Sdfr abort(); 166178825Sdfr mask = ~0; 167178825Sdfr goto foo; 168178825Sdfr case kadm_modify: 169178825Sdfr ret = krb5_data_alloc(&data, len); 170178825Sdfr if (ret) 171178825Sdfr krb5_err (scontext, 1, ret, "kadm_modify: data alloc: %d", len); 172178825Sdfr krb5_ret_int32(sp, &mask); 173178825Sdfr krb5_storage_read(sp, data.data, data.length); 174178825Sdfr ret = hdb_value2entry(scontext, &data, &ent); 175178825Sdfr if(ret) 176178825Sdfr abort(); 177178825Sdfr foo: 178178825Sdfr if(ent.principal /* mask & KADM5_PRINCIPAL */) { 179178825Sdfr krb5_unparse_name(scontext, ent.principal, &name1); 180178825Sdfr printf(" principal = %s\n", name1); 181178825Sdfr free(name1); 182178825Sdfr } 183178825Sdfr if(mask & KADM5_PRINC_EXPIRE_TIME) { 184178825Sdfr if(ent.valid_end == NULL) { 185178825Sdfr strlcpy(t, "never", sizeof(t)); 186178825Sdfr } else { 187233294Sstas strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", 188178825Sdfr localtime(ent.valid_end)); 189178825Sdfr } 190178825Sdfr printf(" expires = %s\n", t); 191178825Sdfr } 192178825Sdfr if(mask & KADM5_PW_EXPIRATION) { 193178825Sdfr if(ent.pw_end == NULL) { 194178825Sdfr strlcpy(t, "never", sizeof(t)); 195178825Sdfr } else { 196233294Sstas strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", 197178825Sdfr localtime(ent.pw_end)); 198178825Sdfr } 199178825Sdfr printf(" password exp = %s\n", t); 200178825Sdfr } 201178825Sdfr if(mask & KADM5_LAST_PWD_CHANGE) { 202178825Sdfr } 203178825Sdfr if(mask & KADM5_ATTRIBUTES) { 204233294Sstas unparse_flags(HDBFlags2int(ent.flags), 205178825Sdfr asn1_HDBFlags_units(), t, sizeof(t)); 206178825Sdfr printf(" attributes = %s\n", t); 207178825Sdfr } 208178825Sdfr if(mask & KADM5_MAX_LIFE) { 209178825Sdfr if(ent.max_life == NULL) 210178825Sdfr strlcpy(t, "for ever", sizeof(t)); 211178825Sdfr else 212178825Sdfr unparse_time(*ent.max_life, t, sizeof(t)); 213178825Sdfr printf(" max life = %s\n", t); 214178825Sdfr } 215178825Sdfr if(mask & KADM5_MAX_RLIFE) { 216178825Sdfr if(ent.max_renew == NULL) 217178825Sdfr strlcpy(t, "for ever", sizeof(t)); 218178825Sdfr else 219178825Sdfr unparse_time(*ent.max_renew, t, sizeof(t)); 220178825Sdfr printf(" max rlife = %s\n", t); 221178825Sdfr } 222178825Sdfr if(mask & KADM5_MOD_TIME) { 223178825Sdfr printf(" mod time\n"); 224178825Sdfr } 225178825Sdfr if(mask & KADM5_MOD_NAME) { 226178825Sdfr printf(" mod name\n"); 227178825Sdfr } 228178825Sdfr if(mask & KADM5_KVNO) { 229178825Sdfr printf(" kvno = %d\n", ent.kvno); 230178825Sdfr } 231178825Sdfr if(mask & KADM5_MKVNO) { 232178825Sdfr printf(" mkvno\n"); 233178825Sdfr } 234178825Sdfr if(mask & KADM5_AUX_ATTRIBUTES) { 235178825Sdfr printf(" aux attributes\n"); 236178825Sdfr } 237178825Sdfr if(mask & KADM5_POLICY) { 238178825Sdfr printf(" policy\n"); 239178825Sdfr } 240178825Sdfr if(mask & KADM5_POLICY_CLR) { 241178825Sdfr printf(" mod time\n"); 242178825Sdfr } 243178825Sdfr if(mask & KADM5_LAST_SUCCESS) { 244178825Sdfr printf(" last success\n"); 245178825Sdfr } 246178825Sdfr if(mask & KADM5_LAST_FAILED) { 247178825Sdfr printf(" last failed\n"); 248178825Sdfr } 249178825Sdfr if(mask & KADM5_FAIL_AUTH_COUNT) { 250178825Sdfr printf(" fail auth count\n"); 251178825Sdfr } 252178825Sdfr if(mask & KADM5_KEY_DATA) { 253178825Sdfr printf(" key data\n"); 254178825Sdfr } 255178825Sdfr if(mask & KADM5_TL_DATA) { 256178825Sdfr printf(" tl data\n"); 257178825Sdfr } 258178825Sdfr free_hdb_entry(&ent); 259178825Sdfr break; 260178825Sdfr case kadm_nop : 261178825Sdfr break; 262178825Sdfr default: 263178825Sdfr abort(); 264178825Sdfr } 265178825Sdfr krb5_storage_seek(sp, end, SEEK_SET); 266178825Sdfr} 267178825Sdfr 268178825Sdfrint 269178825Sdfriprop_dump(struct dump_options *opt, int argc, char **argv) 270178825Sdfr{ 271178825Sdfr kadm5_server_context *server_context; 272178825Sdfr krb5_error_code ret; 273178825Sdfr 274233294Sstas server_context = get_kadmin_context(opt->config_file_string, 275178825Sdfr opt->realm_string); 276178825Sdfr 277178825Sdfr ret = kadm5_log_init (server_context); 278178825Sdfr if (ret) 279178825Sdfr krb5_err (context, 1, ret, "kadm5_log_init"); 280178825Sdfr 281178825Sdfr ret = kadm5_log_foreach (server_context, print_entry, NULL); 282178825Sdfr if(ret) 283178825Sdfr krb5_warn(context, ret, "kadm5_log_foreach"); 284178825Sdfr 285178825Sdfr ret = kadm5_log_end (server_context); 286178825Sdfr if (ret) 287178825Sdfr krb5_warn(context, ret, "kadm5_log_end"); 288178825Sdfr return 0; 289178825Sdfr} 290178825Sdfr 291178825Sdfrint 292178825Sdfriprop_truncate(struct truncate_options *opt, int argc, char **argv) 293178825Sdfr{ 294178825Sdfr kadm5_server_context *server_context; 295178825Sdfr krb5_error_code ret; 296178825Sdfr 297233294Sstas server_context = get_kadmin_context(opt->config_file_string, 298178825Sdfr opt->realm_string); 299178825Sdfr 300178825Sdfr ret = kadm5_log_truncate (server_context); 301178825Sdfr if (ret) 302178825Sdfr krb5_err (context, 1, ret, "kadm5_log_truncate"); 303178825Sdfr 304178825Sdfr return 0; 305178825Sdfr} 306178825Sdfr 307178825Sdfrint 308178825Sdfrlast_version(struct last_version_options *opt, int argc, char **argv) 309178825Sdfr{ 310178825Sdfr kadm5_server_context *server_context; 311178825Sdfr krb5_error_code ret; 312178825Sdfr uint32_t version; 313178825Sdfr 314233294Sstas server_context = get_kadmin_context(opt->config_file_string, 315178825Sdfr opt->realm_string); 316178825Sdfr 317178825Sdfr ret = kadm5_log_init (server_context); 318178825Sdfr if (ret) 319178825Sdfr krb5_err (context, 1, ret, "kadm5_log_init"); 320178825Sdfr 321178825Sdfr ret = kadm5_log_get_version (server_context, &version); 322178825Sdfr if (ret) 323178825Sdfr krb5_err (context, 1, ret, "kadm5_log_get_version"); 324178825Sdfr 325178825Sdfr ret = kadm5_log_end (server_context); 326178825Sdfr if (ret) 327178825Sdfr krb5_warn(context, ret, "kadm5_log_end"); 328178825Sdfr 329178825Sdfr printf("version: %lu\n", (unsigned long)version); 330178825Sdfr 331178825Sdfr return 0; 332178825Sdfr} 333178825Sdfr 334178825Sdfr/* 335178825Sdfr * Replay log 336178825Sdfr */ 337178825Sdfr 338178825Sdfrint start_version = -1; 339178825Sdfrint end_version = -1; 340178825Sdfr 341178825Sdfrstatic void 342178825Sdfrapply_entry(kadm5_server_context *server_context, 343178825Sdfr uint32_t ver, 344178825Sdfr time_t timestamp, 345178825Sdfr enum kadm_ops op, 346178825Sdfr uint32_t len, 347233294Sstas krb5_storage *sp, 348178825Sdfr void *ctx) 349178825Sdfr{ 350178825Sdfr struct replay_options *opt = ctx; 351178825Sdfr krb5_error_code ret; 352178825Sdfr 353233294Sstas if((opt->start_version_integer != -1 && ver < (uint32_t)opt->start_version_integer) || 354233294Sstas (opt->end_version_integer != -1 && ver > (uint32_t)opt->end_version_integer)) { 355178825Sdfr /* XXX skip this entry */ 356178825Sdfr krb5_storage_seek(sp, len, SEEK_CUR); 357178825Sdfr return; 358178825Sdfr } 359178825Sdfr printf ("ver %u... ", ver); 360178825Sdfr fflush (stdout); 361178825Sdfr 362178825Sdfr ret = kadm5_log_replay (server_context, 363178825Sdfr op, ver, len, sp); 364178825Sdfr if (ret) 365178825Sdfr krb5_warn (server_context->context, ret, "kadm5_log_replay"); 366233294Sstas 367178825Sdfr printf ("done\n"); 368178825Sdfr} 369178825Sdfr 370178825Sdfrint 371178825Sdfriprop_replay(struct replay_options *opt, int argc, char **argv) 372178825Sdfr{ 373178825Sdfr kadm5_server_context *server_context; 374178825Sdfr krb5_error_code ret; 375178825Sdfr 376233294Sstas server_context = get_kadmin_context(opt->config_file_string, 377178825Sdfr opt->realm_string); 378178825Sdfr 379178825Sdfr ret = server_context->db->hdb_open(context, 380178825Sdfr server_context->db, 381178825Sdfr O_RDWR | O_CREAT, 0600); 382178825Sdfr if (ret) 383178825Sdfr krb5_err (context, 1, ret, "db->open"); 384178825Sdfr 385178825Sdfr ret = kadm5_log_init (server_context); 386178825Sdfr if (ret) 387178825Sdfr krb5_err (context, 1, ret, "kadm5_log_init"); 388178825Sdfr 389178825Sdfr ret = kadm5_log_foreach (server_context, apply_entry, opt); 390178825Sdfr if(ret) 391178825Sdfr krb5_warn(context, ret, "kadm5_log_foreach"); 392178825Sdfr ret = kadm5_log_end (server_context); 393178825Sdfr if (ret) 394178825Sdfr krb5_warn(context, ret, "kadm5_log_end"); 395178825Sdfr ret = server_context->db->hdb_close (context, server_context->db); 396178825Sdfr if (ret) 397178825Sdfr krb5_err (context, 1, ret, "db->close"); 398178825Sdfr 399178825Sdfr return 0; 400178825Sdfr} 401178825Sdfr 402178825Sdfrstatic int help_flag; 403178825Sdfrstatic int version_flag; 404178825Sdfr 405178825Sdfrstatic struct getargs args[] = { 406178825Sdfr { "version", 0, arg_flag, &version_flag, 407233294Sstas NULL, NULL 408233294Sstas }, 409233294Sstas { "help", 'h', arg_flag, &help_flag, 410178825Sdfr NULL, NULL 411178825Sdfr } 412178825Sdfr}; 413178825Sdfr 414178825Sdfrstatic int num_args = sizeof(args) / sizeof(args[0]); 415178825Sdfr 416178825Sdfrint 417178825Sdfrhelp(void *opt, int argc, char **argv) 418178825Sdfr{ 419178825Sdfr if(argc == 0) { 420178825Sdfr sl_help(commands, 1, argv - 1 /* XXX */); 421178825Sdfr } else { 422178825Sdfr SL_cmd *c = sl_match (commands, argv[0], 0); 423178825Sdfr if(c == NULL) { 424178825Sdfr fprintf (stderr, "No such command: %s. " 425178825Sdfr "Try \"help\" for a list of commands\n", 426178825Sdfr argv[0]); 427178825Sdfr } else { 428178825Sdfr if(c->func) { 429233294Sstas static char shelp[] = "--help"; 430233294Sstas char *fake[3]; 431178825Sdfr fake[0] = argv[0]; 432233294Sstas fake[1] = shelp; 433233294Sstas fake[2] = NULL; 434178825Sdfr (*c->func)(2, fake); 435178825Sdfr fprintf(stderr, "\n"); 436178825Sdfr } 437178825Sdfr if(c->help && *c->help) 438178825Sdfr fprintf (stderr, "%s\n", c->help); 439178825Sdfr if((++c)->name && c->func == NULL) { 440178825Sdfr int f = 0; 441178825Sdfr fprintf (stderr, "Synonyms:"); 442178825Sdfr while (c->name && c->func == NULL) { 443178825Sdfr fprintf (stderr, "%s%s", f ? ", " : " ", (c++)->name); 444178825Sdfr f = 1; 445178825Sdfr } 446178825Sdfr fprintf (stderr, "\n"); 447178825Sdfr } 448178825Sdfr } 449178825Sdfr } 450178825Sdfr return 0; 451178825Sdfr} 452178825Sdfr 453178825Sdfrstatic void 454178825Sdfrusage(int status) 455178825Sdfr{ 456178825Sdfr arg_printusage(args, num_args, NULL, "command"); 457178825Sdfr exit(status); 458178825Sdfr} 459178825Sdfr 460178825Sdfrint 461178825Sdfrmain(int argc, char **argv) 462178825Sdfr{ 463178825Sdfr int optidx = 0; 464178825Sdfr krb5_error_code ret; 465178825Sdfr 466178825Sdfr setprogname(argv[0]); 467178825Sdfr 468178825Sdfr if(getarg(args, num_args, argc, argv, &optidx)) 469178825Sdfr usage(1); 470178825Sdfr if(help_flag) 471178825Sdfr usage(0); 472178825Sdfr if(version_flag) { 473178825Sdfr print_version(NULL); 474178825Sdfr exit(0); 475178825Sdfr } 476178825Sdfr argc -= optidx; 477178825Sdfr argv += optidx; 478178825Sdfr if(argc == 0) 479178825Sdfr usage(1); 480178825Sdfr 481178825Sdfr ret = krb5_init_context(&context); 482178825Sdfr if (ret) 483178825Sdfr errx(1, "krb5_init_context failed with: %d\n", ret); 484178825Sdfr 485178825Sdfr ret = sl_command(commands, argc, argv); 486178825Sdfr if(ret == -1) 487178825Sdfr warnx ("unrecognized command: %s", argv[0]); 488178825Sdfr return ret; 489178825Sdfr} 490