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