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(&timestamp));
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