ldap_tkt_policy.c revision 54925bf60766fbb4f1f2d7c843721406a7b7a3fb
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 */
44krb5_error_code
45krb5_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
106cleanup:
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
120krb5_error_code
121krb5_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
183cleanup:
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
198krb5_error_code
199krb5_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
268cleanup:
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
293krb5_error_code
294krb5_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
338cleanup:
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
350krb5_error_code
351krb5_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
388cleanup:
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
398krb5_error_code
399krb5_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
427krb5_error_code
428krb5_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
489cleanup:
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