]> git.sur5r.net Git - openldap/blob - servers/slapd/controls.c
8a022a0dd47e8c169a68c291ccfdfedac7ce5578
[openldap] / servers / slapd / controls.c
1 /* $OpenLDAP$ */
2 /* 
3  * Copyright 1999-2003 The OpenLDAP Foundation.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted only
7  * as authorized by the OpenLDAP Public License.  A copy of this
8  * license is available at http://www.OpenLDAP.org/license.html or
9  * in file LICENSE in the top-level directory of the distribution.
10  */
11 #include "portable.h"
12
13 #include <stdio.h>
14
15 #include <ac/string.h>
16 #include <ac/socket.h>
17
18 #include "slap.h"
19
20 #include "../../libraries/liblber/lber-int.h"
21
22 static SLAP_CTRL_PARSE_FN parseAssert;
23 static SLAP_CTRL_PARSE_FN parseProxyAuthz;
24 static SLAP_CTRL_PARSE_FN parseManageDSAit;
25 static SLAP_CTRL_PARSE_FN parseModifyIncrement;
26 static SLAP_CTRL_PARSE_FN parseNoOp;
27 static SLAP_CTRL_PARSE_FN parsePagedResults;
28 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
29 static SLAP_CTRL_PARSE_FN parsePermissiveModify;
30 static SLAP_CTRL_PARSE_FN parseDomainScope;
31
32 #ifdef LDAP_CONTROL_SUBENTRIES
33 static SLAP_CTRL_PARSE_FN parseSubentries;
34 #endif
35 #ifdef LDAP_SYNC
36 static SLAP_CTRL_PARSE_FN parseLdupSync;
37 #endif
38
39 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
40
41 struct slap_control {
42         /* Control OID */
43         char *sc_oid;
44
45         /* Operations supported by control */
46         slap_mask_t sc_mask;
47
48         /* Extended operations supported by control */
49         char **sc_extendedops;
50
51         /* Control parsing callback */
52         SLAP_CTRL_PARSE_FN *sc_parse;
53
54         LDAP_SLIST_ENTRY(slap_control) sc_next;
55 };
56
57 static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
58         = LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
59
60 /*
61  * all known request control OIDs should be added to this list
62  */
63 char **slap_known_controls = NULL;
64
65 static char *proxy_authz_extops[] = {
66         LDAP_EXOP_MODIFY_PASSWD,
67         LDAP_EXOP_X_WHO_AM_I,
68         NULL
69 };
70
71 static struct slap_control control_defs[] = {
72         { LDAP_CONTROL_ASSERT,
73                 SLAP_CTRL_ACCESS, NULL,
74                 parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
75         { LDAP_CONTROL_VALUESRETURNFILTER,
76                 SLAP_CTRL_SEARCH, NULL,
77                 parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
78 #ifdef LDAP_CONTROL_PAGEDRESULTS
79         { LDAP_CONTROL_PAGEDRESULTS,
80                 SLAP_CTRL_SEARCH, NULL,
81                 parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
82 #endif
83 #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE
84         { LDAP_CONTROL_X_DOMAIN_SCOPE,
85                 SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL,
86                 parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
87 #endif
88 #ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
89         { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
90                 SLAP_CTRL_MODIFY, NULL,
91                 parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
92 #endif
93 #ifdef LDAP_CONTROL_SUBENTRIES
94         { LDAP_CONTROL_SUBENTRIES,
95                 SLAP_CTRL_SEARCH, NULL,
96                 parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
97 #endif
98         { LDAP_CONTROL_NOOP,
99                 SLAP_CTRL_ACCESS, NULL,
100                 parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
101 #ifdef LDAP_SYNC
102         { LDAP_CONTROL_SYNC,
103                 SLAP_CTRL_HIDE|SLAP_CTRL_SEARCH, NULL,
104                 parseLdupSync, LDAP_SLIST_ENTRY_INITIALIZER(next) },
105 #endif
106         { LDAP_CONTROL_MODIFY_INCREMENT,
107                 SLAP_CTRL_MODIFY, NULL,
108                 parseModifyIncrement, LDAP_SLIST_ENTRY_INITIALIZER(next) },
109         { LDAP_CONTROL_MANAGEDSAIT,
110                 SLAP_CTRL_ACCESS, NULL,
111                 parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
112         { LDAP_CONTROL_PROXY_AUTHZ,
113                 SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops,
114                 parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
115         { NULL, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) }
116 };
117
118 /*
119  * Register a supported control.
120  *
121  * This can be called by an OpenLDAP plugin or, indirectly, by a
122  * SLAPI plugin calling slapi_register_supported_control().
123  */
124 int
125 register_supported_control(const char *controloid,
126         slap_mask_t controlmask,
127         char **controlexops,
128         SLAP_CTRL_PARSE_FN *controlparsefn)
129 {
130         struct slap_control *sc;
131         int i;
132
133         if ( controloid == NULL ) {
134                 return LDAP_PARAM_ERROR;
135         }
136
137         sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
138         if ( sc == NULL ) {
139                 return LDAP_NO_MEMORY;
140         }
141         sc->sc_oid = ch_strdup( controloid );
142         sc->sc_mask = controlmask;
143         if ( controlexops != NULL ) {
144                 sc->sc_extendedops = ldap_charray_dup( controlexops );
145                 if ( sc->sc_extendedops == NULL ) {
146                         ch_free( sc );
147                         return LDAP_NO_MEMORY;
148                 }
149         } else {
150                 sc->sc_extendedops = NULL;
151         }
152         sc->sc_parse = controlparsefn;
153
154         /* Update slap_known_controls, too. */
155         if ( slap_known_controls == NULL ) {
156                 slap_known_controls = (char **)SLAP_MALLOC( 2 * sizeof(char *) );
157                 if ( slap_known_controls == NULL ) {
158                         if ( sc->sc_extendedops != NULL ) ldap_charray_free( sc->sc_extendedops );
159                         ch_free( sc );
160                         return LDAP_NO_MEMORY;
161                 }
162                 slap_known_controls[0] = ch_strdup( sc->sc_oid );
163                 slap_known_controls[1] = NULL;
164         } else {
165                 for ( i = 0; slap_known_controls[i] != NULL; i++ )
166                         ;
167                 slap_known_controls = (char **)SLAP_REALLOC( slap_known_controls, (i + 2) * sizeof(char *) );
168                 if ( slap_known_controls == NULL ) {
169                         if ( sc->sc_extendedops != NULL ) ldap_charray_free( sc->sc_extendedops );
170                         ch_free( sc );
171                         return LDAP_NO_MEMORY;
172                 }
173                 slap_known_controls[i++] = ch_strdup( sc->sc_oid );
174                 slap_known_controls[i] = NULL;
175         }
176
177         LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
178         LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
179
180         return LDAP_SUCCESS;
181 }
182
183 /*
184  * One-time initialization of internal controls.
185  */
186 int
187 slap_controls_init( void )
188 {
189         int i, rc;
190         struct slap_control *sc;
191
192         rc = LDAP_SUCCESS;
193
194         for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
195                 rc = register_supported_control( control_defs[i].sc_oid,
196                         control_defs[i].sc_mask, control_defs[i].sc_extendedops,
197                         control_defs[i].sc_parse );
198                 if ( rc != LDAP_SUCCESS )
199                         break;
200         }
201
202         return rc;
203 }
204
205 /*
206  * Free memory associated with list of supported controls.
207  */
208 void
209 controls_destroy( void )
210 {
211         struct slap_control *sc;
212
213         while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
214                 sc = LDAP_SLIST_FIRST(&controls_list);
215                 LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);
216
217                 ch_free( sc->sc_oid );
218                 if ( sc->sc_extendedops != NULL ) {
219                         ldap_charray_free( sc->sc_extendedops );
220                 }
221                 ch_free( sc );
222         }
223         ldap_charray_free( slap_known_controls );
224 }
225
226 /*
227  * Format the supportedControl attribute of the root DSE,
228  * detailing which controls are supported by the directory
229  * server.
230  */
231 int
232 controls_root_dse_info( Entry *e )
233 {
234         AttributeDescription *ad_supportedControl
235                 = slap_schema.si_ad_supportedControl;
236         struct berval vals[2];
237         struct slap_control *sc;
238
239         vals[1].bv_val = NULL;
240         vals[1].bv_len = 0;
241
242         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
243                 if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;
244
245                 vals[0].bv_val = sc->sc_oid;
246                 vals[0].bv_len = strlen( sc->sc_oid );
247
248                 if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
249                         return -1;
250                 }
251         }
252
253         return 0;
254 }
255
256 /*
257  * Return a list of OIDs and operation masks for supported
258  * controls. Used by SLAPI.
259  */
260 int
261 get_supported_controls(char ***ctrloidsp,
262         slap_mask_t **ctrlmasks)
263 {
264         int i, n;
265         char **oids;
266         slap_mask_t *masks;
267         int rc;
268         struct slap_control *sc;
269
270         n = 0;
271
272         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
273                 n++;
274         }
275
276         if ( n == 0 ) {
277                 *ctrloidsp = NULL;
278                 *ctrlmasks = NULL;
279                 return LDAP_SUCCESS;
280         }
281
282         oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
283         if ( oids == NULL ) {
284                 return LDAP_NO_MEMORY;
285         }
286         masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
287         if  ( masks == NULL ) {
288                 ch_free( oids );
289                 return LDAP_NO_MEMORY;
290         }
291
292         n = 0;
293
294         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
295                 oids[n] = ch_strdup( sc->sc_oid );
296                 masks[n] = sc->sc_mask;
297                 n++;
298         }
299         oids[n] = NULL;
300         masks[n] = 0;
301
302         *ctrloidsp = oids;
303         *ctrlmasks = masks;
304
305         return LDAP_SUCCESS;
306 }
307
308 /*
309  * Find a control given its OID.
310  */
311 static struct slap_control *
312 find_ctrl( const char *oid )
313 {
314         struct slap_control *sc;
315
316         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
317                 if ( strcmp( oid, sc->sc_oid ) == 0 ) {
318                         return sc;
319                 }
320         }
321
322         return NULL;
323 }
324
325 void slap_free_ctrls(
326         Operation *op,
327         LDAPControl **ctrls
328 )
329 {
330         int i;
331
332         for (i=0; ctrls[i]; i++) {
333                 op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
334         }
335         op->o_tmpfree( ctrls, op->o_tmpmemctx );
336 }
337
338 int get_ctrls(
339         Operation *op,
340         SlapReply *rs,
341         int sendres )
342 {
343         int nctrls = 0;
344         ber_tag_t tag;
345         ber_len_t len;
346         char *opaque;
347         BerElement *ber = op->o_ber;
348         struct slap_control *sc;
349         struct berval bv;
350
351         len = ber_pvt_ber_remaining(ber);
352
353         if( len == 0) {
354                 /* no controls */
355                 rs->sr_err = LDAP_SUCCESS;
356                 return rs->sr_err;
357         }
358
359         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
360                 if( tag == LBER_ERROR ) {
361                         rs->sr_err = SLAPD_DISCONNECT;
362                         rs->sr_text = "unexpected data in PDU";
363                 }
364
365                 goto return_results;
366         }
367
368 #ifdef NEW_LOGGING
369         LDAP_LOG( OPERATION, ENTRY,
370                 "get_ctrls: conn %lu\n", op->o_connid, 0, 0 );
371 #else
372         Debug( LDAP_DEBUG_TRACE,
373                 "=> get_ctrls\n", 0, 0, 0 );
374 #endif
375
376         if( op->o_protocol < LDAP_VERSION3 ) {
377                 rs->sr_err = SLAPD_DISCONNECT;
378                 rs->sr_text = "controls require LDAPv3";
379                 goto return_results;
380         }
381
382         /* one for first control, one for termination */
383         op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
384
385 #if 0
386         if( op->ctrls == NULL ) {
387                 rs->sr_err = LDAP_NO_MEMORY;
388                 rs->sr_text = "no memory";
389                 goto return_results;
390         }
391 #endif
392
393         op->o_ctrls[nctrls] = NULL;
394
395         /* step through each element */
396         for( tag = ber_first_element( ber, &len, &opaque );
397                 tag != LBER_ERROR;
398                 tag = ber_next_element( ber, &len, opaque ) )
399         {
400                 LDAPControl *c;
401                 LDAPControl **tctrls;
402
403                 c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
404                 memset(c, 0, sizeof(LDAPControl));
405
406                 /* allocate pointer space for current controls (nctrls)
407                  * + this control + extra NULL
408                  */
409                 tctrls = op->o_tmprealloc( op->o_ctrls,
410                         (nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
411
412 #if 0
413                 if( tctrls == NULL ) {
414                         ch_free( c );
415                         ldap_controls_free(op->o_ctrls);
416                         op->o_ctrls = NULL;
417
418                         rs->sr_err = LDAP_NO_MEMORY;
419                         rs->sr_text = "no memory";
420                         goto return_results;
421                 }
422 #endif
423                 op->o_ctrls = tctrls;
424
425                 op->o_ctrls[nctrls++] = c;
426                 op->o_ctrls[nctrls] = NULL;
427
428                 tag = ber_scanf( ber, "{m" /*}*/, &bv );
429                 c->ldctl_oid = bv.bv_val;
430
431                 if( tag == LBER_ERROR ) {
432 #ifdef NEW_LOGGING
433                         LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu get OID failed.\n",
434                                 op->o_connid, 0, 0 );
435 #else
436                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
437                                 0, 0, 0 );
438 #endif
439
440                         slap_free_ctrls( op, op->o_ctrls );
441                         op->o_ctrls = NULL;
442                         rs->sr_err = SLAPD_DISCONNECT;
443                         rs->sr_text = "decoding controls error";
444                         goto return_results;
445
446                 } else if( c->ldctl_oid == NULL ) {
447 #ifdef NEW_LOGGING
448                         LDAP_LOG( OPERATION, INFO,
449                                 "get_ctrls: conn %lu got emtpy OID.\n",
450                                 op->o_connid, 0, 0 );
451 #else
452                         Debug( LDAP_DEBUG_TRACE,
453                                 "get_ctrls: conn %lu got emtpy OID.\n",
454                                 op->o_connid, 0, 0 );
455 #endif
456
457                         slap_free_ctrls( op, op->o_ctrls );
458                         op->o_ctrls = NULL;
459                         rs->sr_err = LDAP_PROTOCOL_ERROR;
460                         rs->sr_text = "OID field is empty";
461                         goto return_results;
462                 }
463
464                 tag = ber_peek_tag( ber, &len );
465
466                 if( tag == LBER_BOOLEAN ) {
467                         ber_int_t crit;
468                         tag = ber_scanf( ber, "b", &crit );
469
470                         if( tag == LBER_ERROR ) {
471 #ifdef NEW_LOGGING
472                                 LDAP_LOG( OPERATION, INFO, 
473                                         "get_ctrls: conn %lu get crit failed.\n", 
474                                         op->o_connid, 0, 0 );
475 #else
476                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
477                                         0, 0, 0 );
478 #endif
479                                 slap_free_ctrls( op, op->o_ctrls );
480                                 op->o_ctrls = NULL;
481                                 rs->sr_err = SLAPD_DISCONNECT;
482                                 rs->sr_text = "decoding controls error";
483                                 goto return_results;
484                         }
485
486                         c->ldctl_iscritical = (crit != 0);
487                         tag = ber_peek_tag( ber, &len );
488                 }
489
490                 if( tag == LBER_OCTETSTRING ) {
491                         tag = ber_scanf( ber, "m", &c->ldctl_value );
492
493                         if( tag == LBER_ERROR ) {
494 #ifdef NEW_LOGGING
495                                 LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu: "
496                                         "%s (%scritical): get value failed.\n",
497                                         op->o_connid, c->ldctl_oid,
498                                         c->ldctl_iscritical ? "" : "non" );
499 #else
500                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
501                                         "%s (%scritical): get value failed.\n",
502                                         op->o_connid, c->ldctl_oid,
503                                         c->ldctl_iscritical ? "" : "non" );
504 #endif
505                                 slap_free_ctrls( op, op->o_ctrls );
506                                 op->o_ctrls = NULL;
507                                 rs->sr_err = SLAPD_DISCONNECT;
508                                 rs->sr_text = "decoding controls error";
509                                 goto return_results;
510                         }
511                 }
512
513 #ifdef NEW_LOGGING
514                 LDAP_LOG( OPERATION, INFO, 
515                         "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n",
516                         op->o_connid, c->ldctl_oid, c->ldctl_iscritical ? "" : "non" );
517 #else
518                 Debug( LDAP_DEBUG_TRACE,
519                         "=> get_ctrls: oid=\"%s\" (%scritical)\n",
520                         c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
521 #endif
522
523                 sc = find_ctrl( c->ldctl_oid );
524                 if( sc != NULL ) {
525                         /* recognized control */
526                         slap_mask_t tagmask;
527                         switch( op->o_tag ) {
528                         case LDAP_REQ_ADD:
529                                 tagmask = SLAP_CTRL_ADD;
530                                 break;
531                         case LDAP_REQ_BIND:
532                                 tagmask = SLAP_CTRL_BIND;
533                                 break;
534                         case LDAP_REQ_COMPARE:
535                                 tagmask = SLAP_CTRL_COMPARE;
536                                 break;
537                         case LDAP_REQ_DELETE:
538                                 tagmask = SLAP_CTRL_DELETE;
539                                 break;
540                         case LDAP_REQ_MODIFY:
541                                 tagmask = SLAP_CTRL_MODIFY;
542                                 break;
543                         case LDAP_REQ_RENAME:
544                                 tagmask = SLAP_CTRL_RENAME;
545                                 break;
546                         case LDAP_REQ_SEARCH:
547                                 tagmask = SLAP_CTRL_SEARCH;
548                                 break;
549                         case LDAP_REQ_UNBIND:
550                                 tagmask = SLAP_CTRL_UNBIND;
551                                 break;
552                         case LDAP_REQ_ABANDON:
553                                 tagmask = SLAP_CTRL_ABANDON;
554                                 break;
555                         case LDAP_REQ_EXTENDED:
556                                 tagmask=~0L;
557                                 assert( op->ore_reqoid.bv_val != NULL );
558                                 if( sc->sc_extendedops != NULL ) {
559                                         int i;
560                                         for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
561                                                 if( strcmp( op->ore_reqoid.bv_val, sc->sc_extendedops[i] )
562                                                         == 0 )
563                                                 {
564                                                         tagmask=0L;
565                                                         break;
566                                                 }
567                                         }
568                                 }
569                                 break;
570                         default:
571                                 rs->sr_err = LDAP_OTHER;
572                                 rs->sr_text = "controls internal error";
573                                 goto return_results;
574                         }
575
576                         if (( sc->sc_mask & tagmask ) == tagmask ) {
577                                 /* available extension */
578
579                                 if( !sc->sc_parse ) {
580                                         rs->sr_err = LDAP_OTHER;
581                                         rs->sr_text = "not yet implemented";
582                                         goto return_results;
583                                 }
584
585                                 rs->sr_err = sc->sc_parse( op, rs, c );
586
587                                 if( rs->sr_err != LDAP_SUCCESS ) goto return_results;
588
589                                 if ( sc->sc_mask & SLAP_CTRL_FRONTEND ) {
590                                         /* kludge to disable backend_control() check */
591                                         c->ldctl_iscritical = 0;
592
593                                 } else if ( tagmask == SLAP_CTRL_SEARCH &&
594                                         sc->sc_mask & SLAP_CTRL_FRONTEND_SEARCH )
595                                 {
596                                         /* kludge to disable backend_control() check */
597                                         c->ldctl_iscritical = 0;
598                                 }
599
600                         } else if( c->ldctl_iscritical ) {
601                                 /* unavailable CRITICAL control */
602                                 rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
603                                 rs->sr_text = "critical extension is unavailable";
604                                 goto return_results;
605                         }
606
607                 } else if( c->ldctl_iscritical ) {
608                         /* unrecognized CRITICAL control */
609                         rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
610                         rs->sr_text = "critical extension is not recognized";
611                         goto return_results;
612                 }
613         }
614
615 return_results:
616 #ifdef NEW_LOGGING
617         LDAP_LOG( OPERATION, RESULTS, 
618                 "get_ctrls: n=%d rc=%d err=\"%s\"\n",
619                 nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "" );
620 #else
621         Debug( LDAP_DEBUG_TRACE,
622                 "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
623                 nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
624 #endif
625
626         if( sendres && rs->sr_err != LDAP_SUCCESS ) {
627                 if( rs->sr_err == SLAPD_DISCONNECT ) {
628                         rs->sr_err = LDAP_PROTOCOL_ERROR;
629                         send_ldap_disconnect( op, rs );
630                         rs->sr_err = SLAPD_DISCONNECT;
631                 } else {
632                         send_ldap_result( op, rs );
633                 }
634         }
635
636         return rs->sr_err;
637 }
638
639 static int parseModifyIncrement (
640         Operation *op,
641         SlapReply *rs,
642         LDAPControl *ctrl )
643 {
644 #if 0
645         if ( op->o_parseModifyIncrement != SLAP_NO_CONTROL ) {
646                 rs->sr_text = "modifyIncrement control specified multiple times";
647                 return LDAP_PROTOCOL_ERROR;
648         }
649 #endif
650
651         if ( ctrl->ldctl_value.bv_len ) {
652                 rs->sr_text = "modifyIncrement control value not empty";
653                 return LDAP_PROTOCOL_ERROR;
654         }
655
656 #if 0
657         op->o_parseModifyIncrement = ctrl->ldctl_iscritical
658                 ? SLAP_CRITICAL_CONTROL
659                 : SLAP_NONCRITICAL_CONTROL;
660 #endif
661
662         return LDAP_SUCCESS;
663 }
664
665 static int parseManageDSAit (
666         Operation *op,
667         SlapReply *rs,
668         LDAPControl *ctrl )
669 {
670         if ( op->o_managedsait != SLAP_NO_CONTROL ) {
671                 rs->sr_text = "manageDSAit control specified multiple times";
672                 return LDAP_PROTOCOL_ERROR;
673         }
674
675         if ( ctrl->ldctl_value.bv_len ) {
676                 rs->sr_text = "manageDSAit control value not empty";
677                 return LDAP_PROTOCOL_ERROR;
678         }
679
680         op->o_managedsait = ctrl->ldctl_iscritical
681                 ? SLAP_CRITICAL_CONTROL
682                 : SLAP_NONCRITICAL_CONTROL;
683
684         return LDAP_SUCCESS;
685 }
686
687 static int parseProxyAuthz (
688         Operation *op,
689         SlapReply *rs,
690         LDAPControl *ctrl )
691 {
692         int rc;
693         struct berval dn = { 0, NULL };
694
695         if ( op->o_proxy_authz != SLAP_NO_CONTROL ) {
696                 rs->sr_text = "proxy authorization control specified multiple times";
697                 return LDAP_PROTOCOL_ERROR;
698         }
699
700         op->o_proxy_authz = ctrl->ldctl_iscritical
701                 ? SLAP_CRITICAL_CONTROL
702                 : SLAP_NONCRITICAL_CONTROL;
703
704 #ifdef NEW_LOGGING
705         LDAP_LOG( OPERATION, ARGS, 
706                 "parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
707                 op->o_connid,
708                 ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
709                 0 );
710 #else
711         Debug( LDAP_DEBUG_ARGS,
712                 "parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
713                 op->o_connid,
714                 ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
715                 0 );
716 #endif
717
718         if( ctrl->ldctl_value.bv_len == 0 ) {
719 #ifdef NEW_LOGGING
720                 LDAP_LOG( OPERATION, RESULTS, 
721                         "parseProxyAuthz: conn=%lu anonymous\n", 
722                         op->o_connid, 0, 0 );
723 #else
724                 Debug( LDAP_DEBUG_TRACE,
725                         "parseProxyAuthz: conn=%lu anonymous\n", 
726                         op->o_connid, 0, 0 );
727 #endif
728
729                 /* anonymous */
730                 free( op->o_dn.bv_val );
731                 op->o_dn.bv_len = 0;
732                 op->o_dn.bv_val = ch_strdup( "" );
733
734                 free( op->o_ndn.bv_val );
735                 op->o_ndn.bv_len = 0;
736                 op->o_ndn.bv_val = ch_strdup( "" );
737
738                 return LDAP_SUCCESS;
739         }
740
741         rc = slap_sasl_getdn( op->o_conn, op,
742                 ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len,
743                 NULL, &dn, SLAP_GETDN_AUTHZID );
744
745         if( rc != LDAP_SUCCESS || !dn.bv_len ) {
746                 if ( dn.bv_val ) {
747                         ch_free( dn.bv_val );
748                 }
749                 rs->sr_text = "authzId mapping failed";
750                 return LDAP_PROXY_AUTHZ_FAILURE;
751         }
752
753 #ifdef NEW_LOGGING
754         LDAP_LOG( OPERATION, RESULTS, 
755                 "parseProxyAuthz: conn=%lu \"%s\"\n", 
756                 op->o_connid,
757                 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
758 #else
759         Debug( LDAP_DEBUG_TRACE,
760                 "parseProxyAuthz: conn=%lu \"%s\"\n", 
761                 op->o_connid,
762                 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
763 #endif
764
765         rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
766
767         if( rc ) {
768                 ch_free( dn.bv_val );
769                 rs->sr_text = "not authorized to assume identity";
770                 return LDAP_PROXY_AUTHZ_FAILURE;
771         }
772
773         ch_free( op->o_dn.bv_val );
774         ch_free( op->o_ndn.bv_val );
775
776         op->o_dn.bv_val = NULL;
777         op->o_ndn = dn;
778
779         /*
780          * NOTE: since slap_sasl_getdn() returns a normalized dn,
781          * from now on op->o_dn is normalized
782          */
783         ber_dupbv( &op->o_dn, &dn );
784
785         return LDAP_SUCCESS;
786 }
787
788 static int parseNoOp (
789         Operation *op,
790         SlapReply *rs,
791         LDAPControl *ctrl )
792 {
793         if ( op->o_noop != SLAP_NO_CONTROL ) {
794                 rs->sr_text = "noop control specified multiple times";
795                 return LDAP_PROTOCOL_ERROR;
796         }
797
798         if ( ctrl->ldctl_value.bv_len ) {
799                 rs->sr_text = "noop control value not empty";
800                 return LDAP_PROTOCOL_ERROR;
801         }
802
803         op->o_noop = ctrl->ldctl_iscritical
804                 ? SLAP_CRITICAL_CONTROL
805                 : SLAP_NONCRITICAL_CONTROL;
806
807         return LDAP_SUCCESS;
808 }
809
810 #ifdef LDAP_CONTROL_PAGEDRESULTS
811 static int parsePagedResults (
812         Operation *op,
813         SlapReply *rs,
814         LDAPControl *ctrl )
815 {
816         ber_tag_t tag;
817         ber_int_t size;
818         BerElement *ber;
819         struct berval cookie = { 0, NULL };
820
821         if ( op->o_pagedresults != SLAP_NO_CONTROL ) {
822                 rs->sr_text = "paged results control specified multiple times";
823                 return LDAP_PROTOCOL_ERROR;
824         }
825
826         if ( ctrl->ldctl_value.bv_len == 0 ) {
827                 rs->sr_text = "paged results control value is empty (or absent)";
828                 return LDAP_PROTOCOL_ERROR;
829         }
830
831         /* Parse the control value
832          *      realSearchControlValue ::= SEQUENCE {
833          *              size    INTEGER (0..maxInt),
834          *                              -- requested page size from client
835          *                              -- result set size estimate from server
836          *              cookie  OCTET STRING
837          * }
838          */
839         ber = ber_init( &ctrl->ldctl_value );
840         if( ber == NULL ) {
841                 rs->sr_text = "internal error";
842                 return LDAP_OTHER;
843         }
844
845         tag = ber_scanf( ber, "{im}", &size, &cookie );
846         (void) ber_free( ber, 1 );
847
848         if( tag == LBER_ERROR ) {
849                 rs->sr_text = "paged results control could not be decoded";
850                 return LDAP_PROTOCOL_ERROR;
851         }
852
853         if( size < 0 ) {
854                 rs->sr_text = "paged results control size invalid";
855                 return LDAP_PROTOCOL_ERROR;
856         }
857
858         if( cookie.bv_len ) {
859                 PagedResultsCookie reqcookie;
860                 if( cookie.bv_len != sizeof( reqcookie ) ) {
861                         /* bad cookie */
862                         rs->sr_text = "paged results cookie is invalid";
863                         return LDAP_PROTOCOL_ERROR;
864                 }
865
866                 AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
867
868                 if( reqcookie > op->o_pagedresults_state.ps_cookie ) {
869                         /* bad cookie */
870                         rs->sr_text = "paged results cookie is invalid";
871                         return LDAP_PROTOCOL_ERROR;
872
873                 } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) {
874                         rs->sr_text = "paged results cookie is invalid or old";
875                         return LDAP_UNWILLING_TO_PERFORM;
876                 }
877         } else {
878                 /* Initial request.  Initialize state. */
879                 op->o_pagedresults_state.ps_cookie = 0;
880                 op->o_pagedresults_state.ps_id = NOID;
881         }
882
883         op->o_pagedresults_size = size;
884
885         op->o_pagedresults = ctrl->ldctl_iscritical
886                 ? SLAP_CRITICAL_CONTROL
887                 : SLAP_NONCRITICAL_CONTROL;
888
889         return LDAP_SUCCESS;
890 }
891 #endif
892
893 static int parseAssert (
894         Operation *op,
895         SlapReply *rs,
896         LDAPControl *ctrl )
897 {
898         BerElement      *ber;
899         struct berval   fstr = { 0, NULL };
900         const char *err_msg = "";
901
902         if ( op->o_assert != SLAP_NO_CONTROL ) {
903                 rs->sr_text = "assert control specified multiple times";
904                 return LDAP_PROTOCOL_ERROR;
905         }
906
907         if ( ctrl->ldctl_value.bv_len == 0 ) {
908                 rs->sr_text = "assert control value is empty (or absent)";
909                 return LDAP_PROTOCOL_ERROR;
910         }
911
912         ber = ber_init( &(ctrl->ldctl_value) );
913         if (ber == NULL) {
914                 rs->sr_text = "internal error";
915                 return LDAP_OTHER;
916         }
917         
918         rs->sr_err = get_filter( op, ber, &(op->o_assertion), &rs->sr_text);
919
920         if( rs->sr_err != LDAP_SUCCESS ) {
921                 if( rs->sr_err == SLAPD_DISCONNECT ) {
922                         rs->sr_err = LDAP_PROTOCOL_ERROR;
923                         send_ldap_disconnect( op, rs );
924                         rs->sr_err = SLAPD_DISCONNECT;
925                 } else {
926                         send_ldap_result( op, rs );
927                 }
928                 if( op->o_assertion != NULL) {
929                         filter_free_x( op, op->o_assertion ); 
930                 }
931         }
932 #ifdef LDAP_DEBUG
933         else {
934                 filter2bv_x( op, op->o_assertion, &fstr );
935         }
936
937 #ifdef NEW_LOGGING
938         LDAP_LOG( OPERATION, ARGS, 
939                 "parseAssert: conn %ld assert: %s\n", 
940                 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
941 #else
942         Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
943                 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
944 #endif
945         op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
946 #endif
947
948         op->o_assert = ctrl->ldctl_iscritical
949                 ? SLAP_CRITICAL_CONTROL
950                 : SLAP_NONCRITICAL_CONTROL;
951
952         rs->sr_err = LDAP_SUCCESS;
953         return LDAP_SUCCESS;
954 }
955
956 int parseValuesReturnFilter (
957         Operation *op,
958         SlapReply *rs,
959         LDAPControl *ctrl )
960 {
961         BerElement      *ber;
962         struct berval   fstr = { 0, NULL };
963         const char *err_msg = "";
964
965         if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
966                 rs->sr_text = "valuesReturnFilter control specified multiple times";
967                 return LDAP_PROTOCOL_ERROR;
968         }
969
970         if ( ctrl->ldctl_value.bv_len == 0 ) {
971                 rs->sr_text = "valuesReturnFilter control value is empty (or absent)";
972                 return LDAP_PROTOCOL_ERROR;
973         }
974
975         ber = ber_init( &(ctrl->ldctl_value) );
976         if (ber == NULL) {
977                 rs->sr_text = "internal error";
978                 return LDAP_OTHER;
979         }
980         
981         rs->sr_err = get_vrFilter( op, ber, &(op->o_vrFilter), &rs->sr_text);
982
983         if( rs->sr_err != LDAP_SUCCESS ) {
984                 if( rs->sr_err == SLAPD_DISCONNECT ) {
985                         rs->sr_err = LDAP_PROTOCOL_ERROR;
986                         send_ldap_disconnect( op, rs );
987                         rs->sr_err = SLAPD_DISCONNECT;
988                 } else {
989                         send_ldap_result( op, rs );
990                 }
991                 if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter ); 
992
993         }
994 #ifdef LDAP_DEBUG
995         else {
996                 vrFilter2bv( op, op->o_vrFilter, &fstr );
997         }
998
999 #ifdef NEW_LOGGING
1000         LDAP_LOG( OPERATION, ARGS, 
1001                 "parseValuesReturnFilter: conn %d       vrFilter: %s\n", 
1002                 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
1003 #else
1004         Debug( LDAP_DEBUG_ARGS, "       vrFilter: %s\n",
1005                 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
1006 #endif
1007         op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1008 #endif
1009
1010         op->o_valuesreturnfilter = ctrl->ldctl_iscritical
1011                 ? SLAP_CRITICAL_CONTROL
1012                 : SLAP_NONCRITICAL_CONTROL;
1013
1014         rs->sr_err = LDAP_SUCCESS;
1015         return LDAP_SUCCESS;
1016 }
1017
1018 #ifdef LDAP_CONTROL_SUBENTRIES
1019 static int parseSubentries (
1020         Operation *op,
1021         SlapReply *rs,
1022         LDAPControl *ctrl )
1023 {
1024         if ( op->o_subentries != SLAP_NO_CONTROL ) {
1025                 rs->sr_text = "subentries control specified multiple times";
1026                 return LDAP_PROTOCOL_ERROR;
1027         }
1028
1029         /* FIXME: should use BER library */
1030         if( ( ctrl->ldctl_value.bv_len != 3 )
1031                 && ( ctrl->ldctl_value.bv_val[0] != 0x01 )
1032                 && ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
1033         {
1034                 rs->sr_text = "subentries control value encoding is bogus";
1035                 return LDAP_PROTOCOL_ERROR;
1036         }
1037
1038         op->o_subentries = ctrl->ldctl_iscritical
1039                 ? SLAP_CRITICAL_CONTROL
1040                 : SLAP_NONCRITICAL_CONTROL;
1041
1042         op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
1043
1044         return LDAP_SUCCESS;
1045 }
1046 #endif
1047
1048 #ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
1049 static int parsePermissiveModify (
1050         Operation *op,
1051         SlapReply *rs,
1052         LDAPControl *ctrl )
1053 {
1054         if ( op->o_permissive_modify != SLAP_NO_CONTROL ) {
1055                 rs->sr_text = "permissiveModify control specified multiple times";
1056                 return LDAP_PROTOCOL_ERROR;
1057         }
1058
1059         if ( ctrl->ldctl_value.bv_len ) {
1060                 rs->sr_text = "permissiveModify control value not empty";
1061                 return LDAP_PROTOCOL_ERROR;
1062         }
1063
1064         op->o_permissive_modify = ctrl->ldctl_iscritical
1065                 ? SLAP_CRITICAL_CONTROL
1066                 : SLAP_NONCRITICAL_CONTROL;
1067
1068         return LDAP_SUCCESS;
1069 }
1070 #endif
1071
1072 #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE
1073 static int parseDomainScope (
1074         Operation *op,
1075         SlapReply *rs,
1076         LDAPControl *ctrl )
1077 {
1078         if ( op->o_domain_scope != SLAP_NO_CONTROL ) {
1079                 rs->sr_text = "domainScope control specified multiple times";
1080                 return LDAP_PROTOCOL_ERROR;
1081         }
1082
1083         if ( ctrl->ldctl_value.bv_len ) {
1084                 rs->sr_text = "domainScope control value not empty";
1085                 return LDAP_PROTOCOL_ERROR;
1086         }
1087
1088         op->o_domain_scope = ctrl->ldctl_iscritical
1089                 ? SLAP_CRITICAL_CONTROL
1090                 : SLAP_NONCRITICAL_CONTROL;
1091
1092         return LDAP_SUCCESS;
1093 }
1094 #endif
1095
1096 #ifdef LDAP_SYNC
1097 static int parseLdupSync (
1098         Operation *op,
1099         SlapReply *rs,
1100         LDAPControl *ctrl )
1101 {
1102         ber_tag_t tag;
1103         BerElement *ber;
1104         ber_int_t mode;
1105         ber_len_t len;
1106         struct berval cookie = { 0, NULL };
1107
1108         if ( op->o_sync != SLAP_NO_CONTROL ) {
1109                 rs->sr_text = "LDAP Sync control specified multiple times";
1110                 return LDAP_PROTOCOL_ERROR;
1111         }
1112
1113         if ( ctrl->ldctl_value.bv_len == 0 ) {
1114                 rs->sr_text = "LDAP Sync control value is empty (or absent)";
1115                 return LDAP_PROTOCOL_ERROR;
1116         }
1117
1118         /* Parse the control value
1119          *      syncRequestValue ::= SEQUENCE {
1120          *              mode   ENUMERATED {
1121          *                      -- 0 unused
1122          *                      refreshOnly             (1),
1123          *                      -- 2 reserved
1124          *                      refreshAndPersist       (3)
1125          *              },
1126          *              cookie  syncCookie OPTIONAL
1127          *      }
1128          */
1129
1130         ber = ber_init( &ctrl->ldctl_value );
1131         if( ber == NULL ) {
1132                 rs->sr_text = "internal error";
1133                 return LDAP_OTHER;
1134         }
1135
1136         if ( (tag = ber_scanf( ber, "{i" /*}*/, &mode )) == LBER_ERROR ) {
1137                 rs->sr_text = "LDAP Sync control : mode decoding error";
1138                 return LDAP_PROTOCOL_ERROR;
1139         }
1140
1141         switch( mode ) {
1142         case LDAP_SYNC_REFRESH_ONLY:
1143                 mode = SLAP_SYNC_REFRESH;
1144                 break;
1145         case LDAP_SYNC_REFRESH_AND_PERSIST:
1146                 mode = SLAP_SYNC_REFRESH_AND_PERSIST;
1147                 break;
1148         default:
1149                 rs->sr_text = "LDAP Sync control : unknown update mode";
1150                 return LDAP_PROTOCOL_ERROR;
1151         }
1152
1153         tag = ber_peek_tag( ber, &len );
1154
1155         if ( tag == LDAP_SYNC_TAG_COOKIE ) {
1156                 if (( ber_scanf( ber, /*{*/ "m}",
1157                                         &cookie )) == LBER_ERROR ) {
1158                         rs->sr_text = "LDAP Sync control : cookie decoding error";
1159                         return LDAP_PROTOCOL_ERROR;
1160                 }
1161         } else {
1162                 if (( ber_scanf( ber, /*{*/ "}")) == LBER_ERROR ) {
1163                         rs->sr_text = "LDAP Sync control : decoding error";
1164                         return LDAP_PROTOCOL_ERROR;
1165                 }
1166                 cookie.bv_len = 0;
1167                 cookie.bv_val = NULL;
1168         }
1169
1170         ber_dupbv( &op->o_sync_state, &cookie );
1171
1172         (void) ber_free( ber, 1 );
1173
1174         op->o_sync_mode = (char) mode;
1175
1176         op->o_sync = ctrl->ldctl_iscritical
1177                 ? SLAP_CRITICAL_CONTROL
1178                 : SLAP_NONCRITICAL_CONTROL;
1179
1180         return LDAP_SUCCESS;
1181 }
1182 #endif