~ubuntu-branches/ubuntu/maverick/openldap/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/slapd/overlays/collect.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2009-02-18 18:44:00 UTC
  • mfrom: (0.1.1 upstream)
  • mto: (0.3.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20090218184400-xmj1e22xo7i50ar6
Tags: upstream-2.4.14
ImportĀ upstreamĀ versionĀ 2.4.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* collect.c - Demonstration of overlay code */
2
 
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/collect.c,v 1.5.2.4 2008/02/11 23:26:48 kurt Exp $ */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/collect.c,v 1.5.2.8 2009/01/22 00:01:12 kurt Exp $ */
3
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4
4
 *
5
 
 * Copyright 2003-2008 The OpenLDAP Foundation.
 
5
 * Copyright 2003-2009 The OpenLDAP Foundation.
6
6
 * Portions Copyright 2003 Howard Chu.
7
7
 * All rights reserved.
8
8
 *
31
31
#include "slap.h"
32
32
#include "config.h"
33
33
 
 
34
#include "lutil.h"
 
35
 
34
36
/* This is a cheap hack to implement a collective attribute.
35
37
 *
36
38
 * This demonstration overlay looks for a specified attribute in an
43
45
typedef struct collect_info {
44
46
        struct collect_info *ci_next;
45
47
        struct berval ci_dn;
46
 
        AttributeDescription *ci_ad;
 
48
        int ci_ad_num;
 
49
        AttributeDescription *ci_ad[1];
47
50
} collect_info;
48
51
 
 
52
/*
 
53
 * inserts a collect_info into on->on_bi.bi_private taking into account
 
54
 * order. this means longer dn's (i.e. more specific dn's) will be found
 
55
 * first when searching, allowing some limited overlap of dn's
 
56
 */
 
57
static void
 
58
insert_ordered( slap_overinst *on, collect_info *ci ) {
 
59
        collect_info *find = on->on_bi.bi_private;
 
60
        collect_info *prev = NULL;
 
61
        int found = 0;
 
62
 
 
63
        while (!found) {
 
64
                if (find == NULL) {
 
65
                        if (prev == NULL) {
 
66
                                /* base case - empty list */
 
67
                                on->on_bi.bi_private = ci;
 
68
                                ci->ci_next = NULL;
 
69
                        } else {
 
70
                                /* final case - end of list */
 
71
                                prev->ci_next = ci;
 
72
                                ci->ci_next = NULL;
 
73
                        }
 
74
                        found = 1;
 
75
                } else if (find->ci_dn.bv_len <= ci->ci_dn.bv_len) { 
 
76
                        /* insert into list here */
 
77
                        if (prev == NULL) {
 
78
                                /* entry is head of list */
 
79
                                ci->ci_next = on->on_bi.bi_private;
 
80
                                on->on_bi.bi_private = ci;
 
81
                        } else {
 
82
                                /* entry is not head of list */
 
83
                                prev->ci_next = ci;
 
84
                                ci->ci_next = find;
 
85
                        }
 
86
                        found = 1;
 
87
                } else {
 
88
                        /* keep looking */
 
89
                        prev = find;
 
90
                        find = find->ci_next;
 
91
                }
 
92
        }
 
93
}
 
94
 
49
95
static int
50
96
collect_cf( ConfigArgs *c )
51
97
{
52
98
        slap_overinst *on = (slap_overinst *)c->bi;
53
 
        int rc = 1;
 
99
        int rc = 1, idx;
54
100
 
55
101
        switch( c->op ) {
56
102
        case SLAP_CONFIG_EMIT:
58
104
                collect_info *ci;
59
105
                for ( ci = on->on_bi.bi_private; ci; ci = ci->ci_next ) {
60
106
                        struct berval bv;
 
107
                        char *ptr;
61
108
                        int len;
62
109
 
63
 
                        bv.bv_len = ci->ci_dn.bv_len + STRLENOF("\"\" ") +
64
 
                                ci->ci_ad->ad_cname.bv_len;
 
110
                        /* calculate the length & malloc memory */
 
111
                        bv.bv_len = ci->ci_dn.bv_len + STRLENOF("\"\" ");
 
112
                        for (idx=0; idx<ci->ci_ad_num; idx++) {
 
113
                                bv.bv_len += ci->ci_ad[idx]->ad_cname.bv_len;
 
114
                                if (idx<(ci->ci_ad_num-1)) { 
 
115
                                        bv.bv_len++;
 
116
                                }
 
117
                        }
65
118
                        bv.bv_val = ch_malloc( bv.bv_len + 1 );
66
 
                        len = snprintf( bv.bv_val, bv.bv_len + 1, "\"%s\" %s",
67
 
                                ci->ci_dn.bv_val, ci->ci_ad->ad_cname.bv_val );
68
 
                        assert( len == bv.bv_len );
 
119
 
 
120
                        /* copy the value and update len */
 
121
                        len = snprintf( bv.bv_val, bv.bv_len + 1, "\"%s\" ", 
 
122
                                ci->ci_dn.bv_val);
 
123
                        ptr = bv.bv_val + len;
 
124
                        for (idx=0; idx<ci->ci_ad_num; idx++) {
 
125
                                ptr = lutil_strncopy( ptr,
 
126
                                        ci->ci_ad[idx]->ad_cname.bv_val,
 
127
                                        ci->ci_ad[idx]->ad_cname.bv_len);
 
128
                                if (idx<(ci->ci_ad_num-1)) {
 
129
                                        *ptr++ = ',';
 
130
                                }
 
131
                        }
 
132
                        *ptr = '\0';
 
133
                        bv.bv_len = ptr - bv.bv_val;
 
134
 
69
135
                        ber_bvarray_add( &c->rvalue_vals, &bv );
70
136
                        rc = 0;
71
137
                }
98
164
                collect_info *ci;
99
165
                struct berval bv, dn;
100
166
                const char *text;
101
 
                AttributeDescription *ad = NULL;
102
 
 
 
167
                int idx, count=0;
 
168
                char *arg;
 
169
 
 
170
                /* count delimiters in attribute argument */
 
171
                arg = strtok(c->argv[2], ",");
 
172
                while (arg!=NULL) {
 
173
                        count++;
 
174
                        arg = strtok(NULL, ",");
 
175
                }
 
176
 
 
177
                /* allocate config info with room for attribute array */
 
178
                ci = ch_malloc( sizeof( collect_info ) +
 
179
                        sizeof( AttributeDescription * ) * count );
 
180
 
 
181
                /* validate and normalize dn */
103
182
                ber_str2bv( c->argv[1], 0, 0, &bv );
104
183
                if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL ) ) {
105
184
                        snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid DN: \"%s\"",
108
187
                                "%s: %s\n", c->log, c->cr_msg, 0 );
109
188
                        return ARG_BAD_CONF;
110
189
                }
