]> git.sur5r.net Git - openldap/blob - servers/slapd/controls.c
SLAPI - Netscape plugin API for slapd - based on patch contributed by Steve Omrani...
[openldap] / servers / slapd / controls.c
1 /* $OpenLDAP$ */
2 /* 
3  * Copyright 1999-2002 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 #define SLAP_CTRL_FRONTEND                      0x80000000U
23 #define SLAP_CTRL_FRONTEND_SEARCH       0x01000000U     /* for NOOP */
24
25 #define SLAP_CTRL_OPFLAGS                       0x0000FFFFU
26 #define SLAP_CTRL_ABANDON                       0x00000001U
27 #define SLAP_CTRL_ADD                           0x00002002U
28 #define SLAP_CTRL_BIND                          0x00000004U
29 #define SLAP_CTRL_COMPARE                       0x00001008U
30 #define SLAP_CTRL_DELETE                        0x00002010U
31 #define SLAP_CTRL_MODIFY                        0x00002020U
32 #define SLAP_CTRL_RENAME                        0x00002040U
33 #define SLAP_CTRL_SEARCH                        0x00001080U
34 #define SLAP_CTRL_UNBIND                        0x00000100U
35
36 #define SLAP_CTRL_INTROGATE     (SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH)
37 #define SLAP_CTRL_UPDATE \
38         (SLAP_CTRL_ADD|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME)
39 #define SLAP_CTRL_ACCESS        (SLAP_CTRL_INTROGATE|SLAP_CTRL_UPDATE)
40
41 typedef int (SLAP_CTRL_PARSE_FN) LDAP_P((
42         Connection *conn,
43         Operation *op,
44         LDAPControl *ctrl,
45         const char **text ));
46
47 static SLAP_CTRL_PARSE_FN parseProxyAuthz;
48 static SLAP_CTRL_PARSE_FN parseManageDSAit;
49 static SLAP_CTRL_PARSE_FN parseNoOp;
50 static SLAP_CTRL_PARSE_FN parsePagedResults;
51 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
52
53 #ifdef LDAP_CONTROL_SUBENTRIES
54 static SLAP_CTRL_PARSE_FN parseSubentries;
55 #endif
56 #ifdef LDAP_CLIENT_UPDATE
57 static SLAP_CTRL_PARSE_FN parseClientUpdate;
58 #endif
59
60 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
61
62 static char *proxy_authz_extops[] = {
63         LDAP_EXOP_MODIFY_PASSWD,
64         LDAP_EXOP_X_WHO_AM_I,
65         NULL
66 };
67
68 static struct slap_control {
69         char *sc_oid;
70         slap_mask_t sc_mask;
71         char **sc_extendedops;
72         SLAP_CTRL_PARSE_FN *sc_parse;
73
74 } supportedControls[] = {
75         { LDAP_CONTROL_PROXY_AUTHZ,
76                 SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops,
77                 parseProxyAuthz },
78         { LDAP_CONTROL_MANAGEDSAIT,
79                 SLAP_CTRL_ACCESS, NULL,
80                 parseManageDSAit },
81         { LDAP_CONTROL_NOOP,
82                 SLAP_CTRL_ACCESS, NULL,
83                 parseNoOp },
84         { LDAP_CONTROL_PAGEDRESULTS,
85                 SLAP_CTRL_SEARCH, NULL,
86                 parsePagedResults },
87         { LDAP_CONTROL_VALUESRETURNFILTER,
88                 SLAP_CTRL_SEARCH, NULL,
89                 parseValuesReturnFilter },
90 #ifdef LDAP_CONTROL_SUBENTRIES
91         { LDAP_CONTROL_SUBENTRIES,
92                 SLAP_CTRL_SEARCH, NULL,
93                 parseSubentries },
94 #endif
95 #ifdef LDAP_CLIENT_UPDATE
96         { LDAP_CONTROL_CLIENT_UPDATE,
97                 SLAP_CTRL_SEARCH, NULL,
98                 parseClientUpdate },
99 #endif /* LDAP_CLIENT_UPDATE */
100         { NULL }
101 };
102
103 char *
104 get_supported_ctrl(int index)
105 {
106         return supportedControls[index].sc_oid;
107 }
108
109 slap_mask_t
110 get_supported_ctrl_mask(int index)
111 {
112         return supportedControls[index].sc_mask;
113 }
114
115 static struct slap_control *
116 find_ctrl( const char *oid )
117 {
118         int i;
119         for( i=0; supportedControls[i].sc_oid; i++ ) {
120                 if( strcmp( oid, supportedControls[i].sc_oid ) == 0 ) {
121                         return &supportedControls[i];
122                 }
123         }
124         return NULL;
125 }
126
127 int get_ctrls(
128         Connection *conn,
129         Operation *op,
130         int sendres )
131 {
132         int nctrls = 0;
133         ber_tag_t tag;
134         ber_len_t len;
135         char *opaque;
136         BerElement *ber = op->o_ber;
137         struct slap_control *sc;
138         int rc = LDAP_SUCCESS;
139         const char *errmsg = NULL;
140
141         len = ber_pvt_ber_remaining(ber);
142
143         if( len == 0) {
144                 /* no controls */
145                 rc = LDAP_SUCCESS;
146                 return rc;
147         }
148
149         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
150                 if( tag == LBER_ERROR ) {
151                         rc = SLAPD_DISCONNECT;
152                         errmsg = "unexpected data in PDU";
153                 }
154
155                 goto return_results;
156         }
157
158 #ifdef NEW_LOGGING
159         LDAP_LOG( OPERATION, ENTRY, "get_ctrls: conn %lu\n", conn->c_connid, 0, 0 );
160 #else
161         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 );
162 #endif
163         if( op->o_protocol < LDAP_VERSION3 ) {
164                 rc = SLAPD_DISCONNECT;
165                 errmsg = "controls require LDAPv3";
166                 goto return_results;
167         }
168
169         /* one for first control, one for termination */
170         op->o_ctrls = ch_malloc( 2 * sizeof(LDAPControl *) );
171
172 #if 0
173         if( op->ctrls == NULL ) {
174                 rc = LDAP_NO_MEMORY;
175                 errmsg = "no memory";
176                 goto return_results;
177         }
178 #endif
179
180         op->o_ctrls[nctrls] = NULL;
181
182         /* step through each element */
183         for( tag = ber_first_element( ber, &len, &opaque );
184                 tag != LBER_ERROR;
185                 tag = ber_next_element( ber, &len, opaque ) )
186         {
187                 LDAPControl *c;
188                 LDAPControl **tctrls;
189
190                 c = ch_calloc( 1, sizeof(LDAPControl) );
191
192 #if 0
193                 if( c == NULL ) {
194                         ldap_controls_free(op->o_ctrls);
195                         op->o_ctrls = NULL;
196
197                         rc = LDAP_NO_MEMORY;
198                         errmsg = "no memory";
199                         goto return_results;
200                 }
201 #endif
202
203                 /* allocate pointer space for current controls (nctrls)
204                  * + this control + extra NULL
205                  */
206                 tctrls = ch_realloc( op->o_ctrls,
207                         (nctrls+2) * sizeof(LDAPControl *));
208
209 #if 0
210                 if( tctrls == NULL ) {
211                         ch_free( c );
212                         ldap_controls_free(op->o_ctrls);
213                         op->o_ctrls = NULL;
214
215                         rc = LDAP_NO_MEMORY;
216                         errmsg = "no memory";
217                         goto return_results;
218                 }
219 #endif
220                 op->o_ctrls = tctrls;
221
222                 op->o_ctrls[nctrls++] = c;
223                 op->o_ctrls[nctrls] = NULL;
224
225                 tag = ber_scanf( ber, "{a" /*}*/, &c->ldctl_oid );
226
227                 if( tag == LBER_ERROR ) {
228 #ifdef NEW_LOGGING
229                         LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu get OID failed.\n",
230                                 conn->c_connid, 0, 0 );
231 #else
232                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
233                                 0, 0, 0 );
234 #endif
235                         ldap_controls_free( op->o_ctrls );
236                         op->o_ctrls = NULL;
237                         rc = SLAPD_DISCONNECT;
238                         errmsg = "decoding controls error";
239                         goto return_results;
240                 }
241
242                 tag = ber_peek_tag( ber, &len );
243
244                 if( tag == LBER_BOOLEAN ) {
245                         ber_int_t crit;
246                         tag = ber_scanf( ber, "b", &crit );
247
248                         if( tag == LBER_ERROR ) {
249 #ifdef NEW_LOGGING
250                                 LDAP_LOG( OPERATION, INFO, 
251                                         "get_ctrls: conn %lu get crit failed.\n", 
252                                         conn->c_connid, 0, 0 );
253 #else
254                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
255                                         0, 0, 0 );
256 #endif
257                                 ldap_controls_free( op->o_ctrls );
258                                 op->o_ctrls = NULL;
259                                 rc = SLAPD_DISCONNECT;
260                                 errmsg = "decoding controls error";
261                                 goto return_results;
262                         }
263
264                         c->ldctl_iscritical = (crit != 0);
265                         tag = ber_peek_tag( ber, &len );
266                 }
267
268                 if( tag == LBER_OCTETSTRING ) {
269                         tag = ber_scanf( ber, "o", &c->ldctl_value );
270
271                         if( tag == LBER_ERROR ) {
272 #ifdef NEW_LOGGING
273                                 LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu: "
274                                         "%s (%scritical): get value failed.\n",
275                                         conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)",
276                                         c->ldctl_iscritical ? "" : "non" );
277 #else
278                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
279                                         "%s (%scritical): get value failed.\n",
280                                         conn->c_connid,
281                                         c->ldctl_oid ? c->ldctl_oid : "(NULL)",
282                                         c->ldctl_iscritical ? "" : "non" );
283 #endif
284                                 ldap_controls_free( op->o_ctrls );
285                                 op->o_ctrls = NULL;
286                                 rc = SLAPD_DISCONNECT;
287                                 errmsg = "decoding controls error";
288                                 goto return_results;
289                         }
290                 }
291
292 #ifdef NEW_LOGGING
293                 LDAP_LOG( OPERATION, INFO, 
294                         "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n",
295                         conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)",
296                         c->ldctl_iscritical ? "" : "non" );
297 #else
298                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: oid=\"%s\" (%scritical)\n",
299                         c->ldctl_oid ? c->ldctl_oid : "(NULL)",
300                         c->ldctl_iscritical ? "" : "non",
301                         0 );
302 #endif
303
304                 sc = find_ctrl( c->ldctl_oid );
305                 if( sc != NULL ) {
306                         /* recognized control */
307                         slap_mask_t tagmask;
308                         switch( op->o_tag ) {
309                         case LDAP_REQ_ADD:
310                                 tagmask = SLAP_CTRL_ADD;
311                                 break;
312                         case LDAP_REQ_BIND:
313                                 tagmask = SLAP_CTRL_BIND;
314                                 break;
315                         case LDAP_REQ_COMPARE:
316                                 tagmask = SLAP_CTRL_COMPARE;
317                                 break;
318                         case LDAP_REQ_DELETE:
319                                 tagmask = SLAP_CTRL_DELETE;
320                                 break;
321                         case LDAP_REQ_MODIFY:
322                                 tagmask = SLAP_CTRL_MODIFY;
323                                 break;
324                         case LDAP_REQ_RENAME:
325                                 tagmask = SLAP_CTRL_RENAME;
326                                 break;
327                         case LDAP_REQ_SEARCH:
328                                 tagmask = SLAP_CTRL_SEARCH;
329                                 break;
330                         case LDAP_REQ_UNBIND:
331                                 tagmask = SLAP_CTRL_UNBIND;
332                                 break;
333                         case LDAP_REQ_ABANDON:
334                                 tagmask = SLAP_CTRL_ABANDON;
335                                 break;
336                         case LDAP_REQ_EXTENDED:
337                                 tagmask=~0L;
338                                 assert( op->o_extendedop != NULL );
339                                 if( sc->sc_extendedops != NULL ) {
340                                         int i;
341                                         for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
342                                                 if( strcmp( op->o_extendedop, sc->sc_extendedops[i] )
343                                                         == 0 )
344                                                 {
345                                                         tagmask=0L;
346                                                         break;
347                                                 }
348                                         }
349                                 }
350                                 break;
351                         default:
352                                 rc = LDAP_OTHER;
353                                 errmsg = "controls internal error";
354                                 goto return_results;
355                         }
356
357                         if (( sc->sc_mask & tagmask ) == tagmask ) {
358                                 /* available extension */
359
360                                 if( !sc->sc_parse ) {
361                                         rc = LDAP_OTHER;
362                                         errmsg = "not yet implemented";
363                                         goto return_results;
364                                 }
365
366                                 rc = sc->sc_parse( conn, op, c, &errmsg );
367
368                                 if( rc != LDAP_SUCCESS ) goto return_results;
369
370                                 if ( sc->sc_mask & SLAP_CTRL_FRONTEND ) {
371                                         /* kludge to disable backend_control() check */
372                                         c->ldctl_iscritical = 0;
373
374                                 } else if ( tagmask == SLAP_CTRL_SEARCH &&
375                                         sc->sc_mask & SLAP_CTRL_FRONTEND_SEARCH )
376                                 {
377                                         /* kludge to disable backend_control() check */
378                                         c->ldctl_iscritical = 0;
379                                 }
380
381                         } else if( c->ldctl_iscritical ) {
382                                 /* unavailable CRITICAL control */
383                                 rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
384                                 errmsg = "critical extension is unavailable";
385                                 goto return_results;
386                         }
387
388                 } else if( c->ldctl_iscritical ) {
389                         /* unrecognized CRITICAL control */
390                         rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
391                         errmsg = "critical extension is not recognized";
392                         goto return_results;
393                 }
394         }
395
396 return_results:
397 #ifdef NEW_LOGGING
398         LDAP_LOG( OPERATION, RESULTS, 
399                 "get_ctrls: n=%d rc=%d err=\"%s\"\n",
400                 nctrls, rc, errmsg ? errmsg : "" );
401 #else
402         Debug( LDAP_DEBUG_TRACE,
403                 "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
404                 nctrls, rc, errmsg ? errmsg : "");
405 #endif
406
407         if( sendres && rc != LDAP_SUCCESS ) {
408                 if( rc == SLAPD_DISCONNECT ) {
409                         send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, errmsg );
410                 } else {
411                         send_ldap_result( conn, op, rc,
412                                 NULL, errmsg, NULL, NULL );
413                 }
414         }
415
416         return rc;
417 }
418
419 static int parseManageDSAit (
420         Connection *conn,
421         Operation *op,
422         LDAPControl *ctrl,
423         const char **text )
424 {
425         if ( op->o_managedsait != SLAP_NO_CONTROL ) {
426                 *text = "manageDSAit control specified multiple times";
427                 return LDAP_PROTOCOL_ERROR;
428         }
429
430         if ( ctrl->ldctl_value.bv_len ) {
431                 *text = "manageDSAit control value not empty";
432                 return LDAP_PROTOCOL_ERROR;
433         }
434
435         op->o_managedsait = ctrl->ldctl_iscritical
436                 ? SLAP_CRITICAL_CONTROL
437                 : SLAP_NONCRITICAL_CONTROL;
438
439         return LDAP_SUCCESS;
440 }
441
442 static int parseProxyAuthz (
443         Connection *conn,
444         Operation *op,
445         LDAPControl *ctrl,
446         const char **text )
447 {
448         int rc;
449         struct berval dn;
450
451         if ( op->o_proxy_authz != SLAP_NO_CONTROL ) {
452                 *text = "proxy authorization control specified multiple times";
453                 return LDAP_PROTOCOL_ERROR;
454         }
455
456         op->o_proxy_authz = ctrl->ldctl_iscritical
457                 ? SLAP_CRITICAL_CONTROL
458                 : SLAP_NONCRITICAL_CONTROL;
459
460 #ifdef NEW_LOGGING
461         LDAP_LOG( OPERATION, ARGS, 
462                 "parseProxyAuthz: conn %d authzid=\"%s\"\n", 
463                 conn->c_connid,
464                 ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
465                 0 );
466 #else
467         Debug( LDAP_DEBUG_ARGS,
468                 "parseProxyAuthz: conn %d authzid=\"%s\"\n", 
469                 conn->c_connid,
470                 ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
471                 0 );
472 #endif
473
474         if( ctrl->ldctl_value.bv_len == 0 ) {
475 #ifdef NEW_LOGGING
476                 LDAP_LOG( OPERATION, RESULTS, 
477                         "parseProxyAuthz: conn=%d anonymous\n", 
478                         conn->c_connid, 0, 0 );
479 #else
480                 Debug( LDAP_DEBUG_TRACE,
481                         "parseProxyAuthz: conn=%d anonymous\n", 
482                         conn->c_connid, 0, 0 );
483 #endif
484
485                 /* anonymous */
486                 free( op->o_dn.bv_val );
487                 op->o_dn.bv_len = 0;
488                 op->o_dn.bv_val = ch_strdup( "" );
489
490                 free( op->o_ndn.bv_val );
491                 op->o_ndn.bv_len = 0;
492                 op->o_ndn.bv_val = ch_strdup( "" );
493
494                 return LDAP_SUCCESS;
495         }
496
497         rc = slap_sasl_getdn( conn,
498                 ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len,
499                 NULL, &dn, SLAP_GETDN_AUTHZID );
500
501         if( rc != LDAP_SUCCESS || !dn.bv_len ) {
502                 *text = "authzId mapping failed";
503                 return LDAP_PROXY_AUTHZ_FAILURE;
504         }
505
506 #ifdef NEW_LOGGING
507         LDAP_LOG( OPERATION, RESULTS, 
508                 "parseProxyAuthz: conn=%d \"%s\"\n", 
509                 conn->c_connid,
510                 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
511 #else
512         Debug( LDAP_DEBUG_TRACE,
513                 "parseProxyAuthz: conn=%d \"%s\"\n", 
514                 conn->c_connid,
515                 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
516 #endif
517
518         rc = slap_sasl_authorized( conn, &op->o_ndn, &dn );
519
520         if( rc ) {
521                 ch_free( dn.bv_val );
522                 *text = "not authorized to assume identity";
523                 return LDAP_PROXY_AUTHZ_FAILURE;
524         }
525
526         ch_free( op->o_dn.bv_val );
527         ch_free( op->o_ndn.bv_val );
528
529         op->o_dn.bv_val = NULL;
530         op->o_ndn = dn;
531         ber_dupbv( &op->o_dn, &dn );
532
533         return LDAP_SUCCESS;
534 }
535
536 static int parseNoOp (
537         Connection *conn,
538         Operation *op,
539         LDAPControl *ctrl,
540         const char **text )
541 {
542         if ( op->o_noop != SLAP_NO_CONTROL ) {
543                 *text = "noop control specified multiple times";
544                 return LDAP_PROTOCOL_ERROR;
545         }
546
547         if ( ctrl->ldctl_value.bv_len ) {
548                 *text = "noop control value not empty";
549                 return LDAP_PROTOCOL_ERROR;
550         }
551
552         op->o_noop = ctrl->ldctl_iscritical
553                 ? SLAP_CRITICAL_CONTROL
554                 : SLAP_NONCRITICAL_CONTROL;
555
556         return LDAP_SUCCESS;
557 }
558
559 static int parsePagedResults (
560         Connection *conn,
561         Operation *op,
562         LDAPControl *ctrl,
563         const char **text )
564 {
565         ber_tag_t tag;
566         ber_int_t size;
567         BerElement *ber;
568         struct berval cookie = { 0, NULL };
569
570         if ( op->o_pagedresults != SLAP_NO_CONTROL ) {
571                 *text = "paged results control specified multiple times";
572                 return LDAP_PROTOCOL_ERROR;
573         }
574
575         if ( ctrl->ldctl_value.bv_len == 0 ) {
576                 *text = "paged results control value is empty (or absent)";
577                 return LDAP_PROTOCOL_ERROR;
578         }
579
580         /* Parse the control value
581          *      realSearchControlValue ::= SEQUENCE {
582          *              size    INTEGER (0..maxInt),
583          *                              -- requested page size from client
584          *                              -- result set size estimate from server
585          *              cookie  OCTET STRING
586          */
587         ber = ber_init( &ctrl->ldctl_value );
588         if( ber == NULL ) {
589                 *text = "internal error";
590                 return LDAP_OTHER;
591         }
592
593         tag = ber_scanf( ber, "{im}", &size, &cookie );
594         (void) ber_free( ber, 1 );
595
596         if( tag == LBER_ERROR ) {
597                 *text = "paged results control could not be decoded";
598                 return LDAP_PROTOCOL_ERROR;
599         }
600
601         if( size < 0 ) {
602                 *text = "paged results control size invalid";
603                 return LDAP_PROTOCOL_ERROR;
604         }
605
606         if( cookie.bv_len ) {
607                 PagedResultsCookie reqcookie;
608                 if( cookie.bv_len != sizeof( reqcookie ) ) {
609                         /* bad cookie */
610                         *text = "paged results cookie is invalid";
611                         return LDAP_PROTOCOL_ERROR;
612                 }
613
614                 AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
615
616                 if( reqcookie > op->o_pagedresults_state.ps_cookie ) {
617                         /* bad cookie */
618                         *text = "paged results cookie is invalid";
619                         return LDAP_PROTOCOL_ERROR;
620
621                 } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) {
622                         *text = "paged results cookie is invalid or old";
623                         return LDAP_UNWILLING_TO_PERFORM;
624                 }
625         } else {
626                 /* Initial request.  Initialize state. */
627                 op->o_pagedresults_state.ps_cookie = 0;
628                 op->o_pagedresults_state.ps_id = NOID;
629         }
630
631         op->o_pagedresults_size = size;
632
633         op->o_pagedresults = ctrl->ldctl_iscritical
634                 ? SLAP_CRITICAL_CONTROL
635                 : SLAP_NONCRITICAL_CONTROL;
636
637         return LDAP_SUCCESS;
638 }
639
640 int parseValuesReturnFilter (
641         Connection *conn,
642         Operation *op,
643         LDAPControl *ctrl,
644         const char **text )
645 {
646         int             rc;
647         BerElement      *ber;
648         struct berval   fstr = { 0, NULL };
649         const char *err_msg = "";
650
651         if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
652                 *text = "valuesReturnFilter control specified multiple times";
653                 return LDAP_PROTOCOL_ERROR;
654         }
655
656         if ( ctrl->ldctl_value.bv_len == 0 ) {
657                 *text = "valuesReturnFilter control value is empty (or absent)";
658                 return LDAP_PROTOCOL_ERROR;
659         }
660
661         ber = ber_init( &(ctrl->ldctl_value) );
662         if (ber == NULL) {
663                 *text = "internal error";
664                 return LDAP_OTHER;
665         }
666         
667         rc = get_vrFilter( conn, ber, &(op->vrFilter), &err_msg);
668
669         if( rc != LDAP_SUCCESS ) {
670                 text = &err_msg;
671                 if( rc == SLAPD_DISCONNECT ) {
672                         send_ldap_disconnect( conn, op,
673                                 LDAP_PROTOCOL_ERROR, *text );
674                 } else {
675                         send_ldap_result( conn, op, rc,
676                                 NULL, *text, NULL, NULL );
677                 }
678                 if( fstr.bv_val != NULL) free( fstr.bv_val );
679                 if( op->vrFilter != NULL) vrFilter_free( op->vrFilter ); 
680
681         } else {
682                 vrFilter2bv( op->vrFilter, &fstr );
683         }
684
685 #ifdef NEW_LOGGING
686         LDAP_LOG( OPERATION, ARGS, 
687                 "parseValuesReturnFilter: conn %d       vrFilter: %s\n", 
688                 conn->c_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
689 #else
690         Debug( LDAP_DEBUG_ARGS, "       vrFilter: %s\n",
691                 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
692 #endif
693
694         op->o_valuesreturnfilter = ctrl->ldctl_iscritical
695                 ? SLAP_CRITICAL_CONTROL
696                 : SLAP_NONCRITICAL_CONTROL;
697
698         return LDAP_SUCCESS;
699 }
700
701 #ifdef LDAP_CONTROL_SUBENTRIES
702 static int parseSubentries (
703         Connection *conn,
704         Operation *op,
705         LDAPControl *ctrl,
706         const char **text )
707 {
708         if ( op->o_subentries != SLAP_NO_CONTROL ) {
709                 *text = "subentries control specified multiple times";
710                 return LDAP_PROTOCOL_ERROR;
711         }
712
713         /* FIXME: should use BER library */
714         if( ( ctrl->ldctl_value.bv_len != 3 )
715                 && ( ctrl->ldctl_value.bv_val[0] != 0x01 )
716                 && ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
717         {
718                 *text = "subentries control value encoding is bogus";
719                 return LDAP_PROTOCOL_ERROR;
720         }
721
722         op->o_subentries = ctrl->ldctl_iscritical
723                 ? SLAP_CRITICAL_CONTROL
724                 : SLAP_NONCRITICAL_CONTROL;
725
726         op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
727
728         return LDAP_SUCCESS;
729 }
730 #endif
731
732 #ifdef LDAP_CLIENT_UPDATE
733 static int parseClientUpdate (
734         Connection *conn,
735         Operation *op,
736         LDAPControl *ctrl,
737         const char **text )
738 {
739         ber_tag_t tag;
740         BerElement *ber;
741         ber_int_t type;
742         ber_int_t interval;
743         ber_len_t len;
744         struct berval scheme = { 0, NULL };
745         struct berval cookie = { 0, NULL };
746
747         if ( op->o_clientupdate != SLAP_NO_CONTROL ) {
748                 *text = "LCUP client update control specified multiple times";
749                 return LDAP_PROTOCOL_ERROR;
750         }
751
752         if ( ctrl->ldctl_value.bv_len == 0 ) {
753                 *text = "LCUP client update control value is empty (or absent)";
754                 return LDAP_PROTOCOL_ERROR;
755         }
756
757         /* Parse the control value
758          *      ClientUpdateControlValue ::= SEQUENCE {
759          *              updateType      ENUMERATED {
760          *                                      synchronizeOnly {0},
761          *                                      synchronizeAndPersist {1},
762          *                                      persistOnly {2} },
763          *              sendCookieInterval INTEGER OPTIONAL,
764          *              cookie          LCUPCookie OPTIONAL
765          *      }
766          */
767
768         ber = ber_init( &ctrl->ldctl_value );
769         if( ber == NULL ) {
770                 *text = "internal error";
771                 return LDAP_OTHER;
772         }
773
774         if ( (tag = ber_scanf( ber, "{i" /*}*/, &type )) == LBER_ERROR ) {
775                 *text = "LCUP client update control : decoding error";
776                 return LDAP_PROTOCOL_ERROR;
777         }
778
779         switch( type ) {
780         case LDAP_CUP_SYNC_ONLY:
781                 type = SLAP_LCUP_SYNC;
782                 break;
783         case LDAP_CUP_SYNC_AND_PERSIST:
784                 type = SLAP_LCUP_SYNC_AND_PERSIST;
785                 break;
786         case LDAP_CUP_PERSIST_ONLY:
787                 type = SLAP_LCUP_PERSIST;
788                 break;
789         default:
790                 *text = "LCUP client update control : unknown update type";
791                 return LDAP_PROTOCOL_ERROR;
792         }
793
794         if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) {
795                 *text = "LCUP client update control : decoding error";
796                 return LDAP_PROTOCOL_ERROR;
797         }
798
799         if ( tag == LDAP_TAG_INTERVAL ) {
800                 if ( (tag = ber_scanf( ber, "i", &interval )) == LBER_ERROR ) {
801                         *text = "LCUP client update control : decoding error";
802                         return LDAP_PROTOCOL_ERROR;
803                 }
804                 
805                 if ( interval <= 0 ) {
806                         /* server chooses interval */
807                         interval = LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL;
808                 }
809
810         } else {
811                 /* server chooses interval */
812                 interval = LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL;
813         }
814
815         if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) {
816                 *text = "LCUP client update control : decoding error";
817                 return LDAP_PROTOCOL_ERROR;
818         }
819
820         if ( tag == LDAP_TAG_COOKIE ) {
821                 if ( (tag = ber_scanf( ber, /*{*/ "{mm}}",
822                                         &scheme, &cookie )) == LBER_ERROR ) {
823                         *text = "LCUP client update control : decoding error";
824                         return LDAP_PROTOCOL_ERROR;
825                 }
826         }
827
828         /* TODO : Cookie Scheme Validation */
829 #if 0
830         if ( lcup_cookie_scheme_validate(scheme) != LDAP_SUCCESS ) {
831                 *text = "Unsupported LCUP cookie scheme";
832                 return LCUP_UNSUPPORTED_SCHEME;
833         }
834
835         if ( lcup_cookie_validate(scheme, cookie) != LDAP_SUCCESS ) {
836                 *text = "Invalid LCUP cookie";
837                 return LCUP_INVALID_COOKIE;
838         }
839 #endif
840
841         ber_dupbv( &op->o_clientupdate_state, &cookie );
842
843         (void) ber_free( ber, 1 );
844
845         op->o_clientupdate_type = (char) type;
846         op->o_clientupdate_interval = interval;
847
848         op->o_clientupdate = ctrl->ldctl_iscritical
849                 ? SLAP_CRITICAL_CONTROL
850                 : SLAP_NONCRITICAL_CONTROL;
851
852         return LDAP_SUCCESS;
853 }
854 #endif /* LDAP_CLIENT_UPDATE */