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