111
 
                if ( slap_str2ad( c->argv[2], &ad, &text ) ) {
112
 
                        snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"",
113
 
                                c->argv[0], c->argv[2] );
114
 
                        Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
115
 
                                "%s: %s\n", c->log, c->cr_msg, 0 );
116
 
                        return ARG_BAD_CONF;
 
190
 
 
191
                /* load attribute description for attribute list */
 
192
                arg = c->argv[2];
 
193
                for( idx=0; idx<count; idx++) {
 
194
                        ci->ci_ad[idx] = NULL;
 
195
 
 
196
                        if ( slap_str2ad( arg, &ci->ci_ad[idx], &text ) ) {
 
197
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), 
 
198
                                        "%s attribute description unknown: \"%s\"",
 
199
                                        c->argv[0], arg);
 
200
                                Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
 
201
                                        "%s: %s\n", c->log, c->cr_msg, 0 );
 
202
                                return ARG_BAD_CONF;
 
203
                        }
 
204
                        while(*arg!='\0') {
 
205
                                arg++; /* skip to end of argument */
 
206
                        }
 
207
                        if (idx<count-1) {
 
208
                                arg++; /* skip inner delimiters */
 
209
                        }
117
210
                }
118
211
 
119
212
                /* The on->on_bi.bi_private pointer can be used for
120
213
                 * anything this instance of the overlay needs.
121
214
                 */
122
 
                ci = ch_malloc( sizeof( collect_info ));
123
 
                ci->ci_ad = ad;
 
215
                ci->ci_ad[count] = NULL;
 
216
                ci->ci_ad_num = count;
124
217
                ci->ci_dn = dn;
125
 
                ci->ci_next = on->on_bi.bi_private;
126
 
                on->on_bi.bi_private = ci;
 
218
 
 
219
                /* creates list of ci's ordered by dn length */ 
 
220
                insert_ordered ( on, ci );
 
221
 
127
222
                rc = 0;
128
223
                }
129
224
        }
167
262
}
168
263
 
169
264
static int
 
265
collect_modify( Operation *op, SlapReply *rs)
 
266
{
 
267
        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
 
268
        collect_info *ci = on->on_bi.bi_private;
 
269
        Modifications *ml;
 
270
        char errMsg[100];
 
271
        int idx;
 
272
 
 
273
        for ( ml = op->orm_modlist; ml != NULL; ml = ml->sml_next) {
 
274
                for (; ci; ci=ci->ci_next ) {
 
275
                        /* Is this entry an ancestor of this collectinfo ? */
 
276
                        if (!dnIsSuffix(&op->o_req_ndn, &ci->ci_dn)) {
 
277
                                /* this collectinfo does not match */
 
278
                                continue;
 
279
                        }
 
280
 
 
281
                        /* Is this entry the same as the template DN ? */
 
282
                        if ( dn_match(&op->o_req_ndn, &ci->ci_dn)) {
 
283
                                /* all changes in this ci are allowed */
 
284
                                continue;
 
285
                        }
 
286
 
 
287
                        /* check for collect attributes - disallow modify if present */
 
288
                        for(idx=0; idx<ci->ci_ad_num; idx++) {
 
289
                                if (ml->sml_desc == ci->ci_ad[idx]) {
 
290
                                        rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
 
291
                                        snprintf( errMsg, sizeof( errMsg ), 
 
292
                                                "cannot change virtual attribute '%s'",
 
293
                                                ci->ci_ad[idx]->ad_cname.bv_val);
 
294
                                        rs->sr_text = errMsg;
 
295
                                        send_ldap_result( op, rs );
 
296
                                        return rs->sr_err;
 
297
                                }
 
298
                        }
 
299
                }
 
300
 
 
301
        }
 
302
 
 
303
        return SLAP_CB_CONTINUE;
 
304
}
 
