Back to index

openldap  2.4.31
deref.c
Go to the documentation of this file.
00001 /* deref.c - dereference overlay */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2008 Pierangelo Masarati.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This work was initially developed by Pierangelo Masarati
00019  * for inclusion in OpenLDAP Software.
00020  */
00021 
00022 #include "portable.h"
00023 
00024 #ifdef SLAPD_OVER_DEREF
00025 
00026 #include <stdio.h>
00027 
00028 #include "ac/string.h"
00029 #include "ac/socket.h"
00030 
00031 #include "slap.h"
00032 #include "config.h"
00033 
00034 #include "lutil.h"
00035 
00036 /*
00037  * 1. Specification
00038  *
00039  * 1.1. Request
00040  *
00041  *  controlValue ::= SEQUENCE OF derefSpec DerefSpec
00042  *
00043  *  DerefSpec ::= SEQUENCE {
00044  *      derefAttr       attributeDescription,    ; DN-valued
00045  *      attributes      AttributeList }
00046  *
00047  *  AttributeList ::= SEQUENCE OF attr AttributeDescription
00048  *
00049  *  derefAttr MUST be unique within controlValue
00050  *
00051  *
00052  * 1.2. Response
00053  *
00054  *  controlValue ::= SEQUENCE OF DerefRes
00055  *
00056  * From RFC 4511:
00057  *      PartialAttribute ::= SEQUENCE {
00058  *           type       AttributeDescription,
00059  *           vals       SET OF value AttributeValue }
00060  *
00061  *      PartialAttributeList ::= SEQUENCE OF
00062  *                           partialAttribute PartialAttribute
00063  *
00064  *  DerefRes ::= SEQUENCE {
00065  *      derefAttr       AttributeDescription,
00066  *      derefVal        LDAPDN,
00067  *      attrVals        [0] PartialAttributeList OPTIONAL }
00068  *
00069  *  If vals is empty, partialAttribute is omitted.
00070  *  If all vals in attrVals are empty, attrVals is omitted.
00071  *      
00072  * 2. Examples
00073  *
00074  * 2.1. Example
00075  *
00076  * 2.1.1. Request
00077  *
00078  * { { member, { GUID, SID } }, { memberOf, { GUID, SID } } }
00079  *
00080  * 2.1.2. Response
00081  *
00082  * { { memberOf, "cn=abartlet,cn=users,dc=abartlet,dc=net",
00083  *     { { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fa" ] },
00084  *       { SID, [ "S-1-2-3-2345" ] } } },
00085  *   { memberOf, "cn=ando,cn=users,dc=sys-net,dc=it",
00086  *     { { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fb" ] },
00087  *       { SID, [ "S-1-2-3-2346" ] } } } }
00088  *
00089  * 2.2. Example
00090  *
00091  * 2.2.1. Request
00092  *
00093  * { { member, { cn, uid, drink } } }
00094  *
00095  * 2.2.2. Response
00096  *
00097  * { { member, "cn=ando,cn=users,dc=sys-net,dc=it",
00098  *     { { cn, [ "ando", "Pierangelo Masarati" ] },
00099  *       { uid, [ "ando" ] } } },
00100  *   { member, "dc=sys-net,dc=it" } }
00101  *
00102  *
00103  * 3. Security considerations
00104  *
00105  * The control result must not disclose information the client's
00106  * identity could not have accessed directly by performing the related
00107  * search operations.  The presence of a derefVal in the control
00108  * response does not imply neither the existence of nor any access
00109  * privilege to the corresponding entry.  It is merely a consequence
00110  * of the read access the client's identity has on the corresponding
00111  * attribute's value.
00112  */
00113 
00114 #define o_deref                    o_ctrlflag[deref_cid]
00115 #define o_ctrlderef         o_controls[deref_cid]
00116 
00117 typedef struct DerefSpec {
00118        AttributeDescription *ds_derefAttr;
00119        AttributeDescription **ds_attributes;
00120        int                  ds_nattrs;
00121        struct DerefSpec     *ds_next;
00122 } DerefSpec;
00123 
00124 typedef struct DerefVal {
00125        struct berval dv_derefSpecVal;
00126        BerVarray     *dv_attrVals;
00127 } DerefVal;
00128 
00129 typedef struct DerefRes {
00130        DerefSpec            dr_spec;
00131        DerefVal             *dr_vals;
00132        struct DerefRes             *dr_next;
00133 } DerefRes;
00134 
00135 typedef struct deref_cb_t {
00136        slap_overinst *dc_on;
00137        DerefSpec *dc_ds;
00138 } deref_cb_t;
00139 
00140 static int                  deref_cid;
00141 static slap_overinst               deref;
00142 
00143 static int
00144 deref_parseCtrl (
00145        Operation *op,
00146        SlapReply *rs,
00147        LDAPControl *ctrl )
00148 {
00149        ber_tag_t tag;
00150        BerElementBuffer berbuf;
00151        BerElement *ber = (BerElement *)&berbuf;
00152        ber_len_t len;
00153        char *last;
00154        DerefSpec *dshead = NULL, **dsp = &dshead;
00155        BerVarray attributes = NULL;
00156 
00157        if ( op->o_deref != SLAP_CONTROL_NONE ) {
00158               rs->sr_text = "Dereference control specified multiple times";
00159               return LDAP_PROTOCOL_ERROR;
00160        }
00161 
00162        if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
00163               rs->sr_text = "Dereference control value is absent";
00164               return LDAP_PROTOCOL_ERROR;
00165        }
00166 
00167        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
00168               rs->sr_text = "Dereference control value is empty";
00169               return LDAP_PROTOCOL_ERROR;
00170        }
00171 
00172        ber_init2( ber, &ctrl->ldctl_value, 0 );
00173 
00174        for ( tag = ber_first_element( ber, &len, &last );
00175               tag != LBER_DEFAULT;
00176               tag = ber_next_element( ber, &len, last ) )
00177        {
00178               struct berval derefAttr;
00179               DerefSpec *ds, *dstmp;
00180               const char *text;
00181               int rc;
00182               ber_len_t cnt = sizeof(struct berval);
00183               ber_len_t off = 0;
00184 
00185               if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR )
00186               {
00187                      rs->sr_text = "Dereference control: derefSpec decoding error";
00188                      rs->sr_err = LDAP_PROTOCOL_ERROR;
00189                      goto done;
00190               }
00191 
00192               ds = (DerefSpec *)op->o_tmpcalloc( 1,
00193                      sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
00194                      op->o_tmpmemctx );
00195               ds->ds_attributes = (AttributeDescription **)&ds[ 1 ];
00196               ds->ds_nattrs = cnt;
00197 
00198               rc = slap_bv2ad( &derefAttr, &ds->ds_derefAttr, &text );
00199               if ( rc != LDAP_SUCCESS ) {
00200                      rs->sr_text = "Dereference control: derefAttr decoding error";
00201                      rs->sr_err = LDAP_PROTOCOL_ERROR;
00202                      goto done;
00203               }
00204 
00205               for ( dstmp = dshead; dstmp && dstmp != ds; dstmp = dstmp->ds_next ) {
00206                      if ( dstmp->ds_derefAttr == ds->ds_derefAttr ) {
00207                             rs->sr_text = "Dereference control: derefAttr must be unique within control";
00208                             rs->sr_err = LDAP_PROTOCOL_ERROR;
00209                             goto done;
00210                      }
00211               }
00212 
00213               if ( !( ds->ds_derefAttr->ad_type->sat_syntax->ssyn_flags & SLAP_SYNTAX_DN )) {
00214                      if ( ctrl->ldctl_iscritical ) {
00215                             rs->sr_text = "Dereference control: derefAttr syntax not distinguishedName";
00216                             rs->sr_err = LDAP_PROTOCOL_ERROR;
00217                             goto done;
00218                      }
00219 
00220                      rs->sr_err = LDAP_SUCCESS;
00221                      goto justcleanup;
00222               }
00223 
00224               for ( cnt = 0; !BER_BVISNULL( &attributes[ cnt ] ); cnt++ ) {
00225                      rc = slap_bv2ad( &attributes[ cnt ], &ds->ds_attributes[ cnt ], &text );
00226                      if ( rc != LDAP_SUCCESS ) {
00227                             rs->sr_text = "Dereference control: attribute decoding error";
00228                             rs->sr_err = LDAP_PROTOCOL_ERROR;
00229                             goto done;
00230                      }
00231               }
00232 
00233               ber_memfree_x( attributes, op->o_tmpmemctx );
00234               attributes = NULL;
00235 
00236               *dsp = ds;
00237               dsp = &ds->ds_next;
00238        }
00239 
00240        op->o_ctrlderef = (void *)dshead;
00241 
00242        op->o_deref = ctrl->ldctl_iscritical
00243               ? SLAP_CONTROL_CRITICAL
00244               : SLAP_CONTROL_NONCRITICAL;
00245 
00246        rs->sr_err = LDAP_SUCCESS;
00247 
00248 done:;
00249        if ( rs->sr_err != LDAP_SUCCESS ) {
00250 justcleanup:;
00251               for ( ; dshead; ) {
00252                      DerefSpec *dsnext = dshead->ds_next;
00253                      op->o_tmpfree( dshead, op->o_tmpmemctx );
00254                      dshead = dsnext;
00255               }
00256        }
00257 
00258        if ( attributes != NULL ) {
00259               ber_memfree_x( attributes, op->o_tmpmemctx );
00260        }
00261 
00262        return rs->sr_err;
00263 }
00264 
00265 static int
00266 deref_cleanup( Operation *op, SlapReply *rs )
00267 {
00268        if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) {
00269               op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
00270               op->o_callback = NULL;
00271 
00272               op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
00273               op->o_ctrlderef = NULL;
00274        }
00275 
00276        return SLAP_CB_CONTINUE;
00277 }
00278 
00279 static int
00280 deref_response( Operation *op, SlapReply *rs )
00281 {
00282        int rc = SLAP_CB_CONTINUE;
00283 
00284        if ( rs->sr_type == REP_SEARCH ) {
00285               BerElementBuffer berbuf;
00286               BerElement *ber = (BerElement *) &berbuf;
00287               deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private;
00288               DerefSpec *ds;
00289               DerefRes *dr, *drhead = NULL, **drp = &drhead;
00290               struct berval bv = BER_BVNULL;
00291               int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
00292               struct berval ctrlval;
00293               LDAPControl *ctrl, *ctrlsp[2];
00294               AccessControlState acl_state = ACL_STATE_INIT;
00295               static char dummy = '\0';
00296               Entry *ebase;
00297               int i;
00298 
00299               rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on );
00300               if ( rc != LDAP_SUCCESS || ebase == NULL ) {
00301                      return SLAP_CB_CONTINUE;
00302               }
00303 
00304               for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
00305                      Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr );
00306 
00307                      if ( a != NULL ) {
00308                             DerefVal *dv;
00309                             BerVarray *bva;
00310 
00311                             if ( !access_allowed( op, rs->sr_entry, a->a_desc,
00312                                           NULL, ACL_READ, &acl_state ) )
00313                             {
00314                                    continue;
00315                             }
00316 
00317                             dr = op->o_tmpcalloc( 1,
00318                                    sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
00319                                    op->o_tmpmemctx );
00320                             dr->dr_spec = *ds;
00321                             dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
00322                             bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
00323 
00324                             bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
00325                             nAttrs++;
00326                             nDerefRes++;
00327 
00328                             for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
00329                                    Entry *e = NULL;
00330 
00331                                    dv[ i ].dv_attrVals = bva;
00332                                    bva += ds->ds_nattrs;
00333 
00334 
00335                                    if ( !access_allowed( op, rs->sr_entry, a->a_desc,
00336                                                  &a->a_nvals[ i ], ACL_READ, &acl_state ) )
00337                                    {
00338                                           dv[ i ].dv_derefSpecVal.bv_val = &dummy;
00339                                           continue;
00340                                    }
00341 
00342                                    ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx );
00343                                    bv.bv_len += dv[ i ].dv_derefSpecVal.bv_len;
00344                                    nVals++;
00345                                    nDerefVals++;
00346 
00347                                    rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
00348                                    if ( rc == LDAP_SUCCESS && e != NULL ) {
00349                                           int j;
00350 
00351                                           if ( access_allowed( op, e, slap_schema.si_ad_entry,
00352                                                  NULL, ACL_READ, NULL ) )
00353                                           {
00354                                                  for ( j = 0; j < ds->ds_nattrs; j++ ) {
00355                                                         Attribute *aa;
00356 
00357                                                         if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
00358                                                                ACL_READ, &acl_state ) )
00359                                                         {
00360                                                                continue;
00361                                                         }
00362 
00363                                                         aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
00364                                                         if ( aa != NULL ) {
00365                                                                unsigned k, h, last = aa->a_numvals;
00366 
00367                                                                ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ],
00368                                                                       aa->a_vals, op->o_tmpmemctx );
00369 
00370                                                                bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
00371 
00372                                                                for ( k = 0, h = 0; k < aa->a_numvals; k++ ) {
00373                                                                       if ( !access_allowed( op, e,
00374                                                                              aa->a_desc,
00375                                                                              &aa->a_nvals[ k ],
00376                                                                              ACL_READ, &acl_state ) )
00377                                                                       {
00378                                                                              op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val,
00379                                                                                     op->o_tmpmemctx );
00380                                                                              dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ];
00381                                                                              BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] );
00382                                                                              continue;
00383                                                                       }
00384                                                                       bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len;
00385                                                                       nVals++;
00386                                                                       h++;
00387                                                                }
00388                                                                nAttrs++;
00389                                                         }
00390                                                  }
00391                                           }
00392 
00393                                           overlay_entry_release_ov( op, e, 0, dc->dc_on );
00394                                    }
00395                             }
00396 
00397                             *drp = dr;
00398                             drp = &dr->dr_next;
00399                      }
00400               }
00401               overlay_entry_release_ov( op, ebase, 0, dc->dc_on );
00402 
00403               if ( drhead == NULL ) {
00404                      return SLAP_CB_CONTINUE;
00405               }
00406 
00407               /* cook the control value */
00408               bv.bv_len += nVals * sizeof(struct berval)
00409                      + nAttrs * sizeof(struct berval)
00410                      + nDerefVals * sizeof(DerefVal)
00411                      + nDerefRes * sizeof(DerefRes);
00412               bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
00413 
00414               ber_init2( ber, &bv, LBER_USE_DER );
00415               ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
00416 
00417               rc = ber_printf( ber, "{" /*}*/ );
00418               for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
00419                      for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
00420                             int j, first = 1;
00421 
00422                             if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) {
00423                                    continue;
00424                             }
00425 
00426                             rc = ber_printf( ber, "{OO" /*}*/,
00427                                    &dr->dr_spec.ds_derefAttr->ad_cname,
00428                                    &dr->dr_vals[ i ].dv_derefSpecVal );
00429                             op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx );
00430                             for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
00431                                    if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
00432                                           if ( first ) {
00433                                                  rc = ber_printf( ber, "t{" /*}*/,
00434                                                         (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) );
00435                                                  first = 0;
00436                                           }
00437                                           rc = ber_printf( ber, "{O[W]}",
00438                                                  &dr->dr_spec.ds_attributes[ j ]->ad_cname,
00439                                                  dr->dr_vals[ i ].dv_attrVals[ j ] );
00440                                           op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ],
00441                                                  op->o_tmpmemctx );
00442                                    }
00443                             }
00444                             if ( !first ) {
00445                                    rc = ber_printf( ber, /*{{*/ "}N}" );
00446                             } else {
00447                                    rc = ber_printf( ber, /*{*/ "}" );
00448                             }
00449                      }
00450               }
00451               rc = ber_printf( ber, /*{*/ "}" );
00452               if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
00453                      if ( op->o_deref == SLAP_CONTROL_CRITICAL ) {
00454                             rc = LDAP_CONSTRAINT_VIOLATION;
00455 
00456                      } else {
00457                             rc = SLAP_CB_CONTINUE;
00458                      }
00459                      goto cleanup;
00460               }
00461 
00462               ctrl = op->o_tmpcalloc( 1,
00463                      sizeof( LDAPControl ) + ctrlval.bv_len + 1,
00464                      op->o_tmpmemctx );
00465               ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ];
00466               ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
00467               ctrl->ldctl_iscritical = 0;
00468               ctrl->ldctl_value.bv_len = ctrlval.bv_len;
00469               AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
00470               ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';
00471 
00472               ber_free_buf( ber );
00473 
00474               ctrlsp[0] = ctrl;
00475               ctrlsp[1] = NULL;
00476               slap_add_ctrls( op, rs, ctrlsp );
00477 
00478               rc = SLAP_CB_CONTINUE;
00479 
00480 cleanup:;
00481               /* release all */
00482               for ( ; drhead != NULL; ) {
00483                      DerefRes *drnext = drhead->dr_next;
00484                      op->o_tmpfree( drhead, op->o_tmpmemctx );
00485                      drhead = drnext;
00486               }
00487 
00488        } else if ( rs->sr_type == REP_RESULT ) {
00489               rc = deref_cleanup( op, rs );
00490        }
00491 
00492        return rc;
00493 }
00494 
00495 static int
00496 deref_op_search( Operation *op, SlapReply *rs )
00497 {
00498        if ( op->o_deref ) {
00499               slap_callback *sc;
00500               deref_cb_t *dc;
00501 
00502               sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
00503 
00504               dc = (deref_cb_t *)&sc[ 1 ];
00505               dc->dc_on = (slap_overinst *)op->o_bd->bd_info;
00506               dc->dc_ds = (DerefSpec *)op->o_ctrlderef;
00507 
00508               sc->sc_response = deref_response;
00509               sc->sc_cleanup = deref_cleanup;
00510               sc->sc_private = (void *)dc;
00511 
00512               sc->sc_next = op->o_callback->sc_next;
00513                 op->o_callback->sc_next = sc;
00514        }
00515 
00516        return SLAP_CB_CONTINUE;
00517 }
00518 
00519 int
00520 deref_initialize(void)
00521 {
00522        int rc;
00523 
00524        rc = register_supported_control( LDAP_CONTROL_X_DEREF,
00525               SLAP_CTRL_SEARCH, NULL,
00526               deref_parseCtrl, &deref_cid );
00527        if ( rc != LDAP_SUCCESS ) {
00528               Debug( LDAP_DEBUG_ANY,
00529                      "deref_init: Failed to register control (%d)\n",
00530                      rc, 0, 0 );
00531               return -1;
00532        }
00533 
00534        deref.on_bi.bi_type = "deref";
00535        deref.on_bi.bi_op_search = deref_op_search;
00536 
00537        return overlay_register( &deref );
00538 }
00539 
00540 #if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
00541 int
00542 init_module( int argc, char *argv[] )
00543 {
00544        return deref_initialize();
00545 }
00546 #endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
00547 
00548 #endif /* SLAPD_OVER_DEREF */