xref: /illumos-gate/usr/src/lib/krb5/kadm5/srv/server_init.c (revision 3441f6a1af86b9b2f883f3323bf02c9dd0f7a94d)
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 /*
9  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10  *
11  *	Openvision retains the copyright to derivative works of
12  *	this source code.  Do *NOT* create a derivative of this
13  *	source code before consulting with your legal department.
14  *	Do *NOT* integrate *ANY* of this source code into another
15  *	product before consulting with your legal department.
16  *
17  *	For further information, read the top-level Openvision
18  *	copyright which is contained in the top-level MIT Kerberos
19  *	copyright.
20  *
21  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
22  *
23  */
24 
25 
26 /*
27  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
28  *
29  * $Id: server_init.c,v 1.8 2002/10/15 15:40:49 epeisach Exp $
30  * $Source: /cvs/krbdev/krb5/src/lib/kadm5/srv/server_init.c,v $
31  */
32 
33 #if !defined(lint) && !defined(__CODECENTER__)
34 static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/server_init.c,v 1.8 2002/10/15 15:40:49 epeisach Exp $";
35 #endif
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <com_err.h>
40 #include <kadm5/admin.h>
41 #include <krb5.h>
42 #include "server_internal.h"
43 #include <kdb/kdb_log.h>
44 
45 /*
46  * Function check_handle
47  *
48  * Purpose: Check a server handle and return a com_err code if it is
49  * invalid or 0 if it is valid.
50  *
51  * Arguments:
52  *
53  * 	handle		The server handle.
54  */
55 
56 static int check_handle(void *handle)
57 {
58      CHECK_HANDLE(handle);
59      return 0;
60 }
61 
62 kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
63 				     char *service_name,
64 				     kadm5_config_params *params,
65 				     krb5_ui_4 struct_version,
66 				     krb5_ui_4 api_version,
67 				     void **server_handle)
68 {
69      return kadm5_init(client_name, pass, service_name, params,
70 		       struct_version, api_version,
71 		       server_handle);
72 }
73 
74 kadm5_ret_t kadm5_init_with_creds(char *client_name,
75 				  krb5_ccache ccache,
76 				  char *service_name,
77 				  kadm5_config_params *params,
78 				  krb5_ui_4 struct_version,
79 				  krb5_ui_4 api_version,
80 				  void **server_handle)
81 {
82      /*
83       * A program calling init_with_creds *never* expects to prompt the
84       * user.  Therefore, always pass a dummy password in case this is
85       * KADM5_API_VERSION_1.  If this is KADM5_API_VERSION_2 and
86       * MKEY_FROM_KBD is non-zero, return an error.
87       */
88      if (api_version == KADM5_API_VERSION_2 && params &&
89 	 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
90 	 params->mkey_from_kbd)
91 	  return KADM5_BAD_SERVER_PARAMS;
92      return kadm5_init(client_name, NULL, service_name, params,
93 		       struct_version, api_version,
94 		       server_handle);
95 }
96 
97 
98 kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
99 				 char *service_name,
100 				 kadm5_config_params *params,
101 				 krb5_ui_4 struct_version,
102 				 krb5_ui_4 api_version,
103 				 void **server_handle)
104 {
105      /*
106       * A program calling init_with_skey *never* expects to prompt the
107       * user.  Therefore, always pass a dummy password in case this is
108       * KADM5_API_VERSION_1.  If this is KADM5_API_VERSION_2 and
109       * MKEY_FROM_KBD is non-zero, return an error.
110       */
111      if (api_version == KADM5_API_VERSION_2 && params &&
112 	 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
113 	 params->mkey_from_kbd)
114 	  return KADM5_BAD_SERVER_PARAMS;
115      return kadm5_init(client_name, NULL, service_name, params,
116 		       struct_version, api_version,
117 		       server_handle);
118 }
119 
120 kadm5_ret_t kadm5_init(char *client_name, char *pass,
121 		       char *service_name,
122 		       kadm5_config_params *params_in,
123 		       krb5_ui_4 struct_version,
124 		       krb5_ui_4 api_version,
125 		       void **server_handle)
126 {
127      int ret;
128      kadm5_server_handle_t handle;
129      kadm5_config_params params_local; /* for v1 compat */
130 
131     if (! server_handle)
132 	 return EINVAL;
133 
134     if (! client_name)
135 	 return EINVAL;
136 
137     if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle)))
138 	 return ENOMEM;
139     memset(handle, 0, sizeof(*handle));
140 
141     ret = (int) krb5_init_context(&(handle->context));
142     if (ret) {
143 	 free(handle);
144 	 return(ret);
145     }
146 
147     handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
148     handle->struct_version = struct_version;
149     handle->api_version = api_version;
150 
151      /*
152       * Verify the version numbers before proceeding; we can't use
153       * CHECK_HANDLE because not all fields are set yet.
154       */
155      GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
156 			  KADM5_NEW_SERVER_API_VERSION);
157 
158      /*
159       * Acquire relevant profile entries.  In version 2, merge values
160       * in params_in with values from profile, based on
161       * params_in->mask.
162       *
163       * In version 1, we've given a realm (which may be NULL) instead
164       * of params_in.  So use that realm, make params_in contain an
165       * empty mask, and behave like version 2.
166       */
167      memset((char *) &params_local, 0, sizeof(params_local));
168      if (api_version == KADM5_API_VERSION_1) {
169 	  params_local.realm = (char *) params_in;
170 	  if (params_in)
171 	       params_local.mask = KADM5_CONFIG_REALM;
172 	  params_in = &params_local;
173      }
174 
175 #define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
176      if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
177 	  krb5_free_context(handle->context);
178 	  free(handle);
179 	  return KADM5_BAD_SERVER_PARAMS;
180      }
181 
182      ret = kadm5_get_config_params(handle->context, (char *) NULL,
183 				       (char *) NULL, params_in,
184 				       &handle->params);
185      if (ret) {
186 	  krb5_free_context(handle->context);
187 	  free(handle);
188 	  return(ret);
189      }
190 
191 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \
192 			 KADM5_CONFIG_ADBNAME | \
193 			 KADM5_CONFIG_ADB_LOCKFILE | \
194 			 KADM5_CONFIG_ENCTYPE | \
195 			 KADM5_CONFIG_FLAGS | \
196 			 KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \
197 			 KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES)
198 
199      if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
200 	  krb5_free_context(handle->context);
201 	  free(handle);
202 	  return KADM5_MISSING_CONF_PARAMS;
203      }
204 
205      /*
206       * Set the db_name based on configuration before calling
207       * krb5_db_init, so it will get used.
208       */
209 
210     ret = krb5_db_set_name(handle->context, handle->params.dbname);
211     if (ret) {
212 	 free(handle);
213 	 return(ret);
214     }
215 
216     ret = krb5_db_init(handle->context);
217     if (ret) {
218 	 krb5_free_context(handle->context);
219 	 free(handle);
220 	 return(ret);
221     }
222 
223     if ((ret = krb5_parse_name(handle->context, client_name,
224 			       &handle->current_caller))) {
225 	 krb5_db_fini(handle->context);
226 	 krb5_free_context(handle->context);
227 	 free(handle);
228 	 return ret;
229     }
230 
231     if (! (handle->lhandle = malloc(sizeof(*handle)))) {
232 	 krb5_db_fini(handle->context);
233 	 krb5_free_context(handle->context);
234 	 free(handle);
235 	 return ENOMEM;
236     }
237     *handle->lhandle = *handle;
238     handle->lhandle->api_version = KADM5_API_VERSION_2;
239     handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
240     handle->lhandle->lhandle = handle->lhandle;
241 
242     /* can't check the handle until current_caller is set */
243     ret = check_handle((void *) handle);
244     if (ret) {
245         free(handle);
246 	return ret;
247     }
248 
249     /*
250      * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL
251      * or an empty string, reads the master password from [the stash
252      * file].  Otherwise, the non-NULL password is ignored and the
253      * user is prompted for it via the tty."  However, the code was
254      * implemented the other way: when a non-NULL password was
255      * provided, the stash file was used.  This is somewhat more
256      * sensible, as then a local or remote client that provides a
257      * password does not prompt the user.  This code maintains the
258      * previous actual behavior, and not the old spec behavior,
259      * because that is how the unit tests are written.
260      *
261      * In KADM5_API_VERSION_2, this decision is controlled by
262      * params.
263      *
264      * kdb_init_master's third argument is "from_keyboard".
265      */
266     /*
267      * Solaris Kerberos: Setting to an unknown enc type will make the function
268      * read the encryption type in the stash file instead of assumming that it
269      * is the default type.
270      */
271     if (handle->params.enctype == DEFAULT_KDC_ENCTYPE)
272 	handle->params.enctype = ENCTYPE_UNKNOWN;
273     ret = kdb_init_master(handle, handle->params.realm,
274 			  (handle->api_version == KADM5_API_VERSION_1 ?
275 			   ((pass == NULL) || !(strlen(pass))) :
276 			   ((handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
277 			    && handle->params.mkey_from_kbd)
278 			   ));
279     if (ret) {
280         krb5_db_fini(handle->context);
281 	krb5_free_context(handle->context);
282 	free(handle);
283 	return ret;
284     }
285     /*
286      * Solaris Kerberos: We used the enc type that was discovered in the stash
287      * file to associate with the other magic principals in the database.
288      */
289     handle->params.enctype = handle->master_keyblock.enctype;
290 
291     ret = kdb_init_hist(handle, handle->params.realm);
292     if (ret) {
293 	 krb5_db_fini(handle->context);
294 	 krb5_free_context(handle->context);
295 	 free(handle);
296 	 return ret;
297     }
298 
299     ret = init_dict(&handle->params);
300     if (ret) {
301          krb5_db_fini(handle->context);
302 	 krb5_free_principal(handle->context, handle->current_caller);
303 	 krb5_free_context(handle->context);
304 	 free(handle);
305 	 return ret;
306     }
307 
308     ret = adb_policy_init(handle);
309     if (ret) {
310 	 krb5_db_fini(handle->context);
311 	 krb5_free_principal(handle->context, handle->current_caller);
312 	 krb5_free_context(handle->context);
313 	 free(handle);
314 	 return ret;
315     }
316     handle->lhandle->policy_db = handle->policy_db;
317 
318     *server_handle = (void *) handle;
319 
320     return KADM5_OK;
321 }
322 
323 kadm5_ret_t kadm5_destroy(void *server_handle)
324 {
325     kadm5_server_handle_t handle = server_handle;
326 
327     CHECK_HANDLE(server_handle);
328 
329     destroy_dict();
330 
331     adb_policy_close(handle);
332     krb5_db_fini(handle->context);
333     krb5_free_principal(handle->context, handle->current_caller);
334     kadm5_free_config_params(handle->context, &handle->params);
335     krb5_free_context(handle->context);
336     handle->magic_number = 0;
337     free(handle->lhandle);
338     free(handle);
339 
340     return KADM5_OK;
341 }
342 
343 kadm5_ret_t kadm5_lock(void *server_handle)
344 {
345     kadm5_server_handle_t handle = server_handle;
346     kadm5_ret_t ret;
347 
348     CHECK_HANDLE(server_handle);
349     ret = osa_adb_open_and_lock(handle->policy_db, OSA_ADB_EXCLUSIVE);
350     if (ret)
351 	return ret;
352     ret = krb5_db_lock(handle->context, KRB5_LOCKMODE_EXCLUSIVE);
353     if (ret)
354 	return ret;
355 
356     return KADM5_OK;
357 }
358 
359 kadm5_ret_t kadm5_unlock(void *server_handle)
360 {
361     kadm5_server_handle_t handle = server_handle;
362     kadm5_ret_t ret;
363 
364     CHECK_HANDLE(server_handle);
365     ret = osa_adb_close_and_unlock(handle->policy_db);
366     if (ret)
367 	return ret;
368     ret = krb5_db_unlock(handle->context);
369     if (ret)
370 	return ret;
371 
372     return KADM5_OK;
373 }
374 
375 kadm5_ret_t kadm5_flush(void *server_handle)
376 {
377      kadm5_server_handle_t handle = server_handle;
378      kadm5_ret_t ret;
379 
380      CHECK_HANDLE(server_handle);
381 
382      if ((ret = krb5_db_fini(handle->context)) ||
383 	 /*
384 	  * Set the db_name based on configuration before calling
385 	  * krb5_db_init, so it will get used.
386 	  */
387 	 (ret = krb5_db_set_name(handle->context,
388 				     handle->params.dbname)) ||
389 	 (ret = krb5_db_init(handle->context)) ||
390 	 (ret = adb_policy_close(handle)) ||
391 	 (ret = adb_policy_init(handle))) {
392 	  (void) kadm5_destroy(server_handle);
393 	  return ret;
394      }
395      return KADM5_OK;
396 }
397 
398 int _kadm5_check_handle(void *handle)
399 {
400      CHECK_HANDLE(handle);
401      return 0;
402 }
403 
404 krb5_error_code
405 kadm5_init_iprop(void *handle)
406 {
407 	kadm5_server_handle_t iprop_h;
408 	krb5_error_code retval;
409 
410 	iprop_h = handle;
411 	if (iprop_h->params.iprop_enabled) {
412 		ulog_set_role(iprop_h->context, IPROP_MASTER);
413 		if ((retval = ulog_map(iprop_h->context, &iprop_h->params,
414 		    FKCOMMAND)) != 0)
415 			return (retval);
416 	}
417 	return (0);
418 }
419