]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/addpartial/addpartial-overlay.c
improvements by David Hawes (ITS#5756)
[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: 8385 $
20  * Updated: $Date: 2008-11-04 12:19:52 -0500 (Tue, 04 Nov 2008) $
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 collect_error_msg_cb( Operation *op, SlapReply *rs);
37
38 static slap_overinst addpartial;
39
40 /**
41  *  The meat of the overlay.  Search for the record, determine changes, take
42  *  action or fall through.
43  */
44 static int addpartial_add( Operation *op, SlapReply *rs)
45 {
46     Operation nop = *op;
47     SlapReply nrs = { REP_RESULT };
48     Entry *toAdd = NULL;
49     Entry *found = NULL;
50     slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
51     int rc;
52
53     toAdd = op->oq_add.rs_e;
54
55     Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
56           addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
57
58     /* if the user doesn't have access, fall through to the normal ADD */
59     if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
60                        NULL, ACL_WRITE, NULL))
61     {
62         return SLAP_CB_CONTINUE;
63     }
64
65     rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
66
67     if(rc != LDAP_SUCCESS)
68     {
69         Debug(LDAP_DEBUG_TRACE,
70               "%s: no entry found, falling through to normal add\n",
71               addpartial.on_bi.bi_type, 0, 0);
72         return SLAP_CB_CONTINUE;
73     }
74     else
75     { 
76         Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
77               0,0);
78
79         if(found)
80         {
81             Attribute *attr = NULL;
82             Attribute *at = NULL;
83             int ret;
84             Modifications *mods = NULL;
85             Modifications **modtail = &mods;
86             Modifications *mod = NULL;
87
88             Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
89                   addpartial.on_bi.bi_type,0,0);
90
91            /* determine if the changes are in the found entry */ 
92             for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
93             {
94                 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
95
96                 at = attr_find(found->e_attrs, attr->a_desc);
97                 if(!at)
98                 {
99                     Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
100                           addpartial.on_bi.bi_type,
101                           attr->a_desc->ad_cname.bv_val,0);
102                     mod = (Modifications *) ch_malloc(sizeof(
103                                                             Modifications));
104                     mod->sml_flags = 0;
105                     mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
106                     mod->sml_op &= LDAP_MOD_OP;
107                     mod->sml_next = NULL;
108                     mod->sml_desc = attr->a_desc;
109                     mod->sml_type = attr->a_desc->ad_cname;
110                     mod->sml_values = attr->a_vals;
111                     mod->sml_nvalues = attr->a_nvals;
112                     mod->sml_numvals = attr->a_numvals;
113                     *modtail = mod;
114                     modtail = &mod->sml_next;
115                 }
116                 else
117                 {
118                     MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
119                     struct berval *bv;
120                     const char *text;
121                     int acount , bcount;
122                     Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
123                           addpartial.on_bi.bi_type,
124                           attr->a_desc->ad_cname.bv_val,0);
125
126                     for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 
127                         bv++, acount++)
128                     {
129                         /* count num values for attr */
130                     }
131                     for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 
132                         bv++, bcount++)
133                     {
134                         /* count num values for attr */
135                     }
136                     if(acount != bcount)
137                     {
138                         Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
139                               addpartial.on_bi.bi_type,
140                               "replace all",0);
141                         mod = (Modifications *) ch_malloc(sizeof(
142                                                                 Modifications));
143                         mod->sml_flags = 0;
144                         mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
145                         mod->sml_op &= LDAP_MOD_OP;
146                         mod->sml_next = NULL;
147                         mod->sml_desc = attr->a_desc;
148                         mod->sml_type = attr->a_desc->ad_cname;
149                         mod->sml_values = attr->a_vals;
150                         mod->sml_nvalues = attr->a_nvals;
151                         mod->sml_numvals = attr->a_numvals;
152                         *modtail = mod;
153                         modtail = &mod->sml_next;
154                         continue;
155                     }
156                     
157                     for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
158                     {
159                         struct berval *v;
160                         ret = -1;
161                         
162                         for(v = at->a_vals; v->bv_val != NULL; v++)
163                         {
164                             int r;
165                             if(mr && ((r = value_match(&ret, attr->a_desc, mr,
166                                            SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
167                                            bv, v, &text)) == 0))
168                             {
169                                 if(ret == 0)
170                                     break;
171                             }
172                             else
173                             {
174                                 Debug(LDAP_DEBUG_TRACE,
175                                       "%s: \tvalue DNE, r: %d \n",
176                                       addpartial.on_bi.bi_type,
177                                       r,0);
178                                 ret = strcmp(bv->bv_val, v->bv_val);
179                                 if(ret == 0)
180                                     break;
181                             }
182                         }
183
184                         if(ret == 0)
185                         {
186                             Debug(LDAP_DEBUG_TRACE,
187                                   "%s: \tvalue %s exists, ret: %d\n",
188                                   addpartial.on_bi.bi_type, bv->bv_val, ret);
189                         }
190                         else
191                         {
192                             Debug(LDAP_DEBUG_TRACE,
193                                   "%s: \tvalue %s DNE, ret: %d\n",
194                                   addpartial.on_bi.bi_type, bv->bv_val, ret);
195                             mod = (Modifications *) ch_malloc(sizeof(
196                                                                 Modifications));
197                             mod->sml_flags = 0;
198                             mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
199                             mod->sml_op &= LDAP_MOD_OP;
200                             mod->sml_next = NULL;
201                             mod->sml_desc = attr->a_desc;
202                             mod->sml_type = attr->a_desc->ad_cname;
203                             mod->sml_values = attr->a_vals;
204                             mod->sml_nvalues = attr->a_nvals;
205                             mod->sml_numvals = attr->a_numvals;
206                             *modtail = mod;
207                             modtail = &mod->sml_next;
208                             break;
209                         }
210                     }
211                 }
212             }
213
214             /* determine if any attributes were deleted */
215             for(attr = found->e_attrs; attr; attr = attr->a_next)
216             {
217                 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
218
219                 at = NULL;
220                 at = attr_find(toAdd->e_attrs, attr->a_desc);
221                 if(!at)
222                 {
223                     Debug(LDAP_DEBUG_TRACE,
224                           "%s: Attribute %s not found in new entry!!!\n",
225                           addpartial.on_bi.bi_type,
226                           attr->a_desc->ad_cname.bv_val, 0);
227                     mod = (Modifications *) ch_malloc(sizeof(
228                                                         Modifications));
229                     mod->sml_flags = 0;
230                     mod->sml_op = LDAP_MOD_REPLACE;
231                     mod->sml_next = NULL;
232                     mod->sml_desc = attr->a_desc;
233                     mod->sml_type = attr->a_desc->ad_cname;
234                     mod->sml_values = NULL;
235                     mod->sml_nvalues = NULL;
236                     mod->sml_numvals = 0;
237                     *modtail = mod;
238                     modtail = &mod->sml_next;
239                 }
240                 else
241                 {
242                     Debug(LDAP_DEBUG_TRACE,
243                           "%s: Attribute %s found in new entry\n",
244                           addpartial.on_bi.bi_type,
245                           at->a_desc->ad_cname.bv_val, 0);
246                 }
247             }
248
249             overlay_entry_release_ov(&nop, found, 0, on);
250
251             if(mods)
252             {
253                 Modifications *m = NULL;
254                 Modifications *toDel;
255                 int modcount;
256                 slap_callback nullcb = { NULL, collect_error_msg_cb, 
257                                          NULL, NULL };
258
259                 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
260                       addpartial.on_bi.bi_type, 0, 0);
261
262                 memset(&nrs, 0, sizeof(nrs));
263                 nrs.sr_type = REP_RESULT;
264                 nrs.sr_err = LDAP_SUCCESS;
265                 nrs.sr_entry = NULL;
266                 nrs.sr_text = NULL;
267
268                 nop.o_tag = LDAP_REQ_MODIFY;
269                 nop.orm_modlist = mods;
270                 nop.orm_no_opattrs = 0;
271                 nop.o_callback = &nullcb;
272                 nop.o_bd->bd_info = (BackendInfo *) on->on_info;
273
274                 for(m = mods, modcount = 0; m; m = m->sml_next, 
275                     modcount++)
276                 {
277                     /* count number of mods */
278                 }
279
280                 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
281                       addpartial.on_bi.bi_type, modcount, 0);
282
283                 if(nop.o_bd->be_modify)
284                 {
285                     rc = (nop.o_bd->be_modify)(&nop, &nrs);
286                 }
287
288                 if(rc == LDAP_SUCCESS)
289                 {
290                     Debug(LDAP_DEBUG_TRACE,
291                           "%s: modify successful\n",
292                           addpartial.on_bi.bi_type, 0, 0);
293                 }
294                 else
295                 {
296                     Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
297                           addpartial.on_bi.bi_type, rc, 0);
298                     rs->sr_err = rc;
299                     if(nullcb.sc_private)
300                     {
301                         rs->sr_text = nullcb.sc_private;
302                     }
303                 }
304
305                 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
306                       addpartial.on_bi.bi_type, 0, 0);
307
308                 for(toDel = mods; toDel; toDel = mods)
309                 {
310                     mods = mods->sml_next;
311                     ch_free(toDel);
312                 }
313             }
314             else
315             {
316                 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
317                       addpartial.on_bi.bi_type, 0, 0);
318             }
319         }
320         else
321         {
322             Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
323                   addpartial.on_bi.bi_type, 0, 0);
324         }
325
326         op->o_callback = NULL;
327         send_ldap_result( op, rs );
328         ch_free((void *)rs->sr_text);
329         rs->sr_text = NULL;
330
331         return LDAP_SUCCESS;
332     }
333 }
334
335 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
336 {
337     if(rs->sr_text)
338     {
339         op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
340     }
341
342     return LDAP_SUCCESS;
343 }
344
345 int addpartial_init() 
346 {
347     addpartial.on_bi.bi_type = "addpartial";
348     addpartial.on_bi.bi_op_add = addpartial_add;
349
350     return (overlay_register(&addpartial));
351 }
352
353 int init_module(int argc, char *argv[]) 
354 {
355     return addpartial_init();
356 }