Back to index

openldap  2.4.31
controls.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 1998-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 #include "portable.h"
00017 
00018 #include <stdio.h>
00019 
00020 #include <ac/string.h>
00021 #include <ac/socket.h>
00022 
00023 #include "slap.h"
00024 #include "ldif.h"
00025 #include "lutil.h"
00026 
00027 #include "../../libraries/liblber/lber-int.h"
00028 
00029 static SLAP_CTRL_PARSE_FN parseAssert;
00030 static SLAP_CTRL_PARSE_FN parseDomainScope;
00031 static SLAP_CTRL_PARSE_FN parseDontUseCopy;
00032 static SLAP_CTRL_PARSE_FN parseManageDSAit;
00033 static SLAP_CTRL_PARSE_FN parseNoOp;
00034 static SLAP_CTRL_PARSE_FN parsePagedResults;
00035 static SLAP_CTRL_PARSE_FN parsePermissiveModify;
00036 static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead;
00037 static SLAP_CTRL_PARSE_FN parseProxyAuthz;
00038 static SLAP_CTRL_PARSE_FN parseRelax;
00039 static SLAP_CTRL_PARSE_FN parseSearchOptions;
00040 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
00041 static SLAP_CTRL_PARSE_FN parseSortedResults;
00042 #endif
00043 static SLAP_CTRL_PARSE_FN parseSubentries;
00044 #ifdef SLAP_CONTROL_X_TREE_DELETE
00045 static SLAP_CTRL_PARSE_FN parseTreeDelete;
00046 #endif
00047 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
00048 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
00049 static SLAP_CTRL_PARSE_FN parseSessionTracking;
00050 #endif
00051 #ifdef SLAP_CONTROL_X_WHATFAILED
00052 static SLAP_CTRL_PARSE_FN parseWhatFailed;
00053 #endif
00054 
00055 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
00056 
00057 const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ);
00058 const struct berval slap_post_read_bv = BER_BVC(LDAP_CONTROL_POST_READ);
00059 
00060 struct slap_control_ids slap_cids;
00061 
00062 struct slap_control {
00063        /* Control OID */
00064        char *sc_oid;
00065 
00066        /* The controlID for this control */
00067        int sc_cid;
00068 
00069        /* Operations supported by control */
00070        slap_mask_t sc_mask;
00071 
00072        /* Extended operations supported by control */
00073        char **sc_extendedops;             /* input */
00074        BerVarray sc_extendedopsbv; /* run-time use */
00075 
00076        /* Control parsing callback */
00077        SLAP_CTRL_PARSE_FN *sc_parse;
00078 
00079        LDAP_SLIST_ENTRY(slap_control) sc_next;
00080 };
00081 
00082 static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
00083        = LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
00084 
00085 /*
00086  * all known request control OIDs should be added to this list
00087  */
00088 /*
00089  * NOTE: initialize num_known_controls to 1 so that cid = 0 always
00090  * addresses an undefined control; this allows to safely test for 
00091  * well known controls even if they are not registered, e.g. if 
00092  * they get moved to modules.  An example is sc_LDAPsync, which 
00093  * is implemented in the syncprov overlay and thus, if configured 
00094  * as dynamic module, may not be registered.  One side effect is that 
00095  * slap_known_controls[0] == NULL, so it should always be used 
00096  * starting from 1.
00097  * FIXME: should we define the "undefined control" oid?
00098  */
00099 char *slap_known_controls[SLAP_MAX_CIDS+1];
00100 static int num_known_controls = 1;
00101 
00102 static char *proxy_authz_extops[] = {
00103        LDAP_EXOP_MODIFY_PASSWD,
00104        LDAP_EXOP_WHO_AM_I,
00105        LDAP_EXOP_REFRESH,
00106        NULL
00107 };
00108 
00109 static char *manageDSAit_extops[] = {
00110        LDAP_EXOP_REFRESH,
00111        NULL
00112 };
00113 
00114 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
00115 static char *session_tracking_extops[] = {
00116        LDAP_EXOP_MODIFY_PASSWD,
00117        LDAP_EXOP_WHO_AM_I,
00118        LDAP_EXOP_REFRESH,
00119        NULL
00120 };
00121 #endif
00122 
00123 static struct slap_control control_defs[] = {
00124        {  LDAP_CONTROL_ASSERT,
00125               (int)offsetof(struct slap_control_ids, sc_assert),
00126               SLAP_CTRL_UPDATE|SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH,
00127               NULL, NULL,
00128               parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00129        { LDAP_CONTROL_PRE_READ,
00130               (int)offsetof(struct slap_control_ids, sc_preRead),
00131               SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
00132               NULL, NULL,
00133               parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00134        { LDAP_CONTROL_POST_READ,
00135               (int)offsetof(struct slap_control_ids, sc_postRead),
00136               SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
00137               NULL, NULL,
00138               parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00139        { LDAP_CONTROL_VALUESRETURNFILTER,
00140               (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
00141               SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH,
00142               NULL, NULL,
00143               parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00144        { LDAP_CONTROL_PAGEDRESULTS,
00145               (int)offsetof(struct slap_control_ids, sc_pagedResults),
00146               SLAP_CTRL_SEARCH,
00147               NULL, NULL,
00148               parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00149 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
00150        { LDAP_CONTROL_SORTREQUEST,
00151               (int)offsetof(struct slap_control_ids, sc_sortedResults),
00152               SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
00153               NULL, NULL,
00154               parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00155 #endif
00156        { LDAP_CONTROL_X_DOMAIN_SCOPE,
00157               (int)offsetof(struct slap_control_ids, sc_domainScope),
00158               SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
00159               NULL, NULL,
00160               parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00161        { LDAP_CONTROL_DONTUSECOPY,
00162               (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
00163               SLAP_CTRL_GLOBAL|SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE,
00164               NULL, NULL,
00165               parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00166        { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
00167               (int)offsetof(struct slap_control_ids, sc_permissiveModify),
00168               SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE,
00169               NULL, NULL,
00170               parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00171 #ifdef SLAP_CONTROL_X_TREE_DELETE
00172        { LDAP_CONTROL_X_TREE_DELETE,
00173               (int)offsetof(struct slap_control_ids, sc_treeDelete),
00174               SLAP_CTRL_DELETE|SLAP_CTRL_HIDE,
00175               NULL, NULL,
00176               parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00177 #endif
00178        { LDAP_CONTROL_X_SEARCH_OPTIONS,
00179               (int)offsetof(struct slap_control_ids, sc_searchOptions),
00180               SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
00181               NULL, NULL,
00182               parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00183        { LDAP_CONTROL_SUBENTRIES,
00184               (int)offsetof(struct slap_control_ids, sc_subentries),
00185               SLAP_CTRL_SEARCH,
00186               NULL, NULL,
00187               parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00188        { LDAP_CONTROL_NOOP,
00189               (int)offsetof(struct slap_control_ids, sc_noOp),
00190               SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
00191               NULL, NULL,
00192               parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00193        { LDAP_CONTROL_RELAX,
00194               (int)offsetof(struct slap_control_ids, sc_relax),
00195               SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
00196               NULL, NULL,
00197               parseRelax, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00198 #ifdef LDAP_X_TXN
00199        { LDAP_CONTROL_X_TXN_SPEC,
00200               (int)offsetof(struct slap_control_ids, sc_txnSpec),
00201               SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
00202               NULL, NULL,
00203               txn_spec_ctrl, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00204 #endif
00205        { LDAP_CONTROL_MANAGEDSAIT,
00206               (int)offsetof(struct slap_control_ids, sc_manageDSAit),
00207               SLAP_CTRL_ACCESS,
00208               manageDSAit_extops, NULL,
00209               parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00210        { LDAP_CONTROL_PROXY_AUTHZ,
00211               (int)offsetof(struct slap_control_ids, sc_proxyAuthz),
00212               SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS,
00213               proxy_authz_extops, NULL,
00214               parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00215 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
00216        { LDAP_CONTROL_X_SESSION_TRACKING,
00217               (int)offsetof(struct slap_control_ids, sc_sessionTracking),
00218               SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_BIND|SLAP_CTRL_HIDE,
00219               session_tracking_extops, NULL,
00220               parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00221 #endif
00222 #ifdef SLAP_CONTROL_X_WHATFAILED
00223        { LDAP_CONTROL_X_WHATFAILED,
00224               (int)offsetof(struct slap_control_ids, sc_whatFailed),
00225               SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
00226               NULL, NULL,
00227               parseWhatFailed, LDAP_SLIST_ENTRY_INITIALIZER(next) },
00228 #endif
00229 
00230        { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
00231 };
00232 
00233 static struct slap_control *
00234 find_ctrl( const char *oid );
00235 
00236 /*
00237  * Register a supported control.
00238  *
00239  * This can be called by an OpenLDAP plugin or, indirectly, by a
00240  * SLAPI plugin calling slapi_register_supported_control().
00241  *
00242  * NOTE: if flags == 1 the control is replaced if already registered;
00243  * otherwise registering an already registered control is not allowed.
00244  */
00245 int
00246 register_supported_control2(const char *controloid,
00247        slap_mask_t controlmask,
00248        char **controlexops,
00249        SLAP_CTRL_PARSE_FN *controlparsefn,
00250        unsigned flags,
00251        int *controlcid)
00252 {
00253        struct slap_control *sc = NULL;
00254        int i;
00255        BerVarray extendedopsbv = NULL;
00256 
00257        if ( num_known_controls >= SLAP_MAX_CIDS ) {
00258               Debug( LDAP_DEBUG_ANY, "Too many controls registered."
00259                      " Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
00260               SLAP_MAX_CIDS, 0, 0 );
00261               return LDAP_OTHER;
00262        }
00263 
00264        if ( controloid == NULL ) {
00265               return LDAP_PARAM_ERROR;
00266        }
00267 
00268        /* check if already registered */
00269        for ( i = 0; slap_known_controls[ i ]; i++ ) {
00270               if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
00271                      if ( flags == 1 ) {
00272                             Debug( LDAP_DEBUG_TRACE,
00273                                    "Control %s already registered; replacing.\n",
00274                                    controloid, 0, 0 );
00275                             /* (find and) replace existing handler */
00276                             sc = find_ctrl( controloid );
00277                             assert( sc != NULL );
00278                             break;
00279                      }
00280 
00281                      Debug( LDAP_DEBUG_ANY,
00282                             "Control %s already registered.\n",
00283                             controloid, 0, 0 );
00284                      return LDAP_PARAM_ERROR;
00285               }
00286        }
00287 
00288        /* turn compatible extended operations into bervals */
00289        if ( controlexops != NULL ) {
00290               int i;
00291 
00292               for ( i = 0; controlexops[ i ]; i++ );
00293 
00294               extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
00295               if ( extendedopsbv == NULL ) {
00296                      return LDAP_NO_MEMORY;
00297               }
00298 
00299               for ( i = 0; controlexops[ i ]; i++ ) {
00300                      ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] );
00301               }
00302        }
00303 
00304        if ( sc == NULL ) {
00305               sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
00306               if ( sc == NULL ) {
00307                      return LDAP_NO_MEMORY;
00308               }
00309 
00310               sc->sc_oid = ch_strdup( controloid );
00311               sc->sc_cid = num_known_controls;
00312 
00313               /* Update slap_known_controls, too. */
00314               slap_known_controls[num_known_controls - 1] = sc->sc_oid;
00315               slap_known_controls[num_known_controls++] = NULL;
00316 
00317               LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
00318               LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
00319 
00320        } else {
00321               if ( sc->sc_extendedopsbv ) {
00322                      /* FIXME: in principle, we should rather merge
00323                       * existing extops with those supported by the
00324                       * new control handling implementation.
00325                       * In fact, whether a control is compatible with
00326                       * an extop should not be a matter of implementation.
00327                       * We likely also need a means for a newly
00328                       * registered extop to declare that it is
00329                       * comptible with an already registered control.
00330                       */
00331                      ber_bvarray_free( sc->sc_extendedopsbv );
00332                      sc->sc_extendedopsbv = NULL;
00333                      sc->sc_extendedops = NULL;
00334               }
00335        }
00336 
00337        sc->sc_extendedopsbv = extendedopsbv;
00338        sc->sc_mask = controlmask;
00339        sc->sc_parse = controlparsefn;
00340        if ( controlcid ) {
00341               *controlcid = sc->sc_cid;
00342        }
00343 
00344        return LDAP_SUCCESS;
00345 }
00346 
00347 #ifdef SLAP_CONFIG_DELETE
00348 int
00349 unregister_supported_control( const char *controloid )
00350 {
00351        struct slap_control *sc;
00352        int i;
00353 
00354        if ( controloid == NULL || (sc = find_ctrl( controloid )) == NULL ){
00355               return -1;
00356        }
00357 
00358        for ( i = 0; slap_known_controls[ i ]; i++ ) {
00359               if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
00360                      do {
00361                             slap_known_controls[ i ] = slap_known_controls[ i+1 ];
00362                      } while ( slap_known_controls[ i++ ] );
00363                      num_known_controls--;
00364                      break;
00365               }
00366        }
00367 
00368        LDAP_SLIST_REMOVE(&controls_list, sc, slap_control, sc_next);
00369        ch_free( sc->sc_oid );
00370        if ( sc->sc_extendedopsbv != NULL ) {
00371               ber_bvarray_free( sc->sc_extendedopsbv );
00372        }
00373        ch_free( sc );
00374 
00375        return 0;
00376 }
00377 #endif /* SLAP_CONFIG_DELETE */
00378 
00379 /*
00380  * One-time initialization of internal controls.
00381  */
00382 int
00383 slap_controls_init( void )
00384 {
00385        int i, rc;
00386 
00387        rc = LDAP_SUCCESS;
00388 
00389        for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
00390               int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
00391               rc = register_supported_control( control_defs[i].sc_oid,
00392                      control_defs[i].sc_mask, control_defs[i].sc_extendedops,
00393                      control_defs[i].sc_parse, cid );
00394               if ( rc != LDAP_SUCCESS ) break;
00395        }
00396 
00397        return rc;
00398 }
00399 
00400 /*
00401  * Free memory associated with list of supported controls.
00402  */
00403 void
00404 controls_destroy( void )
00405 {
00406        struct slap_control *sc;
00407 
00408        while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
00409               sc = LDAP_SLIST_FIRST(&controls_list);
00410               LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);
00411 
00412               ch_free( sc->sc_oid );
00413               if ( sc->sc_extendedopsbv != NULL ) {
00414                      ber_bvarray_free( sc->sc_extendedopsbv );
00415               }
00416               ch_free( sc );
00417        }
00418 }
00419 
00420 /*
00421  * Format the supportedControl attribute of the root DSE,
00422  * detailing which controls are supported by the directory
00423  * server.
00424  */
00425 int
00426 controls_root_dse_info( Entry *e )
00427 {
00428        AttributeDescription *ad_supportedControl
00429               = slap_schema.si_ad_supportedControl;
00430        struct berval vals[2];
00431        struct slap_control *sc;
00432 
00433        vals[1].bv_val = NULL;
00434        vals[1].bv_len = 0;
00435 
00436        LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
00437               if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;
00438 
00439               vals[0].bv_val = sc->sc_oid;
00440               vals[0].bv_len = strlen( sc->sc_oid );
00441 
00442               if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
00443                      return -1;
00444               }
00445        }
00446 
00447        return 0;
00448 }
00449 
00450 /*
00451  * Return a list of OIDs and operation masks for supported
00452  * controls. Used by SLAPI.
00453  */
00454 int
00455 get_supported_controls(char ***ctrloidsp,
00456        slap_mask_t **ctrlmasks)
00457 {
00458        int n;
00459        char **oids;
00460        slap_mask_t *masks;
00461        struct slap_control *sc;
00462 
00463        n = 0;
00464 
00465        LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
00466               n++;
00467        }
00468 
00469        if ( n == 0 ) {
00470               *ctrloidsp = NULL;
00471               *ctrlmasks = NULL;
00472               return LDAP_SUCCESS;
00473        }
00474 
00475        oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
00476        if ( oids == NULL ) {
00477               return LDAP_NO_MEMORY;
00478        }
00479        masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
00480        if  ( masks == NULL ) {
00481               SLAP_FREE( oids );
00482               return LDAP_NO_MEMORY;
00483        }
00484 
00485        n = 0;
00486 
00487        LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
00488               oids[n] = ch_strdup( sc->sc_oid );
00489               masks[n] = sc->sc_mask;
00490               n++;
00491        }
00492        oids[n] = NULL;
00493        masks[n] = 0;
00494 
00495        *ctrloidsp = oids;
00496        *ctrlmasks = masks;
00497 
00498        return LDAP_SUCCESS;
00499 }
00500 
00501 /*
00502  * Find a control given its OID.
00503  */
00504 static struct slap_control *
00505 find_ctrl( const char *oid )
00506 {
00507        struct slap_control *sc;
00508 
00509        LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
00510               if ( strcmp( oid, sc->sc_oid ) == 0 ) {
00511                      return sc;
00512               }
00513        }
00514 
00515        return NULL;
00516 }
00517 
00518 int
00519 slap_find_control_id(
00520        const char *oid,
00521        int *cid )
00522 {
00523        struct slap_control *ctrl = find_ctrl( oid );
00524        if ( ctrl ) {
00525               if ( cid ) *cid = ctrl->sc_cid;
00526               return LDAP_SUCCESS;
00527        }
00528        return LDAP_CONTROL_NOT_FOUND;
00529 }
00530 
00531 int
00532 slap_global_control( Operation *op, const char *oid, int *cid )
00533 {
00534        struct slap_control *ctrl = find_ctrl( oid );
00535 
00536        if ( ctrl == NULL ) {
00537               /* should not be reachable */
00538               Debug( LDAP_DEBUG_ANY,
00539                      "slap_global_control: unrecognized control: %s\n",      
00540                      oid, 0, 0 );
00541               return LDAP_CONTROL_NOT_FOUND;
00542        }
00543 
00544        if ( cid ) *cid = ctrl->sc_cid;
00545 
00546        if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
00547               ( ( op->o_tag & LDAP_REQ_SEARCH ) &&
00548               ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
00549        {
00550               return LDAP_COMPARE_TRUE;
00551        }
00552 
00553 #if 0
00554        Debug( LDAP_DEBUG_TRACE,
00555               "slap_global_control: unavailable control: %s\n",      
00556               oid, 0, 0 );
00557 #endif
00558 
00559        return LDAP_COMPARE_FALSE;
00560 }
00561 
00562 void slap_free_ctrls(
00563        Operation *op,
00564        LDAPControl **ctrls )
00565 {
00566        int i;
00567 
00568        for (i=0; ctrls[i]; i++) {
00569               op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
00570        }
00571        op->o_tmpfree( ctrls, op->o_tmpmemctx );
00572 }
00573 
00574 int slap_add_ctrls(
00575        Operation *op,
00576        SlapReply *rs,
00577        LDAPControl **ctrls )
00578 {
00579        int i = 0, j;
00580        LDAPControl **ctrlsp;
00581 
00582        if ( rs->sr_ctrls ) {
00583               for ( ; rs->sr_ctrls[ i ]; i++ ) ;
00584        }
00585 
00586        for ( j=0; ctrls[j]; j++ ) ;
00587 
00588        ctrlsp = op->o_tmpalloc(( i+j+1 )*sizeof(LDAPControl *), op->o_tmpmemctx );
00589        i = 0;
00590        if ( rs->sr_ctrls ) {
00591               for ( ; rs->sr_ctrls[i]; i++ )
00592                      ctrlsp[i] = rs->sr_ctrls[i];
00593        }
00594        for ( j=0; ctrls[j]; j++)
00595               ctrlsp[i++] = ctrls[j];
00596        ctrlsp[i] = NULL;
00597 
00598        if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED )
00599               op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
00600        rs->sr_ctrls = ctrlsp;
00601        rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
00602        return i;
00603 }
00604 
00605 int slap_parse_ctrl(
00606        Operation *op,
00607        SlapReply *rs,
00608        LDAPControl *control,
00609        const char **text )
00610 {
00611        struct slap_control *sc;
00612        int rc = LDAP_SUCCESS;
00613 
00614        sc = find_ctrl( control->ldctl_oid );
00615        if( sc != NULL ) {
00616               /* recognized control */
00617               slap_mask_t tagmask;
00618               switch( op->o_tag ) {
00619               case LDAP_REQ_ADD:
00620                      tagmask = SLAP_CTRL_ADD;
00621                      break;
00622               case LDAP_REQ_BIND:
00623                      tagmask = SLAP_CTRL_BIND;
00624                      break;
00625               case LDAP_REQ_COMPARE:
00626                      tagmask = SLAP_CTRL_COMPARE;
00627                      break;
00628               case LDAP_REQ_DELETE:
00629                      tagmask = SLAP_CTRL_DELETE;
00630                      break;
00631               case LDAP_REQ_MODIFY:
00632                      tagmask = SLAP_CTRL_MODIFY;
00633                      break;
00634               case LDAP_REQ_RENAME:
00635                      tagmask = SLAP_CTRL_RENAME;
00636                      break;
00637               case LDAP_REQ_SEARCH:
00638                      tagmask = SLAP_CTRL_SEARCH;
00639                      break;
00640               case LDAP_REQ_UNBIND:
00641                      tagmask = SLAP_CTRL_UNBIND;
00642                      break;
00643               case LDAP_REQ_ABANDON:
00644                      tagmask = SLAP_CTRL_ABANDON;
00645                      break;
00646               case LDAP_REQ_EXTENDED:
00647                      tagmask=~0L;
00648                      assert( op->ore_reqoid.bv_val != NULL );
00649                      if( sc->sc_extendedopsbv != NULL ) {
00650                             int i;
00651                             for( i=0; !BER_BVISNULL( &sc->sc_extendedopsbv[i] ); i++ ) {
00652                                    if( bvmatch( &op->ore_reqoid,
00653                                           &sc->sc_extendedopsbv[i] ) )
00654                                    {
00655                                           tagmask=0L;
00656                                           break;
00657                                    }
00658                             }
00659                      }
00660                      break;
00661               default:
00662                      *text = "controls internal error";
00663                      return LDAP_OTHER;
00664               }
00665 
00666               if (( sc->sc_mask & tagmask ) == tagmask ) {
00667                      /* available extension */
00668                      if ( sc->sc_parse ) {
00669                             rc = sc->sc_parse( op, rs, control );
00670                             assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
00671 
00672                      } else if ( control->ldctl_iscritical ) {
00673                             *text = "not yet implemented";
00674                             rc = LDAP_OTHER;
00675                      }
00676 
00677 
00678               } else if ( control->ldctl_iscritical ) {
00679                      /* unavailable CRITICAL control */
00680                      *text = "critical extension is unavailable";
00681                      rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
00682               }
00683 
00684        } else if ( control->ldctl_iscritical ) {
00685               /* unrecognized CRITICAL control */
00686               *text = "critical extension is not recognized";
00687               rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
00688        }
00689 
00690        return rc;
00691 }
00692 
00693 int get_ctrls(
00694        Operation *op,
00695        SlapReply *rs,
00696        int sendres )
00697 {
00698        int nctrls = 0;
00699        ber_tag_t tag;
00700        ber_len_t len;
00701        char *opaque;
00702        BerElement *ber = op->o_ber;
00703        struct berval bv;
00704 #ifdef SLAP_CONTROL_X_WHATFAILED
00705        /* NOTE: right now, slapd checks the validity of each control
00706         * while parsing.  As a consequence, it can only detect one
00707         * cause of failure at a time.  This results in returning
00708         * exactly one OID with the whatFailed control, or no control
00709         * at all.
00710         */
00711        char *failed_oid = NULL;
00712 #endif
00713 
00714        len = ber_pvt_ber_remaining(ber);
00715 
00716        if( len == 0) {
00717               /* no controls */
00718               rs->sr_err = LDAP_SUCCESS;
00719               return rs->sr_err;
00720        }
00721 
00722        if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
00723               if( tag == LBER_ERROR ) {
00724                      rs->sr_err = SLAPD_DISCONNECT;
00725                      rs->sr_text = "unexpected data in PDU";
00726               }
00727 
00728               goto return_results;
00729        }
00730 
00731        Debug( LDAP_DEBUG_TRACE,
00732               "=> get_ctrls\n", 0, 0, 0 );
00733 
00734        if( op->o_protocol < LDAP_VERSION3 ) {
00735               rs->sr_err = SLAPD_DISCONNECT;
00736               rs->sr_text = "controls require LDAPv3";
00737               goto return_results;
00738        }
00739 
00740        /* one for first control, one for termination */
00741        op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
00742 
00743 #if 0
00744        if( op->ctrls == NULL ) {
00745               rs->sr_err = LDAP_NO_MEMORY;
00746               rs->sr_text = "no memory";
00747               goto return_results;
00748        }
00749 #endif
00750 
00751        op->o_ctrls[nctrls] = NULL;
00752 
00753        /* step through each element */
00754        for( tag = ber_first_element( ber, &len, &opaque );
00755               tag != LBER_ERROR;
00756               tag = ber_next_element( ber, &len, opaque ) )
00757        {
00758               LDAPControl *c;
00759               LDAPControl **tctrls;
00760 
00761               c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
00762               memset(c, 0, sizeof(LDAPControl));
00763 
00764               /* allocate pointer space for current controls (nctrls)
00765                * + this control + extra NULL
00766                */
00767               tctrls = op->o_tmprealloc( op->o_ctrls,
00768                      (nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
00769 
00770 #if 0
00771               if( tctrls == NULL ) {
00772                      ch_free( c );
00773                      ldap_controls_free(op->o_ctrls);
00774                      op->o_ctrls = NULL;
00775 
00776                      rs->sr_err = LDAP_NO_MEMORY;
00777                      rs->sr_text = "no memory";
00778                      goto return_results;
00779               }
00780 #endif
00781               op->o_ctrls = tctrls;
00782 
00783               op->o_ctrls[nctrls++] = c;
00784               op->o_ctrls[nctrls] = NULL;
00785 
00786               tag = ber_scanf( ber, "{m" /*}*/, &bv );
00787               c->ldctl_oid = bv.bv_val;
00788 
00789               if( tag == LBER_ERROR ) {
00790                      Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
00791                             0, 0, 0 );
00792 
00793                      slap_free_ctrls( op, op->o_ctrls );
00794                      op->o_ctrls = NULL;
00795                      rs->sr_err = SLAPD_DISCONNECT;
00796                      rs->sr_text = "decoding controls error";
00797                      goto return_results;
00798 
00799               } else if( c->ldctl_oid == NULL ) {
00800                      Debug( LDAP_DEBUG_TRACE,
00801                             "get_ctrls: conn %lu got emtpy OID.\n",
00802                             op->o_connid, 0, 0 );
00803 
00804                      slap_free_ctrls( op, op->o_ctrls );
00805                      op->o_ctrls = NULL;
00806                      rs->sr_err = LDAP_PROTOCOL_ERROR;
00807                      rs->sr_text = "OID field is empty";
00808                      goto return_results;
00809               }
00810 
00811               tag = ber_peek_tag( ber, &len );
00812 
00813               if( tag == LBER_BOOLEAN ) {
00814                      ber_int_t crit;
00815                      tag = ber_scanf( ber, "b", &crit );
00816 
00817                      if( tag == LBER_ERROR ) {
00818                             Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
00819                                    0, 0, 0 );
00820                             slap_free_ctrls( op, op->o_ctrls );
00821                             op->o_ctrls = NULL;
00822                             rs->sr_err = SLAPD_DISCONNECT;
00823                             rs->sr_text = "decoding controls error";
00824                             goto return_results;
00825                      }
00826 
00827                      c->ldctl_iscritical = (crit != 0);
00828                      tag = ber_peek_tag( ber, &len );
00829               }
00830 
00831               if( tag == LBER_OCTETSTRING ) {
00832                      tag = ber_scanf( ber, "m", &c->ldctl_value );
00833 
00834                      if( tag == LBER_ERROR ) {
00835                             Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
00836                                    "%s (%scritical): get value failed.\n",
00837                                    op->o_connid, c->ldctl_oid,
00838                                    c->ldctl_iscritical ? "" : "non" );
00839                             slap_free_ctrls( op, op->o_ctrls );
00840                             op->o_ctrls = NULL;
00841                             rs->sr_err = SLAPD_DISCONNECT;
00842                             rs->sr_text = "decoding controls error";
00843                             goto return_results;
00844                      }
00845               }
00846 
00847               Debug( LDAP_DEBUG_TRACE,
00848                      "=> get_ctrls: oid=\"%s\" (%scritical)\n",
00849                      c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
00850 
00851               rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
00852               if ( rs->sr_err != LDAP_SUCCESS ) {
00853 #ifdef SLAP_CONTROL_X_WHATFAILED
00854                      failed_oid = c->ldctl_oid;
00855 #endif
00856                      goto return_results;
00857               }
00858        }
00859 
00860 return_results:
00861        Debug( LDAP_DEBUG_TRACE,
00862               "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
00863               nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
00864 
00865        if( sendres && rs->sr_err != LDAP_SUCCESS ) {
00866               if( rs->sr_err == SLAPD_DISCONNECT ) {
00867                      rs->sr_err = LDAP_PROTOCOL_ERROR;
00868                      send_ldap_disconnect( op, rs );
00869                      rs->sr_err = SLAPD_DISCONNECT;
00870               } else {
00871 #ifdef SLAP_CONTROL_X_WHATFAILED
00872                      /* might have not been parsed yet? */
00873                      if ( failed_oid != NULL ) {
00874                             if ( !get_whatFailed( op ) ) {
00875                                    /* look it up */
00876 
00877                                    /* step through each remaining element */
00878                                    for ( ; tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) )
00879                                    {
00880                                           LDAPControl c = { 0 };
00881 
00882                                           tag = ber_scanf( ber, "{m" /*}*/, &bv );
00883                                           c.ldctl_oid = bv.bv_val;
00884 
00885                                           if ( tag == LBER_ERROR ) {
00886                                                  slap_free_ctrls( op, op->o_ctrls );
00887                                                  op->o_ctrls = NULL;
00888                                                  break;
00889 
00890                                           } else if ( c.ldctl_oid == NULL ) {
00891                                                  slap_free_ctrls( op, op->o_ctrls );
00892                                                  op->o_ctrls = NULL;
00893                                                  break;
00894                                           }
00895 
00896                                           tag = ber_peek_tag( ber, &len );
00897                                           if ( tag == LBER_BOOLEAN ) {
00898                                                  ber_int_t crit;
00899                                                  tag = ber_scanf( ber, "b", &crit );
00900                                                  if( tag == LBER_ERROR ) {
00901                                                         slap_free_ctrls( op, op->o_ctrls );
00902                                                         op->o_ctrls = NULL;
00903                                                         break;
00904                                                  }
00905 
00906                                                  tag = ber_peek_tag( ber, &len );
00907                                           }
00908 
00909                                           if ( tag == LBER_OCTETSTRING ) {
00910                                                  tag = ber_scanf( ber, "m", &c.ldctl_value );
00911 
00912                                                  if( tag == LBER_ERROR ) {
00913                                                         slap_free_ctrls( op, op->o_ctrls );
00914                                                         op->o_ctrls = NULL;
00915                                                         break;
00916                                                  }
00917                                           }
00918 
00919                                           if ( strcmp( c.ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) == 0 ) {
00920                                                  const char *text;
00921                                                  slap_parse_ctrl( op, rs, &c, &text );
00922                                                  break;
00923                                           }
00924                                    }
00925                             }
00926 
00927                             if ( get_whatFailed( op ) ) {
00928                                    char *oids[ 2 ];
00929                                    oids[ 0 ] = failed_oid;
00930                                    oids[ 1 ] = NULL;
00931                                    slap_ctrl_whatFailed_add( op, rs, oids );
00932                             }
00933                      }
00934 #endif
00935 
00936                      send_ldap_result( op, rs );
00937               }
00938        }
00939 
00940        return rs->sr_err;
00941 }
00942 
00943 int
00944 slap_remove_control(
00945        Operation     *op,
00946        SlapReply     *rs,
00947        int           ctrl,
00948        BI_chk_controls      fnc )
00949 {
00950        int           i, j;
00951 
00952        switch ( op->o_ctrlflag[ ctrl ] ) {
00953        case SLAP_CONTROL_NONCRITICAL:
00954               for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) {
00955                      if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
00956                             slap_known_controls[ ctrl - 1 ] ) == 0 )
00957                      {
00958                             j = i;
00959                      }
00960               }
00961 
00962               if ( j == -1 ) {
00963                      rs->sr_err = LDAP_OTHER;
00964                      break;
00965               }
00966 
00967               if ( fnc ) {
00968                      (void)fnc( op, rs );
00969               }
00970 
00971               op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx );
00972 
00973               if ( i > 1 ) {
00974                      AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ],
00975                             ( i - j ) * sizeof( LDAPControl * ) );
00976 
00977               } else {
00978                      op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
00979                      op->o_ctrls = NULL;
00980               }
00981 
00982               op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED;
00983 
00984               Debug( LDAP_DEBUG_ANY, "%s: "
00985                      "non-critical control \"%s\" not supported; stripped.\n",
00986                      op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
00987               /* fall thru */
00988 
00989        case SLAP_CONTROL_IGNORED:
00990        case SLAP_CONTROL_NONE:
00991               rs->sr_err = SLAP_CB_CONTINUE;
00992               break;
00993 
00994        case SLAP_CONTROL_CRITICAL:
00995               rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
00996               if ( fnc ) {
00997                      (void)fnc( op, rs );
00998               }
00999               Debug( LDAP_DEBUG_ANY, "%s: "
01000                      "critical control \"%s\" not supported.\n",
01001                      op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
01002               break;
01003 
01004        default:
01005               /* handle all cases! */
01006               assert( 0 );
01007        }
01008 
01009        return rs->sr_err;
01010 }
01011 
01012 static int parseDontUseCopy (
01013        Operation *op,
01014        SlapReply *rs,
01015        LDAPControl *ctrl )
01016 {
01017        if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) {
01018               rs->sr_text = "dontUseCopy control specified multiple times";
01019               return LDAP_PROTOCOL_ERROR;
01020        }
01021 
01022        if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
01023               rs->sr_text = "dontUseCopy control value not absent";
01024               return LDAP_PROTOCOL_ERROR;
01025        }
01026 
01027        if ( ( global_disallows & SLAP_DISALLOW_DONTUSECOPY_N_CRIT )
01028               && !ctrl->ldctl_iscritical )
01029        {
01030               rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
01031               return LDAP_PROTOCOL_ERROR;
01032        }
01033 
01034        op->o_dontUseCopy = ctrl->ldctl_iscritical
01035               ? SLAP_CONTROL_CRITICAL
01036               : SLAP_CONTROL_NONCRITICAL;
01037 
01038        return LDAP_SUCCESS;
01039 }
01040 
01041 static int parseRelax (
01042        Operation *op,
01043        SlapReply *rs,
01044        LDAPControl *ctrl )
01045 {
01046        if ( op->o_relax != SLAP_CONTROL_NONE ) {
01047               rs->sr_text = "relax control specified multiple times";
01048               return LDAP_PROTOCOL_ERROR;
01049        }
01050 
01051        if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
01052               rs->sr_text = "relax control value not absent";
01053               return LDAP_PROTOCOL_ERROR;
01054        }
01055 
01056        op->o_relax = ctrl->ldctl_iscritical
01057               ? SLAP_CONTROL_CRITICAL
01058               : SLAP_CONTROL_NONCRITICAL;
01059 
01060        return LDAP_SUCCESS;
01061 }
01062 
01063 static int parseManageDSAit (
01064        Operation *op,
01065        SlapReply *rs,
01066        LDAPControl *ctrl )
01067 {
01068        if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
01069               rs->sr_text = "manageDSAit control specified multiple times";
01070               return LDAP_PROTOCOL_ERROR;
01071        }
01072 
01073        if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
01074               rs->sr_text = "manageDSAit control value not absent";
01075               return LDAP_PROTOCOL_ERROR;
01076        }
01077 
01078        op->o_managedsait = ctrl->ldctl_iscritical
01079               ? SLAP_CONTROL_CRITICAL
01080               : SLAP_CONTROL_NONCRITICAL;
01081 
01082        return LDAP_SUCCESS;
01083 }
01084 
01085 static int parseProxyAuthz (
01086        Operation *op,
01087        SlapReply *rs,
01088        LDAPControl *ctrl )
01089 {
01090        int           rc;
01091        struct berval dn = BER_BVNULL;
01092 
01093        if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
01094               rs->sr_text = "proxy authorization control specified multiple times";
01095               return LDAP_PROTOCOL_ERROR;
01096        }
01097 
01098        if ( BER_BVISNULL( &ctrl->ldctl_value )) {
01099               rs->sr_text = "proxy authorization control value absent";
01100               return LDAP_PROTOCOL_ERROR;
01101        }
01102 
01103        if ( ( global_disallows & SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT )
01104               && !ctrl->ldctl_iscritical )
01105        {
01106               rs->sr_text = "proxied authorization criticality of FALSE not allowed";
01107               return LDAP_PROTOCOL_ERROR;
01108        }
01109 
01110        if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON )
01111               && BER_BVISEMPTY( &op->o_ndn ) )
01112        {
01113               rs->sr_text = "anonymous proxied authorization not allowed";
01114               return LDAP_PROXIED_AUTHORIZATION_DENIED;
01115        }
01116 
01117        op->o_proxy_authz = ctrl->ldctl_iscritical
01118               ? SLAP_CONTROL_CRITICAL
01119               : SLAP_CONTROL_NONCRITICAL;
01120 
01121        Debug( LDAP_DEBUG_ARGS,
01122               "parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
01123               op->o_connid,
01124               ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
01125               0 );
01126 
01127        if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
01128               Debug( LDAP_DEBUG_TRACE,
01129                      "parseProxyAuthz: conn=%lu anonymous\n", 
01130                      op->o_connid, 0, 0 );
01131 
01132               /* anonymous */
01133               if ( !BER_BVISNULL( &op->o_ndn ) ) {
01134                      op->o_ndn.bv_val[ 0 ] = '\0';
01135               }
01136               op->o_ndn.bv_len = 0;
01137 
01138               if ( !BER_BVISNULL( &op->o_dn ) ) {
01139                      op->o_dn.bv_val[ 0 ] = '\0';
01140               }
01141               op->o_dn.bv_len = 0;
01142 
01143               return LDAP_SUCCESS;
01144        }
01145 
01146        rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
01147                      NULL, &dn, SLAP_GETDN_AUTHZID );
01148 
01149        /* FIXME: empty DN in proxyAuthz control should be legal... */
01150        if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
01151               if ( dn.bv_val ) {
01152                      ch_free( dn.bv_val );
01153               }
01154               rs->sr_text = "authzId mapping failed";
01155               return LDAP_PROXIED_AUTHORIZATION_DENIED;
01156        }
01157 
01158        Debug( LDAP_DEBUG_TRACE,
01159               "parseProxyAuthz: conn=%lu \"%s\"\n", 
01160               op->o_connid,
01161               dn.bv_len ? dn.bv_val : "(NULL)", 0 );
01162 
01163        rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
01164 
01165        if ( rc ) {
01166               ch_free( dn.bv_val );
01167               rs->sr_text = "not authorized to assume identity";
01168               return LDAP_PROXIED_AUTHORIZATION_DENIED;
01169        }
01170 
01171        ch_free( op->o_ndn.bv_val );
01172 
01173        /*
01174         * NOTE: since slap_sasl_getdn() returns a normalized dn,
01175         * from now on op->o_dn is normalized
01176         */
01177        op->o_ndn = dn;
01178        ber_bvreplace( &op->o_dn, &dn );
01179 
01180        Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
01181            op->o_log_prefix, dn.bv_val, 0, 0, 0 );
01182 
01183        return LDAP_SUCCESS;
01184 }
01185 
01186 static int parseNoOp (
01187        Operation *op,
01188        SlapReply *rs,
01189        LDAPControl *ctrl )
01190 {
01191        if ( op->o_noop != SLAP_CONTROL_NONE ) {
01192               rs->sr_text = "noop control specified multiple times";
01193               return LDAP_PROTOCOL_ERROR;
01194        }
01195 
01196        if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
01197               rs->sr_text = "noop control value not empty";
01198               return LDAP_PROTOCOL_ERROR;
01199        }
01200 
01201        op->o_noop = ctrl->ldctl_iscritical
01202               ? SLAP_CONTROL_CRITICAL
01203               : SLAP_CONTROL_NONCRITICAL;
01204 
01205        return LDAP_SUCCESS;
01206 }
01207 
01208 static int parsePagedResults (
01209        Operation *op,
01210        SlapReply *rs,
01211        LDAPControl *ctrl )
01212 {
01213        BerElementBuffer berbuf;
01214        BerElement    *ber = (BerElement *)&berbuf;
01215        struct berval cookie;
01216        PagedResultsState    *ps;
01217        int           rc = LDAP_SUCCESS;
01218        ber_tag_t     tag;
01219        ber_int_t     size;
01220 
01221        if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
01222               rs->sr_text = "paged results control specified multiple times";
01223               return LDAP_PROTOCOL_ERROR;
01224        }
01225 
01226        if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
01227               rs->sr_text = "paged results control value is absent";
01228               return LDAP_PROTOCOL_ERROR;
01229        }
01230 
01231        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
01232               rs->sr_text = "paged results control value is empty";
01233               return LDAP_PROTOCOL_ERROR;
01234        }
01235 
01236        /* Parse the control value
01237         *     realSearchControlValue ::= SEQUENCE {
01238         *            size   INTEGER (0..maxInt),
01239         *                          -- requested page size from client
01240         *                          -- result set size estimate from server
01241         *            cookie OCTET STRING
01242         * }
01243         */
01244        ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER );
01245 
01246        tag = ber_scanf( ber, "{im}", &size, &cookie );
01247 
01248        if ( tag == LBER_ERROR ) {
01249               rs->sr_text = "paged results control could not be decoded";
01250               rc = LDAP_PROTOCOL_ERROR;
01251               goto done;
01252        }
01253 
01254        if ( size < 0 ) {
01255               rs->sr_text = "paged results control size invalid";
01256               rc = LDAP_PROTOCOL_ERROR;
01257               goto done;
01258        }
01259 
01260        ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
01261        *ps = op->o_conn->c_pagedresults_state;
01262        ps->ps_size = size;
01263        ps->ps_cookieval = cookie;
01264        op->o_pagedresults_state = ps;
01265        if ( !cookie.bv_len ) {
01266               ps->ps_count = 0;
01267               ps->ps_cookie = 0;
01268               /* taint ps_cookie, to detect whether it's set */
01269               op->o_conn->c_pagedresults_state.ps_cookie = NOID;
01270        }
01271 
01272        /* NOTE: according to RFC 2696 3.:
01273 
01274     If the page size is greater than or equal to the sizeLimit value, the
01275     server should ignore the control as the request can be satisfied in a
01276     single page.
01277 
01278         * NOTE: this assumes that the op->ors_slimit be set
01279         * before the controls are parsed.     
01280         */
01281 
01282        if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
01283               op->o_pagedresults = SLAP_CONTROL_IGNORED;
01284 
01285        } else if ( ctrl->ldctl_iscritical ) {
01286               op->o_pagedresults = SLAP_CONTROL_CRITICAL;
01287 
01288        } else {
01289               op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
01290        }
01291 
01292 done:;
01293        return rc;
01294 }
01295 
01296 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
01297 static int parseSortedResults (
01298        Operation *op,
01299        SlapReply *rs,
01300        LDAPControl *ctrl )
01301 {
01302        int           rc = LDAP_SUCCESS;
01303 
01304        if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
01305               rs->sr_text = "sorted results control specified multiple times";
01306               return LDAP_PROTOCOL_ERROR;
01307        }
01308 
01309        if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
01310               rs->sr_text = "sorted results control value is absent";
01311               return LDAP_PROTOCOL_ERROR;
01312        }
01313 
01314        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
01315               rs->sr_text = "sorted results control value is empty";
01316               return LDAP_PROTOCOL_ERROR;
01317        }
01318 
01319        /* blow off parsing the value */
01320 
01321        op->o_sortedresults = ctrl->ldctl_iscritical
01322               ? SLAP_CONTROL_CRITICAL
01323               : SLAP_CONTROL_NONCRITICAL;
01324 
01325        return rc;
01326 }
01327 #endif
01328 
01329 static int parseAssert (
01330        Operation *op,
01331        SlapReply *rs,
01332        LDAPControl *ctrl )
01333 {
01334        BerElement    *ber;
01335        struct berval fstr = BER_BVNULL;
01336 
01337        if ( op->o_assert != SLAP_CONTROL_NONE ) {
01338               rs->sr_text = "assert control specified multiple times";
01339               return LDAP_PROTOCOL_ERROR;
01340        }
01341 
01342        if ( BER_BVISNULL( &ctrl->ldctl_value )) {
01343               rs->sr_text = "assert control value is absent";
01344               return LDAP_PROTOCOL_ERROR;
01345        }
01346 
01347        if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
01348               rs->sr_text = "assert control value is empty";
01349               return LDAP_PROTOCOL_ERROR;
01350        }
01351 
01352        ber = ber_init( &(ctrl->ldctl_value) );
01353        if (ber == NULL) {
01354               rs->sr_text = "assert control: internal error";
01355               return LDAP_OTHER;
01356        }
01357 
01358        rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
01359               &rs->sr_text);
01360        (void) ber_free( ber, 1 );
01361        if( rs->sr_err != LDAP_SUCCESS ) {
01362               if( rs->sr_err == SLAPD_DISCONNECT ) {
01363                      rs->sr_err = LDAP_PROTOCOL_ERROR;
01364                      send_ldap_disconnect( op, rs );
01365                      rs->sr_err = SLAPD_DISCONNECT;
01366               } else {
01367                      send_ldap_result( op, rs );
01368               }
01369               if( op->o_assertion != NULL ) {
01370                      filter_free_x( op, op->o_assertion, 1 );
01371               }
01372               return rs->sr_err;
01373        }
01374 
01375 #ifdef LDAP_DEBUG
01376        filter2bv_x( op, op->o_assertion, &fstr );
01377 
01378        Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
01379               op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
01380        op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
01381 #endif
01382 
01383        op->o_assert = ctrl->ldctl_iscritical
01384               ? SLAP_CONTROL_CRITICAL
01385               : SLAP_CONTROL_NONCRITICAL;
01386 
01387        rs->sr_err = LDAP_SUCCESS;
01388        return LDAP_SUCCESS;
01389 }
01390 
01391 #define READMSG(post, msg) \
01392        ( post ? "postread control: " msg : "preread control: " msg )
01393 
01394 static int
01395 parseReadAttrs(
01396        Operation *op,
01397        SlapReply *rs,
01398        LDAPControl *ctrl,
01399        int post )
01400 {
01401        ber_len_t     siz, off, i;
01402        BerElement    *ber;
01403        AttributeName *an = NULL;
01404 
01405        if ( ( post && op->o_postread != SLAP_CONTROL_NONE ) ||
01406               ( !post && op->o_preread != SLAP_CONTROL_NONE ) )
01407        {
01408               rs->sr_text = READMSG( post, "specified multiple times" );
01409               return LDAP_PROTOCOL_ERROR;
01410        }
01411 
01412        if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
01413               rs->sr_text = READMSG( post, "value is absent" );
01414               return LDAP_PROTOCOL_ERROR;
01415        }
01416 
01417        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
01418               rs->sr_text = READMSG( post, "value is empty" );
01419               return LDAP_PROTOCOL_ERROR;
01420        }
01421 
01422 #ifdef LDAP_X_TXN
01423        if ( op->o_txnSpec ) { /* temporary limitation */
01424               rs->sr_text = READMSG( post, "cannot perform in transaction" );
01425               return LDAP_UNWILLING_TO_PERFORM;
01426        }
01427 #endif
01428 
01429        ber = ber_init( &ctrl->ldctl_value );
01430        if ( ber == NULL ) {
01431               rs->sr_text = READMSG( post, "internal error" );
01432               return LDAP_OTHER;
01433        }
01434 
01435        rs->sr_err = LDAP_SUCCESS;
01436        siz = sizeof( AttributeName );
01437        off = offsetof( AttributeName, an_name );
01438        if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
01439               rs->sr_text = READMSG( post, "decoding error" );
01440               rs->sr_err = LDAP_PROTOCOL_ERROR;
01441               goto done;
01442        }
01443 
01444        for ( i = 0; i < siz; i++ ) {
01445               const char    *dummy = NULL;
01446               int           rc;
01447 
01448               an[i].an_desc = NULL;
01449               an[i].an_oc = NULL;
01450               an[i].an_flags = 0;
01451               rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
01452               if ( rc == LDAP_SUCCESS ) {
01453                      an[i].an_name = an[i].an_desc->ad_cname;
01454 
01455               } else {
01456                      int                  j;
01457                      static struct berval special_attrs[] = {
01458                             BER_BVC( LDAP_NO_ATTRS ),
01459                             BER_BVC( LDAP_ALL_USER_ATTRIBUTES ),
01460                             BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ),
01461                             BER_BVNULL
01462                      };
01463 
01464                      /* deal with special attribute types */
01465                      for ( j = 0; !BER_BVISNULL( &special_attrs[ j ] ); j++ ) {
01466                             if ( bvmatch( &an[i].an_name, &special_attrs[ j ] ) ) {
01467                                    an[i].an_name = special_attrs[ j ];
01468                                    break;
01469                             }
01470                      }
01471 
01472                      if ( BER_BVISNULL( &special_attrs[ j ] ) && ctrl->ldctl_iscritical ) {
01473                             rs->sr_err = rc;
01474                             rs->sr_text = dummy ? dummy
01475                                    : READMSG( post, "unknown attributeType" );
01476                             goto done;
01477                      }
01478               }
01479        }
01480 
01481        if ( post ) {
01482               op->o_postread_attrs = an;
01483               op->o_postread = ctrl->ldctl_iscritical
01484                      ? SLAP_CONTROL_CRITICAL
01485                      : SLAP_CONTROL_NONCRITICAL;
01486        } else {
01487               op->o_preread_attrs = an;
01488               op->o_preread = ctrl->ldctl_iscritical
01489                      ? SLAP_CONTROL_CRITICAL
01490                      : SLAP_CONTROL_NONCRITICAL;
01491        }
01492 
01493 done:
01494        (void) ber_free( ber, 1 );
01495        return rs->sr_err;
01496 }
01497 
01498 static int parsePreRead (
01499        Operation *op,
01500        SlapReply *rs,
01501        LDAPControl *ctrl )
01502 {
01503        return parseReadAttrs( op, rs, ctrl, 0 );
01504 }
01505 
01506 static int parsePostRead (
01507        Operation *op,
01508        SlapReply *rs,
01509        LDAPControl *ctrl )
01510 {
01511        return parseReadAttrs( op, rs, ctrl, 1 );
01512 }
01513 
01514 static int parseValuesReturnFilter (
01515        Operation *op,
01516        SlapReply *rs,
01517        LDAPControl *ctrl )
01518 {
01519        BerElement    *ber;
01520        struct berval fstr = BER_BVNULL;
01521 
01522        if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
01523               rs->sr_text = "valuesReturnFilter control specified multiple times";
01524               return LDAP_PROTOCOL_ERROR;
01525        }
01526 
01527        if ( BER_BVISNULL( &ctrl->ldctl_value )) {
01528               rs->sr_text = "valuesReturnFilter control value is absent";
01529               return LDAP_PROTOCOL_ERROR;
01530        }
01531 
01532        if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
01533               rs->sr_text = "valuesReturnFilter control value is empty";
01534               return LDAP_PROTOCOL_ERROR;
01535        }
01536 
01537        ber = ber_init( &(ctrl->ldctl_value) );
01538        if (ber == NULL) {
01539               rs->sr_text = "internal error";
01540               return LDAP_OTHER;
01541        }
01542 
01543        rs->sr_err = get_vrFilter( op, ber,
01544               (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
01545 
01546        (void) ber_free( ber, 1 );
01547 
01548        if( rs->sr_err != LDAP_SUCCESS ) {
01549               if( rs->sr_err == SLAPD_DISCONNECT ) {
01550                      rs->sr_err = LDAP_PROTOCOL_ERROR;
01551                      send_ldap_disconnect( op, rs );
01552                      rs->sr_err = SLAPD_DISCONNECT;
01553               } else {
01554                      send_ldap_result( op, rs );
01555               }
01556               if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter ); 
01557        }
01558 #ifdef LDAP_DEBUG
01559        else {
01560               vrFilter2bv( op, op->o_vrFilter, &fstr );
01561        }
01562 
01563        Debug( LDAP_DEBUG_ARGS, "   vrFilter: %s\n",
01564               fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
01565        op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
01566 #endif
01567 
01568        op->o_valuesreturnfilter = ctrl->ldctl_iscritical
01569               ? SLAP_CONTROL_CRITICAL
01570               : SLAP_CONTROL_NONCRITICAL;
01571 
01572        rs->sr_err = LDAP_SUCCESS;
01573        return LDAP_SUCCESS;
01574 }
01575 
01576 static int parseSubentries (
01577        Operation *op,
01578        SlapReply *rs,
01579        LDAPControl *ctrl )
01580 {
01581        if ( op->o_subentries != SLAP_CONTROL_NONE ) {
01582               rs->sr_text = "subentries control specified multiple times";
01583               return LDAP_PROTOCOL_ERROR;
01584        }
01585 
01586        /* FIXME: should use BER library */
01587        if( ( ctrl->ldctl_value.bv_len != 3 )
01588               || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
01589               || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
01590        {
01591               rs->sr_text = "subentries control value encoding is bogus";
01592               return LDAP_PROTOCOL_ERROR;
01593        }
01594 
01595        op->o_subentries = ctrl->ldctl_iscritical
01596               ? SLAP_CONTROL_CRITICAL
01597               : SLAP_CONTROL_NONCRITICAL;
01598 
01599        if (ctrl->ldctl_value.bv_val[2]) {
01600               set_subentries_visibility( op );
01601        }
01602 
01603        return LDAP_SUCCESS;
01604 }
01605 
01606 static int parsePermissiveModify (
01607        Operation *op,
01608        SlapReply *rs,
01609        LDAPControl *ctrl )
01610 {
01611        if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) {
01612               rs->sr_text = "permissiveModify control specified multiple times";
01613               return LDAP_PROTOCOL_ERROR;
01614        }
01615 
01616        if ( BER_BVISNULL( &ctrl->ldctl_value )) {
01617               rs->sr_text = "permissiveModify control value not absent";
01618               return LDAP_PROTOCOL_ERROR;
01619        }
01620 
01621        op->o_permissive_modify = ctrl->ldctl_iscritical
01622               ? SLAP_CONTROL_CRITICAL
01623               : SLAP_CONTROL_NONCRITICAL;
01624 
01625        return LDAP_SUCCESS;
01626 }
01627 
01628 static int parseDomainScope (
01629        Operation *op,
01630        SlapReply *rs,
01631        LDAPControl *ctrl )
01632 {
01633        if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
01634               rs->sr_text = "domainScope control specified multiple times";
01635               return LDAP_PROTOCOL_ERROR;
01636        }
01637 
01638        if ( BER_BVISNULL( &ctrl->ldctl_value )) {
01639               rs->sr_text = "domainScope control value not empty";
01640               return LDAP_PROTOCOL_ERROR;
01641        }
01642 
01643        op->o_domain_scope = ctrl->ldctl_iscritical
01644               ? SLAP_CONTROL_CRITICAL
01645               : SLAP_CONTROL_NONCRITICAL;
01646 
01647        return LDAP_SUCCESS;
01648 }
01649 
01650 #ifdef SLAP_CONTROL_X_TREE_DELETE
01651 static int parseTreeDelete (
01652        Operation *op,
01653        SlapReply *rs,
01654        LDAPControl *ctrl )
01655 {
01656        if ( op->o_tree_delete != SLAP_CONTROL_NONE ) {
01657               rs->sr_text = "treeDelete control specified multiple times";
01658               return LDAP_PROTOCOL_ERROR;
01659        }
01660 
01661        if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
01662               rs->sr_text = "treeDelete control value not absent";
01663               return LDAP_PROTOCOL_ERROR;
01664        }
01665 
01666        op->o_tree_delete = ctrl->ldctl_iscritical
01667               ? SLAP_CONTROL_CRITICAL
01668               : SLAP_CONTROL_NONCRITICAL;
01669 
01670        return LDAP_SUCCESS;
01671 }
01672 #endif
01673 
01674 static int parseSearchOptions (
01675        Operation *op,
01676        SlapReply *rs,
01677        LDAPControl *ctrl )
01678 {
01679        BerElement *ber;
01680        ber_int_t search_flags;
01681        ber_tag_t tag;
01682 
01683        if ( BER_BVISNULL( &ctrl->ldctl_value )) {
01684               rs->sr_text = "searchOptions control value is absent";
01685               return LDAP_PROTOCOL_ERROR;
01686        }
01687 
01688        if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
01689               rs->sr_text = "searchOptions control value is empty";
01690               return LDAP_PROTOCOL_ERROR;
01691        }
01692 
01693        ber = ber_init( &ctrl->ldctl_value );
01694        if( ber == NULL ) {
01695               rs->sr_text = "internal error";
01696               return LDAP_OTHER;
01697        }
01698 
01699        tag = ber_scanf( ber, "{i}", &search_flags );
01700        (void) ber_free( ber, 1 );
01701 
01702        if ( tag == LBER_ERROR ) {
01703               rs->sr_text = "searchOptions control decoding error";
01704               return LDAP_PROTOCOL_ERROR;
01705        }
01706 
01707        if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
01708               /* Search flags not recognised so far,
01709                * including:
01710                *            LDAP_SEARCH_FLAG_PHANTOM_ROOT
01711                */
01712               if ( ctrl->ldctl_iscritical ) {
01713                      rs->sr_text = "searchOptions contained unrecognized flag";
01714                      return LDAP_UNWILLING_TO_PERFORM;
01715               }
01716 
01717               /* Ignore */
01718               Debug( LDAP_DEBUG_TRACE,
01719                      "searchOptions: conn=%lu unrecognized flag(s) 0x%x (non-critical)\n", 
01720                      op->o_connid, (unsigned)search_flags, 0 );
01721 
01722               return LDAP_SUCCESS;
01723        }
01724 
01725        if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
01726               if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
01727                      rs->sr_text = "searchOptions control specified multiple times "
01728                             "or with domainScope control";
01729                      return LDAP_PROTOCOL_ERROR;
01730               }
01731 
01732               op->o_domain_scope = ctrl->ldctl_iscritical
01733                      ? SLAP_CONTROL_CRITICAL
01734                      : SLAP_CONTROL_NONCRITICAL;
01735        }
01736 
01737        return LDAP_SUCCESS;
01738 }
01739 
01740 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
01741 struct berval session_tracking_formats[] = {
01742        BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID ),
01743               BER_BVC( "RADIUS-Acct-Session-Id" ),
01744        BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID ),
01745               BER_BVC( "RADIUS-Acct-Multi-Session-Id" ),
01746        BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ),
01747               BER_BVC( "USERNAME" ),
01748 
01749        BER_BVNULL
01750 };
01751 
01752 static int parseSessionTracking(
01753        Operation *op,
01754        SlapReply *rs,
01755        LDAPControl *ctrl )
01756 {
01757        BerElement           *ber;
01758        ber_tag_t            tag;
01759        ber_len_t            len;
01760        int                  i, rc;
01761 
01762        struct berval        sessionSourceIp = BER_BVNULL,
01763                             sessionSourceName = BER_BVNULL,
01764                             formatOID = BER_BVNULL,
01765                             sessionTrackingIdentifier = BER_BVNULL;
01766 
01767        size_t               st_len, st_pos;
01768 
01769        if ( ctrl->ldctl_iscritical ) {
01770               rs->sr_text = "sessionTracking criticality is TRUE";
01771               return LDAP_PROTOCOL_ERROR;
01772        }
01773 
01774        if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
01775               rs->sr_text = "sessionTracking control value is absent";
01776               return LDAP_PROTOCOL_ERROR;
01777        }
01778 
01779        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
01780               rs->sr_text = "sessionTracking control value is empty";
01781               return LDAP_PROTOCOL_ERROR;
01782        }
01783 
01784        /* TODO: add the capability to determine if a client is allowed
01785         * to use this control, based on identity, ip and so */
01786 
01787        ber = ber_init( &ctrl->ldctl_value );
01788        if ( ber == NULL ) {
01789               rs->sr_text = "internal error";
01790               return LDAP_OTHER;
01791        }
01792 
01793        tag = ber_skip_tag( ber, &len );
01794        if ( tag != LBER_SEQUENCE ) {
01795               tag = LBER_ERROR;
01796               goto error;
01797        }
01798 
01799        /* sessionSourceIp */
01800        tag = ber_peek_tag( ber, &len );
01801        if ( tag == LBER_DEFAULT ) {
01802               tag = LBER_ERROR;
01803               goto error;
01804        }
01805 
01806        if ( len == 0 ) {
01807               tag = ber_skip_tag( ber, &len );
01808 
01809        } else if ( len > 128 ) {
01810               rs->sr_text = "sessionTracking.sessionSourceIp too long";
01811               rs->sr_err = LDAP_PROTOCOL_ERROR;
01812               goto error;
01813 
01814        } else {
01815               tag = ber_scanf( ber, "m", &sessionSourceIp );
01816        }
01817 
01818        if ( ldif_is_not_printable( sessionSourceIp.bv_val, sessionSourceIp.bv_len ) ) {
01819               BER_BVZERO( &sessionSourceIp );
01820        }
01821 
01822        /* sessionSourceName */
01823        tag = ber_peek_tag( ber, &len );
01824        if ( tag == LBER_DEFAULT ) {
01825               tag = LBER_ERROR;
01826               goto error;
01827        }
01828 
01829        if ( len == 0 ) {
01830               tag = ber_skip_tag( ber, &len );
01831 
01832        } else if ( len > 65536 ) {
01833               rs->sr_text = "sessionTracking.sessionSourceName too long";
01834               rs->sr_err = LDAP_PROTOCOL_ERROR;
01835               goto error;
01836 
01837        } else {
01838               tag = ber_scanf( ber, "m", &sessionSourceName );
01839        }
01840 
01841        if ( ldif_is_not_printable( sessionSourceName.bv_val, sessionSourceName.bv_len ) ) {
01842               BER_BVZERO( &sessionSourceName );
01843        }
01844 
01845        /* formatOID */
01846        tag = ber_peek_tag( ber, &len );
01847        if ( tag == LBER_DEFAULT ) {
01848               tag = LBER_ERROR;
01849               goto error;
01850        }
01851 
01852        if ( len == 0 ) {
01853               rs->sr_text = "sessionTracking.formatOID empty";
01854               rs->sr_err = LDAP_PROTOCOL_ERROR;
01855               goto error;
01856 
01857        } else if ( len > 1024 ) {
01858               rs->sr_text = "sessionTracking.formatOID too long";
01859               rs->sr_err = LDAP_PROTOCOL_ERROR;
01860               goto error;
01861 
01862        } else {
01863               tag = ber_scanf( ber, "m", &formatOID );
01864        }
01865 
01866        rc = numericoidValidate( NULL, &formatOID );
01867        if ( rc != LDAP_SUCCESS ) {
01868               rs->sr_text = "sessionTracking.formatOID invalid";
01869               goto error;
01870        }
01871 
01872        for ( i = 0; !BER_BVISNULL( &session_tracking_formats[ i ] ); i += 2 )
01873        {
01874               if ( bvmatch( &formatOID, &session_tracking_formats[ i ] ) ) {
01875                      formatOID = session_tracking_formats[ i + 1 ];
01876                      break;
01877               }
01878        }
01879 
01880        /* sessionTrackingIdentifier */
01881        tag = ber_peek_tag( ber, &len );
01882        if ( tag == LBER_DEFAULT ) {
01883               tag = LBER_ERROR;
01884               goto error;
01885        }
01886 
01887        if ( len == 0 ) {
01888               tag = ber_skip_tag( ber, &len );
01889 
01890        } else {
01891               /* note: should not be more than 65536... */
01892               tag = ber_scanf( ber, "m", &sessionTrackingIdentifier );
01893               if ( ldif_is_not_printable( sessionTrackingIdentifier.bv_val, sessionTrackingIdentifier.bv_len ) ) {
01894                      /* we want the OID printed, at least */
01895                      BER_BVSTR( &sessionTrackingIdentifier, "" );
01896               }
01897        }
01898 
01899        /* closure */
01900        tag = ber_skip_tag( ber, &len );
01901        if ( tag != LBER_DEFAULT || len != 0 ) {
01902               tag = LBER_ERROR;
01903               goto error;
01904        }
01905        tag = 0;
01906 
01907        st_len = 0;
01908        if ( !BER_BVISNULL( &sessionSourceIp ) ) {
01909               st_len += STRLENOF( "IP=" ) + sessionSourceIp.bv_len;
01910        }
01911        if ( !BER_BVISNULL( &sessionSourceName ) ) {
01912               if ( st_len ) st_len++;
01913               st_len += STRLENOF( "NAME=" ) + sessionSourceName.bv_len;
01914        }
01915        if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
01916               if ( st_len ) st_len++;
01917               st_len += formatOID.bv_len + STRLENOF( "=" )
01918                      + sessionTrackingIdentifier.bv_len;
01919        }
01920 
01921        if ( st_len == 0 ) {
01922               goto error;
01923        }
01924 
01925        st_len += STRLENOF( " []" );
01926        st_pos = strlen( op->o_log_prefix );
01927 
01928        if ( sizeof( op->o_log_prefix ) - st_pos > st_len ) {
01929               char   *ptr = &op->o_log_prefix[ st_pos ];
01930 
01931               ptr = lutil_strcopy( ptr, " [" /*]*/ );
01932 
01933               st_len = 0;
01934               if ( !BER_BVISNULL( &sessionSourceIp ) ) {
01935                      ptr = lutil_strcopy( ptr, "IP=" );
01936                      ptr = lutil_strcopy( ptr, sessionSourceIp.bv_val );
01937                      st_len++;
01938               }
01939 
01940               if ( !BER_BVISNULL( &sessionSourceName ) ) {
01941                      if ( st_len ) *ptr++ = ' ';
01942                      ptr = lutil_strcopy( ptr, "NAME=" );
01943                      ptr = lutil_strcopy( ptr, sessionSourceName.bv_val );
01944                      st_len++;
01945               }
01946 
01947               if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
01948                      if ( st_len ) *ptr++ = ' ';
01949                      ptr = lutil_strcopy( ptr, formatOID.bv_val );
01950                      *ptr++ = '=';
01951                      ptr = lutil_strcopy( ptr, sessionTrackingIdentifier.bv_val );
01952               }
01953 
01954               *ptr++ = /*[*/ ']';
01955               *ptr = '\0';
01956        }
01957 
01958 error:;
01959        (void)ber_free( ber, 1 );
01960 
01961        if ( tag == LBER_ERROR ) {
01962               rs->sr_text = "sessionTracking control decoding error";
01963               return LDAP_PROTOCOL_ERROR;
01964        }
01965 
01966 
01967        return rs->sr_err;
01968 }
01969 
01970 int
01971 slap_ctrl_session_tracking_add(
01972        Operation *op,
01973        SlapReply *rs,
01974        struct berval *ip,
01975        struct berval *name,
01976        struct berval *id,
01977        LDAPControl *ctrl )
01978 {
01979        BerElementBuffer berbuf;
01980        BerElement    *ber = (BerElement *)&berbuf;
01981 
01982        static struct berval oid = BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME );
01983 
01984        assert( ctrl != NULL );
01985 
01986        ber_init2( ber, NULL, LBER_USE_DER );
01987 
01988        ber_printf( ber, "{OOOO}", ip, name, &oid, id ); 
01989 
01990        if ( ber_flatten2( ber, &ctrl->ldctl_value, 0 ) == -1 ) {
01991               rs->sr_err = LDAP_OTHER;
01992               goto done;
01993        }
01994 
01995        ctrl->ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
01996        ctrl->ldctl_iscritical = 0;
01997 
01998        rs->sr_err = LDAP_SUCCESS;
01999 
02000 done:;
02001        return rs->sr_err;
02002 }
02003 
02004 int
02005 slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPControl *ctrl )
02006 {
02007        static struct berval bv_unknown = BER_BVC( SLAP_STRING_UNKNOWN );
02008        struct berval        ip = BER_BVNULL,
02009                             name = BER_BVNULL,
02010                             id = BER_BVNULL;
02011 
02012        if ( !BER_BVISNULL( &op->o_conn->c_peer_name ) &&
02013               memcmp( op->o_conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
02014        {
02015               char   *ptr;
02016 
02017               ip.bv_val = op->o_conn->c_peer_name.bv_val + STRLENOF( "IP=" );
02018               ip.bv_len = op->o_conn->c_peer_name.bv_len - STRLENOF( "IP=" );
02019 
02020               ptr = ber_bvchr( &ip, ':' );
02021               if ( ptr ) {
02022                      ip.bv_len = ptr - ip.bv_val;
02023               }
02024        }
02025 
02026        if ( !BER_BVISNULL( &op->o_conn->c_peer_domain ) &&
02027               !bvmatch( &op->o_conn->c_peer_domain, &bv_unknown ) )
02028        {
02029               name = op->o_conn->c_peer_domain;
02030        }
02031 
02032        if ( !BER_BVISNULL( &op->o_dn ) && !BER_BVISEMPTY( &op->o_dn ) ) {
02033               id = op->o_dn;
02034        }
02035 
02036        return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl );
02037 }
02038 #endif
02039 
02040 #ifdef SLAP_CONTROL_X_WHATFAILED
02041 static int parseWhatFailed(
02042        Operation *op,
02043        SlapReply *rs,
02044        LDAPControl *ctrl )
02045 {
02046        if ( op->o_whatFailed != SLAP_CONTROL_NONE ) {
02047               rs->sr_text = "\"WHat Failed?\" control specified multiple times";
02048               return LDAP_PROTOCOL_ERROR;
02049        }
02050 
02051        if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
02052               rs->sr_text = "\"What Failed?\" control value not absent";
02053               return LDAP_PROTOCOL_ERROR;
02054        }
02055 
02056        op->o_whatFailed = ctrl->ldctl_iscritical
02057               ? SLAP_CONTROL_CRITICAL
02058               : SLAP_CONTROL_NONCRITICAL;
02059 
02060        return LDAP_SUCCESS;
02061 }
02062 
02063 int
02064 slap_ctrl_whatFailed_add(
02065        Operation *op,
02066        SlapReply *rs,
02067        char **oids )
02068 {
02069        BerElementBuffer berbuf;
02070        BerElement *ber = (BerElement *) &berbuf;
02071        LDAPControl **ctrls = NULL;
02072        struct berval ctrlval;
02073        int i, rc = LDAP_SUCCESS;
02074 
02075        ber_init2( ber, NULL, LBER_USE_DER );
02076        ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
02077        ber_printf( ber, "[" /*]*/ );
02078        for ( i = 0; oids[ i ] != NULL; i++ ) {
02079               ber_printf( ber, "s", oids[ i ] );
02080        }
02081        ber_printf( ber, /*[*/ "]" );
02082 
02083        if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
02084               rc = LDAP_OTHER;
02085               goto done;
02086        }
02087 
02088        i = 0;
02089        if ( rs->sr_ctrls != NULL ) {
02090               for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
02091                      if ( strcmp( rs->sr_ctrls[ i ]->ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) != 0 ) {
02092                             /* TODO: add */
02093                             assert( 0 );
02094                      }
02095               }
02096        }
02097 
02098        ctrls = op->o_tmprealloc( rs->sr_ctrls,
02099                      sizeof(LDAPControl *)*( i + 2 )
02100                      + sizeof(LDAPControl)
02101                      + ctrlval.bv_len + 1,
02102                      op->o_tmpmemctx );
02103        if ( ctrls == NULL ) {
02104               rc = LDAP_OTHER;
02105               goto done;
02106        }
02107        ctrls[ i + 1 ] = NULL;
02108        ctrls[ i ] = (LDAPControl *)&ctrls[ i + 2 ];
02109        ctrls[ i ]->ldctl_oid = LDAP_CONTROL_X_WHATFAILED;
02110        ctrls[ i ]->ldctl_iscritical = 0;
02111        ctrls[ i ]->ldctl_value.bv_val = (char *)&ctrls[ i ][ 1 ];
02112        AC_MEMCPY( ctrls[ i ]->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len + 1 );
02113        ctrls[ i ]->ldctl_value.bv_len = ctrlval.bv_len;
02114 
02115        ber_free_buf( ber );
02116 
02117        rs->sr_ctrls = ctrls;
02118 
02119 done:;
02120        return rc;
02121 }
02122 #endif