305
 
 
306
static int
170
307
collect_response( Operation *op, SlapReply *rs )
171
308
{
172
309
        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
181
318
                op->o_bd->bd_info = (BackendInfo *)on->on_info;
182
319
 
183
320
                for (; ci; ci=ci->ci_next ) {
184
 
                        BerVarray vals = NULL;
185
 
 
186
 
                        /* Is our configured entry an ancestor of this one? */
187
 
                        if ( !dnIsSuffix( &rs->sr_entry->e_nname, &ci->ci_dn ))
188
 
                                continue;
189
 
 
190
 
                        /* Extract the values of the desired attribute from
191
 
                         * the ancestor entry
192
 
                         */
193
 
                        rc = backend_attribute( op, NULL, &ci->ci_dn, ci->ci_ad, &vals, ACL_READ );
194
 
 
195
 
                        /* If there are any values, merge them into the
196
 
                         * current entry
197
 
                         */
198
 
                        if ( vals ) {
199
 
                                /* The current entry may live in a cache, so
200
 
                                 * don't modify it directly. Make a copy and
201
 
                                 * work with that instead.
202
 
                                 */
203
 
                                if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) {
204
 
                                        rs->sr_entry = entry_dup( rs->sr_entry );
205
 
                                        rs->sr_flags |= REP_ENTRY_MODIFIABLE |
206
 
                                                REP_ENTRY_MUSTBEFREED;
 
321
                        int idx=0;
 
322
 
 
323
                        /* Is this entry an ancestor of this collectinfo ? */
 
324
                        if (!dnIsSuffix(&rs->sr_entry->e_nname, &ci->ci_dn)) {
 
325
                                /* collectinfo does not match */
 
326
                                continue;
 
327
                        }
 
328
 
 
329
                        /* Is this entry the same as the template DN ? */
 
330
                        if ( dn_match(&rs->sr_entry->e_nname, &ci->ci_dn)) {
 
331
                                /* dont apply change to parent */
 
332
                                continue;
 
333
                        }
 
334
 
 
335
                        /* The current entry may live in a cache, so
 
336
                        * don't modify it directly. Make a copy and
 
337
                        * work with that instead.
 
338
                        */
 
339
                        if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) {
 
340
                                rs->sr_entry = entry_dup( rs->sr_entry );
 
341
                                rs->sr_flags |= REP_ENTRY_MODIFIABLE |
 
342
                                        REP_ENTRY_MUSTBEFREED;
 
343
                        }
 
344
 
 
345
                        /* Loop for each attribute in this collectinfo */
 
346
                        for(idx=0; idx<ci->ci_ad_num; idx++) {
 
347
                                BerVarray vals = NULL;
 
348
 
 
349
                                /* Extract the values of the desired attribute from
 
350
                                 * the ancestor entry */
 
351
                                rc = backend_attribute( op, NULL, &ci->ci_dn, 
 
352
                                        ci->ci_ad[idx], &vals, ACL_READ );
 
353
 
 
354
                                /* If there are any values, merge them into the
 
355
                                 * current search result
 
356
                                 */
 
357
                                if ( vals ) {
 
358
                                        attr_merge( rs->sr_entry, ci->ci_ad[idx], 
 
359
                                                vals, NULL );
 
360
                                        ber_bvarray_free_x( vals, op->o_tmpmemctx );
207
361
                                }
208
 
                                attr_merge( rs->sr_entry, ci->ci_ad, vals, NULL );
209
 
                                ber_bvarray_free_x( vals, op->o_tmpmemctx );
210
362
                        }
211
363
                }
212
364
        }
 
365
 
213
366
        /* Default is to just fall through to the normal processing */
214
367
        return SLAP_CB_CONTINUE;
215
368
}
221
374
 
222
375
        collect.on_bi.bi_type = "collect";
223
376
        collect.on_bi.bi_db_destroy = collect_destroy;
 
377
        collect.on_bi.bi_op_modify = collect_modify;
224
378
        collect.on_response = collect_response;
225
379
 
226
380
        collect.on_bi.bi_cf_ocs = collectocs;