Back to index

openldap  2.4.31
extended.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 /*
00017  * LDAPv3 Extended Operation Request
00018  *     ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
00019  *            requestName    [0] LDAPOID,
00020  *            requestValue   [1] OCTET STRING OPTIONAL
00021  *     }
00022  *
00023  * LDAPv3 Extended Operation Response
00024  *     ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
00025  *            COMPONENTS OF LDAPResult,
00026  *            responseName   [10] LDAPOID OPTIONAL,
00027  *            response       [11] OCTET STRING OPTIONAL
00028  *     }
00029  *
00030  */
00031 
00032 #include "portable.h"
00033 
00034 #include <stdio.h>
00035 
00036 #include <ac/socket.h>
00037 #include <ac/string.h>
00038 
00039 #include "slap.h"
00040 #include "lber_pvt.h"
00041 
00042 static struct extop_list {
00043        struct extop_list *next;
00044        struct berval oid;
00045        slap_mask_t flags;
00046        SLAP_EXTOP_MAIN_FN *ext_main;
00047 } *supp_ext_list = NULL;
00048 
00049 static SLAP_EXTOP_MAIN_FN whoami_extop;
00050 
00051 /* This list of built-in extops is for extops that are not part
00052  * of backends or in external modules.    Essentially, this is
00053  * just a way to get built-in extops onto the extop list without
00054  * having a separate init routine for each built-in extop.
00055  */
00056 static struct {
00057        const struct berval *oid;
00058        slap_mask_t flags;
00059        SLAP_EXTOP_MAIN_FN *ext_main;
00060 } builtin_extops[] = {
00061 #ifdef LDAP_X_TXN
00062        { &slap_EXOP_TXN_START, 0, txn_start_extop },
00063        { &slap_EXOP_TXN_END, 0, txn_end_extop },
00064 #endif
00065        { &slap_EXOP_CANCEL, 0, cancel_extop },
00066        { &slap_EXOP_WHOAMI, 0, whoami_extop },
00067        { &slap_EXOP_MODIFY_PASSWD, SLAP_EXOP_WRITES, passwd_extop },
00068        { NULL, 0, NULL }
00069 };
00070 
00071 
00072 static struct extop_list *find_extop(
00073        struct extop_list *list, struct berval *oid );
00074 
00075 struct berval *
00076 get_supported_extop (int index)
00077 {
00078        struct extop_list *ext;
00079 
00080        /* linear scan is slow, but this way doesn't force a
00081         * big change on root_dse.c, where this routine is used.
00082         */
00083        for (ext = supp_ext_list; ext != NULL && --index >= 0; ext = ext->next) {
00084               ; /* empty */
00085        }
00086 
00087        if (ext == NULL) return NULL;
00088 
00089        return &ext->oid;
00090 }
00091 
00092 
00093 int exop_root_dse_info( Entry *e )
00094 {
00095        AttributeDescription *ad_supportedExtension
00096               = slap_schema.si_ad_supportedExtension;
00097        struct berval vals[2];
00098        struct extop_list *ext;
00099 
00100        vals[1].bv_val = NULL;
00101        vals[1].bv_len = 0;
00102 
00103        for (ext = supp_ext_list; ext != NULL; ext = ext->next) {
00104               if( ext->flags & SLAP_EXOP_HIDE ) continue;
00105 
00106               vals[0] = ext->oid;
00107 
00108               if( attr_merge( e, ad_supportedExtension, vals, NULL ) ) {
00109                      return LDAP_OTHER;
00110               }
00111        }
00112 
00113        return LDAP_SUCCESS;
00114 }
00115 
00116 int
00117 do_extended(
00118     Operation *op,
00119     SlapReply *rs
00120 )
00121 {
00122        struct berval reqdata = {0, NULL};
00123        ber_len_t len;
00124 
00125        Debug( LDAP_DEBUG_TRACE, "%s do_extended\n",
00126               op->o_log_prefix, 0, 0 );
00127 
00128        if( op->o_protocol < LDAP_VERSION3 ) {
00129               Debug( LDAP_DEBUG_ANY, "%s do_extended: protocol version (%d) too low\n",
00130                      op->o_log_prefix, op->o_protocol, 0 );
00131               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "requires LDAPv3" );
00132               rs->sr_err = SLAPD_DISCONNECT;
00133               goto done;
00134        }
00135 
00136        if ( ber_scanf( op->o_ber, "{m" /*}*/, &op->ore_reqoid ) == LBER_ERROR ) {
00137               Debug( LDAP_DEBUG_ANY, "%s do_extended: ber_scanf failed\n",
00138                      op->o_log_prefix, 0, 0 );
00139               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00140               rs->sr_err = SLAPD_DISCONNECT;
00141               goto done;
00142        }
00143 
00144        if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) {
00145               if( ber_scanf( op->o_ber, "m", &reqdata ) == LBER_ERROR ) {
00146                      Debug( LDAP_DEBUG_ANY, "%s do_extended: ber_scanf failed\n",
00147                             op->o_log_prefix, 0, 0 );
00148                      send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00149                      rs->sr_err = SLAPD_DISCONNECT;
00150                      goto done;
00151               }
00152        }
00153 
00154        if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
00155               Debug( LDAP_DEBUG_ANY, "%s do_extended: get_ctrls failed\n",
00156                      op->o_log_prefix, 0, 0 );
00157               return rs->sr_err;
00158        } 
00159 
00160        Statslog( LDAP_DEBUG_STATS, "%s EXT oid=%s\n",
00161            op->o_log_prefix, op->ore_reqoid.bv_val, 0, 0, 0 );
00162 
00163        /* check for controls inappropriate for all extended operations */
00164        if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) {
00165               send_ldap_error( op, rs,
00166                      LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
00167                      "manageDSAit control inappropriate" );
00168               goto done;
00169        }
00170 
00171        /* FIXME: temporary? */
00172        if ( reqdata.bv_val ) {
00173               op->ore_reqdata = &reqdata;
00174        }
00175 
00176        op->o_bd = frontendDB;
00177        rs->sr_err = frontendDB->be_extended( op, rs );
00178 
00179        /* clean up in case some overlay set them? */
00180        if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
00181               if ( !BER_BVISNULL( &op->o_req_dn )
00182                      && op->o_req_ndn.bv_val != op->o_req_dn.bv_val )
00183               {
00184                      op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
00185               }
00186               op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
00187               BER_BVZERO( &op->o_req_dn );
00188               BER_BVZERO( &op->o_req_ndn );
00189        }
00190 
00191 done:
00192        return rs->sr_err;
00193 }
00194 
00195 int
00196 fe_extended( Operation *op, SlapReply *rs )
00197 {
00198        struct extop_list    *ext = NULL;
00199        struct berval        reqdata = BER_BVNULL;
00200 
00201        if (op->ore_reqdata) {
00202               reqdata = *op->ore_reqdata;
00203        }
00204 
00205        ext = find_extop(supp_ext_list, &op->ore_reqoid );
00206        if ( ext == NULL ) {
00207               Debug( LDAP_DEBUG_ANY, "%s do_extended: unsupported operation \"%s\"\n",
00208                      op->o_log_prefix, op->ore_reqoid.bv_val, 0 );
00209               send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
00210                      "unsupported extended operation" );
00211               goto done;
00212        }
00213 
00214        op->ore_flags = ext->flags;
00215 
00216        Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n",
00217               op->ore_reqoid.bv_val, 0 ,0 );
00218 
00219        { /* start of OpenLDAP extended operation */
00220               BackendDB     *bd = op->o_bd;
00221 
00222               rs->sr_err = (ext->ext_main)( op, rs );
00223 
00224               if( rs->sr_err != SLAPD_ABANDON ) {
00225                      if ( rs->sr_err == LDAP_REFERRAL && rs->sr_ref == NULL ) {
00226                             rs->sr_ref = referral_rewrite( default_referral,
00227                                    NULL, NULL, LDAP_SCOPE_DEFAULT );
00228                             if ( !rs->sr_ref ) rs->sr_ref = default_referral;
00229                             if ( !rs->sr_ref ) {
00230                                    rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00231                                    rs->sr_text = "referral missing";
00232                             }
00233                      }
00234 
00235                      if ( op->o_bd == NULL )
00236                             op->o_bd = bd;
00237                      send_ldap_extended( op, rs );
00238 
00239                      if ( rs->sr_ref != default_referral ) {
00240                             ber_bvarray_free( rs->sr_ref );
00241                             rs->sr_ref = NULL;
00242                      }
00243               }
00244 
00245               if ( rs->sr_rspoid != NULL ) {
00246                      free( (char *)rs->sr_rspoid );
00247                      rs->sr_rspoid = NULL;
00248               }
00249 
00250               if ( rs->sr_rspdata != NULL ) {
00251                      ber_bvfree( rs->sr_rspdata );
00252                      rs->sr_rspdata = NULL;
00253               }
00254        } /* end of OpenLDAP extended operation */
00255 
00256 done:;
00257        return rs->sr_err;
00258 }
00259 
00260 int
00261 load_extop2(
00262        const struct berval *ext_oid,
00263        slap_mask_t ext_flags,
00264        SLAP_EXTOP_MAIN_FN *ext_main,
00265        unsigned flags )
00266 {
00267        struct berval        oidm = BER_BVNULL;
00268        struct extop_list    *ext;
00269        int                  insertme = 0;
00270 
00271        if ( !ext_main ) {
00272               return -1; 
00273        }
00274 
00275        if ( ext_oid == NULL || BER_BVISNULL( ext_oid ) ||
00276               BER_BVISEMPTY( ext_oid ) )
00277        {
00278               return -1; 
00279        }
00280 
00281        if ( numericoidValidate( NULL, (struct berval *)ext_oid ) !=
00282               LDAP_SUCCESS )
00283        {
00284               oidm.bv_val = oidm_find( ext_oid->bv_val );
00285               if ( oidm.bv_val == NULL ) {
00286                      return -1;
00287               }
00288               oidm.bv_len = strlen( oidm.bv_val );
00289               ext_oid = &oidm;
00290        }
00291 
00292        for ( ext = supp_ext_list; ext; ext = ext->next ) {
00293               if ( bvmatch( ext_oid, &ext->oid ) ) {
00294                      if ( flags == 1 ) {
00295                             break;
00296                      }
00297                      return -1;
00298               }
00299        }
00300 
00301        if ( flags == 0 || ext == NULL ) {
00302               ext = ch_calloc( 1, sizeof(struct extop_list) + ext_oid->bv_len + 1 );
00303               if ( ext == NULL ) {
00304                      return(-1);
00305               }
00306 
00307               ext->oid.bv_val = (char *)(ext + 1);
00308               AC_MEMCPY( ext->oid.bv_val, ext_oid->bv_val, ext_oid->bv_len );
00309               ext->oid.bv_len = ext_oid->bv_len;
00310               ext->oid.bv_val[ext->oid.bv_len] = '\0';
00311 
00312               insertme = 1;
00313        }
00314 
00315        ext->flags = ext_flags;
00316        ext->ext_main = ext_main;
00317 
00318        if ( insertme ) {
00319               ext->next = supp_ext_list;
00320               supp_ext_list = ext;
00321        }
00322 
00323        return(0);
00324 }
00325 
00326 int
00327 extops_init (void)
00328 {
00329        int i;
00330 
00331        for ( i = 0; builtin_extops[i].oid != NULL; i++ ) {
00332               load_extop( (struct berval *)builtin_extops[i].oid,
00333                      builtin_extops[i].flags,
00334                      builtin_extops[i].ext_main );
00335        }
00336        return(0);
00337 }
00338 
00339 int
00340 extops_kill (void)
00341 {
00342        struct extop_list *ext;
00343 
00344        /* we allocated the memory, so we have to free it, too. */
00345        while ((ext = supp_ext_list) != NULL) {
00346               supp_ext_list = ext->next;
00347               ch_free(ext);
00348        }
00349        return(0);
00350 }
00351 
00352 static struct extop_list *
00353 find_extop( struct extop_list *list, struct berval *oid )
00354 {
00355        struct extop_list *ext;
00356 
00357        for (ext = list; ext; ext = ext->next) {
00358               if (bvmatch(&ext->oid, oid))
00359                      return(ext);
00360        }
00361        return(NULL);
00362 }
00363 
00364 
00365 const struct berval slap_EXOP_WHOAMI = BER_BVC(LDAP_EXOP_WHO_AM_I);
00366 
00367 static int
00368 whoami_extop (
00369        Operation *op,
00370        SlapReply *rs )
00371 {
00372        struct berval *bv;
00373 
00374        if ( op->ore_reqdata != NULL ) {
00375               /* no request data should be provided */
00376               rs->sr_text = "no request data expected";
00377               return LDAP_PROTOCOL_ERROR;
00378        }
00379 
00380        Statslog( LDAP_DEBUG_STATS, "%s WHOAMI\n",
00381            op->o_log_prefix, 0, 0, 0, 0 );
00382 
00383        op->o_bd = op->o_conn->c_authz_backend;
00384        if( backend_check_restrictions( op, rs,
00385               (struct berval *)&slap_EXOP_WHOAMI ) != LDAP_SUCCESS )
00386        {
00387               return rs->sr_err;
00388        }
00389 
00390        bv = (struct berval *) ch_malloc( sizeof(struct berval) );
00391        if( op->o_dn.bv_len ) {
00392               bv->bv_len = op->o_dn.bv_len + STRLENOF( "dn:" );
00393               bv->bv_val = ch_malloc( bv->bv_len + 1 );
00394               AC_MEMCPY( bv->bv_val, "dn:", STRLENOF( "dn:" ) );
00395               AC_MEMCPY( &bv->bv_val[STRLENOF( "dn:" )], op->o_dn.bv_val,
00396                      op->o_dn.bv_len );
00397               bv->bv_val[bv->bv_len] = '\0';
00398 
00399        } else {
00400               bv->bv_len = 0;
00401               bv->bv_val = NULL;
00402        }
00403 
00404        rs->sr_rspdata = bv;
00405        return LDAP_SUCCESS;
00406 }