xref: /illumos-gate/usr/src/lib/krb5/kadm5/srv/server_init.c (revision 56a424cca6b3f91f31bdab72a4626c48c779fe8b)
1 /*
2  * Copyright 2006 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     ret = kdb_init_master(handle, handle->params.realm,
267 			  (handle->api_version == KADM5_API_VERSION_1 ?
268 			   ((pass == NULL) || !(strlen(pass))) :
269 			   ((handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
270 			    && handle->params.mkey_from_kbd)
271 			   ));
272     if (ret) {
273         krb5_db_fini(handle->context);
274 	krb5_free_context(handle->context);
275 	free(handle);
276 	return ret;
277     }
278 
279     ret = kdb_init_hist(handle, handle->params.realm);
280     if (ret) {
281 	 krb5_db_fini(handle->context);
282 	 krb5_free_context(handle->context);
283 	 free(handle);
284 	 return ret;
285     }
286 
287     ret = init_dict(&handle->params);
288     if (ret) {
289          krb5_db_fini(handle->context);
290 	 krb5_free_principal(handle->context, handle->current_caller);
291 	 krb5_free_context(handle->context);
292 	 free(handle);
293 	 return ret;
294     }
295 
296     ret = adb_policy_init(handle);
297     if (ret) {
298 	 krb5_db_fini(handle->context);
299 	 krb5_free_principal(handle->context, handle->current_caller);
300 	 krb5_free_context(handle->context);
301 	 free(handle);
302 	 return ret;
303     }
304     handle->lhandle->policy_db = handle->policy_db;
305 
306     *server_handle = (void *) handle;
307 
308     return KADM5_OK;
309 }
310 
311 kadm5_ret_t kadm5_destroy(void *server_handle)
312 {
313     kadm5_server_handle_t handle = server_handle;
314 
315     CHECK_HANDLE(server_handle);
316 
317     destroy_dict();
318 
319     adb_policy_close(handle);
320     krb5_db_fini(handle->context);
321     krb5_free_principal(handle->context, handle->current_caller);
322     kadm5_free_config_params(handle->context, &handle->params);
323     krb5_free_context(handle->context);
324     handle->magic_number = 0;
325     free(handle->lhandle);
326     free(handle);
327 
328     return KADM5_OK;
329 }
330 
331 kadm5_ret_t kadm5_lock(void *server_handle)
332 {
333     kadm5_server_handle_t handle = server_handle;
334     kadm5_ret_t ret;
335 
336     CHECK_HANDLE(server_handle);
337     ret = osa_adb_open_and_lock(handle->policy_db, OSA_ADB_EXCLUSIVE);
338     if (ret)
339 	return ret;
340     ret = krb5_db_lock(handle->context, KRB5_LOCKMODE_EXCLUSIVE);
341     if (ret)
342 	return ret;
343 
344     return KADM5_OK;
345 }
346 
347 kadm5_ret_t kadm5_unlock(void *server_handle)
348 {
349     kadm5_server_handle_t handle = server_handle;
350     kadm5_ret_t ret;
351 
352     CHECK_HANDLE(server_handle);
353     ret = osa_adb_close_and_unlock(handle->policy_db);
354     if (ret)
355 	return ret;
356     ret = krb5_db_unlock(handle->context);
357     if (ret)
358 	return ret;
359 
360     return KADM5_OK;
361 }
362 
363 kadm5_ret_t kadm5_flush(void *server_handle)
364 {
365      kadm5_server_handle_t handle = server_handle;
366      kadm5_ret_t ret;
367 
368      CHECK_HANDLE(server_handle);
369 
370      if ((ret = krb5_db_fini(handle->context)) ||
371 	 /*
372 	  * Set the db_name based on configuration before calling
373 	  * krb5_db_init, so it will get used.
374 	  */
375 	 (ret = krb5_db_set_name(handle->context,
376 				     handle->params.dbname)) ||
377 	 (ret = krb5_db_init(handle->context)) ||
378 	 (ret = adb_policy_close(handle)) ||
379 	 (ret = adb_policy_init(handle))) {
380 	  (void) kadm5_destroy(server_handle);
381 	  return ret;
382      }
383      return KADM5_OK;
384 }
385 
386 int _kadm5_check_handle(void *handle)
387 {
388      CHECK_HANDLE(handle);
389      return 0;
390 }
391 
392 krb5_error_code
393 kadm5_init_iprop(void *handle)
394 {
395 	kadm5_server_handle_t iprop_h;
396 	krb5_error_code retval;
397 
398 	iprop_h = handle;
399 	if (iprop_h->params.iprop_enabled) {
400 		ulog_set_role(iprop_h->context, IPROP_MASTER);
401 		if ((retval = ulog_map(iprop_h->context, &iprop_h->params,
402 		    FKCOMMAND)) != 0)
403 			return (retval);
404 	}
405 	return (0);
406 }
407