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