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