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
43 static krb5_context context;
44
45 static kadm5_server_context *
get_kadmin_context(const char * config_file,char * realm)46 get_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
94 static 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
108 static kadm5_ret_t
print_entry(kadm5_server_context * server_context,uint32_t ver,time_t timestamp,enum kadm_ops op,uint32_t len,krb5_storage * sp,void * ctx)109 print_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
291 int
iprop_dump(struct dump_options * opt,int argc,char ** argv)292 iprop_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
354 int
iprop_truncate(struct truncate_options * opt,int argc,char ** argv)355 iprop_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
401 int
last_version(struct last_version_options * opt,int argc,char ** argv)402 last_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
459 int
signal_master(struct signal_options * opt,int argc,char ** argv)460 signal_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
477 int start_version = -1;
478 int end_version = -1;
479
480 static kadm5_ret_t
apply_entry(kadm5_server_context * server_context,uint32_t ver,time_t timestamp,enum kadm_ops op,uint32_t len,krb5_storage * sp,void * ctx)481 apply_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
509 int
iprop_replay(struct replay_options * opt,int argc,char ** argv)510 iprop_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
551 static int help_flag;
552 static int version_flag;
553
554 static 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
563 static int num_args = sizeof(args) / sizeof(args[0]);
564
565 int
help(void * opt,int argc,char ** argv)566 help(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
602 static void
usage(int status)603 usage(int status)
604 {
605 arg_printusage(args, num_args, NULL, "command");
606 exit(status);
607 }
608
609 int
main(int argc,char ** argv)610 main(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