*** empty log message ***
[heimdal.git] / kdc / hprop.c
blob952017a8782c929ebec6ecede2d0b1d23fd7a545
1 /*
2 * Copyright (c) 1997 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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "hprop.h"
40 #ifdef KRB4
41 #define Principal Principal4
42 #include <krb.h>
43 #include <krb_db.h>
44 #endif
46 RCSID("$Id$");
48 static int version_flag;
49 static int help_flag;
50 static char *ktname = HPROP_KEYTAB;
51 static char *database;
52 static char *mkeyfile;
53 static int to_stdout;
54 static int verbose_flag;
55 static int encrypt_flag;
56 static int decrypt_flag;
57 static EncryptionKey mkey5;
58 static krb5_data msched5;
60 #ifdef KRB4
61 static int v4_db;
62 #endif
64 static int
65 open_socket(krb5_context context, const char *hostname)
67 int s;
68 struct hostent *hp;
69 struct sockaddr_in sin;
70 s = socket(AF_INET, SOCK_STREAM, 0);
71 if(s < 0){
72 warn("socket");
73 return -1;
75 hp = roken_gethostbyname(hostname);
76 if(hp == NULL){
77 warnx("%s: %s", hostname, hstrerror(h_errno));
78 close(s);
79 return -1;
81 memset(&sin, 0, sizeof(sin));
82 sin.sin_family = AF_INET;
83 sin.sin_port = krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT);
84 memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
85 if(connect(s, (struct sockaddr*)&sin, sizeof(sin)) < 0){
86 warn("connect");
87 close(s);
88 return -1;
90 return s;
93 struct prop_data{
94 krb5_context context;
95 krb5_auth_context auth_context;
96 int sock;
99 int hdb_entry2value(krb5_context, hdb_entry*, krb5_data*);
101 static krb5_error_code
102 v5_prop(krb5_context context, HDB *db, hdb_entry *entry, void *appdata)
104 krb5_error_code ret;
105 struct prop_data *pd = appdata;
106 krb5_data data;
108 if(encrypt_flag)
109 hdb_seal_keys(entry, msched5);
110 if(decrypt_flag)
111 hdb_unseal_keys(entry, msched5);
113 ret = hdb_entry2value(context, entry, &data);
114 if(ret) return ret;
116 if(to_stdout)
117 ret = send_clear(context, STDOUT_FILENO, data);
118 else
119 ret = send_priv(context, pd->auth_context, &data, pd->sock);
120 krb5_data_free(&data);
121 return ret;
124 #ifdef KRB4
125 static des_cblock mkey4;
126 static des_key_schedule msched4;
127 static char realm[REALM_SZ];
129 static int
130 v4_prop(void *arg, Principal *p)
132 struct prop_data *pd = arg;
133 hdb_entry ent;
134 krb5_error_code ret;
136 memset(&ent, 0, sizeof(ent));
138 ret = krb5_425_conv_principal(pd->context, p->name, p->instance, realm,
139 &ent.principal);
140 if(ret){
141 krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, realm);
142 return 0;
145 if(verbose_flag){
146 char *s;
147 krb5_unparse_name(pd->context, ent.principal, &s);
148 krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s);
149 free(s);
152 ent.keys.len = 1;
153 ALLOC(ent.keys.val);
154 ent.keys.val[0].mkvno = p->kdc_key_ver;
155 ent.keys.val[0].salt = calloc(1, sizeof(*ent.keys.val[0].salt));
156 ent.keys.val[0].salt->type = pa_pw_salt;
157 ent.kvno = p->key_version;
158 ent.keys.val[0].key.keytype = KEYTYPE_DES;
159 krb5_data_alloc(&ent.keys.val[0].key.keyvalue, sizeof(des_cblock));
162 unsigned char *key = ent.keys.val[0].key.keyvalue.data;
163 memcpy(key, &p->key_low, 4);
164 memcpy(key + 4, &p->key_high, 4);
165 kdb_encrypt_key((des_cblock*)key, (des_cblock*)key, &mkey4, msched4, 0);
168 ALLOC(ent.max_life);
169 *ent.max_life = krb_life_to_time(0, p->max_life);
170 if(*ent.max_life == NEVERDATE){
171 free(ent.max_life);
172 ent.max_life = NULL;
175 ALLOC(ent.pw_end);
176 *ent.pw_end = p->exp_date;
177 ret = krb5_make_principal(pd->context, &ent.created_by.principal,
178 realm,
179 "kadmin",
180 "hprop",
181 NULL);
182 if(ret){
183 krb5_warn(pd->context, ret, "krb5_make_principal");
184 ret = 0;
185 goto out;
187 ent.created_by.time = time(NULL);
188 ALLOC(ent.modified_by);
189 ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance,
190 realm, &ent.modified_by->principal);
191 if(ret){
192 krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, realm);
193 ent.modified_by->principal = NULL;
194 ret = 0;
195 goto out;
197 ent.modified_by->time = p->mod_date;
199 ent.flags.forwardable = 1;
200 ent.flags.renewable = 1;
201 ent.flags.proxiable = 1;
202 ent.flags.postdate = 1;
203 ent.flags.client = 1;
204 ent.flags.server = 1;
206 ret = v5_prop(pd->context, NULL, &ent, pd);
207 out:
208 hdb_free_entry(pd->context, &ent);
209 return ret;
212 #endif
215 struct getargs args[] = {
216 { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" },
217 #ifdef KRB4
218 #endif
219 { "database", 'd', arg_string, &database, "database", "file" },
220 #ifdef KRB4
221 { "v4-db", '4', arg_flag, &v4_db, "use version 4 database" },
222 #endif
223 { "keytab", 'k', arg_string, &ktname, "keytab to use for authentication", "keytab" },
224 { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys" },
225 { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys" },
226 { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout" },
227 { "verbose", 'v', arg_flag, &verbose_flag },
228 { "version", 0, arg_flag, &version_flag },
229 { "help", 'h', arg_flag, &help_flag }
232 static int num_args = sizeof(args) / sizeof(args[0]);
234 static void
235 usage(int ret)
237 arg_printusage (args, num_args, "host ...");
238 exit (ret);
241 static void
242 get_creds(krb5_context context, krb5_ccache *cache)
244 krb5_keytab keytab;
245 krb5_principal client;
246 krb5_error_code ret;
247 krb5_get_init_creds_opt init_opts;
248 krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP;
249 krb5_creds creds;
251 ret = krb5_kt_resolve(context, ktname, &keytab);
252 if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve");
254 ret = krb5_make_principal(context, &client, NULL,
255 "kadmin", HPROP_NAME, NULL);
256 if(ret) krb5_err(context, 1, ret, "krb5_make_principal");
258 krb5_get_init_creds_opt_init(&init_opts);
259 krb5_get_init_creds_opt_set_preauth_list(&init_opts, &preauth, 1);
261 ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, &init_opts);
262 if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds");
264 ret = krb5_kt_close(context, keytab);
265 if(ret) krb5_err(context, 1, ret, "krb5_kt_close");
267 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache);
268 if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new");
270 ret = krb5_cc_initialize(context, *cache, client);
271 if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize");
273 ret = krb5_cc_store_cred(context, *cache, &creds);
274 if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred");
277 int main(int argc, char **argv)
279 krb5_error_code ret;
280 krb5_context context;
281 krb5_auth_context ac;
282 krb5_principal server;
283 krb5_ccache ccache;
284 int fd;
285 HDB *db;
286 int optind = 0;
287 int i;
288 #ifdef KRB4
289 int e;
290 #endif
293 set_progname(argv[0]);
295 if(getarg(args, num_args, argc, argv, &optind))
296 usage(1);
298 if(help_flag)
299 usage(0);
301 if(version_flag){
302 fprintf(stderr, "%s (%s)\n", __progname, heimdal_version);
303 exit(0);
306 ret = krb5_init_context(&context);
307 if(ret)
308 exit(1);
310 if(encrypt_flag && decrypt_flag)
311 krb5_errx(context, 1,
312 "Only one of `--encrypt' and `--decrypt' is meaningful");
314 if(!to_stdout)
315 get_creds(context, &ccache);
317 ret = hdb_read_master_key(context, mkeyfile, &mkey5);
318 if(ret && ret != ENOENT)
319 krb5_err(context, 1, ret, "hdb_read_master_key");
320 if(ret){
321 if(encrypt_flag || decrypt_flag)
322 krb5_errx(context, 1, "No master key file found");
323 }else{
324 ret = hdb_process_master_key(context, mkey5, &msched5);
325 if(ret)
326 krb5_err(context, 1, ret, "hdb_process_master_key");
329 #ifdef KRB4
330 if(v4_db){
331 e = kerb_db_set_name (database);
332 if(e) krb5_errx(context, 1, "kerb_db_set_name: %s", krb_get_err_text(e));
333 e = kdb_get_master_key(0, &mkey4, msched4);
334 if(e) krb5_errx(context, 1, "kdb_get_master_key: %s", krb_get_err_text(e));
335 e = krb_get_lrealm(realm, 1);
336 if(e) krb5_errx(context, 1, "krb_get_lrealm: %s", krb_get_err_text(e));
337 }else
338 #endif
340 ret = hdb_create (context, &db, database);
341 if(ret)
342 krb5_err(context, 1, ret, "hdb_create: %s", database);
343 ret = db->open(context, db, O_RDONLY, 0);
344 if(ret)
345 krb5_err(context, 1, ret, "db->open");
348 if(to_stdout){
349 struct prop_data pd;
350 pd.context = context;
351 pd.auth_context = ac;
352 pd.sock = fd;
354 #ifdef KRB4
355 if(v4_db){
356 e = kerb_db_iterate ((k_iter_proc_t)v4_prop, &pd);
357 if(e)
358 krb5_errx(context, 1, "kerb_db_iterate: %s",
359 krb_get_err_text(e));
360 } else
361 #endif
363 ret = hdb_foreach(context, db, v5_prop, &pd);
364 if(ret)
365 krb5_err(context, 1, ret, "hdb_foreach");
367 }else{
369 for(i = optind; i < argc; i++){
370 fd = open_socket(context, argv[i]);
371 if(fd < 0)
372 continue;
374 ret = krb5_sname_to_principal(context, argv[i],
375 HPROP_NAME, KRB5_NT_SRV_HST, &server);
376 if(ret) {
377 krb5_warn(context, ret, "krb5_sname_to_principal(%s)", argv[i]);
378 close(fd);
379 continue;
382 ac = NULL;
383 ret = krb5_sendauth(context,
384 &ac,
385 &fd,
386 HPROP_VERSION,
387 NULL,
388 server,
389 AP_OPTS_MUTUAL_REQUIRED,
390 NULL, /* in_data */
391 NULL, /* in_creds */
392 ccache,
393 NULL,
394 NULL,
395 NULL);
397 if(ret){
398 krb5_warn(context, ret, "krb5_sendauth");
399 close(fd);
400 continue;
404 struct prop_data pd;
405 pd.context = context;
406 pd.auth_context = ac;
407 pd.sock = fd;
409 #ifdef KRB4
410 if(v4_db)
411 e = kerb_db_iterate ((k_iter_proc_t)v4_prop, &pd);
412 else
413 #endif
414 ret = hdb_foreach(context, db, v5_prop, &pd);
416 if(ret)
417 krb5_warn(context, ret, "krb5_sendauth");
418 else {
419 krb5_data data;
420 data.data = NULL;
421 data.length = 0;
422 ret = send_priv(context, ac, &data, fd);
426 krb5_data data;
427 ret = recv_priv(context, ac, fd, &data);
428 if(ret) krb5_warn(context, ret, "recv_priv");
429 if(data.length != 0)
430 krb5_data_free(&data); /* XXX */
433 if(ret) krb5_warn(context, ret, "send_priv");
434 krb5_auth_con_free(context, ac);
435 close(fd);
438 exit(0);