1/* addpartial-overlay.c */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2004-2011 The OpenLDAP Foundation.
6 * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * http://www.OpenLDAP.org/license.html.
16 */
17/* ACKNOLEDGEDMENTS:
18 * This work was initially developed by David Hawes of Virginia Tech
19 * for inclusion in OpenLDAP Software.
20 */
21/* addpartial-overlay
22 *
23 * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
24 * change has actually taken place for that record, and then performs a modify
25 * request for those values that have changed (modified, added, deleted).  If
26 * the record has not changed in any way, it is ignored.  If the record does not
27 * exist, the record falls through to the normal add mechanism.  This overlay is
28 * useful for replicating from sources that are not LDAPs where it is easier to
29 * build entire records than to determine the changes (i.e. a database).
30 */
31
32#include "portable.h"
33#include "slap.h"
34
35static int collect_error_msg_cb( Operation *op, SlapReply *rs);
36
37static slap_overinst addpartial;
38
39/**
40 *  The meat of the overlay.  Search for the record, determine changes, take
41 *  action or fall through.
42 */
43static int addpartial_add( Operation *op, SlapReply *rs)
44{
45    Operation nop = *op;
46    Entry *toAdd = NULL;
47    Entry *found = NULL;
48    slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
49    int rc;
50
51    toAdd = op->oq_add.rs_e;
52
53    Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
54          addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
55
56    /* if the user doesn't have access, fall through to the normal ADD */
57    if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
58                       NULL, ACL_WRITE, NULL))
59    {
60        return SLAP_CB_CONTINUE;
61    }
62
63    rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
64
65    if(rc != LDAP_SUCCESS)
66    {
67        Debug(LDAP_DEBUG_TRACE,
68              "%s: no entry found, falling through to normal add\n",
69              addpartial.on_bi.bi_type, 0, 0);
70        return SLAP_CB_CONTINUE;
71    }
72    else
73    {
74        Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
75              0,0);
76
77        if(found)
78        {
79            Attribute *attr = NULL;
80            Attribute *at = NULL;
81            int ret;
82            Modifications *mods = NULL;
83            Modifications **modtail = &mods;
84            Modifications *mod = NULL;
85
86            Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
87                  addpartial.on_bi.bi_type,0,0);
88
89           /* determine if the changes are in the found entry */
90            for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
91            {
92                if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
93
94                at = attr_find(found->e_attrs, attr->a_desc);
95                if(!at)
96                {
97                    Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
98                          addpartial.on_bi.bi_type,
99                          attr->a_desc->ad_cname.bv_val,0);
100                    mod = (Modifications *) ch_malloc(sizeof(
101                                                            Modifications));
102                    mod->sml_flags = 0;
103                    mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
104                    mod->sml_op &= LDAP_MOD_OP;
105                    mod->sml_next = NULL;
106                    mod->sml_desc = attr->a_desc;
107                    mod->sml_type = attr->a_desc->ad_cname;
108                    mod->sml_values = attr->a_vals;
109                    mod->sml_nvalues = attr->a_nvals;
110                    mod->sml_numvals = attr->a_numvals;
111                    *modtail = mod;
112                    modtail = &mod->sml_next;
113                }
114                else
115                {
116                    MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
117                    struct berval *bv;
118                    const char *text;
119                    int acount , bcount;
120                    Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
121                          addpartial.on_bi.bi_type,
122                          attr->a_desc->ad_cname.bv_val,0);
123
124                    for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
125                        bv++, acount++)
126                    {
127                        /* count num values for attr */
128                    }
129                    for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
130                        bv++, bcount++)
131                    {
132                        /* count num values for attr */
133                    }
134                    if(acount != bcount)
135                    {
136                        Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
137                              addpartial.on_bi.bi_type,
138                              "replace all",0);
139                        mod = (Modifications *) ch_malloc(sizeof(
140                                                                Modifications));
141                        mod->sml_flags = 0;
142                        mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
143                        mod->sml_op &= LDAP_MOD_OP;
144                        mod->sml_next = NULL;
145                        mod->sml_desc = attr->a_desc;
146                        mod->sml_type = attr->a_desc->ad_cname;
147                        mod->sml_values = attr->a_vals;
148                        mod->sml_nvalues = attr->a_nvals;
149                        mod->sml_numvals = attr->a_numvals;
150                        *modtail = mod;
151                        modtail = &mod->sml_next;
152                        continue;
153                    }
154
155                    for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
156                    {
157                        struct berval *v;
158                        ret = -1;
159
160                        for(v = at->a_vals; v->bv_val != NULL; v++)
161                        {
162                            int r;
163                            if(mr && ((r = value_match(&ret, attr->a_desc, mr,
164                                           SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
165                                           bv, v, &text)) == 0))
166                            {
167                                if(ret == 0)
168                                    break;
169                            }
170                            else
171                            {
172                                Debug(LDAP_DEBUG_TRACE,
173                                      "%s: \tvalue DNE, r: %d \n",
174                                      addpartial.on_bi.bi_type,
175                                      r,0);
176                                ret = strcmp(bv->bv_val, v->bv_val);
177                                if(ret == 0)
178                                    break;
179                            }
180                        }
181
182                        if(ret == 0)
183                        {
184                            Debug(LDAP_DEBUG_TRACE,
185                                  "%s: \tvalue %s exists, ret: %d\n",
186                                  addpartial.on_bi.bi_type, bv->bv_val, ret);
187                        }
188                        else
189                        {
190                            Debug(LDAP_DEBUG_TRACE,
191                                  "%s: \tvalue %s DNE, ret: %d\n",
192                                  addpartial.on_bi.bi_type, bv->bv_val, ret);
193                            mod = (Modifications *) ch_malloc(sizeof(
194                                                                Modifications));
195                            mod->sml_flags = 0;
196                            mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
197                            mod->sml_op &= LDAP_MOD_OP;
198                            mod->sml_next = NULL;
199                            mod->sml_desc = attr->a_desc;
200                            mod->sml_type = attr->a_desc->ad_cname;
201                            mod->sml_values = attr->a_vals;
202                            mod->sml_nvalues = attr->a_nvals;
203                            mod->sml_numvals = attr->a_numvals;
204                            *modtail = mod;
205                            modtail = &mod->sml_next;
206                            break;
207                        }
208                    }
209                }
210            }
211
212            /* determine if any attributes were deleted */
213            for(attr = found->e_attrs; attr; attr = attr->a_next)
214            {
215                if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
216
217                at = NULL;
218                at = attr_find(toAdd->e_attrs, attr->a_desc);
219                if(!at)
220                {
221                    Debug(LDAP_DEBUG_TRACE,
222                          "%s: Attribute %s not found in new entry!!!\n",
223                          addpartial.on_bi.bi_type,
224                          attr->a_desc->ad_cname.bv_val, 0);
225                    mod = (Modifications *) ch_malloc(sizeof(
226                                                        Modifications));
227                    mod->sml_flags = 0;
228                    mod->sml_op = LDAP_MOD_REPLACE;
229                    mod->sml_next = NULL;
230                    mod->sml_desc = attr->a_desc;
231                    mod->sml_type = attr->a_desc->ad_cname;
232                    mod->sml_values = NULL;
233                    mod->sml_nvalues = NULL;
234                    mod->sml_numvals = 0;
235                    *modtail = mod;
236                    modtail = &mod->sml_next;
237                }
238                else
239                {
240                    Debug(LDAP_DEBUG_TRACE,
241                          "%s: Attribute %s found in new entry\n",
242                          addpartial.on_bi.bi_type,
243                          at->a_desc->ad_cname.bv_val, 0);
244                }
245            }
246
247            overlay_entry_release_ov(&nop, found, 0, on);
248
249            if(mods)
250            {
251                Modifications *m = NULL;
252                Modifications *toDel;
253                int modcount;
254                slap_callback nullcb = { NULL, collect_error_msg_cb,
255                                         NULL, NULL };
256
257                Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
258                      addpartial.on_bi.bi_type, 0, 0);
259
260                nop.o_tag = LDAP_REQ_MODIFY;
261                nop.orm_modlist = mods;
262                nop.orm_no_opattrs = 0;
263                nop.o_callback = &nullcb;
264                nop.o_bd->bd_info = (BackendInfo *) on->on_info;
265
266                for(m = mods, modcount = 0; m; m = m->sml_next,
267                    modcount++)
268                {
269                    /* count number of mods */
270                }
271
272                Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
273                      addpartial.on_bi.bi_type, modcount, 0);
274
275                if(nop.o_bd->be_modify)
276                {
277                    SlapReply nrs = { REP_RESULT };
278                    rc = (nop.o_bd->be_modify)(&nop, &nrs);
279                }
280
281                if(rc == LDAP_SUCCESS)
282                {
283                    Debug(LDAP_DEBUG_TRACE,
284                          "%s: modify successful\n",
285                          addpartial.on_bi.bi_type, 0, 0);
286                }
287                else
288                {
289                    Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
290                          addpartial.on_bi.bi_type, rc, 0);
291                    rs->sr_err = rc;
292                    if(nullcb.sc_private)
293                    {
294                        rs->sr_text = nullcb.sc_private;
295                    }
296                }
297
298                Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
299                      addpartial.on_bi.bi_type, 0, 0);
300
301                for(toDel = mods; toDel; toDel = mods)
302                {
303                    mods = mods->sml_next;
304                    ch_free(toDel);
305                }
306            }
307            else
308            {
309                Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
310                      addpartial.on_bi.bi_type, 0, 0);
311            }
312        }
313        else
314        {
315            Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
316                  addpartial.on_bi.bi_type, 0, 0);
317        }
318
319        op->o_callback = NULL;
320        send_ldap_result( op, rs );
321        ch_free((void *)rs->sr_text);
322        rs->sr_text = NULL;
323
324        return LDAP_SUCCESS;
325    }
326}
327
328static int collect_error_msg_cb( Operation *op, SlapReply *rs)
329{
330    if(rs->sr_text)
331    {
332        op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
333    }
334
335    return LDAP_SUCCESS;
336}
337
338int addpartial_init()
339{
340    addpartial.on_bi.bi_type = "addpartial";
341    addpartial.on_bi.bi_op_add = addpartial_add;
342
343    return (overlay_register(&addpartial));
344}
345
346int init_module(int argc, char *argv[])
347{
348    return addpartial_init();
349}
350