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