Home | History | Annotate | Line # | Download | only in addpartial
      1 /*	$NetBSD: addpartial-overlay.c,v 1.4 2025/09/05 21:16:15 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-2024 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.4 2025/09/05 21:16:15 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  */
     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 
    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 
    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 
    351 int init_module(int argc, char *argv[])
    352 {
    353     return addpartial_init();
    354 }
    355