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