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
krb5_ldap_create_policy(context,policy,mask)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
krb5_ldap_modify_policy(context,policy,mask)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
krb5_ldap_read_policy(context,policyname,policy,omask)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
krb5_ldap_delete_policy(context,policyname)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
krb5_ldap_list_policy(context,containerdn,policy)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
krb5_ldap_free_policy(context,policy)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
krb5_ldap_list(context,list,objectclass,containerdn)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