libtommath: Fix possible integer overflow CVE-2023-36328
[heimdal.git] / lib / kadm5 / iprop-log.c
bloba2ad51e7d0816d630bcb962c686ce0bfd047a70b
1 /*
2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "iprop.h"
35 #include <sl.h>
36 #include <parse_time.h>
37 #include "iprop-commands.h"
39 RCSID("$Id$");
41 static krb5_context context;
43 static kadm5_server_context *
44 get_kadmin_context(const char *config_file, char *realm)
46 kadm5_config_params conf;
47 krb5_error_code ret;
48 void *kadm_handle;
49 char *file = NULL;
50 char **files;
51 int aret;
53 if (config_file == NULL) {
54 aret = asprintf(&file, "%s/kdc.conf", hdb_db_dir(context));
55 if (aret == -1 || file == NULL)
56 errx(1, "out of memory");
57 config_file = file;
60 ret = krb5_prepend_config_files_default(config_file, &files);
61 free(file);
62 if (ret)
63 krb5_err(context, 1, ret, "getting configuration files");
65 ret = krb5_set_config_files(context, files);
66 krb5_free_config_files(files);
67 if (ret)
68 krb5_err(context, 1, ret, "reading configuration files");
70 memset(&conf, 0, sizeof(conf));
71 if(realm) {
72 conf.mask |= KADM5_CONFIG_REALM;
73 conf.realm = realm;
76 ret = kadm5_init_with_password_ctx (context,
77 KADM5_ADMIN_SERVICE,
78 NULL,
79 KADM5_ADMIN_SERVICE,
80 &conf, 0, 0,
81 &kadm_handle);
82 if (ret)
83 krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
85 return (kadm5_server_context *)kadm_handle;
89 * dump log
92 static const char *op_names[] = {
93 "get",
94 "delete",
95 "create",
96 "rename",
97 "chpass",
98 "modify",
99 "randkey",
100 "get_privs",
101 "get_princs",
102 "chpass_with_key",
103 "nop"
106 static kadm5_ret_t
107 print_entry(kadm5_server_context *server_context,
108 uint32_t ver,
109 time_t timestamp,
110 enum kadm_ops op,
111 uint32_t len,
112 krb5_storage *sp,
113 void *ctx)
115 char t[256];
116 const char *entry_kind = ctx;
117 int32_t mask;
118 int32_t nop_time;
119 uint32_t nop_ver;
120 hdb_entry ent;
121 krb5_principal source;
122 char *name1, *name2;
123 krb5_data data;
124 krb5_context scontext = server_context->context;
125 krb5_error_code ret;
127 krb5_data_zero(&data);
129 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(&timestamp));
131 if((int)op < (int)kadm_get || (int)op > (int)kadm_nop) {
132 printf("unknown op: %d\n", op);
133 return 0;
136 printf ("%s%s: ver = %u, timestamp = %s, len = %u\n",
137 entry_kind, op_names[op], ver, t, len);
138 switch(op) {
139 case kadm_delete:
140 ret = krb5_ret_principal(sp, &source);
141 if (ret == 0)
142 ret = krb5_unparse_name(scontext, source, &name1);
143 if (ret)
144 krb5_err(scontext, 1, ret, "Failed to read a delete record");
145 printf(" %s\n", name1);
146 free(name1);
147 krb5_free_principal(scontext, source);
148 break;
149 case kadm_rename:
150 ret = krb5_data_alloc(&data, len);
151 if (ret == 0)
152 ret = krb5_ret_principal(sp, &source);
153 if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1)
154 ret = errno;
155 if (ret == 0)
156 ret = hdb_value2entry(scontext, &data, &ent);
157 if (ret == 0)
158 ret = krb5_unparse_name(scontext, source, &name1);
159 if (ret == 0)
160 ret = krb5_unparse_name(scontext, ent.principal, &name2);
161 if (ret)
162 krb5_err(scontext, 1, ret, "Failed to read a rename record");
163 printf(" %s -> %s\n", name1, name2);
164 free(name1);
165 free(name2);
166 krb5_free_principal(scontext, source);
167 free_hdb_entry(&ent);
168 break;
169 case kadm_create:
170 ret = krb5_data_alloc(&data, len);
171 if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1)
172 ret = errno;
173 if (ret == 0)
174 ret = hdb_value2entry(scontext, &data, &ent);
175 if (ret)
176 krb5_err(scontext, 1, ret, "Failed to read a create record");
177 mask = ~0;
178 goto foo;
179 case kadm_modify:
180 ret = krb5_data_alloc(&data, len);
181 if (ret == 0)
182 ret = krb5_ret_int32(sp, &mask);
183 if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1)
184 ret = errno;
185 if (ret == 0)
186 ret = hdb_value2entry(scontext, &data, &ent);
187 if (ret)
188 krb5_err(scontext, 1, ret, "Failed to read a modify record");
189 foo:
190 if(ent.principal /* mask & KADM5_PRINCIPAL */) {
191 ret = krb5_unparse_name(scontext, ent.principal, &name1);
192 if (ret)
193 krb5_err(scontext, 1, ret,
194 "Failed to process a create or modify record");
195 printf(" principal = %s\n", name1);
196 free(name1);
198 if(mask & KADM5_PRINC_EXPIRE_TIME) {
199 if(ent.valid_end == NULL) {
200 strlcpy(t, "never", sizeof(t));
201 } else {
202 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S",
203 localtime(ent.valid_end));
205 printf(" expires = %s\n", t);
207 if(mask & KADM5_PW_EXPIRATION) {
208 if(ent.pw_end == NULL) {
209 strlcpy(t, "never", sizeof(t));
210 } else {
211 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S",
212 localtime(ent.pw_end));
214 printf(" password exp = %s\n", t);
216 if(mask & KADM5_LAST_PWD_CHANGE) {
218 if(mask & KADM5_ATTRIBUTES) {
219 unparse_flags(HDBFlags2int(ent.flags),
220 asn1_HDBFlags_units(), t, sizeof(t));
221 printf(" attributes = %s\n", t);
223 if(mask & KADM5_MAX_LIFE) {
224 if(ent.max_life == NULL)
225 strlcpy(t, "for ever", sizeof(t));
226 else
227 unparse_time(*ent.max_life, t, sizeof(t));
228 printf(" max life = %s\n", t);
230 if(mask & KADM5_MAX_RLIFE) {
231 if(ent.max_renew == NULL)
232 strlcpy(t, "for ever", sizeof(t));
233 else
234 unparse_time(*ent.max_renew, t, sizeof(t));
235 printf(" max rlife = %s\n", t);
237 if(mask & KADM5_MOD_TIME) {
238 printf(" mod time\n");
240 if(mask & KADM5_MOD_NAME) {
241 printf(" mod name\n");
243 if(mask & KADM5_KVNO) {
244 printf(" kvno = %d\n", ent.kvno);
246 if(mask & KADM5_MKVNO) {
247 printf(" mkvno\n");
249 if(mask & KADM5_AUX_ATTRIBUTES) {
250 printf(" aux attributes\n");
252 if(mask & KADM5_POLICY) {
253 printf(" policy\n");
255 if(mask & KADM5_POLICY_CLR) {
256 printf(" mod time\n");
258 if(mask & KADM5_LAST_SUCCESS) {
259 printf(" last success\n");
261 if(mask & KADM5_LAST_FAILED) {
262 printf(" last failed\n");
264 if(mask & KADM5_FAIL_AUTH_COUNT) {
265 printf(" fail auth count\n");
267 if(mask & KADM5_KEY_DATA) {
268 printf(" key data\n");
270 if(mask & KADM5_TL_DATA) {
271 printf(" tl data\n");
273 free_hdb_entry(&ent);
274 break;
275 case kadm_nop :
276 if (len == 16) {
277 uint64_t off;
278 ret = krb5_ret_uint64(sp, &off);
279 if (ret)
280 krb5_err(scontext, 1, ret, "Failed to read a no-op record");
281 printf("uberblock offset %llu ", (unsigned long long)off);
282 } else {
283 printf("nop");
285 if (len == 16 || len == 8) {
286 ret = krb5_ret_int32(sp, &nop_time);
287 if (ret == 0)
288 ret = krb5_ret_uint32(sp, &nop_ver);
289 if (ret)
290 krb5_err(scontext, 1, ret, "Failed to read a no-op record");
292 timestamp = nop_time;
293 strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(&timestamp));
294 printf("timestamp %s version %u", t, nop_ver);
296 printf("\n");
297 break;
298 default:
299 krb5_errx(scontext, 1, "Unknown record type");
301 krb5_data_free(&data);
303 return 0;
307 iprop_dump(struct dump_options *opt, int argc, char **argv)
309 kadm5_server_context *server_context;
310 krb5_error_code ret;
311 enum kadm_iter_opts iter_opts_1st = 0;
312 enum kadm_iter_opts iter_opts_2nd = 0;
313 char *desc_1st = "";
314 char *desc_2nd = "";
316 server_context = get_kadmin_context(opt->config_file_string,
317 opt->realm_string);
319 if (argc > 0) {
320 free(server_context->log_context.log_file);
321 server_context->log_context.log_file = strdup(argv[0]);
322 if (server_context->log_context.log_file == NULL)
323 krb5_err(context, 1, errno, "strdup");
326 if (opt->reverse_flag) {
327 iter_opts_1st = kadm_backward | kadm_unconfirmed;
328 iter_opts_2nd = kadm_backward | kadm_confirmed;
329 desc_1st = "unconfirmed ";
330 } else {
331 iter_opts_1st = kadm_forward | kadm_confirmed;
332 iter_opts_2nd = kadm_forward | kadm_unconfirmed;
333 desc_2nd = "unconfirmed";
336 if (opt->no_lock_flag) {
337 ret = kadm5_log_init_sharedlock(server_context, LOCK_NB);
338 if (ret == EAGAIN || ret == EWOULDBLOCK) {
339 warnx("Not locking the iprop log");
340 ret = kadm5_log_init_nolock(server_context);
341 if (ret)
342 krb5_err(context, 1, ret, "kadm5_log_init_nolock");
344 } else {
345 warnx("If this command appears to block, try the --no-lock option");
346 ret = kadm5_log_init_sharedlock(server_context, 0);
347 if (ret)
348 krb5_err(context, 1, ret, "kadm5_log_init_sharedlock");
351 ret = kadm5_log_foreach(server_context, iter_opts_1st,
352 NULL, print_entry, desc_1st);
353 if (ret)
354 krb5_warn(context, ret, "kadm5_log_foreach");
356 ret = kadm5_log_foreach(server_context, iter_opts_2nd,
357 NULL, print_entry, desc_2nd);
358 if (ret)
359 krb5_warn(context, ret, "kadm5_log_foreach");
361 ret = kadm5_log_end (server_context);
362 if (ret)
363 krb5_warn(context, ret, "kadm5_log_end");
365 kadm5_destroy(server_context);
366 return 0;
370 iprop_truncate(struct truncate_options *opt, int argc, char **argv)
372 kadm5_server_context *server_context;
373 krb5_error_code ret;
375 server_context = get_kadmin_context(opt->config_file_string,
376 opt->realm_string);
378 if (argc > 0) {
379 free(server_context->log_context.log_file);
380 server_context->log_context.log_file = strdup(argv[0]);
381 if (server_context->log_context.log_file == NULL)
382 krb5_err(context, 1, errno, "strdup");
385 if (opt->keep_entries_integer < 0 &&
386 opt->max_bytes_integer < 0) {
387 opt->keep_entries_integer = 100;
388 opt->max_bytes_integer = 0;
390 if (opt->keep_entries_integer < 0)
391 opt->keep_entries_integer = 0;
392 if (opt->max_bytes_integer < 0)
393 opt->max_bytes_integer = 0;
395 if (opt->reset_flag) {
396 /* First recover unconfirmed records */
397 ret = kadm5_log_init(server_context);
398 if (ret == 0)
399 ret = kadm5_log_reinit(server_context, 0);
400 } else {
401 ret = kadm5_log_init(server_context);
402 if (ret)
403 krb5_err(context, 1, ret, "kadm5_log_init");
404 ret = kadm5_log_truncate(server_context, opt->keep_entries_integer,
405 opt->max_bytes_integer);
407 if (ret)
408 krb5_err(context, 1, ret, "kadm5_log_truncate");
410 kadm5_log_signal_master(server_context);
412 kadm5_destroy(server_context);
413 return 0;
417 last_version(struct last_version_options *opt, int argc, char **argv)
419 kadm5_server_context *server_context;
420 char *alt_argv[2] = { NULL, NULL };
421 krb5_error_code ret;
422 uint32_t version;
423 size_t i;
425 server_context = get_kadmin_context(opt->config_file_string,
426 opt->realm_string);
428 if (argc == 0) {
429 alt_argv[0] = strdup(server_context->log_context.log_file);
430 if (alt_argv[0] == NULL)
431 krb5_err(context, 1, errno, "strdup");
432 argv = alt_argv;
433 argc = 1;
436 for (i = 0; i < argc; i++) {
437 free(server_context->log_context.log_file);
438 server_context->log_context.log_file = strdup(argv[i]);
439 if (server_context->log_context.log_file == NULL)
440 krb5_err(context, 1, errno, "strdup");
442 if (opt->no_lock_flag) {
443 ret = kadm5_log_init_sharedlock(server_context, LOCK_NB);
444 if (ret == EAGAIN || ret == EWOULDBLOCK) {
445 warnx("Not locking the iprop log");
446 ret = kadm5_log_init_nolock(server_context);
447 if (ret)
448 krb5_err(context, 1, ret, "kadm5_log_init_nolock");
450 } else {
451 warnx("If this command appears to block, try the "
452 "--no-lock option");
453 ret = kadm5_log_init_sharedlock(server_context, 0);
454 if (ret)
455 krb5_err(context, 1, ret, "kadm5_log_init_sharedlock");
458 ret = kadm5_log_get_version (server_context, &version);
459 if (ret)
460 krb5_err (context, 1, ret, "kadm5_log_get_version");
462 ret = kadm5_log_end (server_context);
463 if (ret)
464 krb5_warn(context, ret, "kadm5_log_end");
466 printf("version: %lu\n", (unsigned long)version);
469 kadm5_destroy(server_context);
470 free(alt_argv[0]);
471 return 0;
475 signal_master(struct signal_options *opt, int argc, char **argv)
477 kadm5_server_context *server_context;
479 server_context = get_kadmin_context(opt->config_file_string,
480 opt->realm_string);
482 kadm5_log_signal_master(server_context);
484 kadm5_destroy(server_context);
485 return 0;
489 * Replay log
492 int start_version = -1;
493 int end_version = -1;
495 static kadm5_ret_t
496 apply_entry(kadm5_server_context *server_context,
497 uint32_t ver,
498 time_t timestamp,
499 enum kadm_ops op,
500 uint32_t len,
501 krb5_storage *sp,
502 void *ctx)
504 struct replay_options *opt = ctx;
505 krb5_error_code ret;
507 if((opt->start_version_integer != -1 && ver < (uint32_t)opt->start_version_integer) ||
508 (opt->end_version_integer != -1 && ver > (uint32_t)opt->end_version_integer)) {
509 /* XXX skip this entry */
510 return 0;
512 printf ("ver %u... ", ver);
513 fflush (stdout);
515 ret = kadm5_log_replay(server_context, op, ver, len, sp);
516 if (ret)
517 krb5_warn (server_context->context, ret, "kadm5_log_replay");
519 printf ("done\n");
521 return 0;
525 iprop_replay(struct replay_options *opt, int argc, char **argv)
527 kadm5_server_context *server_context;
528 krb5_error_code ret;
530 server_context = get_kadmin_context(opt->config_file_string,
531 opt->realm_string);
533 if (argc > 0) {
534 free(server_context->log_context.log_file);
535 server_context->log_context.log_file = strdup(argv[0]);
536 if (server_context->log_context.log_file == NULL)
537 krb5_err(context, 1, errno, "strdup");
540 ret = server_context->db->hdb_open(context,
541 server_context->db,
542 O_RDWR | O_CREAT, 0600);
543 if (ret)
544 krb5_err (context, 1, ret, "db->open");
546 ret = kadm5_log_init (server_context);
547 if (ret)
548 krb5_err (context, 1, ret, "kadm5_log_init");
550 ret = kadm5_log_foreach(server_context,
551 kadm_forward | kadm_confirmed | kadm_unconfirmed,
552 NULL, apply_entry, opt);
553 if(ret)
554 krb5_warn(context, ret, "kadm5_log_foreach");
555 ret = kadm5_log_end (server_context);
556 if (ret)
557 krb5_warn(context, ret, "kadm5_log_end");
558 ret = server_context->db->hdb_close (context, server_context->db);
559 if (ret)
560 krb5_err (context, 1, ret, "db->close");
562 kadm5_destroy(server_context);
563 return 0;
566 static int help_flag;
567 static int version_flag;
569 static struct getargs args[] = {
570 { "version", 0, arg_flag, &version_flag,
571 NULL, NULL
573 { "help", 'h', arg_flag, &help_flag,
574 NULL, NULL
578 static int num_args = sizeof(args) / sizeof(args[0]);
581 help(void *opt, int argc, char **argv)
583 if(argc == 0) {
584 sl_help(commands, 1, argv - 1 /* XXX */);
585 } else {
586 SL_cmd *c = sl_match (commands, argv[0], 0);
587 if(c == NULL) {
588 fprintf (stderr, "No such command: %s. "
589 "Try \"help\" for a list of commands\n",
590 argv[0]);
591 } else {
592 if(c->func) {
593 static char shelp[] = "--help";
594 char *fake[3];
595 fake[0] = argv[0];
596 fake[1] = shelp;
597 fake[2] = NULL;
598 (*c->func)(2, fake);
599 fprintf(stderr, "\n");
601 if(c->help && *c->help)
602 fprintf (stderr, "%s\n", c->help);
603 if((++c)->name && c->func == NULL) {
604 int f = 0;
605 fprintf (stderr, "Synonyms:");
606 while (c->name && c->func == NULL) {
607 fprintf (stderr, "%s%s", f ? ", " : " ", (c++)->name);
608 f = 1;
610 fprintf (stderr, "\n");
614 return 0;
617 static void
618 usage(int status)
620 arg_printusage(args, num_args, NULL, "command");
621 exit(status);
625 main(int argc, char **argv)
627 int optidx = 0;
628 krb5_error_code ret;
630 setprogname(argv[0]);
632 if(getarg(args, num_args, argc, argv, &optidx))
633 usage(1);
634 if(help_flag)
635 usage(0);
636 if(version_flag) {
637 print_version(NULL);
638 exit(0);
640 argc -= optidx;
641 argv += optidx;
642 if(argc == 0)
643 usage(1);
645 ret = krb5_init_context(&context);
646 if (ret)
647 errx(1, "krb5_init_context failed with: %d\n", ret);
649 ret = sl_command(commands, argc, argv);
650 if(ret == -1)
651 warnx ("unrecognized command: %s", argv[0]);
652 return ret;