1 /*        $NetBSD: controls.c,v 1.3 2021/08/14 16:14:58 christos Exp $          */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 
18 #include <sys/cdefs.h>
19 __RCSID("$NetBSD: controls.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
20 
21 #include "portable.h"
22 
23 #include <stdio.h>
24 
25 #include <ac/string.h>
26 #include <ac/socket.h>
27 
28 #include "slap.h"
29 #include "ldif.h"
30 #include "lutil.h"
31 
32 #include "../../libraries/liblber/lber-int.h"
33 
34 static SLAP_CTRL_PARSE_FN parseAssert;
35 static SLAP_CTRL_PARSE_FN parseDomainScope;
36 static SLAP_CTRL_PARSE_FN parseDontUseCopy;
37 static SLAP_CTRL_PARSE_FN parseManageDSAit;
38 static SLAP_CTRL_PARSE_FN parseNoOp;
39 static SLAP_CTRL_PARSE_FN parsePagedResults;
40 static SLAP_CTRL_PARSE_FN parsePermissiveModify;
41 static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead;
42 static SLAP_CTRL_PARSE_FN parseProxyAuthz;
43 static SLAP_CTRL_PARSE_FN parseRelax;
44 static SLAP_CTRL_PARSE_FN parseSearchOptions;
45 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
46 static SLAP_CTRL_PARSE_FN parseSortedResults;
47 #endif
48 static SLAP_CTRL_PARSE_FN parseSubentries;
49 #ifdef SLAP_CONTROL_X_TREE_DELETE
50 static SLAP_CTRL_PARSE_FN parseTreeDelete;
51 #endif
52 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
53 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
54 static SLAP_CTRL_PARSE_FN parseSessionTracking;
55 #endif
56 #ifdef SLAP_CONTROL_X_WHATFAILED
57 static SLAP_CTRL_PARSE_FN parseWhatFailed;
58 #endif
59 #ifdef SLAP_CONTROL_X_LAZY_COMMIT
60 static SLAP_CTRL_PARSE_FN parseLazyCommit;
61 #endif
62 
63 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
64 
65 const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ);
66 const struct berval slap_post_read_bv = BER_BVC(LDAP_CONTROL_POST_READ);
67 
68 struct slap_control_ids slap_cids;
69 
70 struct slap_control {
71           /* Control OID */
72           char *sc_oid;
73 
74           /* The controlID for this control */
75           int sc_cid;
76 
77           /* Operations supported by control */
78           slap_mask_t sc_mask;
79 
80           /* Extended operations supported by control */
81           char **sc_extendedops;                  /* input */
82           BerVarray sc_extendedopsbv;   /* run-time use */
83 
84           /* Control parsing callback */
85           SLAP_CTRL_PARSE_FN *sc_parse;
86 
87           LDAP_SLIST_ENTRY(slap_control) sc_next;
88 };
89 
90 static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
91           = LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
92 
93 /*
94  * all known request control OIDs should be added to this list
95  */
96 /*
97  * NOTE: initialize num_known_controls to 1 so that cid = 0 always
98  * addresses an undefined control; this allows to safely test for
99  * well known controls even if they are not registered, e.g. if
100  * they get moved to modules.  An example is sc_LDAPsync, which
101  * is implemented in the syncprov overlay and thus, if configured
102  * as dynamic module, may not be registered.  One side effect is that
103  * slap_known_controls[0] == NULL, so it should always be used
104  * starting from 1.
105  * FIXME: should we define the "undefined control" oid?
106  */
107 char *slap_known_controls[SLAP_MAX_CIDS+1];
108 static int num_known_controls = 1;
109 
110 static char *proxy_authz_extops[] = {
111           LDAP_EXOP_MODIFY_PASSWD,
112           LDAP_EXOP_WHO_AM_I,
113           LDAP_EXOP_REFRESH,
114           NULL
115 };
116 
117 static char *manageDSAit_extops[] = {
118           LDAP_EXOP_REFRESH,
119           NULL
120 };
121 
122 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
123 static char *session_tracking_extops[] = {
124           LDAP_EXOP_MODIFY_PASSWD,
125           LDAP_EXOP_WHO_AM_I,
126           LDAP_EXOP_REFRESH,
127           NULL
128 };
129 #endif
130 
131 static struct slap_control control_defs[] = {
132           {  LDAP_CONTROL_ASSERT,
133                     (int)offsetof(struct slap_control_ids, sc_assert),
134                     SLAP_CTRL_UPDATE|SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH,
135                     NULL, NULL,
136                     parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
137           { LDAP_CONTROL_PRE_READ,
138                     (int)offsetof(struct slap_control_ids, sc_preRead),
139                     SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
140                     NULL, NULL,
141                     parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
142           { LDAP_CONTROL_POST_READ,
143                     (int)offsetof(struct slap_control_ids, sc_postRead),
144                     SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
145                     NULL, NULL,
146                     parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
147           { LDAP_CONTROL_VALUESRETURNFILTER,
148                     (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
149                     SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH,
150                     NULL, NULL,
151                     parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
152           { LDAP_CONTROL_PAGEDRESULTS,
153                     (int)offsetof(struct slap_control_ids, sc_pagedResults),
154                     SLAP_CTRL_SEARCH,
155                     NULL, NULL,
156                     parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
157 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
158           { LDAP_CONTROL_SORTREQUEST,
159                     (int)offsetof(struct slap_control_ids, sc_sortedResults),
160                     SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
161                     NULL, NULL,
162                     parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
163 #endif
164           { LDAP_CONTROL_X_DOMAIN_SCOPE,
165                     (int)offsetof(struct slap_control_ids, sc_domainScope),
166                     SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
167                     NULL, NULL,
168                     parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
169           { LDAP_CONTROL_DONTUSECOPY,
170                     (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
171                     SLAP_CTRL_GLOBAL|SLAP_CTRL_INTROGATE,
172                     NULL, NULL,
173                     parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
174           { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
175                     (int)offsetof(struct slap_control_ids, sc_permissiveModify),
176                     SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE,
177                     NULL, NULL,
178                     parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
179 #ifdef SLAP_CONTROL_X_TREE_DELETE
180           { LDAP_CONTROL_X_TREE_DELETE,
181                     (int)offsetof(struct slap_control_ids, sc_treeDelete),
182                     SLAP_CTRL_DELETE|SLAP_CTRL_HIDE,
183                     NULL, NULL,
184                     parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
185 #endif
186           { LDAP_CONTROL_X_SEARCH_OPTIONS,
187                     (int)offsetof(struct slap_control_ids, sc_searchOptions),
188                     SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
189                     NULL, NULL,
190                     parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
191           { LDAP_CONTROL_SUBENTRIES,
192                     (int)offsetof(struct slap_control_ids, sc_subentries),
193                     SLAP_CTRL_SEARCH,
194                     NULL, NULL,
195                     parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
196           { LDAP_CONTROL_NOOP,
197                     (int)offsetof(struct slap_control_ids, sc_noOp),
198                     SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
199                     NULL, NULL,
200                     parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
201           { LDAP_CONTROL_RELAX,
202                     (int)offsetof(struct slap_control_ids, sc_relax),
203                     SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
204                     NULL, NULL,
205                     parseRelax, LDAP_SLIST_ENTRY_INITIALIZER(next) },
206           { LDAP_CONTROL_TXN_SPEC,
207                     (int)offsetof(struct slap_control_ids, sc_txnSpec),
208                     SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
209                     NULL, NULL,
210                     txn_spec_ctrl, LDAP_SLIST_ENTRY_INITIALIZER(next) },
211           { LDAP_CONTROL_MANAGEDSAIT,
212                     (int)offsetof(struct slap_control_ids, sc_manageDSAit),
213                     SLAP_CTRL_ACCESS,
214                     manageDSAit_extops, NULL,
215                     parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
216           { LDAP_CONTROL_PROXY_AUTHZ,
217                     (int)offsetof(struct slap_control_ids, sc_proxyAuthz),
218                     SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS,
219                     proxy_authz_extops, NULL,
220                     parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
221 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
222           { LDAP_CONTROL_X_SESSION_TRACKING,
223                     (int)offsetof(struct slap_control_ids, sc_sessionTracking),
224                     SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_BIND|SLAP_CTRL_HIDE,
225                     session_tracking_extops, NULL,
226                     parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) },
227 #endif
228 #ifdef SLAP_CONTROL_X_WHATFAILED
229           { LDAP_CONTROL_X_WHATFAILED,
230                     (int)offsetof(struct slap_control_ids, sc_whatFailed),
231                     SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
232                     NULL, NULL,
233                     parseWhatFailed, LDAP_SLIST_ENTRY_INITIALIZER(next) },
234 #endif
235 #ifdef SLAP_CONTROL_X_LAZY_COMMIT
236           { LDAP_CONTROL_X_LAZY_COMMIT,
237                     (int)offsetof(struct slap_control_ids, sc_lazyCommit),
238                     SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
239                     NULL, NULL,
240                     parseLazyCommit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
241 #endif
242 
243           { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
244 };
245 
246 static struct slap_control *
247 find_ctrl( const char *oid );
248 
249 /*
250  * Register a supported control.
251  *
252  * This can be called by an OpenLDAP plugin or, indirectly, by a
253  * SLAPI plugin calling slapi_register_supported_control().
254  *
255  * NOTE: if flags == 1 the control is replaced if already registered;
256  * otherwise registering an already registered control is not allowed.
257  */
258 int
register_supported_control2(const char * controloid,slap_mask_t controlmask,char ** controlexops,SLAP_CTRL_PARSE_FN * controlparsefn,unsigned flags,int * controlcid)259 register_supported_control2(const char *controloid,
260           slap_mask_t controlmask,
261           char **controlexops,
262           SLAP_CTRL_PARSE_FN *controlparsefn,
263           unsigned flags,
264           int *controlcid)
265 {
266           struct slap_control *sc = NULL;
267           int i;
268           BerVarray extendedopsbv = NULL;
269 
270           if ( num_known_controls >= SLAP_MAX_CIDS ) {
271                     Debug( LDAP_DEBUG_ANY, "Too many controls registered."
272                               " Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
273                     num_known_controls );
274                     return LDAP_OTHER;
275           }
276 
277           if ( controloid == NULL ) {
278                     return LDAP_PARAM_ERROR;
279           }
280 
281           /* check if already registered */
282           for ( i = 0; slap_known_controls[ i ]; i++ ) {
283                     if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
284                               if ( flags == 1 ) {
285                                         Debug( LDAP_DEBUG_TRACE,
286                                                   "Control %s already registered; replacing.\n",
287                                                   controloid );
288                                         /* (find and) replace existing handler */
289                                         sc = find_ctrl( controloid );
290                                         assert( sc != NULL );
291                                         break;
292                               }
293 
294                               Debug( LDAP_DEBUG_ANY,
295                                         "Control %s already registered.\n",
296                                         controloid );
297                               return LDAP_PARAM_ERROR;
298                     }
299           }
300 
301           /* turn compatible extended operations into bervals */
302           if ( controlexops != NULL ) {
303                     int i;
304 
305                     for ( i = 0; controlexops[ i ]; i++ );
306 
307                     extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
308                     if ( extendedopsbv == NULL ) {
309                               return LDAP_NO_MEMORY;
310                     }
311 
312                     for ( i = 0; controlexops[ i ]; i++ ) {
313                               ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] );
314                     }
315           }
316 
317           if ( sc == NULL ) {
318                     sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
319                     if ( sc == NULL ) {
320                               ber_bvarray_free( extendedopsbv );
321                               return LDAP_NO_MEMORY;
322                     }
323 
324                     sc->sc_oid = ch_strdup( controloid );
325                     sc->sc_cid = num_known_controls;
326 
327                     /* Update slap_known_controls, too. */
328                     slap_known_controls[num_known_controls - 1] = sc->sc_oid;
329                     slap_known_controls[num_known_controls++] = NULL;
330 
331                     LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
332                     LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
333 
334           } else {
335                     if ( sc->sc_extendedopsbv ) {
336                               ber_bvarray_free( sc->sc_extendedopsbv );
337                               sc->sc_extendedopsbv = NULL;
338                               sc->sc_extendedops = NULL;
339                     }
340           }
341 
342           sc->sc_extendedopsbv = extendedopsbv;
343           sc->sc_mask = controlmask;
344           sc->sc_parse = controlparsefn;
345           if ( controlcid ) {
346                     *controlcid = sc->sc_cid;
347           }
348 
349           return LDAP_SUCCESS;
350 }
351 
352 #ifdef SLAP_CONFIG_DELETE
353 int
unregister_supported_control(const char * controloid)354 unregister_supported_control( const char *controloid )
355 {
356           struct slap_control *sc;
357           int i;
358 
359           if ( controloid == NULL || (sc = find_ctrl( controloid )) == NULL ){
360                     return -1;
361           }
362 
363           for ( i = 0; slap_known_controls[ i ]; i++ ) {
364                     if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
365                               do {
366                                         slap_known_controls[ i ] = slap_known_controls[ i+1 ];
367                               } while ( slap_known_controls[ i++ ] );
368                               num_known_controls--;
369                               break;
370                     }
371           }
372 
373           LDAP_SLIST_REMOVE(&controls_list, sc, slap_control, sc_next);
374           ch_free( sc->sc_oid );
375           if ( sc->sc_extendedopsbv != NULL ) {
376                     ber_bvarray_free( sc->sc_extendedopsbv );
377           }
378           ch_free( sc );
379 
380           return 0;
381 }
382 #endif /* SLAP_CONFIG_DELETE */
383 
384 int
register_control_exop(const char * controloid,char * exopoid)385 register_control_exop( const char *controloid, char *exopoid )
386 {
387           struct slap_control *sc = NULL;
388           BerVarray extendedopsbv;
389           char **extendedops;
390           int i;
391 
392           if ( controloid == NULL || exopoid == NULL ) {
393                     return LDAP_PARAM_ERROR;
394           }
395 
396           for ( i = 0; slap_known_controls[ i ]; i++ ) {
397                     if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
398                               sc = find_ctrl( controloid );
399                               assert( sc != NULL );
400                               break;
401                     }
402           }
403 
404           if ( !sc ) {
405                     Debug( LDAP_DEBUG_ANY, "register_control_exop: "
406                               "Control %s not registered.\n",
407                               controloid );
408                     return LDAP_PARAM_ERROR;
409           }
410 
411           for ( i = 0; sc->sc_extendedopsbv && !BER_BVISNULL( &sc->sc_extendedopsbv[ i ] ); i++ ) {
412                     if ( strcmp( exopoid, sc->sc_extendedopsbv[ i ].bv_val ) == 0 ) {
413                               return LDAP_SUCCESS;
414                     }
415           }
416 
417           extendedopsbv = ber_memrealloc( sc->sc_extendedopsbv, (i + 2) * sizeof( struct berval ) );
418           if ( extendedopsbv == NULL ) {
419                     return LDAP_NO_MEMORY;
420           }
421           sc->sc_extendedopsbv = extendedopsbv;
422 
423           ber_str2bv( exopoid, 0, 1, &extendedopsbv[ i ] );
424           BER_BVZERO( &extendedopsbv[ i+1 ] );
425 
426           return LDAP_SUCCESS;
427 }
428 
429 /*
430  * One-time initialization of internal controls.
431  */
432 int
slap_controls_init(void)433 slap_controls_init( void )
434 {
435           int i, rc;
436 
437           rc = LDAP_SUCCESS;
438 
439           for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
440                     int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
441                     rc = register_supported_control( control_defs[i].sc_oid,
442                               control_defs[i].sc_mask, control_defs[i].sc_extendedops,
443                               control_defs[i].sc_parse, cid );
444                     if ( rc != LDAP_SUCCESS ) break;
445           }
446 
447           return rc;
448 }
449 
450 /*
451  * Free memory associated with list of supported controls.
452  */
453 void
controls_destroy(void)454 controls_destroy( void )
455 {
456           struct slap_control *sc;
457 
458           while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
459                     sc = LDAP_SLIST_FIRST(&controls_list);
460                     LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);
461 
462                     ch_free( sc->sc_oid );
463                     if ( sc->sc_extendedopsbv != NULL ) {
464                               ber_bvarray_free( sc->sc_extendedopsbv );
465                     }
466                     ch_free( sc );
467           }
468 }
469 
470 /*
471  * Format the supportedControl attribute of the root DSE,
472  * detailing which controls are supported by the directory
473  * server.
474  */
475 int
controls_root_dse_info(Entry * e)476 controls_root_dse_info( Entry *e )
477 {
478           AttributeDescription *ad_supportedControl
479                     = slap_schema.si_ad_supportedControl;
480           struct berval vals[2];
481           struct slap_control *sc;
482 
483           vals[1].bv_val = NULL;
484           vals[1].bv_len = 0;
485 
486           LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
487                     if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;
488 
489                     vals[0].bv_val = sc->sc_oid;
490                     vals[0].bv_len = strlen( sc->sc_oid );
491 
492                     if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
493                               return -1;
494                     }
495           }
496 
497           return 0;
498 }
499 
500 /*
501  * Return a list of OIDs and operation masks for supported
502  * controls. Used by SLAPI.
503  */
504 int
get_supported_controls(char *** ctrloidsp,slap_mask_t ** ctrlmasks)505 get_supported_controls(char ***ctrloidsp,
506           slap_mask_t **ctrlmasks)
507 {
508           int n;
509           char **oids;
510           slap_mask_t *masks;
511           struct slap_control *sc;
512 
513           n = 0;
514 
515           LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
516                     n++;
517           }
518 
519           if ( n == 0 ) {
520                     *ctrloidsp = NULL;
521                     *ctrlmasks = NULL;
522                     return LDAP_SUCCESS;
523           }
524 
525           oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
526           if ( oids == NULL ) {
527                     return LDAP_NO_MEMORY;
528           }
529           masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
530           if  ( masks == NULL ) {
531                     SLAP_FREE( oids );
532                     return LDAP_NO_MEMORY;
533           }
534 
535           n = 0;
536 
537           LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
538                     oids[n] = ch_strdup( sc->sc_oid );
539                     masks[n] = sc->sc_mask;
540                     n++;
541           }
542           oids[n] = NULL;
543           masks[n] = 0;
544 
545           *ctrloidsp = oids;
546           *ctrlmasks = masks;
547 
548           return LDAP_SUCCESS;
549 }
550 
551 /*
552  * Find a control given its OID.
553  */
554 static struct slap_control *
find_ctrl(const char * oid)555 find_ctrl( const char *oid )
556 {
557           struct slap_control *sc;
558 
559           LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
560                     if ( strcmp( oid, sc->sc_oid ) == 0 ) {
561                               return sc;
562                     }
563           }
564 
565           return NULL;
566 }
567 
568 int
slap_find_control_id(const char * oid,int * cid)569 slap_find_control_id(
570           const char *oid,
571           int *cid )
572 {
573           struct slap_control *ctrl = find_ctrl( oid );
574           if ( ctrl ) {
575                     if ( cid ) *cid = ctrl->sc_cid;
576                     return LDAP_SUCCESS;
577           }
578           return LDAP_CONTROL_NOT_FOUND;
579 }
580 
581 int
slap_global_control(Operation * op,const char * oid,int * cid)582 slap_global_control( Operation *op, const char *oid, int *cid )
583 {
584           struct slap_control *ctrl = find_ctrl( oid );
585 
586           if ( ctrl == NULL ) {
587                     /* should not be reachable */
588                     Debug( LDAP_DEBUG_ANY,
589                               "slap_global_control: unrecognized control: %s\n",
590                               oid );
591                     return LDAP_CONTROL_NOT_FOUND;
592           }
593 
594           if ( cid ) *cid = ctrl->sc_cid;
595 
596           if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
597                     ( ( op->o_tag & LDAP_REQ_SEARCH ) &&
598                     ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
599           {
600                     return LDAP_COMPARE_TRUE;
601           }
602 
603 #if 0
604           Debug( LDAP_DEBUG_TRACE,
605                     "slap_global_control: unavailable control: %s\n",
606                     oid );
607 #endif
608 
609           return LDAP_COMPARE_FALSE;
610 }
611 
slap_free_ctrls(Operation * op,LDAPControl ** ctrls)612 void slap_free_ctrls(
613           Operation *op,
614           LDAPControl **ctrls )
615 {
616           int i;
617 
618           if( ctrls == op->o_ctrls ) {
619                     if( op->o_assertion != NULL ) {
620                               filter_free_x( op, op->o_assertion, 1 );
621                               op->o_assertion = NULL;
622                     }
623                     if( op->o_vrFilter != NULL) {
624                               vrFilter_free( op, op->o_vrFilter );
625                               op->o_vrFilter = NULL;
626                     }
627                     if( op->o_preread_attrs != NULL ) {
628                               op->o_tmpfree( op->o_preread_attrs, op->o_tmpmemctx );
629                               op->o_preread_attrs = NULL;
630                     }
631                     if( op->o_postread_attrs != NULL ) {
632                               op->o_tmpfree( op->o_postread_attrs, op->o_tmpmemctx );
633                               op->o_postread_attrs = NULL;
634                     }
635                     if( op->o_pagedresults_state != NULL ) {
636                               op->o_tmpfree( op->o_pagedresults_state, op->o_tmpmemctx );
637                               op->o_pagedresults_state = NULL;
638                     }
639           }
640 
641           for (i=0; ctrls[i]; i++) {
642                     op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
643           }
644           op->o_tmpfree( ctrls, op->o_tmpmemctx );
645 }
646 
slap_add_ctrls(Operation * op,SlapReply * rs,LDAPControl ** ctrls)647 int slap_add_ctrls(
648           Operation *op,
649           SlapReply *rs,
650           LDAPControl **ctrls )
651 {
652           int i = 0, j;
653           LDAPControl **ctrlsp;
654 
655           if ( rs->sr_ctrls ) {
656                     for ( ; rs->sr_ctrls[ i ]; i++ ) ;
657           }
658 
659           for ( j=0; ctrls[j]; j++ ) ;
660 
661           ctrlsp = op->o_tmpalloc(( i+j+1 )*sizeof(LDAPControl *), op->o_tmpmemctx );
662           i = 0;
663           if ( rs->sr_ctrls ) {
664                     for ( ; rs->sr_ctrls[i]; i++ )
665                               ctrlsp[i] = rs->sr_ctrls[i];
666           }
667           for ( j=0; ctrls[j]; j++)
668                     ctrlsp[i++] = ctrls[j];
669           ctrlsp[i] = NULL;
670 
671           if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED )
672                     op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
673           rs->sr_ctrls = ctrlsp;
674           rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
675           return i;
676 }
677 
slap_parse_ctrl(Operation * op,SlapReply * rs,LDAPControl * control,const char ** text)678 int slap_parse_ctrl(
679           Operation *op,
680           SlapReply *rs,
681           LDAPControl *control,
682           const char **text )
683 {
684           struct slap_control *sc;
685           int rc = LDAP_SUCCESS;
686 
687           sc = find_ctrl( control->ldctl_oid );
688           if( sc != NULL ) {
689                     /* recognized control */
690                     slap_mask_t tagmask;
691                     switch( op->o_tag ) {
692                     case LDAP_REQ_ADD:
693                               tagmask = SLAP_CTRL_ADD;
694                               break;
695                     case LDAP_REQ_BIND:
696                               tagmask = SLAP_CTRL_BIND;
697                               break;
698                     case LDAP_REQ_COMPARE:
699                               tagmask = SLAP_CTRL_COMPARE;
700                               break;
701                     case LDAP_REQ_DELETE:
702                               tagmask = SLAP_CTRL_DELETE;
703                               break;
704                     case LDAP_REQ_MODIFY:
705                               tagmask = SLAP_CTRL_MODIFY;
706                               break;
707                     case LDAP_REQ_RENAME:
708                               tagmask = SLAP_CTRL_RENAME;
709                               break;
710                     case LDAP_REQ_SEARCH:
711                               tagmask = SLAP_CTRL_SEARCH;
712                               break;
713                     case LDAP_REQ_UNBIND:
714                               tagmask = SLAP_CTRL_UNBIND;
715                               break;
716                     case LDAP_REQ_ABANDON:
717                               tagmask = SLAP_CTRL_ABANDON;
718                               break;
719                     case LDAP_REQ_EXTENDED:
720                               tagmask=~0L;
721                               assert( op->ore_reqoid.bv_val != NULL );
722                               if( sc->sc_extendedopsbv != NULL ) {
723                                         int i;
724                                         for( i=0; !BER_BVISNULL( &sc->sc_extendedopsbv[i] ); i++ ) {
725                                                   if( bvmatch( &op->ore_reqoid,
726                                                             &sc->sc_extendedopsbv[i] ) )
727                                                   {
728                                                             tagmask=0L;
729                                                             break;
730                                                   }
731                                         }
732                               }
733                               break;
734                     default:
735                               *text = "controls internal error";
736                               return LDAP_OTHER;
737                     }
738 
739                     if (( sc->sc_mask & tagmask ) == tagmask ) {
740                               /* available extension */
741                               if ( sc->sc_parse ) {
742                                         rc = sc->sc_parse( op, rs, control );
743                                         assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
744 
745                               } else if ( control->ldctl_iscritical ) {
746                                         *text = "not yet implemented";
747                                         rc = LDAP_OTHER;
748                               }
749 
750 
751                     } else if ( control->ldctl_iscritical ) {
752                               /* unavailable CRITICAL control */
753                               *text = "critical extension is unavailable";
754                               rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
755                     }
756 
757           } else if ( control->ldctl_iscritical ) {
758                     /* unrecognized CRITICAL control */
759                     *text = "critical extension is not recognized";
760                     rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
761           }
762 
763           return rc;
764 }
765 
766 int
get_ctrls(Operation * op,SlapReply * rs,int sendres)767 get_ctrls(
768           Operation *op,
769           SlapReply *rs,
770           int sendres )
771 {
772           return get_ctrls2( op, rs, sendres, LDAP_TAG_CONTROLS );
773 }
774 
775 int
get_ctrls2(Operation * op,SlapReply * rs,int sendres,ber_tag_t ctag)776 get_ctrls2(
777           Operation *op,
778           SlapReply *rs,
779           int sendres,
780           ber_tag_t ctag )
781 {
782           int nctrls = 0;
783           ber_tag_t tag;
784           ber_len_t len;
785           char *opaque;
786           BerElement *ber = op->o_ber;
787           struct berval bv;
788 #ifdef SLAP_CONTROL_X_WHATFAILED
789           /* NOTE: right now, slapd checks the validity of each control
790            * while parsing.  As a consequence, it can only detect one
791            * cause of failure at a time.  This results in returning
792            * exactly one OID with the whatFailed control, or no control
793            * at all.
794            */
795           char *failed_oid = NULL;
796 #endif
797 
798           len = ber_pvt_ber_remaining(ber);
799 
800           if( len == 0) {
801                     /* no controls */
802                     rs->sr_err = LDAP_SUCCESS;
803                     return rs->sr_err;
804           }
805 
806           if(( tag = ber_peek_tag( ber, &len )) != ctag ) {
807                     if( tag == LBER_ERROR ) {
808                               rs->sr_err = SLAPD_DISCONNECT;
809                               rs->sr_text = "unexpected data in PDU";
810                     }
811 
812                     goto return_results;
813           }
814 
815           Debug( LDAP_DEBUG_TRACE,
816                     "=> get_ctrls\n" );
817 
818           if( op->o_protocol < LDAP_VERSION3 ) {
819                     rs->sr_err = SLAPD_DISCONNECT;
820                     rs->sr_text = "controls require LDAPv3";
821                     goto return_results;
822           }
823 
824           /* one for first control, one for termination */
825           op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
826 
827 #if 0
828           if( op->ctrls == NULL ) {
829                     rs->sr_err = LDAP_NO_MEMORY;
830                     rs->sr_text = "no memory";
831                     goto return_results;
832           }
833 #endif
834 
835           op->o_ctrls[nctrls] = NULL;
836 
837           /* step through each element */
838           for( tag = ber_first_element( ber, &len, &opaque );
839                     tag != LBER_ERROR;
840                     tag = ber_next_element( ber, &len, opaque ) )
841           {
842                     LDAPControl *c;
843                     LDAPControl **tctrls;
844 
845                     c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
846                     memset(c, 0, sizeof(LDAPControl));
847 
848                     /* allocate pointer space for current controls (nctrls)
849                      * + this control + extra NULL
850                      */
851                     tctrls = op->o_tmprealloc( op->o_ctrls,
852                               (nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
853 
854 #if 0
855                     if( tctrls == NULL ) {
856                               ch_free( c );
857                               ldap_controls_free(op->o_ctrls);
858                               op->o_ctrls = NULL;
859 
860                               rs->sr_err = LDAP_NO_MEMORY;
861                               rs->sr_text = "no memory";
862                               goto return_results;
863                     }
864 #endif
865                     op->o_ctrls = tctrls;
866 
867                     op->o_ctrls[nctrls++] = c;
868                     op->o_ctrls[nctrls] = NULL;
869 
870                     tag = ber_scanf( ber, "{m" /*}*/, &bv );
871                     c->ldctl_oid = bv.bv_val;
872 
873                     if( tag == LBER_ERROR ) {
874                               Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n" );
875 
876                               slap_free_ctrls( op, op->o_ctrls );
877                               op->o_ctrls = NULL;
878                               rs->sr_err = SLAPD_DISCONNECT;
879                               rs->sr_text = "decoding controls error";
880                               goto return_results;
881 
882                     } else if( c->ldctl_oid == NULL ) {
883                               Debug( LDAP_DEBUG_TRACE,
884                                         "get_ctrls: conn %lu got empty OID.\n",
885                                         op->o_connid );
886 
887                               slap_free_ctrls( op, op->o_ctrls );
888                               op->o_ctrls = NULL;
889                               rs->sr_err = LDAP_PROTOCOL_ERROR;
890                               rs->sr_text = "OID field is empty";
891                               goto return_results;
892                     }
893 
894                     tag = ber_peek_tag( ber, &len );
895 
896                     if( tag == LBER_BOOLEAN ) {
897                               ber_int_t crit;
898                               tag = ber_scanf( ber, "b", &crit );
899 
900                               if( tag == LBER_ERROR ) {
901                                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n" );
902                                         slap_free_ctrls( op, op->o_ctrls );
903                                         op->o_ctrls = NULL;
904                                         rs->sr_err = SLAPD_DISCONNECT;
905                                         rs->sr_text = "decoding controls error";
906                                         goto return_results;
907                               }
908 
909                               c->ldctl_iscritical = (crit != 0);
910                               tag = ber_peek_tag( ber, &len );
911                     }
912 
913                     if( tag == LBER_OCTETSTRING ) {
914                               tag = ber_scanf( ber, "m", &c->ldctl_value );
915 
916                               if( tag == LBER_ERROR ) {
917                                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
918                                                   "%s (%scritical): get value failed.\n",
919                                                   op->o_connid, c->ldctl_oid,
920                                                   c->ldctl_iscritical ? "" : "non" );
921                                         slap_free_ctrls( op, op->o_ctrls );
922                                         op->o_ctrls = NULL;
923                                         rs->sr_err = SLAPD_DISCONNECT;
924                                         rs->sr_text = "decoding controls error";
925                                         goto return_results;
926                               }
927                     }
928 
929                     Debug( LDAP_DEBUG_TRACE,
930                               "=> get_ctrls: oid=\"%s\" (%scritical)\n",
931                               c->ldctl_oid, c->ldctl_iscritical ? "" : "non" );
932 
933                     rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
934                     if ( rs->sr_err != LDAP_SUCCESS ) {
935 #ifdef SLAP_CONTROL_X_WHATFAILED
936                               failed_oid = c->ldctl_oid;
937 #endif
938                               goto return_results;
939                     }
940           }
941 
942 return_results:
943           Debug( LDAP_DEBUG_TRACE,
944                     "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
945                     nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
946 
947           if( sendres && rs->sr_err != LDAP_SUCCESS ) {
948                     if( rs->sr_err == SLAPD_DISCONNECT ) {
949                               rs->sr_err = LDAP_PROTOCOL_ERROR;
950                               send_ldap_disconnect( op, rs );
951                               rs->sr_err = SLAPD_DISCONNECT;
952                     } else {
953 #ifdef SLAP_CONTROL_X_WHATFAILED
954                               /* might have not been parsed yet? */
955                               if ( failed_oid != NULL ) {
956                                         if ( !get_whatFailed( op ) ) {
957                                                   /* look it up */
958 
959                                                   /* step through each remaining element */
960                                                   for ( ; tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) )
961                                                   {
962                                                             LDAPControl c = { 0 };
963 
964                                                             tag = ber_scanf( ber, "{m" /*}*/, &bv );
965                                                             c.ldctl_oid = bv.bv_val;
966 
967                                                             if ( tag == LBER_ERROR ) {
968                                                                       slap_free_ctrls( op, op->o_ctrls );
969                                                                       op->o_ctrls = NULL;
970                                                                       break;
971 
972                                                             } else if ( c.ldctl_oid == NULL ) {
973                                                                       slap_free_ctrls( op, op->o_ctrls );
974                                                                       op->o_ctrls = NULL;
975                                                                       break;
976                                                             }
977 
978                                                             tag = ber_peek_tag( ber, &len );
979                                                             if ( tag == LBER_BOOLEAN ) {
980                                                                       ber_int_t crit;
981                                                                       tag = ber_scanf( ber, "b", &crit );
982                                                                       if( tag == LBER_ERROR ) {
983                                                                                 slap_free_ctrls( op, op->o_ctrls );
984                                                                                 op->o_ctrls = NULL;
985                                                                                 break;
986                                                                       }
987 
988                                                                       tag = ber_peek_tag( ber, &len );
989                                                             }
990 
991                                                             if ( tag == LBER_OCTETSTRING ) {
992                                                                       tag = ber_scanf( ber, "m", &c.ldctl_value );
993 
994                                                                       if( tag == LBER_ERROR ) {
995                                                                                 slap_free_ctrls( op, op->o_ctrls );
996                                                                                 op->o_ctrls = NULL;
997                                                                                 break;
998                                                                       }
999                                                             }
1000 
1001                                                             if ( strcmp( c.ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) == 0 ) {
1002                                                                       const char *text;
1003                                                                       slap_parse_ctrl( op, rs, &c, &text );
1004                                                                       break;
1005                                                             }
1006                                                   }
1007                                         }
1008 
1009                                         if ( get_whatFailed( op ) ) {
1010                                                   char *oids[ 2 ];
1011                                                   oids[ 0 ] = failed_oid;
1012                                                   oids[ 1 ] = NULL;
1013                                                   slap_ctrl_whatFailed_add( op, rs, oids );
1014                                         }
1015                               }
1016 #endif
1017 
1018                               send_ldap_result( op, rs );
1019                     }
1020           }
1021 
1022           return rs->sr_err;
1023 }
1024 
1025 int
slap_remove_control(Operation * op,SlapReply * rs,int ctrl,BI_chk_controls fnc)1026 slap_remove_control(
1027           Operation *op,
1028           SlapReply *rs,
1029           int                 ctrl,
1030           BI_chk_controls     fnc )
1031 {
1032           int                 i, j;
1033 
1034           switch ( op->o_ctrlflag[ ctrl ] ) {
1035           case SLAP_CONTROL_NONCRITICAL:
1036                     for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) {
1037                               if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
1038                                         slap_known_controls[ ctrl - 1 ] ) == 0 )
1039                               {
1040                                         j = i;
1041                               }
1042                     }
1043 
1044                     if ( j == -1 ) {
1045                               rs->sr_err = LDAP_OTHER;
1046                               break;
1047                     }
1048 
1049                     if ( fnc ) {
1050                               (void)fnc( op, rs );
1051                     }
1052 
1053                     op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx );
1054 
1055                     if ( i > 1 ) {
1056                               AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ],
1057                                         ( i - j ) * sizeof( LDAPControl * ) );
1058 
1059                     } else {
1060                               op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
1061                               op->o_ctrls = NULL;
1062                     }
1063 
1064                     op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED;
1065 
1066                     Debug( LDAP_DEBUG_ANY, "%s: "
1067                               "non-critical control \"%s\" not supported; stripped.\n",
1068                               op->o_log_prefix, slap_known_controls[ ctrl ] );
1069                     /* fall thru */
1070 
1071           case SLAP_CONTROL_IGNORED:
1072           case SLAP_CONTROL_NONE:
1073                     rs->sr_err = SLAP_CB_CONTINUE;
1074                     break;
1075 
1076           case SLAP_CONTROL_CRITICAL:
1077                     rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
1078                     if ( fnc ) {
1079                               (void)fnc( op, rs );
1080                     }
1081                     Debug( LDAP_DEBUG_ANY, "%s: "
1082                               "critical control \"%s\" not supported.\n",
1083                               op->o_log_prefix, slap_known_controls[ ctrl ] );
1084                     break;
1085 
1086           default:
1087                     /* handle all cases! */
1088                     assert( 0 );
1089           }
1090 
1091           return rs->sr_err;
1092 }
1093 
parseDontUseCopy(Operation * op,SlapReply * rs,LDAPControl * ctrl)1094 static int parseDontUseCopy (
1095           Operation *op,
1096           SlapReply *rs,
1097           LDAPControl *ctrl )
1098 {
1099           if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) {
1100                     rs->sr_text = "dontUseCopy control specified multiple times";
1101                     return LDAP_PROTOCOL_ERROR;
1102           }
1103 
1104           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
1105                     rs->sr_text = "dontUseCopy control value not absent";
1106                     return LDAP_PROTOCOL_ERROR;
1107           }
1108 
1109           if ( ( global_disallows & SLAP_DISALLOW_DONTUSECOPY_N_CRIT )
1110                     && !ctrl->ldctl_iscritical )
1111           {
1112                     rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
1113                     return LDAP_PROTOCOL_ERROR;
1114           }
1115 
1116           op->o_dontUseCopy = ctrl->ldctl_iscritical
1117                     ? SLAP_CONTROL_CRITICAL
1118                     : SLAP_CONTROL_NONCRITICAL;
1119 
1120           return LDAP_SUCCESS;
1121 }
1122 
parseRelax(Operation * op,SlapReply * rs,LDAPControl * ctrl)1123 static int parseRelax (
1124           Operation *op,
1125           SlapReply *rs,
1126           LDAPControl *ctrl )
1127 {
1128           if ( op->o_relax != SLAP_CONTROL_NONE ) {
1129                     rs->sr_text = "relax control specified multiple times";
1130                     return LDAP_PROTOCOL_ERROR;
1131           }
1132 
1133           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
1134                     rs->sr_text = "relax control value not absent";
1135                     return LDAP_PROTOCOL_ERROR;
1136           }
1137 
1138           op->o_relax = ctrl->ldctl_iscritical
1139                     ? SLAP_CONTROL_CRITICAL
1140                     : SLAP_CONTROL_NONCRITICAL;
1141 
1142           return LDAP_SUCCESS;
1143 }
1144 
parseManageDSAit(Operation * op,SlapReply * rs,LDAPControl * ctrl)1145 static int parseManageDSAit (
1146           Operation *op,
1147           SlapReply *rs,
1148           LDAPControl *ctrl )
1149 {
1150           if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
1151                     rs->sr_text = "manageDSAit control specified multiple times";
1152                     return LDAP_PROTOCOL_ERROR;
1153           }
1154 
1155           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
1156                     rs->sr_text = "manageDSAit control value not absent";
1157                     return LDAP_PROTOCOL_ERROR;
1158           }
1159 
1160           op->o_managedsait = ctrl->ldctl_iscritical
1161                     ? SLAP_CONTROL_CRITICAL
1162                     : SLAP_CONTROL_NONCRITICAL;
1163 
1164           return LDAP_SUCCESS;
1165 }
1166 
parseProxyAuthz(Operation * op,SlapReply * rs,LDAPControl * ctrl)1167 static int parseProxyAuthz (
1168           Operation *op,
1169           SlapReply *rs,
1170           LDAPControl *ctrl )
1171 {
1172           int                 rc;
1173           struct berval       dn = BER_BVNULL;
1174 
1175           if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
1176                     rs->sr_text = "proxy authorization control specified multiple times";
1177                     return LDAP_PROTOCOL_ERROR;
1178           }
1179 
1180           if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1181                     rs->sr_text = "proxy authorization control value absent";
1182                     return LDAP_PROTOCOL_ERROR;
1183           }
1184 
1185           if ( ( global_disallows & SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT )
1186                     && !ctrl->ldctl_iscritical )
1187           {
1188                     rs->sr_text = "proxied authorization criticality of FALSE not allowed";
1189                     return LDAP_PROTOCOL_ERROR;
1190           }
1191 
1192           if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON )
1193                     && BER_BVISEMPTY( &op->o_ndn ) )
1194           {
1195                     rs->sr_text = "anonymous proxied authorization not allowed";
1196                     return LDAP_PROXIED_AUTHORIZATION_DENIED;
1197           }
1198 
1199           op->o_proxy_authz = ctrl->ldctl_iscritical
1200                     ? SLAP_CONTROL_CRITICAL
1201                     : SLAP_CONTROL_NONCRITICAL;
1202 
1203           Debug( LDAP_DEBUG_ARGS,
1204                     "parseProxyAuthz: conn %lu authzid=\"%s\"\n",
1205                     op->o_connid,
1206                     ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous" );
1207 
1208           if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1209                     Debug( LDAP_DEBUG_TRACE,
1210                               "parseProxyAuthz: conn=%lu anonymous\n",
1211                               op->o_connid );
1212 
1213                     /* anonymous */
1214                     if ( !BER_BVISNULL( &op->o_ndn ) ) {
1215                               op->o_ndn.bv_val[ 0 ] = '\0';
1216                     }
1217                     op->o_ndn.bv_len = 0;
1218 
1219                     if ( !BER_BVISNULL( &op->o_dn ) ) {
1220                               op->o_dn.bv_val[ 0 ] = '\0';
1221                     }
1222                     op->o_dn.bv_len = 0;
1223 
1224                     return LDAP_SUCCESS;
1225           }
1226 
1227           rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
1228                               NULL, &dn, SLAP_GETDN_AUTHZID );
1229 
1230           /* FIXME: empty DN in proxyAuthz control should be legal... */
1231           if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
1232                     if ( dn.bv_val ) {
1233                               ch_free( dn.bv_val );
1234                     }
1235                     rs->sr_text = "authzId mapping failed";
1236                     return LDAP_PROXIED_AUTHORIZATION_DENIED;
1237           }
1238 
1239           Debug( LDAP_DEBUG_TRACE,
1240                     "parseProxyAuthz: conn=%lu \"%s\"\n",
1241                     op->o_connid,
1242                     dn.bv_len ? dn.bv_val : "(NULL)" );
1243 
1244           rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
1245 
1246           if ( rc ) {
1247                     ch_free( dn.bv_val );
1248                     rs->sr_text = "not authorized to assume identity";
1249                     return LDAP_PROXIED_AUTHORIZATION_DENIED;
1250           }
1251 
1252           ch_free( op->o_ndn.bv_val );
1253 
1254           /*
1255            * NOTE: since slap_sasl_getdn() returns a normalized dn,
1256            * from now on op->o_dn is normalized
1257            */
1258           op->o_ndn = dn;
1259           ber_bvreplace( &op->o_dn, &dn );
1260 
1261           Debug( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
1262               op->o_log_prefix, dn.bv_val );
1263 
1264           return LDAP_SUCCESS;
1265 }
1266 
parseNoOp(Operation * op,SlapReply * rs,LDAPControl * ctrl)1267 static int parseNoOp (
1268           Operation *op,
1269           SlapReply *rs,
1270           LDAPControl *ctrl )
1271 {
1272           if ( op->o_noop != SLAP_CONTROL_NONE ) {
1273                     rs->sr_text = "noop control specified multiple times";
1274                     return LDAP_PROTOCOL_ERROR;
1275           }
1276 
1277           if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
1278                     rs->sr_text = "noop control value not empty";
1279                     return LDAP_PROTOCOL_ERROR;
1280           }
1281 
1282           op->o_noop = ctrl->ldctl_iscritical
1283                     ? SLAP_CONTROL_CRITICAL
1284                     : SLAP_CONTROL_NONCRITICAL;
1285 
1286           return LDAP_SUCCESS;
1287 }
1288 
parsePagedResults(Operation * op,SlapReply * rs,LDAPControl * ctrl)1289 static int parsePagedResults (
1290           Operation *op,
1291           SlapReply *rs,
1292           LDAPControl *ctrl )
1293 {
1294           BerElementBuffer berbuf;
1295           BerElement          *ber = (BerElement *)&berbuf;
1296           struct berval       cookie;
1297           PagedResultsState   *ps;
1298           int                 rc = LDAP_SUCCESS;
1299           ber_tag_t tag;
1300           ber_int_t size;
1301 
1302           if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1303                     rs->sr_text = "paged results control specified multiple times";
1304                     return LDAP_PROTOCOL_ERROR;
1305           }
1306 
1307           if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1308                     rs->sr_text = "paged results control value is absent";
1309                     return LDAP_PROTOCOL_ERROR;
1310           }
1311 
1312           if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1313                     rs->sr_text = "paged results control value is empty";
1314                     return LDAP_PROTOCOL_ERROR;
1315           }
1316 
1317           /* Parse the control value
1318            *        realSearchControlValue ::= SEQUENCE {
1319            *                  size      INTEGER (0..maxInt),
1320            *                                      -- requested page size from client
1321            *                                      -- result set size estimate from server
1322            *                  cookie    OCTET STRING
1323            * }
1324            */
1325           ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER );
1326 
1327           tag = ber_scanf( ber, "{im}", &size, &cookie );
1328 
1329           if ( tag == LBER_ERROR ) {
1330                     rs->sr_text = "paged results control could not be decoded";
1331                     rc = LDAP_PROTOCOL_ERROR;
1332                     goto done;
1333           }
1334 
1335           if ( size < 0 ) {
1336                     rs->sr_text = "paged results control size invalid";
1337                     rc = LDAP_PROTOCOL_ERROR;
1338                     goto done;
1339           }
1340 
1341           ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
1342           *ps = op->o_conn->c_pagedresults_state;
1343           ps->ps_size = size;
1344           ps->ps_cookieval = cookie;
1345           op->o_pagedresults_state = ps;
1346           if ( !cookie.bv_len ) {
1347                     ps->ps_count = 0;
1348                     ps->ps_cookie = 0;
1349                     /* taint ps_cookie, to detect whether it's set */
1350                     op->o_conn->c_pagedresults_state.ps_cookie = NOID;
1351           }
1352 
1353           /* NOTE: according to RFC 2696 3.:
1354 
1355     If the page size is greater than or equal to the sizeLimit value, the
1356     server should ignore the control as the request can be satisfied in a
1357     single page.
1358 
1359            * NOTE: this assumes that the op->ors_slimit be set
1360            * before the controls are parsed.
1361            */
1362 
1363           if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
1364                     op->o_pagedresults = SLAP_CONTROL_IGNORED;
1365 
1366           } else if ( ctrl->ldctl_iscritical ) {
1367                     op->o_pagedresults = SLAP_CONTROL_CRITICAL;
1368 
1369           } else {
1370                     op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
1371           }
1372 
1373 done:;
1374           return rc;
1375 }
1376 
1377 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
parseSortedResults(Operation * op,SlapReply * rs,LDAPControl * ctrl)1378 static int parseSortedResults (
1379           Operation *op,
1380           SlapReply *rs,
1381           LDAPControl *ctrl )
1382 {
1383           int                 rc = LDAP_SUCCESS;
1384 
1385           if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
1386                     rs->sr_text = "sorted results control specified multiple times";
1387                     return LDAP_PROTOCOL_ERROR;
1388           }
1389 
1390           if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1391                     rs->sr_text = "sorted results control value is absent";
1392                     return LDAP_PROTOCOL_ERROR;
1393           }
1394 
1395           if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1396                     rs->sr_text = "sorted results control value is empty";
1397                     return LDAP_PROTOCOL_ERROR;
1398           }
1399 
1400           /* blow off parsing the value */
1401 
1402           op->o_sortedresults = ctrl->ldctl_iscritical
1403                     ? SLAP_CONTROL_CRITICAL
1404                     : SLAP_CONTROL_NONCRITICAL;
1405 
1406           return rc;
1407 }
1408 #endif
1409 
parseAssert(Operation * op,SlapReply * rs,LDAPControl * ctrl)1410 static int parseAssert (
1411           Operation *op,
1412           SlapReply *rs,
1413           LDAPControl *ctrl )
1414 {
1415           BerElement          *ber;
1416           struct berval       fstr = BER_BVNULL;
1417 
1418           if ( op->o_assert != SLAP_CONTROL_NONE ) {
1419                     rs->sr_text = "assert control specified multiple times";
1420                     return LDAP_PROTOCOL_ERROR;
1421           }
1422 
1423           if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1424                     rs->sr_text = "assert control value is absent";
1425                     return LDAP_PROTOCOL_ERROR;
1426           }
1427 
1428           if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1429                     rs->sr_text = "assert control value is empty";
1430                     return LDAP_PROTOCOL_ERROR;
1431           }
1432 
1433           ber = ber_init( &(ctrl->ldctl_value) );
1434           if (ber == NULL) {
1435                     rs->sr_text = "assert control: internal error";
1436                     return LDAP_OTHER;
1437           }
1438 
1439           rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
1440                     &rs->sr_text);
1441           (void) ber_free( ber, 1 );
1442           if( rs->sr_err != LDAP_SUCCESS ) {
1443                     if( rs->sr_err == SLAPD_DISCONNECT ) {
1444                               rs->sr_err = LDAP_PROTOCOL_ERROR;
1445                               send_ldap_disconnect( op, rs );
1446                               rs->sr_err = SLAPD_DISCONNECT;
1447                     } else {
1448                               send_ldap_result( op, rs );
1449                     }
1450                     if( op->o_assertion != NULL ) {
1451                               filter_free_x( op, op->o_assertion, 1 );
1452                               op->o_assertion = NULL;
1453                     }
1454                     return rs->sr_err;
1455           }
1456 
1457 #ifdef LDAP_DEBUG
1458           filter2bv_x( op, op->o_assertion, &fstr );
1459 
1460           Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
1461                     op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" );
1462           op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1463 #endif
1464 
1465           op->o_assert = ctrl->ldctl_iscritical
1466                     ? SLAP_CONTROL_CRITICAL
1467                     : SLAP_CONTROL_NONCRITICAL;
1468 
1469           rs->sr_err = LDAP_SUCCESS;
1470           return LDAP_SUCCESS;
1471 }
1472 
1473 #define READMSG(post, msg) \
1474           ( post ? "postread control: " msg : "preread control: " msg )
1475 
1476 static int
parseReadAttrs(Operation * op,SlapReply * rs,LDAPControl * ctrl,int post)1477 parseReadAttrs(
1478           Operation *op,
1479           SlapReply *rs,
1480           LDAPControl *ctrl,
1481           int post )
1482 {
1483           ber_len_t siz, off, i;
1484           BerElement          *ber;
1485           AttributeName       *an = NULL;
1486 
1487           if ( ( post && op->o_postread != SLAP_CONTROL_NONE ) ||
1488                     ( !post && op->o_preread != SLAP_CONTROL_NONE ) )
1489           {
1490                     rs->sr_text = READMSG( post, "specified multiple times" );
1491                     return LDAP_PROTOCOL_ERROR;
1492           }
1493 
1494           if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1495                     rs->sr_text = READMSG( post, "value is absent" );
1496                     return LDAP_PROTOCOL_ERROR;
1497           }
1498 
1499           if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1500                     rs->sr_text = READMSG( post, "value is empty" );
1501                     return LDAP_PROTOCOL_ERROR;
1502           }
1503 
1504           if ( op->o_txnSpec ) { /* temporary limitation */
1505                     rs->sr_text = READMSG( post, "cannot perform in transaction" );
1506                     return LDAP_UNWILLING_TO_PERFORM;
1507           }
1508 
1509           ber = ber_init( &ctrl->ldctl_value );
1510           if ( ber == NULL ) {
1511                     rs->sr_text = READMSG( post, "internal error" );
1512                     return LDAP_OTHER;
1513           }
1514 
1515           rs->sr_err = LDAP_SUCCESS;
1516           siz = sizeof( AttributeName );
1517           off = offsetof( AttributeName, an_name );
1518           if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1519                     rs->sr_text = READMSG( post, "decoding error" );
1520                     rs->sr_err = LDAP_PROTOCOL_ERROR;
1521                     goto done;
1522           }
1523 
1524           for ( i = 0; i < siz; i++ ) {
1525                     const char          *dummy = NULL;
1526                     int                 rc;
1527 
1528                     an[i].an_desc = NULL;
1529                     an[i].an_oc = NULL;
1530                     an[i].an_flags = 0;
1531                     rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1532                     if ( rc == LDAP_SUCCESS ) {
1533                               an[i].an_name = an[i].an_desc->ad_cname;
1534 
1535                     } else {
1536                               int                           j;
1537                               static struct berval          special_attrs[] = {
1538                                         BER_BVC( LDAP_NO_ATTRS ),
1539                                         BER_BVC( LDAP_ALL_USER_ATTRIBUTES ),
1540                                         BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ),
1541                                         BER_BVNULL
1542                               };
1543 
1544                               /* deal with special attribute types */
1545                               for ( j = 0; !BER_BVISNULL( &special_attrs[ j ] ); j++ ) {
1546                                         if ( bvmatch( &an[i].an_name, &special_attrs[ j ] ) ) {
1547                                                   an[i].an_name = special_attrs[ j ];
1548                                                   break;
1549                                         }
1550                               }
1551 
1552                               if ( BER_BVISNULL( &special_attrs[ j ] ) && ctrl->ldctl_iscritical ) {
1553                                         rs->sr_err = rc;
1554                                         rs->sr_text = dummy ? dummy
1555                                                   : READMSG( post, "unknown attributeType" );
1556                                         goto done;
1557                               }
1558                     }
1559           }
1560 
1561           if ( post ) {
1562                     op->o_postread_attrs = an;
1563                     op->o_postread = ctrl->ldctl_iscritical
1564                               ? SLAP_CONTROL_CRITICAL
1565                               : SLAP_CONTROL_NONCRITICAL;
1566           } else {
1567                     op->o_preread_attrs = an;
1568                     op->o_preread = ctrl->ldctl_iscritical
1569                               ? SLAP_CONTROL_CRITICAL
1570                               : SLAP_CONTROL_NONCRITICAL;
1571           }
1572 
1573 done:
1574           (void) ber_free( ber, 1 );
1575           return rs->sr_err;
1576 }
1577 
parsePreRead(Operation * op,SlapReply * rs,LDAPControl * ctrl)1578 static int parsePreRead (
1579           Operation *op,
1580           SlapReply *rs,
1581           LDAPControl *ctrl )
1582 {
1583           return parseReadAttrs( op, rs, ctrl, 0 );
1584 }
1585 
parsePostRead(Operation * op,SlapReply * rs,LDAPControl * ctrl)1586 static int parsePostRead (
1587           Operation *op,
1588           SlapReply *rs,
1589           LDAPControl *ctrl )
1590 {
1591           return parseReadAttrs( op, rs, ctrl, 1 );
1592 }
1593 
parseValuesReturnFilter(Operation * op,SlapReply * rs,LDAPControl * ctrl)1594 static int parseValuesReturnFilter (
1595           Operation *op,
1596           SlapReply *rs,
1597           LDAPControl *ctrl )
1598 {
1599           BerElement          *ber;
1600           struct berval       fstr = BER_BVNULL;
1601 
1602           if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
1603                     rs->sr_text = "valuesReturnFilter control specified multiple times";
1604                     return LDAP_PROTOCOL_ERROR;
1605           }
1606 
1607           if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1608                     rs->sr_text = "valuesReturnFilter control value is absent";
1609                     return LDAP_PROTOCOL_ERROR;
1610           }
1611 
1612           if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1613                     rs->sr_text = "valuesReturnFilter control value is empty";
1614                     return LDAP_PROTOCOL_ERROR;
1615           }
1616 
1617           ber = ber_init( &(ctrl->ldctl_value) );
1618           if (ber == NULL) {
1619                     rs->sr_text = "internal error";
1620                     return LDAP_OTHER;
1621           }
1622 
1623           rs->sr_err = get_vrFilter( op, ber,
1624                     (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
1625 
1626           (void) ber_free( ber, 1 );
1627 
1628           if( rs->sr_err != LDAP_SUCCESS ) {
1629                     if( rs->sr_err == SLAPD_DISCONNECT ) {
1630                               rs->sr_err = LDAP_PROTOCOL_ERROR;
1631                               send_ldap_disconnect( op, rs );
1632                               rs->sr_err = SLAPD_DISCONNECT;
1633                     } else {
1634                               send_ldap_result( op, rs );
1635                     }
1636                     if( op->o_vrFilter != NULL) {
1637                               vrFilter_free( op, op->o_vrFilter );
1638                               op->o_vrFilter = NULL;
1639                     }
1640           }
1641 #ifdef LDAP_DEBUG
1642           else {
1643                     vrFilter2bv( op, op->o_vrFilter, &fstr );
1644           }
1645 
1646           Debug( LDAP_DEBUG_ARGS, "     vrFilter: %s\n",
1647                     fstr.bv_len ? fstr.bv_val : "empty" );
1648           op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1649 #endif
1650 
1651           op->o_valuesreturnfilter = ctrl->ldctl_iscritical
1652                     ? SLAP_CONTROL_CRITICAL
1653                     : SLAP_CONTROL_NONCRITICAL;
1654 
1655           rs->sr_err = LDAP_SUCCESS;
1656           return LDAP_SUCCESS;
1657 }
1658 
parseSubentries(Operation * op,SlapReply * rs,LDAPControl * ctrl)1659 static int parseSubentries (
1660           Operation *op,
1661           SlapReply *rs,
1662           LDAPControl *ctrl )
1663 {
1664           if ( op->o_subentries != SLAP_CONTROL_NONE ) {
1665                     rs->sr_text = "subentries control specified multiple times";
1666                     return LDAP_PROTOCOL_ERROR;
1667           }
1668 
1669           /* FIXME: should use BER library */
1670           if( ( ctrl->ldctl_value.bv_len != 3 )
1671                     || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
1672                     || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
1673           {
1674                     rs->sr_text = "subentries control value encoding is bogus";
1675                     return LDAP_PROTOCOL_ERROR;
1676           }
1677 
1678           op->o_subentries = ctrl->ldctl_iscritical
1679                     ? SLAP_CONTROL_CRITICAL
1680                     : SLAP_CONTROL_NONCRITICAL;
1681 
1682           if (ctrl->ldctl_value.bv_val[2]) {
1683                     set_subentries_visibility( op );
1684           }
1685 
1686           return LDAP_SUCCESS;
1687 }
1688 
parsePermissiveModify(Operation * op,SlapReply * rs,LDAPControl * ctrl)1689 static int parsePermissiveModify (
1690           Operation *op,
1691           SlapReply *rs,
1692           LDAPControl *ctrl )
1693 {
1694           if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) {
1695                     rs->sr_text = "permissiveModify control specified multiple times";
1696                     return LDAP_PROTOCOL_ERROR;
1697           }
1698 
1699           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
1700                     rs->sr_text = "permissiveModify control value not absent";
1701                     return LDAP_PROTOCOL_ERROR;
1702           }
1703 
1704           op->o_permissive_modify = ctrl->ldctl_iscritical
1705                     ? SLAP_CONTROL_CRITICAL
1706                     : SLAP_CONTROL_NONCRITICAL;
1707 
1708           return LDAP_SUCCESS;
1709 }
1710 
parseDomainScope(Operation * op,SlapReply * rs,LDAPControl * ctrl)1711 static int parseDomainScope (
1712           Operation *op,
1713           SlapReply *rs,
1714           LDAPControl *ctrl )
1715 {
1716           if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1717                     rs->sr_text = "domainScope control specified multiple times";
1718                     return LDAP_PROTOCOL_ERROR;
1719           }
1720 
1721           /* this should be checking BVISNULL, but M$ clients are broken
1722            * and include the value even though the M$ spec says it must be
1723            * omitted. ITS#9100.
1724            */
1725           if ( !BER_BVISEMPTY( &ctrl->ldctl_value )) {
1726                     rs->sr_text = "domainScope control value not absent";
1727                     return LDAP_PROTOCOL_ERROR;
1728           }
1729 
1730           op->o_domain_scope = ctrl->ldctl_iscritical
1731                     ? SLAP_CONTROL_CRITICAL
1732                     : SLAP_CONTROL_NONCRITICAL;
1733 
1734           return LDAP_SUCCESS;
1735 }
1736 
1737 #ifdef SLAP_CONTROL_X_TREE_DELETE
parseTreeDelete(Operation * op,SlapReply * rs,LDAPControl * ctrl)1738 static int parseTreeDelete (
1739           Operation *op,
1740           SlapReply *rs,
1741           LDAPControl *ctrl )
1742 {
1743           if ( op->o_tree_delete != SLAP_CONTROL_NONE ) {
1744                     rs->sr_text = "treeDelete control specified multiple times";
1745                     return LDAP_PROTOCOL_ERROR;
1746           }
1747 
1748           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
1749                     rs->sr_text = "treeDelete control value not absent";
1750                     return LDAP_PROTOCOL_ERROR;
1751           }
1752 
1753           op->o_tree_delete = ctrl->ldctl_iscritical
1754                     ? SLAP_CONTROL_CRITICAL
1755                     : SLAP_CONTROL_NONCRITICAL;
1756 
1757           return LDAP_SUCCESS;
1758 }
1759 #endif
1760 
parseSearchOptions(Operation * op,SlapReply * rs,LDAPControl * ctrl)1761 static int parseSearchOptions (
1762           Operation *op,
1763           SlapReply *rs,
1764           LDAPControl *ctrl )
1765 {
1766           BerElement *ber;
1767           ber_int_t search_flags;
1768           ber_tag_t tag;
1769 
1770           if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1771                     rs->sr_text = "searchOptions control value is absent";
1772                     return LDAP_PROTOCOL_ERROR;
1773           }
1774 
1775           if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1776                     rs->sr_text = "searchOptions control value is empty";
1777                     return LDAP_PROTOCOL_ERROR;
1778           }
1779 
1780           ber = ber_init( &ctrl->ldctl_value );
1781           if( ber == NULL ) {
1782                     rs->sr_text = "internal error";
1783                     return LDAP_OTHER;
1784           }
1785 
1786           tag = ber_scanf( ber, "{i}", &search_flags );
1787           (void) ber_free( ber, 1 );
1788 
1789           if ( tag == LBER_ERROR ) {
1790                     rs->sr_text = "searchOptions control decoding error";
1791                     return LDAP_PROTOCOL_ERROR;
1792           }
1793 
1794           if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
1795                     /* Search flags not recognised so far,
1796                      * including:
1797                      *                  LDAP_SEARCH_FLAG_PHANTOM_ROOT
1798                      */
1799                     if ( ctrl->ldctl_iscritical ) {
1800                               rs->sr_text = "searchOptions contained unrecognized flag";
1801                               return LDAP_UNWILLING_TO_PERFORM;
1802                     }
1803 
1804                     /* Ignore */
1805                     Debug( LDAP_DEBUG_TRACE,
1806                               "searchOptions: conn=%lu unrecognized flag(s) 0x%x (non-critical)\n",
1807                               op->o_connid, (unsigned)search_flags );
1808 
1809                     return LDAP_SUCCESS;
1810           }
1811 
1812           if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
1813                     if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1814                               rs->sr_text = "searchOptions control specified multiple times "
1815                                         "or with domainScope control";
1816                               return LDAP_PROTOCOL_ERROR;
1817                     }
1818 
1819                     op->o_domain_scope = ctrl->ldctl_iscritical
1820                               ? SLAP_CONTROL_CRITICAL
1821                               : SLAP_CONTROL_NONCRITICAL;
1822           }
1823 
1824           return LDAP_SUCCESS;
1825 }
1826 
1827 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1828 struct berval session_tracking_formats[] = {
1829           BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID ),
1830                     BER_BVC( "RADIUS-Acct-Session-Id" ),
1831           BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID ),
1832                     BER_BVC( "RADIUS-Acct-Multi-Session-Id" ),
1833           BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ),
1834                     BER_BVC( "USERNAME" ),
1835 
1836           BER_BVNULL
1837 };
1838 
parseSessionTracking(Operation * op,SlapReply * rs,LDAPControl * ctrl)1839 static int parseSessionTracking(
1840           Operation *op,
1841           SlapReply *rs,
1842           LDAPControl *ctrl )
1843 {
1844           BerElement                    *ber;
1845           ber_tag_t           tag;
1846           ber_len_t           len;
1847           int                           i, rc;
1848 
1849           struct berval                 sessionSourceIp = BER_BVNULL,
1850                                         sessionSourceName = BER_BVNULL,
1851                                         formatOID = BER_BVNULL,
1852                                         sessionTrackingIdentifier = BER_BVNULL;
1853 
1854           size_t                        st_len, st_pos;
1855 
1856           if ( ctrl->ldctl_iscritical ) {
1857                     rs->sr_text = "sessionTracking criticality is TRUE";
1858                     return LDAP_PROTOCOL_ERROR;
1859           }
1860 
1861           if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1862                     rs->sr_text = "sessionTracking control value is absent";
1863                     return LDAP_PROTOCOL_ERROR;
1864           }
1865 
1866           if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1867                     rs->sr_text = "sessionTracking control value is empty";
1868                     return LDAP_PROTOCOL_ERROR;
1869           }
1870 
1871           /* TODO: add the capability to determine if a client is allowed
1872            * to use this control, based on identity, ip and so */
1873 
1874           ber = ber_init( &ctrl->ldctl_value );
1875           if ( ber == NULL ) {
1876                     rs->sr_text = "internal error";
1877                     return LDAP_OTHER;
1878           }
1879 
1880           tag = ber_skip_tag( ber, &len );
1881           if ( tag != LBER_SEQUENCE ) {
1882                     tag = LBER_ERROR;
1883                     goto error;
1884           }
1885 
1886           /* sessionSourceIp */
1887           tag = ber_peek_tag( ber, &len );
1888           if ( tag == LBER_DEFAULT ) {
1889                     tag = LBER_ERROR;
1890                     goto error;
1891           }
1892 
1893           if ( len == 0 ) {
1894                     tag = ber_skip_tag( ber, &len );
1895 
1896           } else if ( len > 128 ) {
1897                     rs->sr_text = "sessionTracking.sessionSourceIp too long";
1898                     rs->sr_err = LDAP_PROTOCOL_ERROR;
1899                     goto error;
1900 
1901           } else {
1902                     tag = ber_scanf( ber, "m", &sessionSourceIp );
1903           }
1904 
1905           if ( ldif_is_not_printable( sessionSourceIp.bv_val, sessionSourceIp.bv_len ) ) {
1906                     BER_BVZERO( &sessionSourceIp );
1907           }
1908 
1909           /* sessionSourceName */
1910           tag = ber_peek_tag( ber, &len );
1911           if ( tag == LBER_DEFAULT ) {
1912                     tag = LBER_ERROR;
1913                     goto error;
1914           }
1915 
1916           if ( len == 0 ) {
1917                     tag = ber_skip_tag( ber, &len );
1918 
1919           } else if ( len > 65536 ) {
1920                     rs->sr_text = "sessionTracking.sessionSourceName too long";
1921                     rs->sr_err = LDAP_PROTOCOL_ERROR;
1922                     goto error;
1923 
1924           } else {
1925                     tag = ber_scanf( ber, "m", &sessionSourceName );
1926           }
1927 
1928           if ( ldif_is_not_printable( sessionSourceName.bv_val, sessionSourceName.bv_len ) ) {
1929                     BER_BVZERO( &sessionSourceName );
1930           }
1931 
1932           /* formatOID */
1933           tag = ber_peek_tag( ber, &len );
1934           if ( tag == LBER_DEFAULT ) {
1935                     tag = LBER_ERROR;
1936                     goto error;
1937           }
1938 
1939           if ( len == 0 ) {
1940                     rs->sr_text = "sessionTracking.formatOID empty";
1941                     rs->sr_err = LDAP_PROTOCOL_ERROR;
1942                     goto error;
1943 
1944           } else if ( len > 1024 ) {
1945                     rs->sr_text = "sessionTracking.formatOID too long";
1946                     rs->sr_err = LDAP_PROTOCOL_ERROR;
1947                     goto error;
1948 
1949           } else {
1950                     tag = ber_scanf( ber, "m", &formatOID );
1951           }
1952 
1953           rc = numericoidValidate( NULL, &formatOID );
1954           if ( rc != LDAP_SUCCESS ) {
1955                     rs->sr_text = "sessionTracking.formatOID invalid";
1956                     goto error;
1957           }
1958 
1959           for ( i = 0; !BER_BVISNULL( &session_tracking_formats[ i ] ); i += 2 )
1960           {
1961                     if ( bvmatch( &formatOID, &session_tracking_formats[ i ] ) ) {
1962                               formatOID = session_tracking_formats[ i + 1 ];
1963                               break;
1964                     }
1965           }
1966 
1967           /* sessionTrackingIdentifier */
1968           tag = ber_peek_tag( ber, &len );
1969           if ( tag == LBER_DEFAULT ) {
1970                     tag = LBER_ERROR;
1971                     goto error;
1972           }
1973 
1974           if ( len == 0 ) {
1975                     tag = ber_skip_tag( ber, &len );
1976 
1977           } else {
1978                     /* note: should not be more than 65536... */
1979                     tag = ber_scanf( ber, "m", &sessionTrackingIdentifier );
1980                     if ( ldif_is_not_printable( sessionTrackingIdentifier.bv_val, sessionTrackingIdentifier.bv_len ) ) {
1981                               /* we want the OID printed, at least */
1982                               BER_BVSTR( &sessionTrackingIdentifier, "" );
1983                     }
1984           }
1985 
1986           /* closure */
1987           tag = ber_skip_tag( ber, &len );
1988           if ( tag != LBER_DEFAULT || len != 0 ) {
1989                     tag = LBER_ERROR;
1990                     goto error;
1991           }
1992           tag = 0;
1993 
1994           st_len = 0;
1995           if ( !BER_BVISNULL( &sessionSourceIp ) ) {
1996                     st_len += STRLENOF( "IP=" ) + sessionSourceIp.bv_len;
1997           }
1998           if ( !BER_BVISNULL( &sessionSourceName ) ) {
1999                     if ( st_len ) st_len++;
2000                     st_len += STRLENOF( "NAME=" ) + sessionSourceName.bv_len;
2001           }
2002           if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
2003                     if ( st_len ) st_len++;
2004                     st_len += formatOID.bv_len + STRLENOF( "=" )
2005                               + sessionTrackingIdentifier.bv_len;
2006           }
2007 
2008           if ( st_len == 0 ) {
2009                     goto error;
2010           }
2011 
2012           st_len += STRLENOF( " []" );
2013           st_pos = strlen( op->o_log_prefix );
2014 
2015           if ( sizeof( op->o_log_prefix ) - st_pos > st_len ) {
2016                     char      *ptr = &op->o_log_prefix[ st_pos ];
2017 
2018                     ptr = lutil_strcopy( ptr, " [" /*]*/ );
2019 
2020                     st_len = 0;
2021                     if ( !BER_BVISNULL( &sessionSourceIp ) ) {
2022                               ptr = lutil_strcopy( ptr, "IP=" );
2023                               ptr = lutil_strcopy( ptr, sessionSourceIp.bv_val );
2024                               st_len++;
2025                     }
2026 
2027                     if ( !BER_BVISNULL( &sessionSourceName ) ) {
2028                               if ( st_len ) *ptr++ = ' ';
2029                               ptr = lutil_strcopy( ptr, "NAME=" );
2030                               ptr = lutil_strcopy( ptr, sessionSourceName.bv_val );
2031                               st_len++;
2032                     }
2033 
2034                     if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
2035                               if ( st_len ) *ptr++ = ' ';
2036                               ptr = lutil_strcopy( ptr, formatOID.bv_val );
2037                               *ptr++ = '=';
2038                               ptr = lutil_strcopy( ptr, sessionTrackingIdentifier.bv_val );
2039                     }
2040 
2041                     *ptr++ = /*[*/ ']';
2042                     *ptr = '\0';
2043           }
2044 
2045 error:;
2046           (void)ber_free( ber, 1 );
2047 
2048           if ( tag == LBER_ERROR ) {
2049                     rs->sr_text = "sessionTracking control decoding error";
2050                     return LDAP_PROTOCOL_ERROR;
2051           }
2052 
2053 
2054           return rs->sr_err;
2055 }
2056 
2057 int
slap_ctrl_session_tracking_add(Operation * op,SlapReply * rs,struct berval * ip,struct berval * name,struct berval * id,LDAPControl * ctrl)2058 slap_ctrl_session_tracking_add(
2059           Operation *op,
2060           SlapReply *rs,
2061           struct berval *ip,
2062           struct berval *name,
2063           struct berval *id,
2064           LDAPControl *ctrl )
2065 {
2066           BerElementBuffer berbuf;
2067           BerElement          *ber = (BerElement *)&berbuf;
2068 
2069           static struct berval          oid = BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME );
2070 
2071           assert( ctrl != NULL );
2072 
2073           ber_init2( ber, NULL, LBER_USE_DER );
2074 
2075           ber_printf( ber, "{OOOO}", ip, name, &oid, id );
2076 
2077           if ( ber_flatten2( ber, &ctrl->ldctl_value, 0 ) == -1 ) {
2078                     rs->sr_err = LDAP_OTHER;
2079                     goto done;
2080           }
2081 
2082           ctrl->ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
2083           ctrl->ldctl_iscritical = 0;
2084 
2085           rs->sr_err = LDAP_SUCCESS;
2086 
2087 done:;
2088           return rs->sr_err;
2089 }
2090 
2091 int
slap_ctrl_session_tracking_request_add(Operation * op,SlapReply * rs,LDAPControl * ctrl)2092 slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPControl *ctrl )
2093 {
2094           static struct berval          bv_unknown = BER_BVC( SLAP_STRING_UNKNOWN );
2095           struct berval                 ip = BER_BVNULL,
2096                                         name = BER_BVNULL,
2097                                         id = BER_BVNULL;
2098 
2099           if ( !BER_BVISNULL( &op->o_conn->c_peer_name ) &&
2100                     memcmp( op->o_conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
2101           {
2102                     char      *ptr;
2103 
2104                     ip.bv_val = op->o_conn->c_peer_name.bv_val + STRLENOF( "IP=" );
2105                     ip.bv_len = op->o_conn->c_peer_name.bv_len - STRLENOF( "IP=" );
2106 
2107                     ptr = ber_bvchr( &ip, ':' );
2108                     if ( ptr ) {
2109                               ip.bv_len = ptr - ip.bv_val;
2110                     }
2111           }
2112 
2113           if ( !BER_BVISNULL( &op->o_conn->c_peer_domain ) &&
2114                     !bvmatch( &op->o_conn->c_peer_domain, &bv_unknown ) )
2115           {
2116                     name = op->o_conn->c_peer_domain;
2117           }
2118 
2119           if ( !BER_BVISNULL( &op->o_dn ) && !BER_BVISEMPTY( &op->o_dn ) ) {
2120                     id = op->o_dn;
2121           }
2122 
2123           return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl );
2124 }
2125 #endif
2126 
2127 #ifdef SLAP_CONTROL_X_WHATFAILED
parseWhatFailed(Operation * op,SlapReply * rs,LDAPControl * ctrl)2128 static int parseWhatFailed(
2129           Operation *op,
2130           SlapReply *rs,
2131           LDAPControl *ctrl )
2132 {
2133           if ( op->o_whatFailed != SLAP_CONTROL_NONE ) {
2134                     rs->sr_text = "\"WHat Failed?\" control specified multiple times";
2135                     return LDAP_PROTOCOL_ERROR;
2136           }
2137 
2138           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
2139                     rs->sr_text = "\"What Failed?\" control value not absent";
2140                     return LDAP_PROTOCOL_ERROR;
2141           }
2142 
2143           op->o_whatFailed = ctrl->ldctl_iscritical
2144                     ? SLAP_CONTROL_CRITICAL
2145                     : SLAP_CONTROL_NONCRITICAL;
2146 
2147           return LDAP_SUCCESS;
2148 }
2149 
2150 int
slap_ctrl_whatFailed_add(Operation * op,SlapReply * rs,char ** oids)2151 slap_ctrl_whatFailed_add(
2152           Operation *op,
2153           SlapReply *rs,
2154           char **oids )
2155 {
2156           BerElementBuffer berbuf;
2157           BerElement *ber = (BerElement *) &berbuf;
2158           LDAPControl **ctrls = NULL;
2159           struct berval ctrlval;
2160           int i, rc = LDAP_SUCCESS;
2161 
2162           ber_init2( ber, NULL, LBER_USE_DER );
2163           ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2164           ber_printf( ber, "[" /*]*/ );
2165           for ( i = 0; oids[ i ] != NULL; i++ ) {
2166                     ber_printf( ber, "s", oids[ i ] );
2167           }
2168           ber_printf( ber, /*[*/ "]" );
2169 
2170           if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
2171                     rc = LDAP_OTHER;
2172                     goto done;
2173           }
2174 
2175           i = 0;
2176           if ( rs->sr_ctrls != NULL ) {
2177                     for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
2178                               if ( strcmp( rs->sr_ctrls[ i ]->ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) != 0 ) {
2179                                         /* TODO: add */
2180                                         assert( 0 );
2181                               }
2182                     }
2183           }
2184 
2185           ctrls = op->o_tmprealloc( rs->sr_ctrls,
2186                               sizeof(LDAPControl *)*( i + 2 )
2187                               + sizeof(LDAPControl)
2188                               + ctrlval.bv_len + 1,
2189                               op->o_tmpmemctx );
2190           if ( ctrls == NULL ) {
2191                     rc = LDAP_OTHER;
2192                     goto done;
2193           }
2194           ctrls[ i + 1 ] = NULL;
2195           ctrls[ i ] = (LDAPControl *)&ctrls[ i + 2 ];
2196           ctrls[ i ]->ldctl_oid = LDAP_CONTROL_X_WHATFAILED;
2197           ctrls[ i ]->ldctl_iscritical = 0;
2198           ctrls[ i ]->ldctl_value.bv_val = (char *)&ctrls[ i ][ 1 ];
2199           AC_MEMCPY( ctrls[ i ]->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len + 1 );
2200           ctrls[ i ]->ldctl_value.bv_len = ctrlval.bv_len;
2201 
2202           ber_free_buf( ber );
2203 
2204           rs->sr_ctrls = ctrls;
2205 
2206 done:;
2207           return rc;
2208 }
2209 #endif
2210 
2211 #ifdef SLAP_CONTROL_X_LAZY_COMMIT
parseLazyCommit(Operation * op,SlapReply * rs,LDAPControl * ctrl)2212 static int parseLazyCommit(
2213           Operation *op,
2214           SlapReply *rs,
2215           LDAPControl *ctrl )
2216 {
2217           if ( op->o_lazyCommit != SLAP_CONTROL_NONE ) {
2218                     rs->sr_text = "\"Lazy Commit?\" control specified multiple times";
2219                     return LDAP_PROTOCOL_ERROR;
2220           }
2221 
2222           if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
2223                     rs->sr_text = "\"Lazy Commit?\" control value not absent";
2224                     return LDAP_PROTOCOL_ERROR;
2225           }
2226 
2227           op->o_lazyCommit = ctrl->ldctl_iscritical
2228                     ? SLAP_CONTROL_CRITICAL
2229                     : SLAP_CONTROL_NONCRITICAL;
2230 
2231           return LDAP_SUCCESS;
2232 }
2233 #endif
2234