addpartial-overlay.c 12.9 KB
Newer Older
1
2
3
/* addpartial-overlay.c */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
Gavin Henry's avatar
Gavin Henry committed
4
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 2004-2020 The OpenLDAP Foundation.
6
 * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
Gavin Henry's avatar
Gavin Henry committed
7
8
9
10
11
12
13
14
15
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * http://www.OpenLDAP.org/license.html.
16
17
18
19
20
21
 */
/* ACKNOLEDGEDMENTS:
 * This work was initially developed by David Hawes of Virginia Tech
 * for inclusion in OpenLDAP Software.
 */
/* addpartial-overlay
Gavin Henry's avatar
Gavin Henry committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 *
 * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
 * change has actually taken place for that record, and then performs a modify
 * request for those values that have changed (modified, added, deleted).  If
 * the record has not changed in any way, it is ignored.  If the record does not
 * exist, the record falls through to the normal add mechanism.  This overlay is
 * useful for replicating from sources that are not LDAPs where it is easier to
 * build entire records than to determine the changes (i.e. a database). 
 */

#include "portable.h" 
#include "slap.h"

static int collect_error_msg_cb( Operation *op, SlapReply *rs);

static slap_overinst addpartial;

/**
 *  The meat of the overlay.  Search for the record, determine changes, take
 *  action or fall through.
 */
static int addpartial_add( Operation *op, SlapReply *rs)
{
    Operation nop = *op;
    Entry *toAdd = NULL;
47
    Entry *found = NULL;
Gavin Henry's avatar
Gavin Henry committed
48
49
50
51
52
53
    slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
    int rc;

    toAdd = op->oq_add.rs_e;

    Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
54
          addpartial.on_bi.bi_type, toAdd->e_nname.bv_val );
Gavin Henry's avatar
Gavin Henry committed
55
56

    /* if the user doesn't have access, fall through to the normal ADD */
Howard Chu's avatar
Howard Chu committed
57
58
    if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
                       NULL, ACL_WRITE, NULL))
Gavin Henry's avatar
Gavin Henry committed
59
60
61
62
    {
        return SLAP_CB_CONTINUE;
    }

63
    rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
Gavin Henry's avatar
Gavin Henry committed
64
65

    if(rc != LDAP_SUCCESS)
66
67
68
    {
        Debug(LDAP_DEBUG_TRACE,
              "%s: no entry found, falling through to normal add\n",
69
              addpartial.on_bi.bi_type );
Gavin Henry's avatar
Gavin Henry committed
70
        return SLAP_CB_CONTINUE;
71
    }
Gavin Henry's avatar
Gavin Henry committed
72
73
    else
    { 
74
        Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type );
Gavin Henry's avatar
Gavin Henry committed
75
76
77
78
79
80
81
82
83
84
85

        if(found)
        {
            Attribute *attr = NULL;
            Attribute *at = NULL;
            int ret;
            Modifications *mods = NULL;
            Modifications **modtail = &mods;
            Modifications *mod = NULL;

            Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
86
                  addpartial.on_bi.bi_type );
Gavin Henry's avatar
Gavin Henry committed
87
88
89
90
91
92
93
94
95
96
97

           /* determine if the changes are in the found entry */ 
            for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
            {
                if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;

                at = attr_find(found->e_attrs, attr->a_desc);
                if(!at)
                {
                    Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
                          addpartial.on_bi.bi_type,
98
                          attr->a_desc->ad_cname.bv_val );
Gavin Henry's avatar
Gavin Henry committed
99
100
101
102
103
104
105
                    mod = (Modifications *) ch_malloc(sizeof(
                                                            Modifications));
                    mod->sml_flags = 0;
                    mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
                    mod->sml_op &= LDAP_MOD_OP;
                    mod->sml_next = NULL;
                    mod->sml_desc = attr->a_desc;
106
                    mod->sml_type = attr->a_desc->ad_cname;
Gavin Henry's avatar
Gavin Henry committed
107
108
                    mod->sml_values = attr->a_vals;
                    mod->sml_nvalues = attr->a_nvals;
109
                    mod->sml_numvals = attr->a_numvals;
Gavin Henry's avatar
Gavin Henry committed
110
111
112
113
114
115
116
117
118
119
120
                    *modtail = mod;
                    modtail = &mod->sml_next;
                }
                else
                {
                    MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
                    struct berval *bv;
                    const char *text;
                    int acount , bcount;
                    Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
                          addpartial.on_bi.bi_type,
121
                          attr->a_desc->ad_cname.bv_val );
