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