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