1 /* 2 * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "kadmin_locl.h" 37 #include "kadmin-commands.h" 38 #include <kadm5/private.h> 39 40 static kadm5_ret_t 41 create_random_entry(krb5_principal princ, 42 unsigned max_life, 43 unsigned max_rlife, 44 uint32_t attributes) 45 { 46 kadm5_principal_ent_rec ent; 47 kadm5_ret_t ret; 48 int mask = 0; 49 krb5_keyblock *keys; 50 int n_keys, i; 51 char *name; 52 const char *password; 53 char pwbuf[512]; 54 55 random_password(pwbuf, sizeof(pwbuf)); 56 password = pwbuf; 57 58 ret = krb5_unparse_name(context, princ, &name); 59 if (ret) { 60 krb5_warn(context, ret, "failed to unparse principal name"); 61 return ret; 62 } 63 64 memset(&ent, 0, sizeof(ent)); 65 ent.principal = princ; 66 mask |= KADM5_PRINCIPAL; 67 if (max_life) { 68 ent.max_life = max_life; 69 mask |= KADM5_MAX_LIFE; 70 } 71 if (max_rlife) { 72 ent.max_renewable_life = max_rlife; 73 mask |= KADM5_MAX_RLIFE; 74 } 75 ent.attributes |= attributes | KRB5_KDB_DISALLOW_ALL_TIX; 76 mask |= KADM5_ATTRIBUTES; 77 78 /* Create the entry with a random password */ 79 ret = kadm5_create_principal(kadm_handle, &ent, mask, password); 80 if(ret) { 81 krb5_warn(context, ret, "create_random_entry(%s): randkey failed", 82 name); 83 goto out; 84 } 85 86 /* Replace the string2key based keys with real random bytes */ 87 ret = kadm5_randkey_principal(kadm_handle, princ, &keys, &n_keys); 88 if(ret) { 89 krb5_warn(context, ret, "create_random_entry(%s): randkey failed", 90 name); 91 goto out; 92 } 93 for(i = 0; i < n_keys; i++) 94 krb5_free_keyblock_contents(context, &keys[i]); 95 free(keys); 96 ret = kadm5_get_principal(kadm_handle, princ, &ent, 97 KADM5_PRINCIPAL | KADM5_ATTRIBUTES); 98 if(ret) { 99 krb5_warn(context, ret, "create_random_entry(%s): " 100 "unable to get principal", name); 101 goto out; 102 } 103 ent.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); 104 ent.kvno = 1; 105 ret = kadm5_modify_principal(kadm_handle, &ent, 106 KADM5_ATTRIBUTES|KADM5_KVNO); 107 kadm5_free_principal_ent (kadm_handle, &ent); 108 if(ret) { 109 krb5_warn(context, ret, "create_random_entry(%s): " 110 "unable to modify principal", name); 111 goto out; 112 } 113 out: 114 free(name); 115 return ret; 116 } 117 118 extern int local_flag; 119 120 int 121 init(struct init_options *opt, int argc, char **argv) 122 { 123 kadm5_ret_t ret; 124 int i; 125 HDB *db; 126 krb5_deltat max_life = 0, max_rlife = 0; 127 128 if (!local_flag) { 129 krb5_warnx(context, "init is only available in local (-l) mode"); 130 return 0; 131 } 132 133 if (opt->realm_max_ticket_life_string) { 134 if (str2deltat (opt->realm_max_ticket_life_string, &max_life) != 0) { 135 krb5_warnx (context, "unable to parse \"%s\"", 136 opt->realm_max_ticket_life_string); 137 return 0; 138 } 139 } 140 if (opt->realm_max_renewable_life_string) { 141 if (str2deltat (opt->realm_max_renewable_life_string, &max_rlife) != 0) { 142 krb5_warnx (context, "unable to parse \"%s\"", 143 opt->realm_max_renewable_life_string); 144 return 0; 145 } 146 } 147 148 db = _kadm5_s_get_db(kadm_handle); 149 150 ret = db->hdb_open(context, db, O_RDWR | O_CREAT, 0600); 151 if(ret){ 152 krb5_warn(context, ret, "hdb_open"); 153 return 0; 154 } 155 db->hdb_close(context, db); 156 for(i = 0; i < argc; i++){ 157 krb5_principal princ; 158 const char *realm = argv[i]; 159 160 if (opt->realm_max_ticket_life_string == NULL) { 161 max_life = 0; 162 if(edit_deltat ("Realm max ticket life", &max_life, NULL, 0)) { 163 return 0; 164 } 165 } 166 if (opt->realm_max_renewable_life_string == NULL) { 167 max_rlife = 0; 168 if(edit_deltat("Realm max renewable ticket life", &max_rlife, 169 NULL, 0)) { 170 return 0; 171 } 172 } 173 174 /* Create `krbtgt/REALM' */ 175 ret = krb5_make_principal(context, &princ, realm, 176 KRB5_TGS_NAME, realm, NULL); 177 if(ret) 178 return 0; 179 180 create_random_entry(princ, max_life, max_rlife, 0); 181 krb5_free_principal(context, princ); 182 183 if (opt->bare_flag) 184 continue; 185 186 /* Create `kadmin/changepw' */ 187 krb5_make_principal(context, &princ, realm, 188 "kadmin", "changepw", NULL); 189 /* 190 * The Windows XP (at least) password changing protocol 191 * request the `kadmin/changepw' ticket with `renewable_ok, 192 * renewable, forwardable' and so fails if we disallow 193 * forwardable here. 194 */ 195 create_random_entry(princ, 5*60, 5*60, 196 KRB5_KDB_DISALLOW_TGT_BASED| 197 KRB5_KDB_PWCHANGE_SERVICE| 198 KRB5_KDB_DISALLOW_POSTDATED| 199 KRB5_KDB_DISALLOW_RENEWABLE| 200 KRB5_KDB_DISALLOW_PROXIABLE| 201 KRB5_KDB_REQUIRES_PRE_AUTH); 202 krb5_free_principal(context, princ); 203 204 /* Create `kadmin/admin' */ 205 krb5_make_principal(context, &princ, realm, 206 "kadmin", "admin", NULL); 207 create_random_entry(princ, 60*60, 60*60, KRB5_KDB_REQUIRES_PRE_AUTH); 208 krb5_free_principal(context, princ); 209 210 /* Create `changepw/kerberos' (for v4 compat) */ 211 krb5_make_principal(context, &princ, realm, 212 "changepw", "kerberos", NULL); 213 create_random_entry(princ, 60*60, 60*60, 214 KRB5_KDB_DISALLOW_TGT_BASED| 215 KRB5_KDB_PWCHANGE_SERVICE); 216 217 krb5_free_principal(context, princ); 218 219 /* Create `kadmin/hprop' for database propagation */ 220 krb5_make_principal(context, &princ, realm, 221 "kadmin", "hprop", NULL); 222 create_random_entry(princ, 60*60, 60*60, 223 KRB5_KDB_REQUIRES_PRE_AUTH| 224 KRB5_KDB_DISALLOW_TGT_BASED); 225 krb5_free_principal(context, princ); 226 227 /* Create `WELLKNOWN/ANONYMOUS' for anonymous as-req */ 228 krb5_make_principal(context, &princ, realm, 229 KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); 230 create_random_entry(princ, 60*60, 60*60, 231 KRB5_KDB_REQUIRES_PRE_AUTH); 232 krb5_free_principal(context, princ); 233 234 235 /* Create `default' */ 236 { 237 kadm5_principal_ent_rec ent; 238 int mask = 0; 239 240 memset (&ent, 0, sizeof(ent)); 241 mask |= KADM5_PRINCIPAL; 242 krb5_make_principal(context, &ent.principal, realm, 243 "default", NULL); 244 mask |= KADM5_MAX_LIFE; 245 ent.max_life = 24 * 60 * 60; 246 mask |= KADM5_MAX_RLIFE; 247 ent.max_renewable_life = 7 * ent.max_life; 248 ent.attributes = KRB5_KDB_DISALLOW_ALL_TIX; 249 mask |= KADM5_ATTRIBUTES; 250 251 ret = kadm5_create_principal(kadm_handle, &ent, mask, ""); 252 if (ret) 253 krb5_err (context, 1, ret, "kadm5_create_principal"); 254 255 krb5_free_principal(context, ent.principal); 256 } 257 } 258 return 0; 259 } 260