xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/addpartial/addpartial-overlay.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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 
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     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 
336 static 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 
346 int 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 
354 int init_module(int argc, char *argv[])
355 {
356     return addpartial_init();
357 }
358