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
;
93 memset(&princ
, 0, sizeof(princ
));
94 ret
= krb5_parse_name(context
, name
, &princ_ent
);
96 krb5_warn(context
, ret
, "krb5_parse_name");
99 princ
.principal
= princ_ent
;
100 mask
|= KADM5_PRINCIPAL
;
102 ret
= set_entry(context
, &princ
, &mask
,
103 max_ticket_life
, max_renewable_life
,
104 expiration
, pw_expiration
, attributes
, policy
);
108 default_ent
= &defrec
;
109 ret
= get_default (kadm_handle
, princ_ent
, default_ent
);
114 default_mask
= KADM5_ATTRIBUTES
| KADM5_MAX_LIFE
| KADM5_MAX_RLIFE
|
115 KADM5_PRINC_EXPIRE_TIME
| KADM5_PW_EXPIRATION
;
119 set_defaults(&princ
, &mask
, default_ent
, default_mask
);
121 if(edit_entry(&princ
, &mask
, default_ent
, default_mask
))
123 if(rand_key
|| key_data
) {
124 princ
.attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
125 mask
|= KADM5_ATTRIBUTES
;
126 random_password (pwbuf
, sizeof(pwbuf
));
128 } else if (rand_password
) {
129 random_password (pwbuf
, sizeof(pwbuf
));
131 } else if(password
== NULL
) {
136 ret
= krb5_unparse_name(context
, princ_ent
, &princ_name
);
139 aret
= asprintf (&prompt
, "%s's Password: ", princ_name
);
143 krb5_set_error_message(context
, ret
, "out of memory");
146 ret
= UI_UTIL_read_pw_string (pwbuf
, sizeof(pwbuf
), prompt
,
147 UI_UTIL_FLAG_VERIFY
|
148 UI_UTIL_FLAG_VERIFY_SILENT
);
151 ret
= KRB5_LIBOS_BADPWDMATCH
;
152 krb5_set_error_message(context
, ret
, "failed to verify password");
158 ret
= kadm5_create_principal(kadm_handle
, &princ
, mask
, password
);
160 krb5_warn(context
, ret
, "kadm5_create_principal");
163 /* Save requested password expiry before it's clobbered */
164 pw_expire
= princ
.pw_expiration
;
166 krb5_keyblock
*new_keys
;
168 ret
= kadm5_randkey_principal_3(kadm_handle
, princ_ent
, 0,
169 nkstuple
, kstuple
, &new_keys
, &n_keys
);
171 krb5_warn(context
, ret
, "kadm5_randkey_principal");
174 for(i
= 0; i
< n_keys
; i
++)
175 krb5_free_keyblock_contents(context
, &new_keys
[i
]);
178 kadm5_get_principal(kadm_handle
, princ_ent
, &princ
,
179 KADM5_PRINCIPAL
| KADM5_KVNO
| KADM5_ATTRIBUTES
);
180 krb5_free_principal(context
, princ_ent
);
181 princ_ent
= princ
.principal
;
182 princ
.attributes
&= (~KRB5_KDB_DISALLOW_ALL_TIX
);
183 princ
.pw_expiration
= pw_expire
;
185 * Updating kvno w/o key data and vice-versa gives _kadm5_setup_entry()
186 * and _kadm5_set_keys2() headaches. But we used to, so we handle
187 * this in in those two functions. Might as well leave this code as
191 kadm5_modify_principal(kadm_handle
, &princ
,
192 KADM5_PW_EXPIRATION
| KADM5_ATTRIBUTES
| KADM5_KVNO
);
193 } else if (key_data
) {
194 ret
= kadm5_chpass_principal_with_key (kadm_handle
, princ_ent
,
197 krb5_warn(context
, ret
, "kadm5_chpass_principal_with_key");
199 kadm5_get_principal(kadm_handle
, princ_ent
, &princ
,
200 KADM5_PRINCIPAL
| KADM5_ATTRIBUTES
);
201 krb5_free_principal(context
, princ_ent
);
202 princ_ent
= princ
.principal
;
203 princ
.attributes
&= (~KRB5_KDB_DISALLOW_ALL_TIX
);
204 princ
.pw_expiration
= pw_expire
;
205 kadm5_modify_principal(kadm_handle
, &princ
,
206 KADM5_PW_EXPIRATION
| KADM5_ATTRIBUTES
);
207 } else if (rand_password
) {
210 krb5_unparse_name(context
, princ_ent
, &princ_name
);
211 printf ("added %s with password \"%s\"\n", princ_name
, password
);
215 kadm5_free_principal_ent(kadm_handle
, &princ
); /* frees princ_ent */
217 kadm5_free_principal_ent (kadm_handle
, default_ent
);
218 if (password
!= NULL
)
219 memset (password
, 0, strlen(password
));
224 * parse the string `key_string' into `key', returning 0 iff succesful.
232 * Parse arguments and add all the principals.
236 add_new_key(struct add_options
*opt
, int argc
, char **argv
)
238 krb5_error_code ret
= 0;
239 krb5_key_salt_tuple
*kstuple
= NULL
;
240 krb5_key_data key_data
[3];
241 krb5_key_data
*kdp
= NULL
;
242 const char *enctypes
;
247 if (opt
->random_key_flag
)
249 if (opt
->random_password_flag
)
251 if (opt
->password_string
)
257 fprintf (stderr
, "give only one of "
258 "--random-key, --random-password, --password, --key\n");
262 enctypes
= opt
->enctypes_string
;
263 if (enctypes
== NULL
|| enctypes
[0] == '\0')
264 enctypes
= krb5_config_get_string(context
, NULL
, "libdefaults",
265 "supported_enctypes", NULL
);
266 if (enctypes
== NULL
|| enctypes
[0] == '\0')
267 enctypes
= "aes128-cts-hmac-sha1-96";
268 ret
= krb5_string_to_keysalts2(context
, enctypes
, &nkstuple
, &kstuple
);
270 fprintf(stderr
, "enctype(s) unknown\n");
275 if (opt
->key_string
) {
278 if (parse_des_key (opt
->key_string
, key_data
, &error
)) {
279 fprintf(stderr
, "failed parsing key \"%s\": %s\n",
280 opt
->key_string
, error
);
287 for(i
= 0; i
< argc
; i
++) {
288 ret
= add_one_principal(argv
[i
],
289 opt
->random_key_flag
,
290 opt
->random_password_flag
,
291 opt
->use_defaults_flag
,
292 opt
->password_string
,
297 opt
->max_ticket_life_string
,
298 opt
->max_renewable_life_string
,
299 opt
->attributes_string
,
300 opt
->expiration_time_string
,
301 opt
->pw_expiration_time_string
);
303 krb5_warn (context
, ret
, "adding %s", argv
[i
]);
309 kadm5_free_key_data (kadm_handle
, &dummy
, key_data
);
315 static krb5_error_code
316 kstuple2etypes(kadm5_principal_ent_rec
*rec
,
319 krb5_key_salt_tuple
*kstuple
)
322 HDB_EncTypeList etypes
;
327 if ((etypes
.val
= calloc(nkstuple
, sizeof(etypes
.val
[0]))) == NULL
)
328 return krb5_enomem(context
);
329 for (i
= 0; i
< nkstuple
; i
++)
330 etypes
.val
[i
] = kstuple
[i
].ks_enctype
;
331 ASN1_MALLOC_ENCODE(HDB_EncTypeList
, buf
.data
, buf
.length
,
334 add_tl(rec
, KRB5_TL_ETYPES
, &buf
);
337 (*maskp
) |= KADM5_TL_DATA
;
342 * Add the namespace `name' to the database.
343 * Prompt for all data not given by the input parameters.
345 static krb5_error_code
346 add_one_namespace(const char *name
,
348 krb5_key_salt_tuple
*kstuple
,
349 const char *max_ticket_life
,
350 const char *max_renewable_life
,
351 const char *key_rotation_epoch
,
352 const char *key_rotation_period
,
353 const char *attributes
)
356 kadm5_principal_ent_rec princ
;
357 krb5_principal princ_ent
= NULL
;
359 int default_mask
= 0;
368 if (!key_rotation_epoch
) {
369 krb5_warnx(context
, "key rotation epoch defaulted to \"now\"");
370 key_rotation_epoch
= "now";
372 if (!key_rotation_period
) {
373 krb5_warnx(context
, "key rotation period defaulted to \"5d\"");
374 key_rotation_period
= "5d";
376 if ((ret
= str2time_t(key_rotation_epoch
, &kre
)) != 0) {
377 krb5_warn(context
, ret
, "invalid rotation epoch: %s",
381 if (ret
== 0 && (ret
= str2deltat(key_rotation_period
, &krp
)) != 0) {
382 krb5_warn(context
, ret
, "invalid rotation period: %s",
383 key_rotation_period
);
388 memset(&princ
, 0, sizeof(princ
));
390 ret
= krb5_parse_name(context
, name
, &princ_ent
);
392 krb5_warn(context
, ret
, "krb5_parse_name");
394 princ
.principal
= princ_ent
;
400 * Check that namespace has exactly one component, and prepend
401 * WELLKNOWN/HOSTBASED-NAMESPACE
403 if (krb5_principal_get_num_comp(context
, princ_ent
) != 2
404 || (comp0
= krb5_principal_get_comp_string(context
, princ_ent
, 0)) == 0
405 || (comp1
= krb5_principal_get_comp_string(context
, princ_ent
, 1)) == 0
406 || *comp0
== 0 || *comp1
== 0
407 || strcmp(comp0
, "krbtgt") == 0)
408 krb5_warn(context
, ret
= EINVAL
,
409 "namespaces must have exactly two non-empty components "
410 "like host-base principal names");
412 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 2, comp0
);
414 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 3, comp1
);
416 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 0,
419 ret
= krb5_principal_set_comp_string(context
, princ_ent
, 1,
422 /* Set up initial key rotation extension */
427 /* Setup key rotation metadata in a convenient way */
428 kr
.flags
= int2KeyRotationFlags(0);
429 kr
.base_key_kvno
= 1;
431 * Avoid kvnos 0/1/2 which don't normally appear in fully created
436 /* XXX: Sanity check */
440 memset(&ext
, 0, sizeof(ext
));
441 ext
.mandatory
= FALSE
;
442 ext
.data
.element
= choice_HDB_extension_data_key_rotation
;
443 ext
.data
.u
.key_rotation
.len
= 1;
444 ext
.data
.u
.key_rotation
.val
= &kr
;
446 ASN1_MALLOC_ENCODE(HDB_extension
, buf
.data
, buf
.length
,
448 add_tl(&princ
, KRB5_TL_EXTENSION
, &buf
);
449 mask
|= KADM5_TL_DATA
;
453 mask
|= KADM5_PRINCIPAL
| KADM5_KVNO
;
455 ret
= set_entry(context
, &princ
, &mask
,
456 max_ticket_life
, max_renewable_life
,
457 "never", "never", attributes
, NSPOLICY
);
460 ret
= edit_entry(&princ
, &mask
, NULL
, default_mask
);
463 ret
= kstuple2etypes(&princ
, &mask
, nkstuple
, kstuple
);
465 /* XXX Shouldn't need a password for this */
466 random_password(pwbuf
, sizeof(pwbuf
));
468 ret
= kadm5_create_principal_3(kadm_handle
, &princ
, mask
,
469 nkstuple
, kstuple
, pwbuf
);
471 krb5_warn(context
, ret
, "kadm5_create_principal_3");
474 kadm5_free_principal_ent(kadm_handle
, &princ
); /* frees princ_ent */
475 memset(pwbuf
, 0, sizeof(pwbuf
));
480 add_new_namespace(struct add_namespace_options
*opt
, int argc
, char **argv
)
482 krb5_error_code ret
= 0;
483 krb5_key_salt_tuple
*kstuple
= NULL
;
484 const char *enctypes
;
488 fprintf(stderr
, "at least one namespace name required\n");
492 enctypes
= opt
->enctypes_string
;
493 if (enctypes
== NULL
|| enctypes
[0] == '\0')
494 enctypes
= krb5_config_get_string(context
, NULL
, "libdefaults",
495 "supported_enctypes", NULL
);
496 if (enctypes
== NULL
|| enctypes
[0] == '\0')
497 enctypes
= "aes128-cts-hmac-sha1-96";
498 ret
= krb5_string_to_keysalts2(context
, enctypes
, &nkstuple
, &kstuple
);
500 fprintf(stderr
, "enctype(s) unknown\n");
504 for (i
= 0; i
< argc
; i
++) {
505 ret
= add_one_namespace(argv
[i
], nkstuple
, kstuple
,
506 opt
->max_ticket_life_string
,
507 opt
->max_renewable_life_string
,
508 opt
->key_rotation_epoch_string
,
509 opt
->key_rotation_period_string
,
510 opt
->attributes_string
);
512 krb5_warn(context
, ret
, "adding namespace %s", argv
[i
]);