]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/addpartial/addpartial-overlay.c
addpartial overlay update for 2.4.6 (ITS#3593)
[openldap] / contrib / slapd-modules / addpartial / addpartial-overlay.c
1 /**
2  * $Id: addpartial-overlay.c 6588 2007-11-07 18:29:25Z dhawes $
3  *
4  * Copyright (C) 2004 Virginia Tech, David Hawes.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * http://www.OpenLDAP.org/license.html.
14  *
15  * SEE LICENSE FOR MORE INFORMATION
16  *
17  * Author:  David H. Hawes, Jr.
18  * Email:   dhawes@vt.edu
19  * Version: $Revision: 6588 $
20  * Updated: $Date: 2007-11-07 13:29:25 -0500 (Wed, 07 Nov 2007) $
21  * 
22  * addpartial-overlay
23  *
24  * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
25  * change has actually taken place for that record, and then performs a modify
26  * request for those values that have changed (modified, added, deleted).  If
27  * the record has not changed in any way, it is ignored.  If the record does not
28  * exist, the record falls through to the normal add mechanism.  This overlay is
29  * useful for replicating from sources that are not LDAPs where it is easier to
30  * build entire records than to determine the changes (i.e. a database). 
31  */
32
33 #include "portable.h" 
34 #include "slap.h"
35
36 static int addpartial_search_cb( Operation *op, SlapReply *rs);
37 static int collect_error_msg_cb( Operation *op, SlapReply *rs);
38
39 static slap_overinst addpartial;
40
41 /**
42  *  The meat of the overlay.  Search for the record, determine changes, take
43  *  action or fall through.
44  */
45 static int addpartial_add( Operation *op, SlapReply *rs)
46 {
47     Operation nop = *op;
48     SlapReply nrs = { REP_RESULT };
49     Filter *filter = NULL;
50     Entry *toAdd = NULL;
51     struct berval fstr = BER_BVNULL;
52     slap_callback cb = { NULL, addpartial_search_cb, NULL, NULL };
53     slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
54     int rc;
55
56     toAdd = op->oq_add.rs_e;
57
58     Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
59           addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
60
61     /* if the user doesn't have access, fall through to the normal ADD */
62     if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
63                        NULL, ACL_WRITE, NULL))
64     {
65         return SLAP_CB_CONTINUE;
66     }
67     
68     rs->sr_text = NULL;
69
70     nop.o_callback = &cb;
71     op->o_bd->bd_info = (BackendInfo *) on->on_info;
72     nop.o_tag = LDAP_REQ_SEARCH;
73     nop.o_ctrls = NULL;
74     
75     filter = str2filter("(objectclass=*)");
76     filter2bv(filter, &fstr);
77
78     nop.ors_scope = LDAP_SCOPE_BASE;
79     nop.ors_deref = LDAP_DEREF_NEVER;
80     nop.ors_slimit = -1;//SLAP_NO_LIMIT;
81     nop.ors_tlimit = -1;//SLAP_NO_LIMIT;
82     nop.ors_attrsonly = 0;
83     nop.ors_attrs = slap_anlist_no_attrs;
84     nop.ors_filter = filter;
85     nop.ors_filterstr = fstr;
86
87     memset(&nrs, 0, sizeof(nrs));
88     nrs.sr_type = REP_RESULT;
89     nrs.sr_err = LDAP_SUCCESS;
90     nrs.sr_entry = NULL;
91     nrs.sr_flags |= REP_ENTRY_MUSTBEFREED;
92     nrs.sr_text = NULL;
93
94     Debug(LDAP_DEBUG_TRACE, "%s: performing search\n", addpartial.on_bi.bi_type,
95           0,0);
96
97     if(nop.o_bd->be_search)
98     {
99         rc = nop.o_bd->be_search(&nop, &nrs);
100         Debug(LDAP_DEBUG_TRACE, "%s: search performed\n",
101               addpartial.on_bi.bi_type,0,0);
102     }
103     else
104     {
105         Debug(LDAP_DEBUG_TRACE, "%s: backend missing search function\n",
106               addpartial.on_bi.bi_type,0,0);
107     }
108
109     if(filter)
110         filter_free(filter);
111     if(fstr.bv_val)
112         ch_free(fstr.bv_val);
113
114     if(rc != LDAP_SUCCESS)
115         return SLAP_CB_CONTINUE;
116     else
117     { 
118         Entry *found = NULL;
119         Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
120               0,0);
121         found = (Entry *) cb.sc_private;
122
123         if(found)
124         {
125             Attribute *attr = NULL;
126             Attribute *at = NULL;
127             int ret;
128             Modifications *mods = NULL;
129             Modifications **modtail = &mods;
130             Modifications *mod = NULL;
131
132             Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
133                   addpartial.on_bi.bi_type,0,0);
134
135            /* determine if the changes are in the found entry */ 
136             for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
137             {
138                 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
139
140                 at = attr_find(found->e_attrs, attr->a_desc);
141                 if(!at)
142                 {
143                     Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
144                           addpartial.on_bi.bi_type,
145                           attr->a_desc->ad_cname.bv_val,0);
146                     mod = (Modifications *) ch_malloc(sizeof(
147                                                             Modifications));
148                     mod->sml_flags = 0;
149                     mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
150                     mod->sml_op &= LDAP_MOD_OP;
151                     mod->sml_next = NULL;
152                     mod->sml_desc = attr->a_desc;
153                     mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val;
154                     mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
155                     mod->sml_values = attr->a_vals;
156                     mod->sml_nvalues = attr->a_nvals;
157                     mod->sml_numvals = attr->a_numvals;
158                     *modtail = mod;
159                     modtail = &mod->sml_next;
160                 }
161                 else
162                 {
163                     MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
164                     struct berval *bv;
165                     const char *text;
166                     int acount , bcount;
167                     Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
168                           addpartial.on_bi.bi_type,
169                           attr->a_desc->ad_cname.bv_val,0);
170
171                     for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 
172                         bv++, acount++)
173                     {
174                         /* count num values for attr */
175                     }
176                     for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 
177                         bv++, bcount++)
178                     {
179                         /* count num values for attr */
180                     }
181                     if(acount != bcount)
182                     {
183                         Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
184                               addpartial.on_bi.bi_type,
185                               "replace all",0);
186                         mod = (Modifications *) ch_malloc(sizeof(
187                                                                 Modifications));
188                         mod->sml_flags = 0;
189                         mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
190                         mod->sml_op &= LDAP_MOD_OP;
191                         mod->sml_next = NULL;
192                         mod->sml_desc = attr->a_desc;
193                         mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val;
194                         mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
195                         mod->sml_values = attr->a_vals;
196                         mod->sml_nvalues = attr->a_nvals;
197                         mod->sml_numvals = attr->a_numvals;
198                         *modtail = mod;
199                         modtail = &mod->sml_next;
200                         continue;
201                     }
202                     
203                     for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
204                     {
205                         struct berval *v;
206                         ret = -1;
207                         
208                         for(v = at->a_vals; v->bv_val != NULL; v++)
209                         {
210                             int r;
211                             if(mr && ((r = value_match(&ret, attr->a_desc, mr,
212                                            SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
213                                            bv, v, &text)) == 0))
214                             {
215                                 if(ret == 0)
216                                     break;
217                             }
218                             else
219                             {
220                                 Debug(LDAP_DEBUG_TRACE,
221                                       "%s: \tvalue DNE, r: %d \n",
222                                       addpartial.on_bi.bi_type,
223                                       r,0);
224                                 ret = strcmp(bv->bv_val, v->bv_val);
225                                 if(ret == 0)
226                                     break;
227                             }
228                         }
229
230                         if(ret == 0)
231                         {
232                             Debug(LDAP_DEBUG_TRACE,
233                                   "%s: \tvalue %s exists, ret: %d\n",
234                                   addpartial.on_bi.bi_type, bv->bv_val, ret);
235                         }
236                         else
237                         {
238                             Debug(LDAP_DEBUG_TRACE,
239                                   "%s: \tvalue %s DNE, ret: %d\n",
240                                   addpartial.on_bi.bi_type, bv->bv_val, ret);
241                             mod = (Modifications *) ch_malloc(sizeof(
242                                                                 Modifications));
243                             mod->sml_flags = 0;
244                             mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
245                             mod->sml_op &= LDAP_MOD_OP;
246                             mod->sml_next = NULL;
247                             mod->sml_desc = attr->a_desc;
248                             mod->sml_type.bv_val = 
249                                                   attr->a_desc->ad_cname.bv_val;
250                             mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
251                             mod->sml_values = attr->a_vals;
252                             mod->sml_nvalues = attr->a_nvals;
253                             mod->sml_numvals = attr->a_numvals;
254                             *modtail = mod;
255                             modtail = &mod->sml_next;
256                             break;
257                         }
258                     }
259                 }
260             }
261
262             /* determine if any attributes were deleted */
263             for(attr = found->e_attrs; attr; attr = attr->a_next)
264             {
265                 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
266
267                 at = NULL;
268                 at = attr_find(toAdd->e_attrs, attr->a_desc);
269                 if(!at)
270                 {
271                     Debug(LDAP_DEBUG_TRACE,
272                           "%s: Attribute %s not found in new entry!!!\n",
273                           addpartial.on_bi.bi_type,
274                           attr->a_desc->ad_cname.bv_val, 0);
275                     mod = (Modifications *) ch_malloc(sizeof(
276                                                         Modifications));
277                     mod->sml_flags = 0;
278                     mod->sml_op = LDAP_MOD_REPLACE;
279                     mod->sml_next = NULL;
280                     mod->sml_desc = attr->a_desc;
281                     mod->sml_type.bv_val = 
282                                           attr->a_desc->ad_cname.bv_val;
283                     mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
284                     mod->sml_values = NULL;
285                     mod->sml_nvalues = NULL;
286                     mod->sml_numvals = 0;
287                     *modtail = mod;
288                     modtail = &mod->sml_next;
289                 }
290                 else
291                 {
292                     Debug(LDAP_DEBUG_TRACE,
293                           "%s: Attribute %s found in new entry\n",
294                           addpartial.on_bi.bi_type,
295                           at->a_desc->ad_cname.bv_val, 0);
296                 }
297             }
298
299             if(mods)
300             {
301                 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
302                       addpartial.on_bi.bi_type, 0, 0);
303                 if(nop.o_bd->be_modify)
304                 {
305                     Modifications *m = NULL;
306                     int modcount;
307                     slap_callback nullcb = { NULL, collect_error_msg_cb, 
308                                              NULL, NULL };
309                     char textbuf[SLAP_TEXT_BUFLEN];
310                     size_t textlen = sizeof textbuf;
311
312                     memset(&nrs, 0, sizeof(nrs));
313                     nrs.sr_type = REP_RESULT;
314                     nrs.sr_err = LDAP_SUCCESS;
315                     nrs.sr_entry = NULL;
316                     nrs.sr_text = NULL;
317
318                     nop.o_tag = LDAP_REQ_MODIFY;
319                     nop.orm_modlist = mods;
320                     nop.o_callback = &nullcb;
321                     nop.o_bd->bd_info = (BackendInfo *) on->on_info;
322
323                     for(m = mods, modcount = 0; m; m = m->sml_next, 
324                         modcount++)
325                     {
326                         /* count number of mods */
327                     }
328
329                     Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
330                           addpartial.on_bi.bi_type, modcount, 0);
331
332                     rc = (nop.o_bd->be_modify)(&nop, &nrs);
333
334                     if(rc == LDAP_SUCCESS)
335                     {
336                         Debug(LDAP_DEBUG_TRACE,
337                               "%s: modify successful\n",
338                               addpartial.on_bi.bi_type, 0, 0);
339                     }
340                     else
341                     {
342                         Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
343                               addpartial.on_bi.bi_type, rc, 0);
344                         rs->sr_err = rc;
345                         if(nrs.sr_text)
346                         {
347                             rs->sr_text = nullcb.sc_private;
348                         }
349                     }
350
351                     Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
352                           addpartial.on_bi.bi_type, 0, 0);
353
354                     if(mods != NULL)
355                     {
356                         Modifications *toDel;
357
358                         for(toDel = mods; toDel; toDel = mods)
359                         {
360                             mods = mods->sml_next;
361                             ch_free(toDel);
362                         }
363                     }
364                 }
365             }
366             else
367             {
368                 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
369                       addpartial.on_bi.bi_type, 0, 0);
370             }
371
372             if(found != NULL)
373                 entry_free(found);
374         }
375         else
376         {
377             Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
378                   addpartial.on_bi.bi_type, 0, 0);
379         }
380
381         op->o_callback = NULL;
382         send_ldap_result( op, rs );
383         ch_free((void *)rs->sr_text);
384         rs->sr_text = NULL;
385
386         return LDAP_SUCCESS;
387     }
388 }
389
390 static int addpartial_search_cb( Operation *op, SlapReply *rs)
391 {
392     Entry *entry = NULL;
393
394     if(rs->sr_type != REP_SEARCH) return 0;
395         
396     Debug(LDAP_DEBUG_TRACE, "%s: addpartial_search_cb\n",
397           addpartial.on_bi.bi_type, 0, 0);
398
399     if(rs->sr_entry)
400     {
401         Debug(LDAP_DEBUG_TRACE, "%s: dn found: %s\n",
402               addpartial.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0);
403         entry = rs->sr_entry;
404         op->o_callback->sc_private = (void *) entry_dup(entry);
405     }
406
407     return 0;
408 }
409
410 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
411 {
412     if(rs->sr_text)
413     {
414         op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
415     }
416
417     return LDAP_SUCCESS;
418 }
419
420 int addpartial_init() 
421 {
422     addpartial.on_bi.bi_type = "addpartial";
423     addpartial.on_bi.bi_op_add = addpartial_add;
424
425     return (overlay_register(&addpartial));
426 }
427
428 int init_module(int argc, char *argv[]) 
429 {
430         return addpartial_init();
431 }