1 #pragma ident "%Z%%M% %I% %E% SMI" 2 3 /* 4 * lib/kdb/kdb_ldap/ldap_create.c 5 * 6 * Copyright (c) 2004-2005, Novell, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * 12 * * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * * The copyright holder's name is not used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 35 * Use is subject to license terms. 36 */ 37 38 #include "ldap_main.h" 39 #include "ldap_realm.h" 40 #include "ldap_principal.h" 41 #include "ldap_krbcontainer.h" 42 #include "ldap_err.h" 43 #include <libintl.h> 44 45 /* 46 * ****************************************************************************** 47 * DAL functions 48 * ****************************************************************************** 49 */ 50 51 /* 52 * This function will create a krbcontainer and realm on the LDAP Server, with 53 * the specified attributes. 54 */ 55 krb5_error_code 56 krb5_ldap_create (krb5_context context, char *conf_section, char **db_args) 57 { 58 krb5_error_code status = 0; 59 char **t_ptr = db_args; 60 krb5_ldap_realm_params *rparams = NULL; 61 kdb5_dal_handle *dal_handle = NULL; 62 krb5_ldap_context *ldap_context=NULL; 63 krb5_boolean realm_obj_created = FALSE; 64 krb5_boolean krbcontainer_obj_created = FALSE; 65 krb5_ldap_krbcontainer_params kparams = {0}; 66 int srv_cnt = 0; 67 int mask = 0; 68 #ifdef HAVE_EDIRECTORY 69 int i = 0, rightsmask = 0; 70 #endif 71 72 /* Clear the global error string */ 73 krb5_clear_error_message(context); 74 75 ldap_context = malloc(sizeof(krb5_ldap_context)); 76 if (ldap_context == NULL) { 77 status = ENOMEM; 78 goto cleanup; 79 } 80 memset(ldap_context, 0, sizeof(*ldap_context)); 81 82 ldap_context->kcontext = context; 83 84 /* populate ldap_context with ldap specific options */ 85 while (t_ptr && *t_ptr) { 86 char *opt = NULL, *val = NULL; 87 88 if ((status = krb5_ldap_get_db_opt(*t_ptr, &opt, &val)) != 0) { 89 goto cleanup; 90 } 91 if (opt && !strcmp(opt, "binddn")) { 92 if (ldap_context->bind_dn) { 93 free (opt); 94 free (val); 95 status = EINVAL; 96 krb5_set_error_message (context, status, gettext("'binddn' missing")); 97 goto cleanup; 98 } 99 if (val == NULL) { 100 status = EINVAL; 101 krb5_set_error_message (context, status, gettext("'binddn' value missing")); 102 free(opt); 103 goto cleanup; 104 } 105 ldap_context->bind_dn = strdup(val); 106 if (ldap_context->bind_dn == NULL) { 107 free (opt); 108 free (val); 109 status = ENOMEM; 110 goto cleanup; 111 } 112 } else if (opt && !strcmp(opt, "nconns")) { 113 if (ldap_context->max_server_conns) { 114 free (opt); 115 free (val); 116 status = EINVAL; 117 krb5_set_error_message (context, status, gettext("'nconns' missing")); 118 goto cleanup; 119 } 120 if (val == NULL) { 121 status = EINVAL; 122 krb5_set_error_message (context, status, gettext("'nconns' value missing")); 123 free(opt); 124 goto cleanup; 125 } 126 ldap_context->max_server_conns = atoi(val) ? atoi(val) : DEFAULT_CONNS_PER_SERVER; 127 } else if (opt && !strcmp(opt, "bindpwd")) { 128 if (ldap_context->bind_pwd) { 129 free (opt); 130 free (val); 131 status = EINVAL; 132 krb5_set_error_message (context, status, gettext("'bindpwd' missing")); 133 goto cleanup; 134 } 135 if (val == NULL) { 136 status = EINVAL; 137 krb5_set_error_message (context, status, gettext("'bindpwd' value missing")); 138 free(opt); 139 goto cleanup; 140 } 141 ldap_context->bind_pwd = strdup(val); 142 if (ldap_context->bind_pwd == NULL) { 143 free (opt); 144 free (val); 145 status = ENOMEM; 146 goto cleanup; 147 } 148 } else if (opt && !strcmp(opt, "host")) { 149 if (val == NULL) { 150 status = EINVAL; 151 krb5_set_error_message (context, status, gettext("'host' value missing")); 152 free(opt); 153 goto cleanup; 154 } 155 if (ldap_context->server_info_list == NULL) 156 ldap_context->server_info_list = 157 (krb5_ldap_server_info **) calloc(SERV_COUNT+1, sizeof(krb5_ldap_server_info *)); 158 159 if (ldap_context->server_info_list == NULL) { 160 free (opt); 161 free (val); 162 status = ENOMEM; 163 goto cleanup; 164 } 165 166 ldap_context->server_info_list[srv_cnt] = 167 (krb5_ldap_server_info *) calloc(1, sizeof(krb5_ldap_server_info)); 168 if (ldap_context->server_info_list[srv_cnt] == NULL) { 169 free (opt); 170 free (val); 171 status = ENOMEM; 172 goto cleanup; 173 } 174 175 ldap_context->server_info_list[srv_cnt]->server_status = NOTSET; 176 177 ldap_context->server_info_list[srv_cnt]->server_name = strdup(val); 178 if (ldap_context->server_info_list[srv_cnt]->server_name == NULL) { 179 free (opt); 180 free (val); 181 status = ENOMEM; 182 goto cleanup; 183 } 184 185 srv_cnt++; 186 #ifdef HAVE_EDIRECTORY 187 } else if (opt && !strcmp(opt, "cert")) { 188 if (val == NULL) { 189 status = EINVAL; 190 krb5_set_error_message (context, status, gettext("'cert' value missing")); 191 free(opt); 192 goto cleanup; 193 } 194 195 if (ldap_context->root_certificate_file == NULL) { 196 ldap_context->root_certificate_file = strdup(val); 197 if (ldap_context->root_certificate_file == NULL) { 198 free (opt); 199 free (val); 200 status = ENOMEM; 201 goto cleanup; 202 } 203 } else { 204 void *tmp=NULL; 205 char *oldstr = NULL; 206 unsigned int len=0; 207 208 oldstr = strdup(ldap_context->root_certificate_file); 209 if (oldstr == NULL) { 210 free (opt); 211 free (val); 212 status = ENOMEM; 213 goto cleanup; 214 } 215 216 tmp = ldap_context->root_certificate_file; 217 len = strlen(ldap_context->root_certificate_file) + 2 + strlen(val); 218 ldap_context->root_certificate_file = realloc(ldap_context->root_certificate_file, 219 len); 220 if (ldap_context->root_certificate_file == NULL) { 221 free (tmp); 222 free (opt); 223 free (val); 224 status = ENOMEM; 225 goto cleanup; 226 } 227 memset(ldap_context->root_certificate_file, 0, len); 228 sprintf(ldap_context->root_certificate_file,"%s %s", oldstr, val); 229 free (oldstr); 230 } 231 #endif 232 } else { 233 /* ignore hash argument. Might have been passed from create */ 234 status = EINVAL; 235 if (opt && !strcmp(opt, "temporary")) { 236 /* 237 * temporary is passed in when kdb5_util load without -update is done. 238 * This is unsupported by the LDAP plugin. 239 */ 240 krb5_set_error_message (context, status, 241 gettext("creation of LDAP entries aborted, plugin requires -update argument")); 242 } else { 243 krb5_set_error_message (context, status, gettext("unknown option \'%s\'"), 244 opt?opt:val); 245 } 246 free(opt); 247 free(val); 248 goto cleanup; 249 } 250 251 free(opt); 252 free(val); 253 t_ptr++; 254 } 255 256 dal_handle = (kdb5_dal_handle *) context->db_context; 257 dal_handle->db_context = (kdb5_dal_handle *) ldap_context; 258 259 status = krb5_ldap_read_server_params(context, conf_section, KRB5_KDB_SRV_TYPE_ADMIN); 260 if (status) { 261 dal_handle->db_context = NULL; 262 prepend_err_str (context, gettext("Error reading LDAP server params: "), status, status); 263 goto cleanup; 264 } 265 status = krb5_ldap_db_init(context, ldap_context); 266 if (status) { 267 goto cleanup; 268 } 269 270 /* read the kerberos container */ 271 if ((status = krb5_ldap_read_krbcontainer_params(context, 272 &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) { 273 274 /* Read the kerberos container location from configuration file */ 275 if (ldap_context->conf_section) { 276 if ((status = profile_get_string(context->profile, 277 KDB_MODULE_SECTION, ldap_context->conf_section, 278 "ldap_kerberos_container_dn", NULL, 279 &kparams.DN)) != 0) { 280 goto cleanup; 281 } 282 } 283 if (kparams.DN == NULL) { 284 if ((status = profile_get_string(context->profile, 285 KDB_MODULE_DEF_SECTION, 286 "ldap_kerberos_container_dn", NULL, 287 NULL, &kparams.DN)) != 0) { 288 goto cleanup; 289 } 290 } 291 292 /* create the kerberos container */ 293 status = krb5_ldap_create_krbcontainer(context, 294 ((kparams.DN != NULL) ? &kparams : NULL)); 295 if (status) 296 goto cleanup; 297 298 krbcontainer_obj_created = TRUE; 299 300 status = krb5_ldap_read_krbcontainer_params(context, 301 &(ldap_context->krbcontainer)); 302 if (status) { 303 krb5_set_error_message(context, status, gettext("while reading kerberos container information")); 304 goto cleanup; 305 } 306 307 } else if (status) { 308 krb5_set_error_message(context, status, gettext("while reading kerberos container information")); 309 goto cleanup; 310 } 311 312 rparams = (krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params)); 313 if (rparams == NULL) { 314 status = ENOMEM; 315 goto cleanup; 316 } 317 memset(rparams, 0, sizeof(*rparams)); 318 rparams->realm_name = strdup(context->default_realm); 319 if (rparams->realm_name == NULL) { 320 status = ENOMEM; 321 goto cleanup; 322 } 323 324 if ((status = krb5_ldap_create_realm(context, rparams, mask))) { 325 krb5_set_error_message(context, status, gettext("while creating realm object entry")); 326 goto cleanup; 327 } 328 329 /* We just created the Realm container. Here starts our transaction tracking */ 330 realm_obj_created = TRUE; 331 332 /* verify realm object */ 333 if ((status = krb5_ldap_read_realm_params(context, 334 rparams->realm_name, 335 &(ldap_context->lrparams), 336 &mask))) { 337 krb5_set_error_message(context, status, gettext("while reading realm object entry")); 338 goto cleanup; 339 } 340 341 #ifdef HAVE_EDIRECTORY 342 if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) || 343 (mask & LDAP_REALM_PASSWDSERVERS)) { 344 345 rightsmask =0; 346 rightsmask |= LDAP_REALM_RIGHTS; 347 rightsmask |= LDAP_SUBTREE_RIGHTS; 348 if ((rparams != NULL) && (rparams->kdcservers != NULL)) { 349 for (i=0; (rparams->kdcservers[i] != NULL); i++) { 350 if ((status=krb5_ldap_add_service_rights(context, 351 LDAP_KDC_SERVICE, rparams->kdcservers[i], 352 rparams->realm_name, rparams->subtree, rightsmask)) != 0) { 353 goto cleanup; 354 } 355 } 356 } 357 358 rightsmask = 0; 359 rightsmask |= LDAP_REALM_RIGHTS; 360 rightsmask |= LDAP_SUBTREE_RIGHTS; 361 if ((rparams != NULL) && (rparams->adminservers != NULL)) { 362 for (i=0; (rparams->adminservers[i] != NULL); i++) { 363 if ((status=krb5_ldap_add_service_rights(context, 364 LDAP_ADMIN_SERVICE, rparams->adminservers[i], 365 rparams->realm_name, rparams->subtree, rightsmask)) != 0) { 366 goto cleanup; 367 } 368 } 369 } 370 371 rightsmask = 0; 372 rightsmask |= LDAP_REALM_RIGHTS; 373 rightsmask |= LDAP_SUBTREE_RIGHTS; 374 if ((rparams != NULL) && (rparams->passwdservers != NULL)) { 375 for (i=0; (rparams->passwdservers[i] != NULL); i++) { 376 if ((status=krb5_ldap_add_service_rights(context, 377 LDAP_PASSWD_SERVICE, rparams->passwdservers[i], 378 rparams->realm_name, rparams->subtree, rightsmask)) != 0) { 379 goto cleanup; 380 } 381 } 382 } 383 } 384 #endif 385 386 cleanup: 387 388 /* If the krbcontainer/realm creation is not complete, do the roll-back here */ 389 if ((krbcontainer_obj_created) && (!realm_obj_created)) { 390 int rc; 391 rc = krb5_ldap_delete_krbcontainer(context, 392 ((kparams.DN != NULL) ? &kparams : NULL)); 393 krb5_set_error_message(context, rc, 394 gettext("could not complete roll-back, error deleting Kerberos Container")); 395 } 396 397 /* should call krb5_ldap_free_krbcontainer_params() but can't */ 398 if (kparams.DN != NULL) 399 krb5_xfree(kparams.DN); 400 401 if (rparams) 402 krb5_ldap_free_realm_params(rparams); 403 404 return(status); 405 } 406