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 *) ¶ms_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 = ¶ms_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