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