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