xref: /illumos-gate/usr/src/lib/krb5/kadm5/srv/server_init.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
1 /*
2  * Copyright 2004 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.5 1997/10/13 15:03:13 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.5 1997/10/13 15:03:13 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     if (ret = (int) krb5_init_context(&(handle->context))) {
142 	 free(handle);
143 	 return(ret);
144     }
145 
146     handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
147     handle->struct_version = struct_version;
148     handle->api_version = api_version;
149 
150      /*
151       * Verify the version numbers before proceeding; we can't use
152       * CHECK_HANDLE because not all fields are set yet.
153       */
154      GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
155 			  KADM5_NEW_SERVER_API_VERSION);
156 
157      /*
158       * Acquire relevant profile entries.  In version 2, merge values
159       * in params_in with values from profile, based on
160       * params_in->mask.
161       *
162       * In version 1, we've given a realm (which may be NULL) instead
163       * of params_in.  So use that realm, make params_in contain an
164       * empty mask, and behave like version 2.
165       */
166      memset((char *) &params_local, 0, sizeof(params_local));
167      if (api_version == KADM5_API_VERSION_1) {
168 	  params_local.realm = (char *) params_in;
169 	  if (params_in)
170 	       params_local.mask = KADM5_CONFIG_REALM;
171 	  params_in = &params_local;
172      }
173 
174 #define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
175      if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
176 	  krb5_free_context(handle->context);
177 	  free(handle);
178 	  return KADM5_BAD_SERVER_PARAMS;
179      }
180 
181      if (ret = kadm5_get_config_params(handle->context,
182 				       (char *) NULL,
183 				       (char *) NULL,
184 				       params_in,
185 				       &handle->params)) {
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      if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
199 	  krb5_free_context(handle->context);
200 	  free(handle);
201 	  return KADM5_MISSING_CONF_PARAMS;
202      }
203 
204     /*
205      * Set the db_name based on configuration before calling
206      * krb5_db_init, so it will get used.
207      */
208     if (ret = krb5_db_set_name(handle->context,
209 				   handle->params.dbname)) {
210 	 free(handle);
211 	 return(ret);
212     }
213 
214     if (ret = krb5_db_init(handle->context)) {
215 	 krb5_free_context(handle->context);
216 	 free(handle);
217 	 return(ret);
218     }
219 
220     if ((ret = krb5_parse_name(handle->context, client_name,
221 			       &handle->current_caller))) {
222 	 krb5_db_fini(handle->context);
223 	 krb5_free_context(handle->context);
224 	 free(handle);
225 	 return ret;
226     }
227 
228      if (! (handle->lhandle = malloc(sizeof(*handle)))) {
229 	  krb5_db_fini(handle->context);
230 	  krb5_free_context(handle->context);
231 	  free(handle);
232 	  return ENOMEM;
233      }
234      *handle->lhandle = *handle;
235      handle->lhandle->api_version = KADM5_API_VERSION_2;
236      handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
237      handle->lhandle->lhandle = handle->lhandle;
238 
239      /* can't check the handle until current_caller is set */
240     if (ret = check_handle((void *) handle)) {
241 	 free(handle);
242 	 return ret;
243     }
244 
245      /*
246       * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL
247       * or an empty string, reads the master password from [the stash
248       * file].  Otherwise, the non-NULL password is ignored and the
249       * user is prompted for it via the tty."  However, the code was
250       * implemented the other way: when a non-NULL password was
251       * provided, the stash file was used.  This is somewhat more
252       * sensible, as then a local or remote client that provides a
253       * password does not prompt the user.  This code maintains the
254       * previous actual behavior, and not the old spec behavior,
255       * because that is how the unit tests are written.
256       *
257       * In KADM5_API_VERSION_2, this decision is controlled by
258       * params.
259       *
260       * kdb_init_master's third argument is "from_keyboard".
261       */
262     if (ret = kdb_init_master(handle, handle->params.realm,
263 			      (handle->api_version == KADM5_API_VERSION_1 ?
264 			       ((pass == NULL) || !(strlen(pass))) :
265 			       ((handle->params.mask &
266 				 KADM5_CONFIG_MKEY_FROM_KBD) &&
267 				handle->params.mkey_from_kbd))
268 			      )) {
269 	 krb5_db_fini(handle->context);
270 	 krb5_free_context(handle->context);
271 	 free(handle);
272 	 return ret;
273     }
274 
275     if ((ret = kdb_init_hist(handle, handle->params.realm))) {
276 	 krb5_db_fini(handle->context);
277 	 krb5_free_context(handle->context);
278 	 free(handle);
279 	 return ret;
280     }
281 
282     if (ret = init_dict(&handle->params)) {
283 	 krb5_db_fini(handle->context);
284 	 krb5_free_principal(handle->context, handle->current_caller);
285 	 krb5_free_context(handle->context);
286 	 free(handle);
287 	 return ret;
288     }
289 
290     if (ret = adb_policy_init(handle)) {
291 	 krb5_db_fini(handle->context);
292 	 krb5_free_principal(handle->context, handle->current_caller);
293 	 krb5_free_context(handle->context);
294 	 free(handle);
295 	 return ret;
296     }
297     handle->lhandle->policy_db = handle->policy_db;
298 
299     *server_handle = (void *) handle;
300 
301     return KADM5_OK;
302 }
303 
304 kadm5_ret_t kadm5_destroy(void *server_handle)
305 {
306     kadm5_server_handle_t handle = server_handle;
307 
308     CHECK_HANDLE(server_handle);
309 
310     destroy_dict();
311 
312     adb_policy_close(handle);
313     krb5_db_fini(handle->context);
314     krb5_free_principal(handle->context, handle->current_caller);
315     kadm5_free_config_params(handle->context, &handle->params);
316     krb5_free_context(handle->context);
317     handle->magic_number = 0;
318     free(handle->lhandle);
319     free(handle);
320 
321     return KADM5_OK;
322 }
323 
324 kadm5_ret_t kadm5_flush(void *server_handle)
325 {
326      kadm5_server_handle_t handle = server_handle;
327      kadm5_ret_t ret;
328 
329      CHECK_HANDLE(server_handle);
330 
331      if ((ret = krb5_db_fini(handle->context)) ||
332 	 /*
333 	  * Set the db_name based on configuration before calling
334 	  * krb5_db_init, so it will get used.
335 	  */
336 	 (ret = krb5_db_set_name(handle->context,
337 				     handle->params.dbname)) ||
338 	 (ret = krb5_db_init(handle->context)) ||
339 	 (ret = adb_policy_close(handle)) ||
340 	 (ret = adb_policy_init(handle))) {
341 	  (void) kadm5_destroy(server_handle);
342 	  return ret;
343      }
344      return KADM5_OK;
345 }
346 
347 int _kadm5_check_handle(void *handle)
348 {
349      CHECK_HANDLE(handle);
350      return 0;
351 }
352 
353 krb5_error_code
354 kadm5_init_iprop(void *handle)
355 {
356 	kadm5_server_handle_t iprop_h;
357 	krb5_error_code retval;
358 
359 	iprop_h = handle;
360 	if (iprop_h->params.iprop_enabled) {
361 		ulog_set_role(iprop_h->context, IPROP_MASTER);
362 		if ((retval = ulog_map(iprop_h->context, &iprop_h->params,
363 		    FKCOMMAND)) != 0)
364 			return (retval);
365 	}
366 	return (0);
367 }
368