1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/create/kdb5_mkdums.c */
3 /*
4 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 *
29 * Edit a KDC database.
30 */
31
32 #include "k5-int.h"
33 #include "kdb.h"
34 #include "com_err.h"
35 #include <ss/ss.h>
36 #include <stdio.h>
37
38
39 #define REALM_SEP '@'
40 #define REALM_SEP_STR "@"
41
42 struct mblock {
43 krb5_deltat max_life;
44 krb5_deltat max_rlife;
45 krb5_timestamp expiration;
46 krb5_flags flags;
47 krb5_kvno mkvno;
48 } mblock = { /* XXX */
49 KRB5_KDB_MAX_LIFE,
50 KRB5_KDB_MAX_RLIFE,
51 KRB5_KDB_EXPIRATION,
52 KRB5_KDB_DEF_FLAGS,
53 1
54 };
55
56 int set_dbname_help (char *, char *);
57
58 static void
usage(who,status)59 usage(who, status)
60 char *who;
61 int status;
62 {
63 fprintf(stderr,
64 "usage: %s -p prefix -n num_to_create [-d dbpathname] [-r realmname]\n",
65 who);
66 fprintf(stderr, "\t [-D depth] [-k enctype] [-M mkeyname]\n");
67
68 exit(status);
69 }
70
71 int master_princ_set = 0;
72 krb5_keyblock master_keyblock;
73 krb5_principal master_princ;
74 krb5_pointer master_random;
75 krb5_context test_context;
76
77 static char *progname;
78 static char *cur_realm = 0;
79 static char *mkey_name = 0;
80 static char *mkey_password = 0;
81 static krb5_boolean manual_mkey = FALSE;
82
83 void add_princ (krb5_context, char *);
84
85 int
main(argc,argv)86 main(argc, argv)
87 int argc;
88 char *argv[];
89 {
90 extern char *optarg;
91 int optchar, i, n;
92 char tmp[4096], tmp2[BUFSIZ], *str_newprinc;
93
94 krb5_error_code retval;
95 char *dbname = 0;
96 int enctypedone = 0;
97 int num_to_create;
98 char principal_string[BUFSIZ];
99 char *suffix = 0;
100 size_t suffix_size = 0;
101 int depth;
102
103 krb5_init_context(&test_context);
104
105 if (strrchr(argv[0], '/'))
106 argv[0] = strrchr(argv[0], '/')+1;
107
108 progname = argv[0];
109
110 memset(principal_string, 0, sizeof(principal_string));
111 num_to_create = 0;
112 depth = 1;
113
114 while ((optchar = getopt(argc, argv, "D:P:p:n:d:r:k:M:e:m")) != -1) {
115 switch(optchar) {
116 case 'D':
117 depth = atoi(optarg); /* how deep to go */
118 break;
119 case 'P': /* Only used for testing!!! */
120 mkey_password = optarg;
121 break;
122 case 'p': /* prefix name to create */
123 strncpy(principal_string, optarg, sizeof(principal_string) - 1);
124 principal_string[sizeof(principal_string) - 1] = '\0';
125 suffix = principal_string + strlen(principal_string);
126 suffix_size = sizeof(principal_string) -
127 (suffix - principal_string);
128 break;
129 case 'n': /* how many to create */
130 num_to_create = atoi(optarg);
131 break;
132 case 'd': /* set db name */
133 dbname = optarg;
134 break;
135 case 'r':
136 cur_realm = optarg;
137 break;
138 case 'k':
139 master_keyblock.enctype = atoi(optarg);
140 enctypedone++;
141 break;
142 case 'M': /* master key name in DB */
143 mkey_name = optarg;
144 break;
145 case 'm':
146 manual_mkey = TRUE;
147 break;
148 case '?':
149 default:
150 usage(progname, 1);
151 /*NOTREACHED*/
152 }
153 }
154
155 if (!(num_to_create && suffix)) usage(progname, 1);
156
157 if (!enctypedone)
158 master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
159
160 if (!krb5_c_valid_enctype(master_keyblock.enctype)) {
161 com_err(progname, KRB5_PROG_ETYPE_NOSUPP,
162 "while setting up enctype %d", master_keyblock.enctype);
163 exit(1);
164 }
165
166 if (!dbname)
167 dbname = DEFAULT_KDB_FILE; /* XXX? */
168
169 if (!cur_realm) {
170 if ((retval = krb5_get_default_realm(test_context, &cur_realm))) {
171 com_err(progname, retval, "while retrieving default realm name");
172 exit(1);
173 }
174 }
175 if ((retval = set_dbname_help(progname, dbname)))
176 exit(retval);
177
178 for (n = 1; n <= num_to_create; n++) {
179 /* build the new principal name */
180 /* we can't pick random names because we need to generate all the names
181 again given a prefix and count to test the db lib and kdb */
182 (void) snprintf(suffix, suffix_size, "%d", n);
183 (void) snprintf(tmp, sizeof(tmp), "%s-DEPTH-1", principal_string);
184 tmp[sizeof(tmp) - 1] = '\0';
185 str_newprinc = tmp;
186 add_princ(test_context, str_newprinc);
187
188 for (i = 2; i <= depth; i++) {
189 (void) snprintf(tmp2, sizeof(tmp2), "/%s-DEPTH-%d",
190 principal_string, i);
191 tmp2[sizeof(tmp2) - 1] = '\0';
192 strncat(tmp, tmp2, sizeof(tmp) - 1 - strlen(tmp));
193 str_newprinc = tmp;
194 add_princ(test_context, str_newprinc);
195 }
196 }
197
198 retval = krb5_db_fini(test_context);
199 memset(master_keyblock.contents, 0,
200 (size_t) master_keyblock.length);
201 if (retval && retval != KRB5_KDB_DBNOTINITED) {
202 com_err(progname, retval, "while closing database");
203 exit(1);
204 }
205 if (master_princ_set)
206 krb5_free_principal(test_context, master_princ);
207 krb5_free_context(test_context);
208 exit(0);
209 }
210
211 void
add_princ(context,str_newprinc)212 add_princ(context, str_newprinc)
213 krb5_context context;
214 char * str_newprinc;
215 {
216 krb5_error_code retval;
217 krb5_principal newprinc;
218 krb5_db_entry *newentry;
219 char princ_name[4096];
220
221 newentry = calloc(1, sizeof(*newentry));
222 if (newentry == NULL) {
223 com_err(progname, ENOMEM, "while allocating DB entry");
224 return;
225 }
226 snprintf(princ_name, sizeof(princ_name), "%s@%s", str_newprinc, cur_realm);
227 if ((retval = krb5_parse_name(context, princ_name, &newprinc))) {
228 com_err(progname, retval, "while parsing '%s'", princ_name);
229 return;
230 }
231
232 /* Add basic data */
233 newentry->len = KRB5_KDB_V1_BASE_LENGTH;
234 newentry->attributes = mblock.flags;
235 newentry->max_life = mblock.max_life;
236 newentry->max_renewable_life = mblock.max_rlife;
237 newentry->expiration = mblock.expiration;
238 newentry->pw_expiration = mblock.expiration;
239
240 /* Add princ to db entry */
241 if ((retval = krb5_copy_principal(context, newprinc, &newentry->princ))) {
242 com_err(progname, retval, "while encoding princ to db entry for '%s'",
243 princ_name);
244 krb5_free_principal(context, newprinc);
245 goto error;
246 }
247
248 {
249 /* Add mod princ to db entry */
250 krb5_timestamp now;
251
252 retval = krb5_timeofday(context, &now);
253 if (retval) {
254 com_err(progname, retval, "while fetching date");
255 krb5_free_principal(context, newprinc);
256 goto error;
257 }
258 retval = krb5_dbe_update_mod_princ_data(context, newentry, now,
259 master_princ);
260 if (retval) {
261 com_err(progname, retval, "while encoding mod_princ data");
262 krb5_free_principal(context, newprinc);
263 goto error;
264 }
265 }
266
267 { /* Add key and salt data to db entry */
268 krb5_data pwd, salt;
269 krb5_keyblock key;
270
271 if ((retval = krb5_principal2salt(context, newprinc, &salt))) {
272 com_err(progname, retval, "while converting princ to salt for '%s'",
273 princ_name);
274 krb5_free_principal(context, newprinc);
275 goto error;
276 }
277
278 krb5_free_principal(context, newprinc);
279
280 pwd.length = strlen(princ_name);
281 pwd.data = princ_name; /* must be able to regenerate */
282 if ((retval = krb5_c_string_to_key(context, master_keyblock.enctype,
283 &pwd, &salt, &key))) {
284 com_err(progname,retval,"while converting password to key for '%s'",
285 princ_name);
286 krb5_free_data_contents(context, &salt);
287 goto error;
288 }
289 krb5_free_data_contents(context, &salt);
290
291 if ((retval = krb5_dbe_create_key_data(context, newentry))) {
292 com_err(progname, retval, "while creating key_data for '%s'",
293 princ_name);
294 free(key.contents);
295 goto error;
296 }
297
298 if ((retval = krb5_dbe_encrypt_key_data(context, &master_keyblock,
299 &key, NULL, 1,
300 newentry->key_data))) {
301 com_err(progname, retval, "while encrypting key for '%s'",
302 princ_name);
303 free(key.contents);
304 goto error;
305 }
306 free(key.contents);
307 }
308
309 if ((retval = krb5_db_put_principal(context, newentry))) {
310 com_err(progname, retval, "while storing principal date");
311 goto error;
312 }
313
314 error: /* Do cleanup of newentry regardless of error */
315 krb5_db_free_principal(context, newentry);
316 return;
317 }
318
319 int
set_dbname_help(pname,dbname)320 set_dbname_help(pname, dbname)
321 char *pname;
322 char *dbname;
323 {
324 krb5_error_code retval;
325 krb5_data pwd, scratch;
326 char *args[2];
327 krb5_db_entry *master_entry;
328
329 /* assemble & parse the master key name */
330
331 if ((retval = krb5_db_setup_mkey_name(test_context, mkey_name, cur_realm,
332 0, &master_princ))) {
333 com_err(pname, retval, "while setting up master key name");
334 return(1);
335 }
336 master_princ_set = 1;
337 if (mkey_password) {
338 pwd.data = mkey_password;
339 pwd.length = strlen(mkey_password);
340 retval = krb5_principal2salt(test_context, master_princ, &scratch);
341 if (retval) {
342 com_err(pname, retval, "while calculated master key salt");
343 return(1);
344 }
345 if ((retval = krb5_c_string_to_key(test_context,
346 master_keyblock.enctype,
347 &pwd, &scratch,
348 &master_keyblock))) {
349 com_err(pname, retval,
350 "while transforming master key from password");
351 return(1);
352 }
353 free(scratch.data);
354 } else {
355 if ((retval = krb5_db_fetch_mkey(test_context, master_princ,
356 master_keyblock.enctype, manual_mkey,
357 FALSE, 0, NULL, NULL,
358 &master_keyblock))) {
359 com_err(pname, retval, "while reading master key");
360 return(1);
361 }
362 }
363
364 /* Ick! Current DAL interface requires that the default_realm
365 field be set in the krb5_context. */
366 if ((retval = krb5_set_default_realm(test_context, cur_realm))) {
367 com_err(pname, retval, "setting default realm");
368 return 1;
369 }
370 /* Pathname is passed to db2 via 'args' parameter. */
371 args[1] = NULL;
372 if (asprintf(&args[0], "dbname=%s", dbname) < 0) {
373 com_err(pname, errno, "while setting up db parameters");
374 return 1;
375 }
376
377 if ((retval = krb5_db_open(test_context, args, KRB5_KDB_OPEN_RO))) {
378 com_err(pname, retval, "while initializing database");
379 return(1);
380 }
381 /* Done with args */
382 free(args[0]);
383
384 if ((retval = krb5_db_fetch_mkey_list(test_context, master_princ,
385 &master_keyblock))){
386 com_err(pname, retval, "while verifying master key");
387 (void) krb5_db_fini(test_context);
388 return(1);
389 }
390 if ((retval = krb5_db_get_principal(test_context, master_princ, 0,
391 &master_entry))) {
392 com_err(pname, retval, "while retrieving master entry");
393 (void) krb5_db_fini(test_context);
394 return(1);
395 }
396
397 mblock.max_life = master_entry->max_life;
398 mblock.max_rlife = master_entry->max_renewable_life;
399 mblock.expiration = master_entry->expiration;
400
401 /* don't set flags, master has some extra restrictions */
402 mblock.mkvno = master_entry->key_data[0].key_data_kvno;
403
404 krb5_db_free_principal(test_context, master_entry);
405 return 0;
406 }
407