1 /* 2 * lib/kdb/kdb_ldap/ldap_tkt_policy.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 #include "ldap_main.h" 32 #include "kdb_ldap.h" 33 #include "ldap_tkt_policy.h" 34 #include "ldap_err.h" 35 #include <libintl.h> 36 37 /* Ticket policy object management */ 38 39 /* 40 * create the Ticket policy object in Directory. 41 */ 42 krb5_error_code 43 krb5_ldap_create_policy(context, policy, mask) 44 krb5_context context; 45 krb5_ldap_policy_params *policy; 46 int mask; 47 { 48 krb5_error_code st=0; 49 LDAP *ld=NULL; 50 char *strval[3]={NULL}, *policy_dn = NULL; 51 LDAPMod **mods=NULL; 52 kdb5_dal_handle *dal_handle=NULL; 53 krb5_ldap_context *ldap_context=NULL; 54 krb5_ldap_server_handle *ldap_server_handle=NULL; 55 56 /* validate the input parameters */ 57 if (policy == NULL || policy->policy == NULL) { 58 st = EINVAL; 59 krb5_set_error_message (context, st, gettext("Ticket Policy Name missing")); 60 goto cleanup; 61 } 62 63 SETUP_CONTEXT(); 64 GET_HANDLE(); 65 66 if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0) 67 goto cleanup; 68 69 memset(strval, 0, sizeof(strval)); 70 strval[0] = policy->policy; 71 if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) 72 goto cleanup; 73 74 memset(strval, 0, sizeof(strval)); 75 strval[0] = "krbTicketPolicy"; 76 strval[1] = "krbTicketPolicyaux"; 77 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) 78 goto cleanup; 79 80 if (mask & LDAP_POLICY_MAXTKTLIFE) { 81 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_ADD, 82 policy->maxtktlife)) != 0) 83 goto cleanup; 84 } 85 86 if (mask & LDAP_POLICY_MAXRENEWLIFE) { 87 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_ADD, 88 policy->maxrenewlife)) != 0) 89 goto cleanup; 90 } 91 92 if (mask & LDAP_POLICY_TKTFLAGS) { 93 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_ADD, 94 policy->tktflags)) != 0) 95 goto cleanup; 96 } 97 98 /* ldap add operation */ 99 if ((st=ldap_add_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { 100 st = set_ldap_error (context, st, OP_ADD); 101 goto cleanup; 102 } 103 104 cleanup: 105 if (policy_dn != NULL) 106 free(policy_dn); 107 108 ldap_mods_free(mods, 1); 109 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 110 return st; 111 } 112 113 114 /* 115 * modify the Ticket policy object in Directory. 116 */ 117 118 krb5_error_code 119 krb5_ldap_modify_policy(context, policy, mask) 120 krb5_context context; 121 krb5_ldap_policy_params *policy; 122 int mask; 123 { 124 int objectmask=0; 125 krb5_error_code st=0; 126 LDAP *ld=NULL; 127 char *attrvalues[]={"krbTicketPolicy", "krbTicketPolicyAux", NULL}, *strval[2]={NULL}; 128 char *policy_dn = NULL; 129 LDAPMod **mods=NULL; 130 kdb5_dal_handle *dal_handle=NULL; 131 krb5_ldap_context *ldap_context=NULL; 132 krb5_ldap_server_handle *ldap_server_handle=NULL; 133 134 /* validate the input parameters */ 135 if (policy == NULL || policy->policy==NULL) { 136 st = EINVAL; 137 krb5_set_error_message (context, st, gettext("Ticket Policy Name missing")); 138 goto cleanup; 139 } 140 141 SETUP_CONTEXT(); 142 GET_HANDLE(); 143 144 if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0) 145 goto cleanup; 146 147 /* the policydn object should be of the krbTicketPolicy object class */ 148 st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask); 149 CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); 150 151 if ((objectmask & 0x02) == 0) { /* add krbticketpolicyaux to the object class list */ 152 memset(strval, 0, sizeof(strval)); 153 strval[0] = "krbTicketPolicyAux"; 154 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) 155 goto cleanup; 156 } 157 158 if (mask & LDAP_POLICY_MAXTKTLIFE) { 159 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, 160 policy->maxtktlife)) != 0) 161 goto cleanup; 162 } 163 164 if (mask & LDAP_POLICY_MAXRENEWLIFE) { 165 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE, 166 policy->maxrenewlife)) != 0) 167 goto cleanup; 168 } 169 170 if (mask & LDAP_POLICY_TKTFLAGS) { 171 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE, 172 policy->tktflags)) != 0) 173 goto cleanup; 174 } 175 176 if ((st=ldap_modify_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { 177 st = set_ldap_error (context, st, OP_MOD); 178 goto cleanup; 179 } 180 181 cleanup: 182 if (policy_dn != NULL) 183 free(policy_dn); 184 185 ldap_mods_free(mods, 1); 186 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 187 return st; 188 } 189 190 191 /* 192 * Read the policy object from the Directory and populate the krb5_ldap_policy_params 193 * structure. 194 */ 195 196 krb5_error_code 197 krb5_ldap_read_policy(context, policyname, policy, omask) 198 krb5_context context; 199 char *policyname; 200 krb5_ldap_policy_params **policy; 201 unsigned int *omask; /* Solaris kerberos: unsigned better for mask */ 202 { 203 krb5_error_code st=0, tempst=0; 204 int objectmask=0; 205 LDAP *ld=NULL; 206 LDAPMessage *result=NULL,*ent=NULL; 207 char *attributes[] = { "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", NULL}; 208 char *attrvalues[] = { "krbTicketPolicy", NULL}, *policy_dn = NULL; 209 krb5_ldap_policy_params *lpolicy=NULL; 210 kdb5_dal_handle *dal_handle=NULL; 211 krb5_ldap_context *ldap_context=NULL; 212 krb5_ldap_server_handle *ldap_server_handle=NULL; 213 214 /* validate the input parameters */ 215 if (policyname == NULL || policy == NULL) { 216 st = EINVAL; 217 krb5_set_error_message(context, st, gettext("Ticket Policy Object information missing")); 218 goto cleanup; 219 } 220 221 SETUP_CONTEXT(); 222 GET_HANDLE(); 223 224 if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0) 225 goto cleanup; 226 227 /* the policydn object should be of the krbTicketPolicy object class */ 228 st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask); 229 CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); 230 231 /* Initialize ticket policy structure */ 232 lpolicy =(krb5_ldap_policy_params *) malloc(sizeof(krb5_ldap_policy_params)); 233 CHECK_NULL(lpolicy); 234 memset(lpolicy, 0, sizeof(krb5_ldap_policy_params)); 235 236 if ((lpolicy->policy = strdup (policyname)) == NULL) { 237 st = ENOMEM; 238 goto cleanup; 239 } 240 241 lpolicy->tl_data = calloc (1, sizeof(*lpolicy->tl_data)); 242 CHECK_NULL(lpolicy->tl_data); 243 lpolicy->tl_data->tl_data_type = KDB_TL_USER_INFO; 244 245 LDAP_SEARCH(policy_dn, LDAP_SCOPE_BASE, "(objectclass=krbTicketPolicy)", attributes); 246 247 *omask = 0; 248 249 ent=ldap_first_entry(ld, result); 250 if (ent != NULL) { 251 if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", (int *) &(lpolicy->maxtktlife)) == 0) 252 *omask |= LDAP_POLICY_MAXTKTLIFE; 253 254 if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", (int *) &(lpolicy->maxrenewlife)) == 0) 255 *omask |= LDAP_POLICY_MAXRENEWLIFE; 256 257 if (krb5_ldap_get_value(ld, ent, "krbticketflags", (int *) &(lpolicy->tktflags)) == 0) 258 *omask |= LDAP_POLICY_TKTFLAGS; 259 } 260 ldap_msgfree(result); 261 262 lpolicy->mask = *omask; 263 store_tl_data(lpolicy->tl_data, KDB_TL_MASK, omask); 264 *policy = lpolicy; 265 266 cleanup: 267 if (st != 0) { 268 krb5_ldap_free_policy(context, lpolicy); 269 *policy = NULL; 270 } 271 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 272 return st; 273 } 274 275 276 /* 277 * Function to delete ticket policy object from the directory. Before 278 * calling this function krb5_ldap_read_policy should be called to 279 * check the existence of the object. This serves one major purpose, 280 * i.e., if the object to be is anything other than the ticket policy 281 * object then the krb5_ldap_read_policy returns an error and thus is 282 * not accidently deleted in this function. 283 * 284 * NOTE: Other kerberos objects (user/realm object) might be having 285 * references to the policy object to be deleted. This situation is 286 * not handled here, instead is taken care of at all the places where 287 * the deleted policy object is read, to ignore a return status of 288 * LDAP_NO_SUCH_OBJECT and continue. 289 */ 290 291 krb5_error_code 292 krb5_ldap_delete_policy(context, policyname) 293 krb5_context context; 294 char *policyname; 295 { 296 int refcount = 0; 297 char *policy_dn = NULL; 298 krb5_error_code st = 0; 299 LDAP *ld = NULL; 300 kdb5_dal_handle *dal_handle=NULL; 301 krb5_ldap_context *ldap_context=NULL; 302 krb5_ldap_server_handle *ldap_server_handle=NULL; 303 304 if (policyname == NULL) { 305 st = EINVAL; 306 prepend_err_str (context, gettext("Ticket Policy Object DN missing"),st,st); 307 goto cleanup; 308 } 309 310 311 SETUP_CONTEXT(); 312 GET_HANDLE(); 313 314 if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0) 315 goto cleanup; 316 317 /* Checking for policy count for 0 and will not permit delete if 318 * it is greater than 0. */ 319 320 if ((st = krb5_ldap_get_reference_count (context, policy_dn, 321 "krbTicketPolicyReference", &refcount, ld)) != 0) 322 goto cleanup; 323 324 if (refcount == 0) { 325 if ((st=ldap_delete_ext_s(ld, policy_dn, NULL, NULL)) != 0) { 326 prepend_err_str (context,ldap_err2string(st),st,st); 327 328 goto cleanup; 329 } 330 } else { 331 st = EINVAL; 332 prepend_err_str (context, gettext("Delete Failed: One or more Principals associated with the Ticket Policy"),st,st); 333 goto cleanup; 334 } 335 336 cleanup: 337 if (policy_dn != NULL) 338 free (policy_dn); 339 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 340 return st; 341 } 342 343 344 /* 345 * list policy objects from Directory 346 */ 347 348 krb5_error_code 349 krb5_ldap_list_policy(context, containerdn, policy) 350 krb5_context context; 351 char *containerdn; 352 char ***policy; 353 { 354 int i, j, count; 355 char **list = NULL; 356 char *policycontainerdn = containerdn; 357 kdb5_dal_handle *dal_handle=NULL; 358 krb5_ldap_context *ldap_context=NULL; 359 krb5_error_code st=0; 360 361 SETUP_CONTEXT(); 362 if (policycontainerdn == NULL) { 363 policycontainerdn = ldap_context->lrparams->realmdn; 364 } 365 366 if ((st = krb5_ldap_list(context, &list, "krbTicketPolicy", policycontainerdn)) != 0) 367 goto cleanup; 368 369 for (i = 0; list[i] != NULL; i++); 370 371 count = i; 372 373 *policy = (char **) calloc ((unsigned) count + 1, sizeof(char *)); 374 if (*policy == NULL) { 375 st = ENOMEM; 376 goto cleanup; 377 } 378 379 for (i = 0, j = 0; list[i] != NULL; i++, j++) { 380 int ret; 381 ret = krb5_ldap_policydn_to_name (context, list[i], &(*policy)[i]); 382 if (ret != 0) 383 j--; 384 } 385 386 cleanup: 387 return st; 388 } 389 390 /* 391 * Function to free the ticket policy object structure. 392 * Note: this function assumes that memory of the policy structure is dynamically allocated and hence the whole 393 * structure is freed up. Care should be taken not to call this function on a static structure 394 */ 395 396 krb5_error_code 397 krb5_ldap_free_policy(context, policy) 398 krb5_context context; 399 krb5_ldap_policy_params *policy; 400 { 401 402 krb5_error_code st=0; 403 404 if (policy == NULL) 405 return st; 406 407 if (policy->policy) 408 free (policy->policy); 409 410 if (policy->tl_data) { 411 if (policy->tl_data->tl_data_contents) 412 free (policy->tl_data->tl_data_contents); 413 free (policy->tl_data); 414 } 415 free (policy); 416 417 return st; 418 } 419 420 /* 421 * This function is general object listing routine. It is currently 422 * used for ticket policy object listing. 423 */ 424 425 krb5_error_code 426 krb5_ldap_list(context, list, objectclass, containerdn) 427 krb5_context context; 428 char ***list; 429 char *objectclass; 430 char *containerdn; 431 { 432 char *filter=NULL, *dn=NULL; 433 krb5_error_code st=0, tempst=0; 434 int i=0, count=0, filterlen=0; 435 LDAP *ld=NULL; 436 LDAPMessage *result=NULL,*ent=NULL; 437 kdb5_dal_handle *dal_handle=NULL; 438 krb5_ldap_context *ldap_context=NULL; 439 krb5_ldap_server_handle *ldap_server_handle=NULL; 440 441 SETUP_CONTEXT(); 442 GET_HANDLE(); 443 444 /* check if the containerdn exists */ 445 if (containerdn) { 446 if ((st=checkattributevalue(ld, containerdn, NULL, NULL, NULL)) != 0) { 447 prepend_err_str (context, gettext("Error reading container object: "), st, st); 448 goto cleanup; 449 } 450 } 451 452 /* set the filter for the search operation */ 453 filterlen = strlen("(objectclass=") + strlen(objectclass) + 1 + 1; 454 filter = malloc ((unsigned) filterlen); 455 if (filter == NULL) { 456 st = ENOMEM; 457 goto cleanup; 458 } 459 snprintf(filter, (unsigned) filterlen,"(objectclass=%s)",objectclass); 460 461 LDAP_SEARCH(containerdn, LDAP_SCOPE_SUBTREE, filter, NULL); 462 463 count = ldap_count_entries(ld, result); 464 if (count == -1) { 465 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st); 466 st = set_ldap_error(context, st, OP_SEARCH); 467 goto cleanup; 468 } 469 *list = (char **) calloc ((unsigned) count+1, sizeof(char *)); 470 if (*list == NULL) { 471 st = ENOMEM; 472 goto cleanup; 473 } 474 475 for (ent=ldap_first_entry(ld, result), count=0; ent != NULL; ent=ldap_next_entry(ld, ent), ++count) { 476 if ((dn=ldap_get_dn(ld, ent)) == NULL) 477 continue; 478 if (((*list)[count] = strdup(dn)) == NULL) { 479 ldap_memfree (dn); 480 st = ENOMEM; 481 goto cleanup; 482 } 483 ldap_memfree(dn); 484 } 485 ldap_msgfree(result); 486 487 cleanup: 488 if (filter) 489 free (filter); 490 491 /* some error, free up all the memory */ 492 if (st != 0) { 493 if (*list) { 494 for (i=0; (*list)[i]; ++i) 495 free ((*list)[i]); 496 free (*list); 497 *list = NULL; 498 } 499 } 500 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 501 return st; 502 } 503