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