something that might resemble domain-x500-compress
[heimdal.git] / kdc / hprop.c
blob2456990236380a28c97bef1bf2e06377f4f8f704
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 int open_socket(krb5_context context, const char *hostname)
66 int s;
67 struct hostent *hp;
68 struct sockaddr_in sin;
69 s = socket(AF_INET, SOCK_STREAM, 0);
70 if(s < 0){
71 warn("socket");
72 return -1;
74 hp = gethostbyname(hostname);
75 if(hp == NULL){
76 warnx("%s: %s", hostname, hstrerror(h_errno));
77 close(s);
78 return -1;
80 memset(&sin, 0, sizeof(sin));
81 sin.sin_family = AF_INET;
82 sin.sin_port = krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT);
83 memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
84 if(connect(s, (struct sockaddr*)&sin, sizeof(sin)) < 0){
85 warn("connect");
86 close(s);
87 return -1;
89 return s;
92 struct prop_data{
93 krb5_context context;
94 krb5_auth_context auth_context;
95 int sock;
98 int hdb_entry2value(krb5_context, hdb_entry*, krb5_data*);
100 krb5_error_code
101 v5_prop(krb5_context context, HDB *db, hdb_entry *entry, void *appdata)
103 krb5_error_code ret;
104 struct prop_data *pd = appdata;
105 krb5_data data;
106 int i;
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);
167 if(encrypt)
168 hdb_seal_keys(&ent, msched5);
170 ALLOC(ent.max_life);
171 *ent.max_life = krb_life_to_time(0, p->max_life);
172 if(*ent.max_life == NEVERDATE){
173 free(ent.max_life);
174 ent.max_life = NULL;
177 ALLOC(ent.pw_end);
178 *ent.pw_end = p->exp_date;
179 ret = krb5_make_principal(pd->context, &ent.created_by.principal,
180 realm,
181 "kadmin",
182 "hprop",
183 NULL);
184 ent.created_by.time = time(NULL);
185 ALLOC(ent.modified_by);
186 krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, realm,
187 &ent.modified_by->principal);
188 ent.modified_by->time = p->mod_date;
190 ent.flags.forwardable = 1;
191 ent.flags.renewable = 1;
192 ent.flags.proxiable = 1;
193 ent.flags.postdate = 1;
194 ent.flags.client = 1;
195 ent.flags.server = 1;
197 ret = v5_prop(pd->context, NULL, &ent, pd);
198 hdb_free_entry(pd->context, &ent);
199 return ret;
202 #endif
205 struct getargs args[] = {
206 { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" },
207 #ifdef KRB4
208 #endif
209 { "database", 'd', arg_string, &database, "database", "file" },
210 #ifdef KRB4
211 { "v4-db", '4', arg_flag, &v4_db, "use version 4 database" },
212 #endif
213 { "keytab", 'k', arg_string, &ktname, "keytab to use for authentication", "keytab" },
214 { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys" },
215 { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys" },
216 { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout" },
217 { "verbose", 'v', arg_flag, &verbose_flag },
218 { "version", 0, arg_flag, &version_flag },
219 { "help", 'h', arg_flag, &help_flag }
222 static int num_args = sizeof(args) / sizeof(args[0]);
224 void usage(int ret)
226 arg_printusage (args, num_args, "host ...");
227 exit (ret);
230 void
231 get_creds(krb5_context context, krb5_ccache *cache)
233 krb5_keytab keytab;
234 krb5_principal client;
235 krb5_error_code ret;
236 krb5_get_init_creds_opt init_opts;
237 krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP;
238 krb5_creds creds;
240 ret = krb5_kt_resolve(context, ktname, &keytab);
241 if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve");
243 ret = krb5_make_principal(context, &client, NULL,
244 "kadmin", HPROP_NAME, NULL);
245 if(ret) krb5_err(context, 1, ret, "krb5_make_principal");
247 krb5_get_init_creds_opt_init(&init_opts);
248 krb5_get_init_creds_opt_set_preauth_list(&init_opts, &preauth, 1);
250 ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, &init_opts);
251 if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds");
253 ret = krb5_kt_close(context, keytab);
254 if(ret) krb5_err(context, 1, ret, "krb5_kt_close");
256 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache);
257 if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new");
259 ret = krb5_cc_initialize(context, *cache, client);
260 if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize");
262 ret = krb5_cc_store_cred(context, *cache, &creds);
263 if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred");
266 int main(int argc, char **argv)
268 krb5_error_code ret;
269 int e;
270 krb5_context context;
271 krb5_auth_context ac;
272 krb5_principal server;
273 krb5_ccache ccache;
274 int fd;
275 HDB *db;
276 int optind = 0;
277 int i;
279 set_progname(argv[0]);
281 if(getarg(args, num_args, argc, argv, &optind))
282 usage(1);
284 if(help_flag)
285 usage(0);
287 if(version_flag){
288 fprintf(stderr, "%s (%s)\n", __progname, heimdal_version);
289 exit(0);
292 ret = krb5_init_context(&context);
293 if(ret)
294 exit(1);
296 if(encrypt_flag && decrypt_flag)
297 krb5_errx(context, 1,
298 "Only one of `--encrypt' and `--decrypt' is meaningful");
300 if(!to_stdout)
301 get_creds(context, &ccache);
303 ret = hdb_read_master_key(context, mkeyfile, &mkey5);
304 if(ret && ret != ENOENT)
305 krb5_err(context, 1, ret, "hdb_read_master_key");
306 if(ret){
307 if(encrypt_flag || decrypt_flag)
308 krb5_errx(context, 1, "No master key file found");
309 }else{
310 ret = hdb_process_master_key(context, mkey5, &msched5);
311 if(ret)
312 krb5_err(context, 1, ret, "hdb_process_master_key");
315 #ifdef KRB4
316 if(v4_db){
317 e = kerb_db_set_name (database);
318 if(e) krb5_errx(context, 1, "kerb_db_set_name: %s", krb_get_err_text(e));
319 e = kdb_get_master_key(0, &mkey4, msched4);
320 if(e) krb5_errx(context, 1, "kdb_get_master_key: %s", krb_get_err_text(e));
321 e = krb_get_lrealm(realm, 1);
322 if(e) krb5_errx(context, 1, "krb_get_lrealm: %s", krb_get_err_text(e));
323 }else
324 #endif
326 ret = hdb_open(context, &db, database, O_RDONLY, 0);
327 if(ret) krb5_err(context, 1, ret, "hdb_open");
330 if(to_stdout){
331 struct prop_data pd;
332 pd.context = context;
333 pd.auth_context = ac;
334 pd.sock = fd;
336 #ifdef KRB4
337 if(v4_db){
338 e = kerb_db_iterate ((k_iter_proc_t)v4_prop, &pd);
339 if(e)
340 krb5_errx(context, 1, "kerb_db_iterate: %s",
341 krb_get_err_text(e));
342 } else {
343 #endif
344 ret = hdb_foreach(context, db, v5_prop, &pd);
345 if(ret)
346 krb5_err(context, 1, ret, "hdb_foreach");
348 }else{
350 for(i = optind; i < argc; i++){
351 fd = open_socket(context, argv[i]);
352 if(fd < 0)
353 continue;
355 ret = krb5_sname_to_principal(context, argv[i],
356 HPROP_NAME, KRB5_NT_SRV_HST, &server);
357 if(ret) {
358 krb5_warn(context, ret, "krb5_sname_to_principal(%s)", argv[i]);
359 close(fd);
360 continue;
363 ac = NULL;
364 ret = krb5_sendauth(context,
365 &ac,
366 &fd,
367 HPROP_VERSION,
368 NULL,
369 server,
370 AP_OPTS_MUTUAL_REQUIRED,
371 NULL, /* in_data */
372 NULL, /* in_creds */
373 ccache,
374 NULL,
375 NULL,
376 NULL);
378 if(ret){
379 krb5_warn(context, ret, "krb5_sendauth");
380 close(fd);
381 continue;
385 struct prop_data pd;
386 pd.context = context;
387 pd.auth_context = ac;
388 pd.sock = fd;
390 #ifdef KRB4
391 if(v4_db)
392 e = kerb_db_iterate ((k_iter_proc_t)v4_prop, &pd);
393 else
394 #endif
395 ret = hdb_foreach(context, db, v5_prop, &pd);
397 if(ret)
398 krb5_warn(context, ret, "krb5_sendauth");
399 else {
400 krb5_data data;
401 data.data = NULL;
402 data.length = 0;
403 ret = send_priv(context, ac, &data, fd);
407 krb5_data data;
408 ret = recv_priv(context, ac, fd, &data);
409 if(ret) krb5_warn(context, ret, "recv_priv");
410 if(data.length != 0)
411 krb5_data_free(&data); /* XXX */
414 if(ret) krb5_warn(context, ret, "send_priv");
415 krb5_auth_con_free(context, ac);
416 close(fd);
419 exit(0);