1/*
2 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
8 *
9 * $Id: kadm5_create.c,v 1.6 1998/10/30 02:52:37 marc Exp $
10 * $Source: /cvs/krbdev/krb5/src/kadmin/dbutil/kadm5_create.c,v $
11 */
12
13/*
14 * Copyright (C) 1998 by the FundsXpress, INC.
15 *
16 * All rights reserved.
17 *
18 * Export of this software from the United States of America may require
19 * a specific license from the United States Government.  It is the
20 * responsibility of any person or organization contemplating export to
21 * obtain such a license before exporting.
22 *
23 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
24 * distribute this software and its documentation for any purpose and
25 * without fee is hereby granted, provided that the above copyright
26 * notice appear in all copies and that both that copyright notice and
27 * this permission notice appear in supporting documentation, and that
28 * the name of FundsXpress. not be used in advertising or publicity pertaining
29 * to distribution of the software without specific, written prior
30 * permission.  FundsXpress makes no representations about the suitability of
31 * this software for any purpose.  It is provided "as is" without express
32 * or implied warranty.
33 *
34 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
35 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
36 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
37 */
38
39#include "string_table.h"
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <k5-int.h>
45#include <kdb.h>
46#include <kadm5/admin.h>
47#include <krb5/adm_proto.h>
48
49#include <krb5.h>
50#include <krb5/kdb.h>
51#include "kdb5_util.h"
52#include <libintl.h>
53
54int
55add_admin_old_princ(void *handle, krb5_context context,
56		    char *name, char *realm, int attrs, int lifetime);
57int
58add_admin_sname_princ(void *handle, krb5_context context,
59    char *sname, int attrs, int lifetime);
60static int
61add_admin_princ(void *handle, krb5_context context,
62    krb5_principal principal, int attrs, int lifetime);
63
64static int add_admin_princs(void *handle, krb5_context context, char *realm);
65
66#define ERR 1
67#define OK 0
68
69#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
70#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
71
72extern char *progname;
73
74/*
75 * Function: kadm5_create
76 *
77 * Purpose: create admin principals in KDC database
78 *
79 * Arguments:	params	(r) configuration parameters to use
80 *
81 * Effects:  Creates KADM5_ADMIN_SERVICE and KADM5_CHANGEPW_SERVICE
82 * principals in the KDC database and sets their attributes
83 * appropriately.
84 */
85int kadm5_create(kadm5_config_params *params)
86{
87     int retval;
88     krb5_context context;
89
90     kadm5_config_params lparams;
91
92     if ((retval = kadm5_init_krb5_context(&context)))
93	  exit(ERR);
94
95     (void) memset(&lparams, 0, sizeof (kadm5_config_params));
96
97     /*
98      * The lock file has to exist before calling kadm5_init, but
99      * params->admin_lockfile may not be set yet...
100      */
101     if ((retval = kadm5_get_config_params(context, 1,
102					   params, &lparams))) {
103	com_err(progname, retval, gettext("while looking up the Kerberos configuration"));
104	  return 1;
105     }
106
107     retval = kadm5_create_magic_princs(&lparams, context);
108
109     kadm5_free_config_params(context, &lparams);
110     krb5_free_context(context);
111
112     return retval;
113}
114
115int kadm5_create_magic_princs(kadm5_config_params *params,
116			      krb5_context context)
117{
118     int retval;
119     void *handle;
120
121     retval = krb5_klog_init(context, "admin_server", progname, 0);
122     if (retval)
123	  return retval;
124     if ((retval = kadm5_init(progname, NULL, NULL, params,
125			      KADM5_STRUCT_VERSION,
126			      KADM5_API_VERSION_2,
127			      db5util_db_args,
128			      &handle))) {
129	com_err(progname, retval,  gettext("while initializing the Kerberos admin interface"));
130	  return retval;
131     }
132
133     retval = add_admin_princs(handle, context, params->realm);
134
135     kadm5_destroy(handle);
136
137     krb5_klog_close(context);
138
139     return retval;
140}
141
142/*
143 * Function: build_name_with_realm
144 *
145 * Purpose: concatenate a name and a realm to form a krb5 name
146 *
147 * Arguments:
148 *
149 * 	name	(input) the name
150 * 	realm	(input) the realm
151 *
152 * Returns:
153 *
154 * 	pointer to name@realm, in allocated memory, or NULL if it
155 * 	cannot be allocated
156 *
157 * Requires: both strings are null-terminated
158 */
159static char *build_name_with_realm(char *name, char *realm)
160{
161     char *n;
162
163     n = (char *) malloc(strlen(name) + strlen(realm) + 2);
164     sprintf(n, "%s@%s", name, realm);
165     return n;
166}
167
168/*
169 * Function: add_admin_princs
170 *
171 * Purpose: create admin principals
172 *
173 * Arguments:
174 *
175 * 	rseed		(input) random seed
176 * 	realm		(input) realm, or NULL for default realm
177 *      <return value>  (output) status, 0 for success, 1 for serious error
178 *
179 * Requires:
180 *
181 * Effects:
182 *
183 * add_admin_princs creates KADM5_ADMIN_SERVICE,
184 * KADM5_CHANGEPW_SERVICE.  If any of these exist a message is
185 * printed.  If any of these existing principal do not have the proper
186 * attributes, a warning message is printed.
187 */
188static int add_admin_princs(void *handle, krb5_context context, char *realm)
189{
190  krb5_error_code ret = 0;
191
192/*
193 * Solaris Kerberos:
194 * The kadmin/admin principal is unused on Solaris. This principal is used
195 * in AUTH_GSSAPI but Solaris doesn't support AUTH_GSSAPI. RPCSEC_GSS can only
196 * be used with host-based principals.
197 *
198 */
199
200#if 0
201  if ((ret = add_admin_old_princ(handle, context,
202  		     KADM5_ADMIN_SERVICE, realm,
203  		     KRB5_KDB_DISALLOW_TGT_BASED,
204  		     ADMIN_LIFETIME)))
205     goto clean_and_exit;
206#endif
207
208	if ((ret = add_admin_old_princ(handle, context,
209			     KADM5_CHANGEPW_SERVICE, realm,
210			     KRB5_KDB_DISALLOW_TGT_BASED |
211			     KRB5_KDB_PWCHANGE_SERVICE,
212			     CHANGEPW_LIFETIME)))
213       goto clean_and_exit;
214
215	if ((ret = add_admin_sname_princ(handle, context,
216		    KADM5_ADMIN_HOST_SERVICE,
217		    KRB5_KDB_DISALLOW_TGT_BASED,
218		    ADMIN_LIFETIME)))
219		goto clean_and_exit;
220
221	if ((ret = add_admin_sname_princ(handle, context,
222		    KADM5_CHANGEPW_HOST_SERVICE,
223		    KRB5_KDB_DISALLOW_TGT_BASED |
224		    KRB5_KDB_PWCHANGE_SERVICE,
225		    ADMIN_LIFETIME)))
226		goto clean_and_exit;
227
228	if ((ret = add_admin_sname_princ(handle, context,
229		    KADM5_KIPROP_HOST_SERVICE,
230		    KRB5_KDB_DISALLOW_TGT_BASED,
231		    ADMIN_LIFETIME)))
232		goto clean_and_exit;
233
234clean_and_exit:
235
236  return ret;
237}
238
239/*
240 * Function: add_admin_princ
241 *
242 * Arguments:
243 *
244 * 	creator		(r) principal to use as "mod_by"
245 * 	rseed		(r) seed for random key generator
246 *	principal	(r) kerberos principal to add
247 * 	attrs		(r) principal's attributes
248 * 	lifetime	(r) principal's max life, or 0
249 * 	not_unique	(r) error message for multiple entries, never used
250 * 	exists		(r) warning message for principal exists
251 * 	wrong_attrs	(r) warning message for wrong attributes
252 *
253 * Returns:
254 *
255 * 	OK on success
256 * 	ERR on serious errors
257 *
258 * Effects:
259 *
260 * If the principal is not unique, not_unique is printed (but this
261 * never happens).  If the principal exists, then exists is printed
262 * and if the principals attributes != attrs, wrong_attrs is printed.
263 * Otherwise, the principal is created with mod_by creator and
264 * attributes attrs and max life of lifetime (if not zero).
265 */
266
267static int add_admin_princ(void *handle, krb5_context context,
268    krb5_principal principal, int attrs, int lifetime)
269{
270     char *fullname;
271     krb5_error_code ret;
272     kadm5_principal_ent_rec ent;
273
274     memset(&ent, 0, sizeof(ent));
275
276	if (krb5_unparse_name(context, principal, &fullname))
277		return ERR;
278
279     ent.principal = principal;
280     ent.max_life = lifetime;
281     ent.attributes = attrs | KRB5_KDB_DISALLOW_ALL_TIX;
282
283     ret = kadm5_create_principal(handle, &ent,
284				  (KADM5_PRINCIPAL | KADM5_MAX_LIFE |
285				   KADM5_ATTRIBUTES),
286				  "to-be-random");
287     if (ret) {
288	  if (ret != KADM5_DUP) {
289	       com_err(progname, ret,
290			gettext(str_PUT_PRINC), fullname);
291	       krb5_free_principal(context, ent.principal);
292	       free(fullname);
293	       return ERR;
294	  }
295     } else {
296	  /* only randomize key if we created the principal */
297
298	  /*
299	   * Solaris Kerberos:
300	   * Create kadmind principals with keys for all supported encryption types.
301	   * Follows a similar pattern to add_principal() in keytab.c.
302	   */
303	  krb5_enctype *tmpenc, *enctype = NULL;
304	  krb5_key_salt_tuple *keysalt;
305	  int num_ks, i;
306	  krb5_int32 normalsalttype;
307
308	  ret = krb5_get_permitted_enctypes(context, &enctype);
309	  if (ret || *enctype == 0) {
310	       com_err(progname, ret,
311		   gettext("while getting list of permitted encryption types"));
312	       krb5_free_principal(context, ent.principal);
313	       free(fullname);
314	       return ERR;
315	  }
316
317	  /* Count the number of enc types */
318	  for (tmpenc = enctype, num_ks = 0; *tmpenc; tmpenc++)
319		num_ks++;
320
321	  keysalt = malloc (sizeof (krb5_key_salt_tuple) * num_ks);
322	  if (keysalt == NULL) {
323	       com_err(progname, ENOMEM,
324		   gettext("while generating list of key salt tuples"));
325	       krb5_free_ktypes(context, enctype);
326	       krb5_free_principal(context, ent.principal);
327	       free(fullname);
328	       return ERR;
329	  }
330
331	  ret = krb5_string_to_salttype("normal", &normalsalttype);
332	  if (ret) {
333	  	com_err(progname, ret,
334	  	 	gettext("while converting \"normal\" to a salttype"));
335		free(keysalt);
336		krb5_free_ktypes(context, enctype);
337	  	krb5_free_principal(context, ent.principal);
338	  	free(fullname);
339	  	return ERR;
340	  }
341
342	  /* Only create keys with "normal" salttype */
343	  for (i = 0; i < num_ks; i++) {
344		keysalt[i].ks_enctype = enctype[i];
345		keysalt[i].ks_salttype = normalsalttype;
346	  }
347
348	  ret = kadm5_randkey_principal_3(handle, ent.principal, FALSE, num_ks,
349	      keysalt, NULL, NULL);
350	  free(keysalt);
351          krb5_free_ktypes (context, enctype);
352
353
354	  if (ret) {
355	       com_err(progname, ret,
356			gettext(str_RANDOM_KEY), fullname);
357	       krb5_free_principal(context, ent.principal);
358	       free(fullname);
359	       return ERR;
360	  }
361
362	  ent.attributes = attrs;
363	  ret = kadm5_modify_principal(handle, &ent, KADM5_ATTRIBUTES);
364	  if (ret) {
365	      com_err(progname, ret,
366	       gettext(str_PUT_PRINC), fullname);
367	       krb5_free_principal(context, ent.principal);
368	       free(fullname);
369	       return ERR;
370	  }
371     }
372
373     krb5_free_principal(context, ent.principal);
374     free(fullname);
375
376     return OK;
377}
378
379int
380add_admin_old_princ(void *handle, krb5_context context,
381    char *name, char *realm, int attrs, int lifetime)
382{
383	char *fullname;
384	krb5_error_code ret;
385	krb5_principal principal;
386
387	fullname = build_name_with_realm(name, realm);
388	if (ret = krb5_parse_name(context, fullname, &principal)) {
389		com_err(progname, ret, gettext(str_PARSE_NAME));
390		return (ERR);
391	}
392
393	return (add_admin_princ(handle, context, principal, attrs, lifetime));
394}
395
396int
397add_admin_sname_princ(void *handle, krb5_context context,
398	     char *sname, int attrs, int lifetime)
399{
400	krb5_error_code ret;
401	krb5_principal principal;
402
403	if (ret = krb5_sname_to_principal(context, NULL, sname,
404					  KRB5_NT_SRV_HST, &principal)) {
405		com_err(progname, ret,
406			gettext("Could not get host based "
407				"service name for %s principal\n"), sname);
408		return (ERR);
409	}
410	return (add_admin_princ(handle, context, principal, attrs, lifetime));
411}
412
413
414
415