2 * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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. 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.
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
34 #include "kadmin_locl.h"
35 #include "kadmin-commands.h"
37 /* No useful password policies for namespaces */
38 #define NSPOLICY "default"
41 * fetch the default principal corresponding to `princ'
44 static krb5_error_code
45 get_default (kadm5_server_context
*contextp
,
47 kadm5_principal_ent_t default_ent
)
50 krb5_principal def_principal
;
51 krb5_const_realm realm
= krb5_principal_get_realm(contextp
->context
, princ
);
53 ret
= krb5_make_principal (contextp
->context
, &def_principal
,
54 realm
, "default", NULL
);
57 ret
= kadm5_get_principal (contextp
, def_principal
, default_ent
,
58 KADM5_PRINCIPAL_NORMAL_MASK
);
59 krb5_free_principal (contextp
->context
, def_principal
);
64 * Add the principal `name' to the database.
65 * Prompt for all data not given by the input parameters.
68 static krb5_error_code
69 add_one_principal(const char *name
,
76 krb5_key_salt_tuple
*kstuple
,
77 krb5_key_data
*key_data
,
78 const char *max_ticket_life
,
79 const char *max_renewable_life
,
80 const char *attributes
,
81 const char *expiration
,
82 const char *pw_expiration
)
85 kadm5_principal_ent_rec princ
, defrec
;
86 kadm5_principal_ent_rec
*default_ent
= NULL
;
87 krb5_principal princ_ent
= NULL
;
88 krb5_timestamp pw_expire
;
92 char *princ_name
= NULL
;
94 memset(&princ
, 0, sizeof(princ
));
95 ret
= krb5_parse_name(context
, name
, &princ_ent
);
97 krb5_warn(context
, ret
, "krb5_parse_name");
102 ret
= krb5_unparse_name(context
, princ_ent
, &princ_name
);
104 krb5_warn(context
, ret
, "krb5_parse_name");
108 princ
.principal
= princ_ent
;
109 mask
|= KADM5_PRINCIPAL
;
111 ret
= set_entry(context
, &princ
, &mask
,
112 max_ticket_life
, max_renewable_life
,
113 expiration
, pw_expiration
, attributes
, policy
);
117 default_ent
= &defrec
;
118 ret
= get_default (kadm_handle
, princ_ent
, default_ent
);
123 default_mask
= KADM5_ATTRIBUTES
| KADM5_MAX_LIFE
| KADM5_MAX_RLIFE
|
124 KADM5_PRINC_EXPIRE_TIME
| KADM5_PW_EXPIRATION
;
128 set_defaults(&princ
, &mask
, default_ent
, default_mask
);
130 if(edit_entry(&princ
, &mask
, default_ent
, default_mask
))
132 if(rand_key
|| key_data
) {
133 princ
.attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
134 mask
|= KADM5_ATTRIBUTES
;
135 random_password (pwbuf
, sizeof(pwbuf
));
137 } else if (rand_password
) {
138 random_password (pwbuf
, sizeof(pwbuf
));
140 } else if(password
== NULL
) {
144 ret
= krb5_unparse_name(context
, princ_ent
, &princ_name
);
147 aret
= asprintf (&prompt
, "%s's Password: ", princ_name
);
150 krb5_set_error_message(context
, ret
, "out of memory");
153 ret
= UI_UTIL_read_pw_string (pwbuf
, sizeof(pwbuf
), prompt
,
154 UI_UTIL_FLAG_VERIFY
|
155 UI_UTIL_FLAG_VERIFY_SILENT
);
158 ret
= KRB5_LIBOS_BADPWDMATCH
;
159 krb5_set_error_message(context
, ret
, "failed to verify password");
165 ret
= kadm5_create_principal(kadm_handle
, &princ
, mask
, password
);
167 krb5_warn(context
, ret
, "kadm5_create_principal");
170 /* Save requested password expiry before it's clobbered */
171 pw_expire
= princ
.pw_expiration
;
173 krb5_keyblock
*new_keys
;
175 ret
= kadm5_randkey_principal_3(kadm_handle
, princ_ent
, 0,
176 nkstuple
, kstuple
, &new_keys
, &n_keys
);
178 krb5_warn(context
, ret
, "kadm5_randkey_principal");
181 for(i
= 0; i
< n_keys
; i
++)
182 krb5_free_keyblock_contents(context
, &new_keys
[i
]);
185 ret
= kadm5_get_principal(kadm_handle
, princ_ent
, &princ
,
186 KADM5_PRINCIPAL
| KADM5_KVNO
|
189 krb5_warn(context
, ret
, "kadm5_get_principal");
192 krb5_free_principal(context
, princ_ent
);
193 princ_ent
= princ
.principal
;
194 princ
.attributes
&= (~KRB5_KDB_DISALLOW_ALL_TIX
);
195 princ
.pw_expiration
= pw_expire
;
197 * Updating kvno w/o key data and vice-versa gives _kadm5_setup_entry()
198 * and _kadm5_set_keys2() headaches. But we used to, so we handle
199 * this in in those two functions. Might as well leave this code as
203 kadm5_modify_principal(kadm_handle
, &princ
,
204 KADM5_PW_EXPIRATION
| KADM5_ATTRIBUTES
| KADM5_KVNO
);
205 } else if (key_data
) {
206 ret
= kadm5_chpass_principal_with_key (kadm_handle
, princ_ent
,
209 krb5_warn(context
, ret
, "kadm5_chpass_principal_with_key");
211 kadm5_get_principal(kadm_handle
, princ_ent
, &princ
,
212 KADM5_PRINCIPAL
| KADM5_ATTRIBUTES
);
213 krb5_free_principal(context
, princ_ent
);
214 princ_ent
= princ
.principal
;
215 princ
.attributes
&= (~KRB5_KDB_DISALLOW_ALL_TIX
);
216 princ
.pw_expiration
= pw_expire
;
217 kadm5_modify_principal(kadm_handle
, &princ
,
218 KADM5_PW_EXPIRATION
| KADM5_ATTRIBUTES
);
219 } else if (rand_password
) {
220 printf ("added %s with password \"%s\"\n", princ_name
, password
);
224 kadm5_free_principal_ent(kadm_handle
, &princ
); /* frees princ_ent */
226 kadm5_free_principal_ent (kadm_handle
, default_ent
);
227 if (password
!= NULL
) {
228 size_t len
= strlen(password
);
229 memset_s(password
, len
, 0, len
);
235 * parse the string `key_string' into `key', returning 0 iff succesful.
243 * Parse arguments and add all the principals.
247 add_new_key(struct add_options
*opt
, int argc
, char **argv
)
249 krb5_error_code ret
= 0;
250 krb5_key_salt_tuple
*kstuple
= NULL
;
251 krb5_key_data key_data
[3];
252 krb5_key_data
*kdp
= NULL
;
253 const char *enctypes
;
258 if (opt
->random_key_flag
)
260 if (opt
->random_password_flag
)
262 if (opt
->password_string
)
268 fprintf (stderr
, "give only one of "
269 "--random-key, --random-password, --password, --key\n");
273 enctypes
= opt
->enctypes_string
;
274 if (enctypes
== NULL
|| enctypes
[0] == '\0')
275 enctypes
= krb5_config_get_string(context
, NULL
, "libdefaults",
276 "supported_enctypes", NULL
);
277 if (enctypes
== NULL
|| enctypes
[0] == '\0')
278 enctypes
= "aes128-cts-hmac-sha1-96";
279 ret
= krb5_string_to_keysalts2(context
, enctypes
, &nkstuple
, &kstuple
);
281 fprintf(stderr
, "enctype(s) unknown\n");
286 if (opt
->key_string
) {
289 if (parse_des_key (opt
->key_string
, key_data
, &error
)) {
290 fprintf(stderr
, "failed parsing key \"%s\": %s\n",
291 opt
->key_string
, error
);
298 for(i
= 0; i
< argc
; i
++) {
299 ret
= add_one_principal(argv
[i
],
300 opt
->random_key_flag
,
301 opt
->random_password_flag
,
302 opt
->use_defaults_flag
,
303 opt
->password_string
,
308 opt
->max_ticket_life_string
,
309 opt
->max_renewable_life_string
,
310 opt
->attributes_string
,
311 opt
->expiration_time_string
,
312 opt
->pw_expiration_time_string
);
314 krb5_warn (context
, ret
, "adding %s", argv
[i
]);
320 kadm5_free_key_data (kadm_handle
, &dummy
, key_data
);
326 static krb5_error_code
327 kstuple2etypes(kadm5_principal_ent_rec
*rec
,
330 krb5_key_salt_tuple
*kstuple
)
333 HDB_EncTypeList etypes
;
338 if ((etypes
.val
= calloc(nkstuple
, sizeof(etypes
.val
[0]))) == NULL
)
339 return krb5_enomem(context
);
340 for (i
= 0; i
< nkstuple
; i
++)
341 etypes
.val
[i
] = kstuple
[i
].ks_enctype
;
342 ASN1_MALLOC_ENCODE(HDB_EncTypeList
, buf
.data
, buf
.length
,
345 add_tl(rec
, KRB5_TL_ETYPES
, &buf
);
348 (*maskp
) |= KADM5_TL_DATA
;
353 * Add the namespace `name' to the database.
354 * Prompt for all data not given by the input parameters.
356 static krb5_error_code
357 add_one_namespace(const char *name
,
359 krb5_key_salt_tuple
*kstuple
,
360 const char *max_ticket_life
,
361 const char *max_renewable_life
,
362 const char *key_rotation_epoch
,
363 const char *key_rotation_period
,
364 const char *attributes
)
367 kadm5_principal_ent_rec princ
;
368 krb5_principal princ_ent
= NULL
;
370 int default_mask
= 0;
379 if (!key_rotation_epoch
) {
380 krb5_warnx(context
, "key rotation epoch defaulted to \"now\"");
381 key_rotation_epoch
= "now";
383 if (!key_rotation_period
) {
384 krb5_warnx(context
, "key rotation period defaulted to \"5d\"");
385 key_rotation_period
= "5d";
387 if ((ret
= str2time_t(key_rotation_epoch
, &kre
)) != 0) {
388 krb5_warn(context
, ret
, "invalid rotation epoch: %s",
392 if (ret
== 0 && (ret
= str2deltat(key_rotation_period
, &krp
)) != 0) {
393 krb5_warn(context
, ret
, "invalid rotation period: %s",
394 key_rotation_period
);
399 memset(&princ
, 0, sizeof(princ
));
401 ret
= krb5_parse_name(context
, name
, &princ_ent
);
403 krb5_warn(context
, ret
, "krb5_parse_name");
405 princ
.principal
= princ_ent
;
411 * Check that namespace has exactly one component, and prepend
412 * WELLKNOWN/HOSTBASED-NAMESPACE
414 if (krb5_principal_get_num_comp(context
, princ_ent
) != 2
415 || (comp0
= krb5_principal_get_comp_string(context
, princ_ent
, 0)) == 0
416 || (comp1
= krb5_principal_get_comp_string(context
, princ_ent
, 1)) == 0
417 || *comp0
== 0 || *comp1
== 0
418 || strcmp(comp0
, "krbtgt") == 0)
419 krb5_warn(context
, ret
= EINVAL
,
420 "namespaces must have exactly two non-empty components "
421 "like host-base principal names");
423 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 2, comp0
);
425 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 3, comp1
);
427 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 0,
430 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 1,
433 /* Set up initial key rotation extension */
438 /* Setup key rotation metadata in a convenient way */
439 kr
.flags
= int2KeyRotationFlags(0);
440 kr
.base_key_kvno
= 1;
442 * Avoid kvnos 0/1/2 which don't normally appear in fully created
447 /* XXX: Sanity check */
451 memset(&ext
, 0, sizeof(ext
));
452 ext
.mandatory
= FALSE
;
453 ext
.data
.element
= choice_HDB_extension_data_key_rotation
;
454 ext
.data
.u
.key_rotation
.len
= 1;
455 ext
.data
.u
.key_rotation
.val
= &kr
;
457 ASN1_MALLOC_ENCODE(HDB_extension
, buf
.data
, buf
.length
,
459 add_tl(&princ
, KRB5_TL_EXTENSION
, &buf
);
460 mask
|= KADM5_TL_DATA
;
464 mask
|= KADM5_PRINCIPAL
| KADM5_KVNO
;
466 ret
= set_entry(context
, &princ
, &mask
,
467 max_ticket_life
, max_renewable_life
,
468 "never", "never", attributes
, NSPOLICY
);
471 ret
= edit_entry(&princ
, &mask
, NULL
, default_mask
);
474 ret
= kstuple2etypes(&princ
, &mask
, nkstuple
, kstuple
);
476 /* XXX Shouldn't need a password for this */
477 random_password(pwbuf
, sizeof(pwbuf
));
479 ret
= kadm5_create_principal_3(kadm_handle
, &princ
, mask
,
480 nkstuple
, kstuple
, pwbuf
);
482 krb5_warn(context
, ret
, "kadm5_create_principal_3");
485 kadm5_free_principal_ent(kadm_handle
, &princ
); /* frees princ_ent */
486 memset(pwbuf
, 0, sizeof(pwbuf
));
491 add_new_namespace(struct add_namespace_options
*opt
, int argc
, char **argv
)
493 krb5_error_code ret
= 0;
494 krb5_key_salt_tuple
*kstuple
= NULL
;
495 const char *enctypes
;
499 fprintf(stderr
, "at least one namespace name required\n");
503 enctypes
= opt
->enctypes_string
;
504 if (enctypes
== NULL
|| enctypes
[0] == '\0')
505 enctypes
= krb5_config_get_string(context
, NULL
, "libdefaults",
506 "supported_enctypes", NULL
);
507 if (enctypes
== NULL
|| enctypes
[0] == '\0')
508 enctypes
= "aes128-cts-hmac-sha1-96";
509 ret
= krb5_string_to_keysalts2(context
, enctypes
, &nkstuple
, &kstuple
);
511 fprintf(stderr
, "enctype(s) unknown\n");
515 for (i
= 0; i
< argc
; i
++) {
516 ret
= add_one_namespace(argv
[i
], nkstuple
, kstuple
,
517 opt
->max_ticket_life_string
,
518 opt
->max_renewable_life_string
,
519 opt
->key_rotation_epoch_string
,
520 opt
->key_rotation_period_string
,
521 opt
->attributes_string
);
523 krb5_warn(context
, ret
, "adding namespace %s", argv
[i
]);