get.c revision 120945
1/*
2 * Copyright (c) 1997 - 2001 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 "ktutil_locl.h"
35
36RCSID("$Id: get.c,v 1.22 2003/01/16 19:03:23 lha Exp $");
37
38static void*
39open_kadmin_connection(char *principal,
40		       const char *realm,
41		       char *admin_server,
42		       int server_port)
43{
44    static kadm5_config_params conf;
45    krb5_error_code ret;
46    void *kadm_handle;
47    memset(&conf, 0, sizeof(conf));
48
49    if(realm) {
50	conf.realm = (char*)realm;
51	conf.mask |= KADM5_CONFIG_REALM;
52    }
53
54    if (admin_server) {
55	conf.admin_server = admin_server;
56	conf.mask |= KADM5_CONFIG_ADMIN_SERVER;
57    }
58
59    if (server_port) {
60	conf.kadmind_port = htons(server_port);
61	conf.mask |= KADM5_CONFIG_KADMIND_PORT;
62    }
63
64    /* should get realm from each principal, instead of doing
65       everything with the same (local) realm */
66
67    ret = kadm5_init_with_password_ctx(context,
68				       principal,
69				       NULL,
70				       KADM5_ADMIN_SERVICE,
71				       &conf, 0, 0,
72				       &kadm_handle);
73    if(ret) {
74	krb5_warn(context, ret, "kadm5_init_with_password");
75	return NULL;
76    }
77    return kadm_handle;
78}
79
80int
81kt_get(int argc, char **argv)
82{
83    krb5_error_code ret = 0;
84    krb5_keytab keytab;
85    void *kadm_handle = NULL;
86    char *principal = NULL;
87    char *realm = NULL;
88    char *admin_server = NULL;
89    int server_port = 0;
90    int help_flag = 0;
91    int optind = 0;
92    struct getarg_strings etype_strs = {0, NULL};
93    krb5_enctype *etypes = NULL;
94    size_t netypes = 0;
95
96    struct getargs args[] = {
97	{ "principal",	'p',	arg_string,   NULL,
98	  "admin principal", "principal"
99	},
100	{ "enctypes",	'e',	arg_strings,	NULL,
101	  "encryption types to use", "enctypes" },
102	{ "realm",	'r',	arg_string,   NULL,
103	  "realm to use", "realm"
104	},
105	{ "admin-server",	'a',	arg_string, NULL,
106	  "server to contact", "host"
107	},
108	{ "server-port",	's',	arg_integer, NULL,
109	  "port to contact", "port number"
110	},
111	{ "help",		'h',	arg_flag,    NULL }
112    };
113    int i = 0, j;
114
115    args[i++].value = &principal;
116    args[i++].value = &etype_strs;
117    args[i++].value = &realm;
118    args[i++].value = &admin_server;
119    args[i++].value = &server_port;
120    args[i++].value = &help_flag;
121
122    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)
123       || help_flag) {
124	arg_printusage(args, sizeof(args) / sizeof(args[0]),
125		       "ktutil get", "principal...");
126	return 1;
127    }
128    if(optind == argc) {
129	krb5_warnx(context, "no principals specified");
130	arg_printusage(args, sizeof(args) / sizeof(args[0]),
131		       "ktutil get", "principal...");
132	return 1;
133    }
134
135    if((keytab = ktutil_open_keytab()) == NULL)
136	return 1;
137
138    if(realm)
139	krb5_set_default_realm(context, realm);
140
141    if (etype_strs.num_strings) {
142	int i;
143
144	etypes = malloc (etype_strs.num_strings * sizeof(*etypes));
145	if (etypes == NULL) {
146	    krb5_warnx(context, "malloc failed");
147	    goto out;
148	}
149	netypes = etype_strs.num_strings;
150	for(i = 0; i < netypes; i++) {
151	    ret = krb5_string_to_enctype(context,
152					 etype_strs.strings[i],
153					 &etypes[i]);
154	    if(ret) {
155		krb5_warnx(context, "unrecognized enctype: %s",
156			   etype_strs.strings[i]);
157		goto out;
158	    }
159	}
160    }
161
162
163    for(i = optind; i < argc; i++){
164	krb5_principal princ_ent;
165	kadm5_principal_ent_rec princ;
166	int mask = 0;
167	krb5_keyblock *keys;
168	int n_keys;
169	int created = 0;
170	krb5_keytab_entry entry;
171
172	ret = krb5_parse_name(context, argv[i], &princ_ent);
173	memset(&princ, 0, sizeof(princ));
174	princ.principal = princ_ent;
175	mask |= KADM5_PRINCIPAL;
176	princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
177	mask |= KADM5_ATTRIBUTES;
178	princ.princ_expire_time = 0;
179	mask |= KADM5_PRINC_EXPIRE_TIME;
180
181	if(kadm_handle == NULL) {
182	    const char *r;
183	    if(realm != NULL)
184		r = realm;
185	    else
186		r = krb5_principal_get_realm(context, princ_ent);
187	    kadm_handle = open_kadmin_connection(principal,
188						 r,
189						 admin_server,
190						 server_port);
191	    if(kadm_handle == NULL) {
192		break;
193	    }
194	}
195
196	ret = kadm5_create_principal(kadm_handle, &princ, mask, "x");
197	if(ret == 0)
198	    created++;
199	else if(ret != KADM5_DUP) {
200	    krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[i]);
201	    krb5_free_principal(context, princ_ent);
202	    continue;
203	}
204	ret = kadm5_randkey_principal(kadm_handle, princ_ent, &keys, &n_keys);
205	if (ret) {
206	    krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[i]);
207	    krb5_free_principal(context, princ_ent);
208	    continue;
209	}
210
211	ret = kadm5_get_principal(kadm_handle, princ_ent, &princ,
212			      KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
213	if (ret) {
214	    krb5_warn(context, ret, "kadm5_get_principal(%s)", argv[i]);
215	    for (j = 0; j < n_keys; j++)
216		krb5_free_keyblock_contents(context, &keys[j]);
217	    krb5_free_principal(context, princ_ent);
218	    continue;
219	}
220	princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
221	mask = KADM5_ATTRIBUTES;
222	if(created) {
223	    princ.kvno = 1;
224	    mask |= KADM5_KVNO;
225	}
226	ret = kadm5_modify_principal(kadm_handle, &princ, mask);
227	if (ret) {
228	    krb5_warn(context, ret, "kadm5_modify_principal(%s)", argv[i]);
229	    for (j = 0; j < n_keys; j++)
230		krb5_free_keyblock_contents(context, &keys[j]);
231	    krb5_free_principal(context, princ_ent);
232	    continue;
233	}
234	for(j = 0; j < n_keys; j++) {
235	    int do_add = TRUE;
236
237	    if (netypes) {
238		int i;
239
240		do_add = FALSE;
241		for (i = 0; i < netypes; ++i)
242		    if (keys[j].keytype == etypes[i]) {
243			do_add = TRUE;
244			break;
245		    }
246	    }
247	    if (do_add) {
248		entry.principal = princ_ent;
249		entry.vno = princ.kvno;
250		entry.keyblock = keys[j];
251		entry.timestamp = time (NULL);
252		ret = krb5_kt_add_entry(context, keytab, &entry);
253		if (ret)
254		    krb5_warn(context, ret, "krb5_kt_add_entry");
255	    }
256	    krb5_free_keyblock_contents(context, &keys[j]);
257	}
258
259	kadm5_free_principal_ent(kadm_handle, &princ);
260	krb5_free_principal(context, princ_ent);
261    }
262 out:
263    free_getarg_strings(&etype_strs);
264    free(etypes);
265    if (kadm_handle)
266	kadm5_destroy(kadm_handle);
267    krb5_kt_close(context, keytab);
268    return ret != 0;
269}
270