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