Gavin Henry's avatar
Gavin Henry committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

                    for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 
                        bv++, acount++)
                    {
                        /* count num values for attr */
                    }
                    for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 
                        bv++, bcount++)
                    {
                        /* count num values for attr */
                    }
                    if(acount != bcount)
                    {
                        Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
                              addpartial.on_bi.bi_type,
137
                              "replace all" );
Gavin Henry's avatar
Gavin Henry committed
138
139
140
141
142
143
144
                        mod = (Modifications *) ch_malloc(sizeof(
                                                                Modifications));
                        mod->sml_flags = 0;
                        mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
                        mod->sml_op &= LDAP_MOD_OP;
                        mod->sml_next = NULL;
                        mod->sml_desc = attr->a_desc;
145
                        mod->sml_type = attr->a_desc->ad_cname;
Gavin Henry's avatar
Gavin Henry committed
146
147
                        mod->sml_values = attr->a_vals;
                        mod->sml_nvalues = attr->a_nvals;
148
                        mod->sml_numvals = attr->a_numvals;
Gavin Henry's avatar
Gavin Henry committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
                        *modtail = mod;
                        modtail = &mod->sml_next;
                        continue;
                    }
                    
                    for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
                    {
                        struct berval *v;
                        ret = -1;
                        
                        for(v = at->a_vals; v->bv_val != NULL; v++)
                        {
                            int r;
                            if(mr && ((r = value_match(&ret, attr->a_desc, mr,
                                           SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
                                           bv, v, &text)) == 0))
                            {
                                if(ret == 0)
                                    break;
                            }
                            else
                            {
                                Debug(LDAP_DEBUG_TRACE,
                                      "%s: \tvalue DNE, r: %d \n",
                                      addpartial.on_bi.bi_type,
174
                                      r );
Gavin Henry's avatar
Gavin Henry committed
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
                                ret = strcmp(bv->bv_val, v->bv_val);
                                if(ret == 0)
                                    break;
                            }
                        }

                        if(ret == 0)
                        {
                            Debug(LDAP_DEBUG_TRACE,
                                  "%s: \tvalue %s exists, ret: %d\n",
                                  addpartial.on_bi.bi_type, bv->bv_val, ret);
                        }
                        else
                        {
                            Debug(LDAP_DEBUG_TRACE,
                                  "%s: \tvalue %s DNE, ret: %d\n",
                                  addpartial.on_bi.bi_type, bv->bv_val, ret);
                            mod = (Modifications *) ch_malloc(sizeof(
                                                                Modifications));
                            mod->sml_flags = 0;
                            mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
                            mod->sml_op &= LDAP_MOD_OP;
                            mod->sml_next = NULL;
                            mod->sml_desc = attr->a_desc;
199
                            mod->sml_type = attr->a_desc->ad_cname;
Gavin Henry's avatar
Gavin Henry committed
200
201
                            mod->sml_values = attr->a_vals;
                            mod->sml_nvalues = attr->a_nvals;
202
                            mod->sml_numvals = attr->a_numvals;
Gavin Henry's avatar
Gavin Henry committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
                            *modtail = mod;
                            modtail = &mod->sml_next;
                            break;
                        }
                    }
                }
            }

            /* determine if any attributes were deleted */
            for(attr = found->e_attrs; attr; attr = attr->a_next)
            {
                if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;

                at = NULL;
                at = attr_find(toAdd->e_attrs, attr->a_desc);
                if(!at)
                {
                    Debug(LDAP_DEBUG_TRACE,
                          "%s: Attribute %s not found in new entry!!!\n",
                          addpartial.on_bi.bi_type,
223
                          attr->a_desc->ad_cname.bv_val );
Gavin Henry's avatar
Gavin Henry committed
224
225
226
227
228
229
                    mod = (Modifications *) ch_malloc(sizeof(
                                                        Modifications));
                    mod->sml_flags = 0;
                    mod->sml_op = LDAP_MOD_REPLACE;
                    mod->sml_next = NULL;
                    mod->sml_desc = attr->a_desc;
230
                    mod->sml_type = attr->a_desc->ad_cname;
Gavin Henry's avatar
Gavin Henry committed
231
232
                    mod->sml_values = NULL;
                    mod->sml_nvalues = NULL;
233
                    mod->sml_numvals = 0;
Gavin Henry's avatar
Gavin Henry committed
234
235
236
237
238
239
240
241
                    *modtail = mod;
                    modtail = &mod->sml_next;
                }
                else
                {
                    Debug(LDAP_DEBUG_TRACE,
                          "%s: Attribute %s found in new entry\n",
                          addpartial.on_bi.bi_type,
242
                          at->a_desc->ad_cname.bv_val );
Gavin Henry's avatar
Gavin Henry committed
243
244
245
                }
            }

