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