xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/kadm5/iprop-log.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
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(&timestamp));
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(&timestamp));
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