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