1/*
2 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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.
32 */
33
34#include "kadmin_locl.h"
35#include "kadmin-commands.h"
36#include <sl.h>
37
38static void usage(int ret) __attribute__((__noreturn__));
39
40
41static char *config_file;
42static char *keyfile;
43int local_flag;
44static int ad_flag;
45static int mit_flag = 1;
46static int help_flag;
47static int version_flag;
48static char *realm;
49static char *admin_server;
50static int server_port = 0;
51static char *client_name;
52static char *keytab;
53static char *check_library  = NULL;
54static char *check_function = NULL;
55static getarg_strings policy_libraries = { 0, NULL };
56
57static struct getargs args[] = {
58    {	"principal", 	'p',	arg_string,	&client_name,
59	"principal to authenticate as", NULL },
60    {   "keytab",	'K',	arg_string,	&keytab,
61   	"keytab for authentication principal", NULL },
62    {
63	"config-file",	'c',	arg_string,	&config_file,
64	"location of config file",	"file"
65    },
66    {
67	"key-file",	'k',	arg_string, &keyfile,
68	"location of master key file", "file"
69    },
70    {
71	"realm",	'r',	arg_string,   &realm,
72	"realm to use", "realm"
73    },
74    {
75	"admin-server",	'a',	arg_string,   &admin_server,
76	"server to contact", "host"
77    },
78    {
79	"server-port",	's',	arg_integer,   &server_port,
80	"port to use", "port number"
81    },
82    {	"ad", 		0, arg_flag, &ad_flag, "active directory admin mode" },
83    {	"mit", 		0, arg_negative_flag, &mit_flag, "mit admin mode" },
84#ifdef HAVE_DLOPEN
85    { "check-library", 0, arg_string, &check_library,
86      "library to load password check function from", "library" },
87    { "check-function", 0, arg_string, &check_function,
88      "password check function to load", "function" },
89    { "policy-libraries", 0, arg_strings, &policy_libraries,
90      "password check function to load", "function" },
91#endif
92    {	"local", 'l', arg_flag, &local_flag, "local admin mode", NULL },
93    {	"help",		'h',	arg_flag,   &help_flag, NULL, NULL },
94    {	"version",	'v',	arg_flag,   &version_flag, NULL, NULL }
95};
96
97static int num_args = sizeof(args) / sizeof(args[0]);
98
99
100krb5_context context;
101void *kadm_handle;
102
103int
104help(void *opt, int argc, char **argv)
105{
106    sl_slc_help(commands, argc, argv);
107    return 0;
108}
109
110static int exit_seen = 0;
111
112int
113exit_kadmin (void *opt, int argc, char **argv)
114{
115    exit_seen = 1;
116    return 0;
117}
118
119int
120lock(void *opt, int argc, char **argv)
121{
122    return kadm5_lock(kadm_handle);
123}
124
125int
126unlock(void *opt, int argc, char **argv)
127{
128    return kadm5_unlock(kadm_handle);
129}
130
131static void
132usage(int ret)
133{
134    arg_printusage (args, num_args, NULL, "[command]");
135    exit (ret);
136}
137
138int
139get_privs(void *opt, int argc, char **argv)
140{
141    uint32_t privs;
142    char str[128];
143    kadm5_ret_t ret;
144
145    ret = kadm5_get_privs(kadm_handle, &privs);
146    if(ret)
147	krb5_warn(context, ret, "kadm5_get_privs");
148    else{
149	ret =_kadm5_privs_to_string(privs, str, sizeof(str));
150	if (ret == 0)
151	    printf("%s\n", str);
152	else
153	    printf("privs: 0x%x\n", (unsigned int)privs);
154    }
155    return 0;
156}
157
158int
159main(int argc, char **argv)
160{
161    krb5_error_code ret;
162    char **files;
163    kadm5_config_params conf;
164    int optidx = 0;
165    int exit_status = 0;
166
167    setprogname(argv[0]);
168
169    ret = krb5_init_context(&context);
170    if (ret)
171	errx (1, "krb5_init_context failed: %d", ret);
172
173    if(getarg(args, num_args, argc, argv, &optidx))
174	usage(1);
175
176    if (help_flag)
177	usage(0);
178
179    if (version_flag) {
180	print_version(NULL);
181	exit(0);
182    }
183
184    argc -= optidx;
185    argv += optidx;
186
187    if (config_file == NULL) {
188	asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context));
189	if (config_file == NULL)
190	    errx(1, "out of memory");
191    }
192
193    ret = krb5_prepend_config_files_default(config_file, &files);
194    if (ret)
195	krb5_err(context, 1, ret, "getting configuration files");
196
197    ret = krb5_set_config_files(context, files);
198    krb5_free_config_files(files);
199    if(ret)
200	krb5_err(context, 1, ret, "reading configuration files");
201
202    memset(&conf, 0, sizeof(conf));
203    if(realm) {
204	krb5_set_default_realm(context, realm); /* XXX should be fixed
205						   some other way */
206	conf.realm = realm;
207	conf.mask |= KADM5_CONFIG_REALM;
208    }
209
210    if (admin_server) {
211	conf.admin_server = admin_server;
212	conf.mask |= KADM5_CONFIG_ADMIN_SERVER;
213    }
214
215    if (server_port) {
216	conf.kadmind_port = htons(server_port);
217	conf.mask |= KADM5_CONFIG_KADMIND_PORT;
218    }
219
220    if (keyfile) {
221	conf.stash_file = keyfile;
222	conf.mask |= KADM5_CONFIG_STASH_FILE;
223    }
224
225    if(local_flag) {
226	int i;
227
228	kadm5_setup_passwd_quality_check (context,
229					  check_library, check_function);
230
231	for (i = 0; i < policy_libraries.num_strings; i++) {
232	    ret = kadm5_add_passwd_quality_verifier(context,
233						    policy_libraries.strings[i]);
234	    if (ret)
235		krb5_err(context, 1, ret, "kadm5_add_passwd_quality_verifier");
236	}
237	ret = kadm5_add_passwd_quality_verifier(context, NULL);
238	if (ret)
239	    krb5_err(context, 1, ret, "kadm5_add_passwd_quality_verifier");
240
241	ret = kadm5_s_init_with_password_ctx(context,
242					     KADM5_ADMIN_SERVICE,
243					     NULL,
244					     KADM5_ADMIN_SERVICE,
245					     &conf, 0, 0,
246					     &kadm_handle);
247    } else if (mit_flag) {
248	ret = kadm5_mit_init_with_password_ctx(context,
249					       client_name,
250					       NULL,
251					       &conf, 0, 0,
252					       &kadm_handle);
253    } else if (ad_flag) {
254	if (client_name == NULL)
255	    krb5_errx(context, 1, "keytab mode require principal name");
256	ret = kadm5_ad_init_with_password_ctx(context,
257					      client_name,
258					      NULL,
259					      KADM5_ADMIN_SERVICE,
260					      &conf, 0, 0,
261					      &kadm_handle);
262    } else if (keytab) {
263	if (client_name == NULL)
264	    krb5_errx(context, 1, "keytab mode require principal name");
265        ret = kadm5_c_init_with_skey_ctx(context,
266					 client_name,
267					 keytab,
268					 KADM5_ADMIN_SERVICE,
269                                         &conf, 0, 0,
270                                         &kadm_handle);
271    } else
272	ret = kadm5_c_init_with_password_ctx(context,
273					     client_name,
274					     NULL,
275					     KADM5_ADMIN_SERVICE,
276					     &conf, 0, 0,
277					     &kadm_handle);
278
279    if(ret)
280	krb5_err(context, 1, ret, "kadm5_init_with_password");
281
282    signal(SIGINT, SIG_IGN); /* ignore signals for now, the sl command
283                                parser will handle SIGINT its own way;
284                                we should really take care of this in
285                                each function, f.i `get' might be
286                                interruptable, but not `create' */
287    if (argc != 0) {
288	ret = sl_command (commands, argc, argv);
289	if(ret == -1)
290	    krb5_warnx (context, "unrecognized command: %s", argv[0]);
291	else if (ret == -2)
292	    ret = 0;
293	if(ret != 0)
294	    exit_status = 1;
295    } else {
296	while(!exit_seen) {
297	    ret = sl_command_loop(commands, "kadmin> ", NULL);
298	    if (ret == -2)
299		exit_seen = 1;
300	    else if (ret != 0)
301		exit_status = 1;
302	}
303    }
304
305    kadm5_destroy(kadm_handle);
306    krb5_free_context(context);
307    return exit_status;
308}
309