246
247
            overlay_entry_release_ov(&nop, found, 0, on);

Gavin Henry's avatar
Gavin Henry committed
248
249
            if(mods)
            {
250
251
252
253
254
255
                Modifications *m = NULL;
                Modifications *toDel;
                int modcount;
                slap_callback nullcb = { NULL, collect_error_msg_cb, 
                                         NULL, NULL };

Gavin Henry's avatar
Gavin Henry committed
256
                Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
257
                      addpartial.on_bi.bi_type );
258
259
260
261
262
263
264
265
266

                nop.o_tag = LDAP_REQ_MODIFY;
                nop.orm_modlist = mods;
                nop.orm_no_opattrs = 0;
                nop.o_callback = &nullcb;
                nop.o_bd->bd_info = (BackendInfo *) on->on_info;

                for(m = mods, modcount = 0; m; m = m->sml_next, 
                    modcount++)
Gavin Henry's avatar
Gavin Henry committed
267
                {
268
269
                    /* count number of mods */
                }
Gavin Henry's avatar
Gavin Henry committed
270

271
                Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
272
                      addpartial.on_bi.bi_type, modcount );
Gavin Henry's avatar
Gavin Henry committed
273

274
275
                if(nop.o_bd->be_modify)
                {
276
                    SlapReply nrs = { REP_RESULT };
Gavin Henry's avatar
Gavin Henry committed
277
                    rc = (nop.o_bd->be_modify)(&nop, &nrs);
278
                }
Gavin Henry's avatar
Gavin Henry committed
279

280
281
282
283
                if(rc == LDAP_SUCCESS)
                {
                    Debug(LDAP_DEBUG_TRACE,
                          "%s: modify successful\n",
284
                          addpartial.on_bi.bi_type );
285
286
287
288
                }
                else
                {
                    Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
289
                          addpartial.on_bi.bi_type, rc );
290
291
                    rs->sr_err = rc;
                    if(nullcb.sc_private)
Gavin Henry's avatar
Gavin Henry committed
292
                    {
293
                        rs->sr_text = nullcb.sc_private;
Gavin Henry's avatar
Gavin Henry committed
294
                    }
295
                }
Gavin Henry's avatar
Gavin Henry committed
296

297
                Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
298
                      addpartial.on_bi.bi_type );
Gavin Henry's avatar
Gavin Henry committed
299

300
301
302
303
                for(toDel = mods; toDel; toDel = mods)
                {
                    mods = mods->sml_next;
                    ch_free(toDel);
Gavin Henry's avatar
Gavin Henry committed
304
305
306
307
308
                }
            }
            else
            {
                Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
309
                      addpartial.on_bi.bi_type );
Gavin Henry's avatar
Gavin Henry committed
310
311
312
313
314
            }
        }
        else
        {
            Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
315
                  addpartial.on_bi.bi_type );
Gavin Henry's avatar
Gavin Henry committed
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
        }

        op->o_callback = NULL;
        send_ldap_result( op, rs );
        ch_free((void *)rs->sr_text);
        rs->sr_text = NULL;

        return LDAP_SUCCESS;
    }
}

static int collect_error_msg_cb( Operation *op, SlapReply *rs)
{
    if(rs->sr_text)
    {
        op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
    }

    return LDAP_SUCCESS;
}

int addpartial_init() 
{
    addpartial.on_bi.bi_type = "addpartial";
340
	addpartial.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
Gavin Henry's avatar
Gavin Henry committed
341
342
343
344
345
346
347
    addpartial.on_bi.bi_op_add = addpartial_add;

    return (overlay_register(&addpartial));
}

int init_module(int argc, char *argv[]) 
{
348
    return addpartial_init();
Gavin Henry's avatar
Gavin Henry committed
349
}