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