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