1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 /*
8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9 *
10 * Openvision retains the copyright to derivative works of
11 * this source code. Do *NOT* create a derivative of this
12 * source code before consulting with your legal department.
13 * Do *NOT* integrate *ANY* of this source code into another
14 * product before consulting with your legal department.
15 *
16 * For further information, read the top-level Openvision
17 * copyright which is contained in the top-level MIT Kerberos
18 * copyright.
19 *
20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
21 *
22 */
23
24
25 /*
26 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
27 *
28 * $Id: server_init.c 18584 2006-09-13 20:30:23Z raeburn $
29 * $Source$
30 */
31
32 #if !defined(lint) && !defined(__CODECENTER__)
33 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 $";
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <com_err.h>
40 #include "k5-int.h" /* needed for gssapiP_krb5.h */
41 #include <kadm5/admin.h>
42 #include <krb5.h>
43 #include "server_internal.h"
44 #include <kdb/kdb_log.h>
45
46 /*
47 * Function check_handle
48 *
49 * Purpose: Check a server handle and return a com_err code if it is
50 * invalid or 0 if it is valid.
51 *
52 * Arguments:
53 *
54 * handle The server handle.
55 */
56
check_handle(void * handle)57 static int check_handle(void *handle)
58 {
59 CHECK_HANDLE(handle);
60 return 0;
61 }
62
dup_db_args(kadm5_server_handle_t handle,char ** db_args)63 static int dup_db_args(kadm5_server_handle_t handle, char **db_args)
64 {
65 int count = 0;
66 int ret = 0;
67
68 for (count=0; db_args && db_args[count]; count++);
69 if (count == 0) {
70 handle->db_args = NULL;
71 goto clean_n_exit;
72 }
73
74 handle->db_args = calloc(sizeof(char*), count+1);
75 if (handle->db_args == NULL) {
76 ret=ENOMEM;
77 goto clean_n_exit;
78 }
79
80 for (count=0; db_args[count]; count++) {
81 handle->db_args[count] = strdup(db_args[count]);
82 if (handle->db_args[count] == NULL) {
83 ret = ENOMEM;
84 goto clean_n_exit;
85 }
86 }
87
88 clean_n_exit:
89 if (ret && handle->db_args) {
90 for (count=0; handle->db_args[count]; count++)
91 free(handle->db_args[count]);
92
93 free(handle->db_args), handle->db_args = NULL;
94 }
95
96 return ret;
97 }
98
free_db_args(kadm5_server_handle_t handle)99 static void free_db_args(kadm5_server_handle_t handle)
100 {
101 int count;
102
103 if (handle->db_args) {
104 for (count=0; handle->db_args[count]; count++)
105 free(handle->db_args[count]);
106
107 free(handle->db_args), handle->db_args = NULL;
108 }
109 }
110
kadm5_init_with_password(char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)111 kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
112 char *service_name,
113 kadm5_config_params *params,
114 krb5_ui_4 struct_version,
115 krb5_ui_4 api_version,
116 char **db_args,
117 void **server_handle)
118 {
119 return kadm5_init(client_name, pass, service_name, params,
120 struct_version, api_version, db_args,
121 server_handle);
122 }
123
kadm5_init_with_creds(char * client_name,krb5_ccache ccache,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)124 kadm5_ret_t kadm5_init_with_creds(char *client_name,
125 krb5_ccache ccache,
126 char *service_name,
127 kadm5_config_params *params,
128 krb5_ui_4 struct_version,
129 krb5_ui_4 api_version,
130 char **db_args,
131 void **server_handle)
132 {
133 /*
134 * A program calling init_with_creds *never* expects to prompt the
135 * user. Therefore, always pass a dummy password in case this is
136 * KADM5_API_VERSION_1. If this is KADM5_API_VERSION_2 and
137 * MKEY_FROM_KBD is non-zero, return an error.
138 */
139 if (api_version == KADM5_API_VERSION_2 && params &&
140 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
141 params->mkey_from_kbd)
142 return KADM5_BAD_SERVER_PARAMS;
143 return kadm5_init(client_name, NULL, service_name, params,
144 struct_version, api_version, db_args,
145 server_handle);
146 }
147
148
kadm5_init_with_skey(char * client_name,char * keytab,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)149 kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
150 char *service_name,
151 kadm5_config_params *params,
152 krb5_ui_4 struct_version,
153 krb5_ui_4 api_version,
154 char **db_args,
155 void **server_handle)
156 {
157 /*
158 * A program calling init_with_skey *never* expects to prompt the
159 * user. Therefore, always pass a dummy password in case this is
160 * KADM5_API_VERSION_1. If this is KADM5_API_VERSION_2 and
161 * MKEY_FROM_KBD is non-zero, return an error.
162 */
163 if (api_version == KADM5_API_VERSION_2 && params &&
164 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
165 params->mkey_from_kbd)
166 return KADM5_BAD_SERVER_PARAMS;
167 return kadm5_init(client_name, NULL, service_name, params,
168 struct_version, api_version, db_args,
169 server_handle);
170 }
171
172 /*
173 * Solaris Kerberos:
174 * A private extended version of kadm5_init which potentially
175 * returns more information in case of an error.
176 */
kadm5_init2(char * client_name,char * pass,char * service_name,kadm5_config_params * params_in,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle,char ** emsg)177 kadm5_ret_t kadm5_init2(char *client_name, char *pass,
178 char *service_name,
179 kadm5_config_params *params_in,
180 krb5_ui_4 struct_version,
181 krb5_ui_4 api_version,
182 char **db_args,
183 void **server_handle,
184 char **emsg)
185 {
186 int ret;
187 kadm5_server_handle_t handle;
188 kadm5_config_params params_local; /* for v1 compat */
189
190 if (emsg)
191 *emsg = NULL;
192
193 if (! server_handle)
194 return EINVAL;
195
196 if (! client_name)
197 return EINVAL;
198
199 if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle)))
200 return ENOMEM;
201 memset(handle, 0, sizeof(*handle));
202
203 ret = dup_db_args(handle, db_args);
204 if (ret) {
205 free(handle);
206 return ret;
207 }
208
209 ret = (int) krb5int_init_context_kdc(&(handle->context));
210 if (ret) {
211 free_db_args(handle);
212 free(handle);
213 return(ret);
214 }
215
216 handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
217 handle->struct_version = struct_version;
218 handle->api_version = api_version;
219
220 /*
221 * Verify the version numbers before proceeding; we can't use
222 * CHECK_HANDLE because not all fields are set yet.
223 */
224 GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
225 KADM5_NEW_SERVER_API_VERSION);
226
227 /*
228 * Acquire relevant profile entries. In version 2, merge values
229 * in params_in with values from profile, based on
230 * params_in->mask.
231 *
232 * In version 1, we've given a realm (which may be NULL) instead
233 * of params_in. So use that realm, make params_in contain an
234 * empty mask, and behave like version 2.
235 */
236 memset((char *) ¶ms_local, 0, sizeof(params_local));
237 if (api_version == KADM5_API_VERSION_1) {
238 params_local.realm = (char *) params_in;
239 if (params_in)
240 params_local.mask = KADM5_CONFIG_REALM;
241 params_in = ¶ms_local;
242 }
243
244 #if 0 /* Now that we look at krb5.conf as well as kdc.conf, we can
245 expect to see admin_server being set sometimes. */
246 #define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
247 if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
248 krb5_free_context(handle->context);
249 free_db_args(handle);
250 free(handle);
251 return KADM5_BAD_SERVER_PARAMS;
252 }
253 #endif
254
255 ret = kadm5_get_config_params(handle->context, 1, params_in,
256 &handle->params);
257 if (ret) {
258 krb5_free_context(handle->context);
259 free_db_args(handle);
260 free(handle);
261 return(ret);
262 }
263
264 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \
265 KADM5_CONFIG_ADBNAME | \
266 KADM5_CONFIG_ADB_LOCKFILE | \
267 KADM5_CONFIG_ENCTYPE | \
268 KADM5_CONFIG_FLAGS | \
269 KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \
270 KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES)
271
272 if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
273 kadm5_free_config_params(handle->context, &handle->params);
274 krb5_free_context(handle->context);
275 free_db_args(handle);
276 free(handle);
277 return KADM5_MISSING_CONF_PARAMS;
278 }
279
280 ret = krb5_set_default_realm(handle->context, handle->params.realm);
281 if (ret) {
282 kadm5_free_config_params(handle->context, &handle->params);
283 krb5_free_context(handle->context);
284 free_db_args(handle);
285 free(handle);
286 return ret;
287 }
288
289 ret = krb5_db_open(handle->context, db_args,
290 KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
291 if (ret) {
292 if (emsg) {
293 const char *m = krb5_get_error_message(handle->context, ret);
294 *emsg = strdup(m);
295 krb5_free_error_message(handle->context, m);
296 }
297 kadm5_free_config_params(handle->context, &handle->params);
298 krb5_free_context(handle->context);
299 free_db_args(handle);
300 free(handle);
301 return(ret);
302 }
303
304 if ((ret = krb5_parse_name(handle->context, client_name,
305 &handle->current_caller))) {
306 krb5_db_fini(handle->context);
307 kadm5_free_config_params(handle->context, &handle->params);
308 krb5_free_context(handle->context);
309 free_db_args(handle);
310 free(handle);
311 return ret;
312 }
313
314 if (! (handle->lhandle = malloc(sizeof(*handle)))) {
315 krb5_db_fini(handle->context);
316 kadm5_free_config_params(handle->context, &handle->params);
317 krb5_free_context(handle->context);
318 free_db_args(handle);
319 free(handle);
320 return ENOMEM;
321 }
322 *handle->lhandle = *handle;
323 handle->lhandle->api_version = KADM5_API_VERSION_2;
324 handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
325 handle->lhandle->lhandle = handle->lhandle;
326
327 /* can't check the handle until current_caller is set */
328 ret = check_handle((void *) handle);
329 if (ret) {
330 krb5_db_fini(handle->context);
331 kadm5_free_config_params(handle->context, &handle->params);
332 krb5_free_context(handle->context);
333 free_db_args(handle);
334 free(handle);
335 return ret;
336 }
337
338 /*
339 * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL
340 * or an empty string, reads the master password from [the stash
341 * file]. Otherwise, the non-NULL password is ignored and the
342 * user is prompted for it via the tty." However, the code was
343 * implemented the other way: when a non-NULL password was
344 * provided, the stash file was used. This is somewhat more
345 * sensible, as then a local or remote client that provides a
346 * password does not prompt the user. This code maintains the
347 * previous actual behavior, and not the old spec behavior,
348 * because that is how the unit tests are written.
349 *
350 * In KADM5_API_VERSION_2, this decision is controlled by
351 * params.
352 *
353 * kdb_init_master's third argument is "from_keyboard".
354 */
355 /*
356 * Solaris Kerberos: Setting to an unknown enc type will make the function
357 * read the encryption type in the stash file instead of assumming that it
358 * is the default type.
359 */
360 if (handle->params.enctype == DEFAULT_KDC_ENCTYPE)
361 handle->params.enctype = ENCTYPE_UNKNOWN;
362 ret = kdb_init_master(handle, handle->params.realm,
363 (handle->api_version == KADM5_API_VERSION_1 ?
364 ((pass == NULL) || !(strlen(pass))) :
365 ((handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
366 && handle->params.mkey_from_kbd)
367 ));
368 if (ret) {
369 krb5_db_fini(handle->context);
370 kadm5_free_config_params(handle->context, &handle->params);
371 krb5_free_context(handle->context);
372 free_db_args(handle);
373 free(handle);
374 return ret;
375 }
376 /*
377 * Solaris Kerberos: We used the enc type that was discovered in the stash
378 * file to associate with the other magic principals in the database.
379 */
380 handle->params.enctype = handle->master_keyblock.enctype;
381
382 ret = kdb_init_hist(handle, handle->params.realm);
383 if (ret) {
384 krb5_db_fini(handle->context);
385 kadm5_free_config_params(handle->context, &handle->params);
386 krb5_free_context(handle->context);
387 free_db_args(handle);
388 free(handle);
389 return ret;
390 }
391
392 ret = init_dict(&handle->params);
393 if (ret) {
394 krb5_db_fini(handle->context);
395 krb5_free_principal(handle->context, handle->current_caller);
396 kadm5_free_config_params(handle->context, &handle->params);
397 krb5_free_context(handle->context);
398 free_db_args(handle);
399 free(handle);
400 return ret;
401 }
402
403 *server_handle = (void *) handle;
404
405 return KADM5_OK;
406 }
407
kadm5_init(char * client_name,char * pass,char * service_name,kadm5_config_params * params_in,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)408 kadm5_ret_t kadm5_init(char *client_name, char *pass,
409 char *service_name,
410 kadm5_config_params *params_in,
411 krb5_ui_4 struct_version,
412 krb5_ui_4 api_version,
413 char **db_args,
414 void **server_handle) {
415 return (kadm5_init2(client_name, pass, service_name, params_in,
416 struct_version, api_version, db_args, server_handle, NULL));
417
418 }
419
kadm5_destroy(void * server_handle)420 kadm5_ret_t kadm5_destroy(void *server_handle)
421 {
422 kadm5_server_handle_t handle = server_handle;
423
424 CHECK_HANDLE(server_handle);
425
426 destroy_dict();
427
428 adb_policy_close(handle);
429 krb5_db_fini(handle->context);
430 krb5_free_principal(handle->context, handle->current_caller);
431 kadm5_free_config_params(handle->context, &handle->params);
432 krb5_free_context(handle->context);
433 handle->magic_number = 0;
434 free(handle->lhandle);
435 free_db_args(handle);
436 free(handle);
437
438 return KADM5_OK;
439 }
440
kadm5_lock(void * server_handle)441 kadm5_ret_t kadm5_lock(void *server_handle)
442 {
443 kadm5_server_handle_t handle = server_handle;
444 kadm5_ret_t ret;
445
446 CHECK_HANDLE(server_handle);
447 ret = krb5_db_lock(handle->context, KRB5_DB_LOCKMODE_EXCLUSIVE);
448 if (ret)
449 return ret;
450
451 return KADM5_OK;
452 }
453
kadm5_unlock(void * server_handle)454 kadm5_ret_t kadm5_unlock(void *server_handle)
455 {
456 kadm5_server_handle_t handle = server_handle;
457 kadm5_ret_t ret;
458
459 CHECK_HANDLE(server_handle);
460 ret = krb5_db_unlock(handle->context);
461 if (ret)
462 return ret;
463
464 return KADM5_OK;
465 }
466
kadm5_flush(void * server_handle)467 kadm5_ret_t kadm5_flush(void *server_handle)
468 {
469 kadm5_server_handle_t handle = server_handle;
470 kadm5_ret_t ret;
471
472 CHECK_HANDLE(server_handle);
473
474 if ((ret = krb5_db_fini(handle->context)) ||
475 (ret = krb5_db_open(handle->context, handle->db_args,
476 KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN)) ||
477 (ret = adb_policy_close(handle)) ||
478 (ret = adb_policy_init(handle))) {
479 (void) kadm5_destroy(server_handle);
480 return ret;
481 }
482 return KADM5_OK;
483 }
484
_kadm5_check_handle(void * handle)485 int _kadm5_check_handle(void *handle)
486 {
487 CHECK_HANDLE(handle);
488 return 0;
489 }
490
491 #include "gssapiP_krb5.h"
kadm5_init_krb5_context(krb5_context * ctx)492 krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
493 {
494 /* Solaris Kerberos: not needed */
495 #if 0 /************** Begin IFDEF'ed OUT *******************************/
496 static int first_time = 1;
497 if (first_time) {
498 krb5_error_code err;
499 err = krb5_gss_use_kdc_context();
500 if (err)
501 return err;
502 first_time = 0;
503 }
504 #endif /**************** END IFDEF'ed OUT *******************************/
505 return krb5int_init_context_kdc(ctx);
506 }
507
508 krb5_error_code
kadm5_init_iprop(void * handle)509 kadm5_init_iprop(void *handle)
510 {
511 kadm5_server_handle_t iprop_h;
512 krb5_error_code retval;
513
514 iprop_h = handle;
515 if (iprop_h->params.iprop_enabled) {
516 ulog_set_role(iprop_h->context, IPROP_MASTER);
517 if ((retval = ulog_map(iprop_h->context, &iprop_h->params,
518 FKCOMMAND)) != 0)
519 return (retval);
520 }
521 return (0);
522 }
523