]> git.sur5r.net Git - openldap/blob - servers/slapd/controls.c
Fix matched values bug
[openldap] / servers / slapd / controls.c
1 /* $OpenLDAP$ */
2 /* 
3  * Copyright 1999-2002 The OpenLDAP Foundation.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted only
7  * as authorized by the OpenLDAP Public License.  A copy of this
8  * license is available at http://www.OpenLDAP.org/license.html or
9  * in file LICENSE in the top-level directory of the distribution.
10  */
11 #include "portable.h"
12
13 #include <stdio.h>
14
15 #include <ac/string.h>
16 #include <ac/socket.h>
17
18 #include "slap.h"
19
20 #include "../../libraries/liblber/lber-int.h"
21
22 #define SLAP_CTRL_FRONTEND      0x80000000U
23
24 #define SLAP_CTRL_OPFLAGS       0x0000FFFFU
25 #define SLAP_CTRL_ABANDON       0x00000001U
26 #define SLAP_CTRL_ADD           0x00002002U
27 #define SLAP_CTRL_BIND          0x00000004U
28 #define SLAP_CTRL_COMPARE       0x00001008U
29 #define SLAP_CTRL_DELETE        0x00002010U
30 #define SLAP_CTRL_MODIFY        0x00002020U
31 #define SLAP_CTRL_RENAME        0x00002040U
32 #define SLAP_CTRL_SEARCH        0x00001080U
33 #define SLAP_CTRL_UNBIND        0x00000100U
34
35 #define SLAP_CTRL_INTROGATE     (SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH)
36 #define SLAP_CTRL_UPDATE \
37         (SLAP_CTRL_ADD|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME)
38 #define SLAP_CTRL_ACCESS        (SLAP_CTRL_INTROGATE|SLAP_CTRL_UPDATE)
39
40 typedef int (SLAP_CTRL_PARSE_FN) LDAP_P((
41         Connection *conn,
42         Operation *op,
43         LDAPControl *ctrl,
44         const char **text ));
45
46 static SLAP_CTRL_PARSE_FN parseManageDSAit;
47 static SLAP_CTRL_PARSE_FN parseSubentries;
48 static SLAP_CTRL_PARSE_FN parseNoOp;
49 static SLAP_CTRL_PARSE_FN parsePagedResults;
50 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
51
52 static struct slap_control {
53         char *sc_oid;
54         slap_mask_t sc_mask;
55         char **sc_extendedops;
56         SLAP_CTRL_PARSE_FN *sc_parse;
57
58 } supportedControls[] = {
59         { LDAP_CONTROL_MANAGEDSAIT,
60                 SLAP_CTRL_ACCESS, NULL,
61                 parseManageDSAit },
62 #ifdef LDAP_CONTROL_SUBENTRIES
63         { LDAP_CONTROL_SUBENTRIES,
64                 SLAP_CTRL_SEARCH, NULL,
65                 parseSubentries },
66 #endif
67 #ifdef LDAP_CONTROL_NOOP
68         { LDAP_CONTROL_NOOP,
69                 SLAP_CTRL_UPDATE, NULL,
70                 parseNoOp },
71 #endif
72 #ifdef LDAP_CONTROL_PAGEDRESULTS_REQUEST
73         { LDAP_CONTROL_PAGEDRESULTS_REQUEST,
74                 SLAP_CTRL_SEARCH, NULL,
75                 parsePagedResults },
76 #endif
77 #ifdef LDAP_CONTROL_VALUESRETURNFILTER
78         { LDAP_CONTROL_VALUESRETURNFILTER,
79                 SLAP_CTRL_SEARCH, NULL,
80                 parseValuesReturnFilter },
81 #endif
82         { NULL }
83 };
84
85 char *
86 get_supported_ctrl(int index)
87 {
88         return supportedControls[index].sc_oid;
89 }
90
91 static struct slap_control *
92 find_ctrl( const char *oid )
93 {
94         int i;
95         for( i=0; supportedControls[i].sc_oid; i++ ) {
96                 if( strcmp( oid, supportedControls[i].sc_oid ) == 0 ) {
97                         return &supportedControls[i];
98                 }
99         }
100         return NULL;
101 }
102
103 int get_ctrls(
104         Connection *conn,
105         Operation *op,
106         int sendres )
107 {
108         int nctrls = 0;
109         ber_tag_t tag;
110         ber_len_t len;
111         char *opaque;
112         BerElement *ber = op->o_ber;
113         struct slap_control *sc;
114         int rc = LDAP_SUCCESS;
115         const char *errmsg = NULL;
116
117         len = ber_pvt_ber_remaining(ber);
118
119         if( len == 0) {
120                 /* no controls */
121                 rc = LDAP_SUCCESS;
122                 return rc;
123         }
124
125         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
126                 if( tag == LBER_ERROR ) {
127                         rc = SLAPD_DISCONNECT;
128                         errmsg = "unexpected data in PDU";
129                 }
130
131                 goto return_results;
132         }
133
134 #ifdef NEW_LOGGING
135         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
136                 "get_ctrls: conn %lu\n", conn->c_connid ));
137 #else
138         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 );
139 #endif
140         if( op->o_protocol < LDAP_VERSION3 ) {
141                 rc = SLAPD_DISCONNECT;
142                 errmsg = "controls require LDAPv3";
143                 goto return_results;
144         }
145
146         /* one for first control, one for termination */
147         op->o_ctrls = ch_malloc( 2 * sizeof(LDAPControl *) );
148
149 #if 0
150         if( op->ctrls == NULL ) {
151                 rc = LDAP_NO_MEMORY;
152                 errmsg = "no memory";
153                 goto return_results;
154         }
155 #endif
156
157         op->o_ctrls[nctrls] = NULL;
158
159         /* step through each element */
160         for( tag = ber_first_element( ber, &len, &opaque );
161                 tag != LBER_ERROR;
162                 tag = ber_next_element( ber, &len, opaque ) )
163         {
164                 LDAPControl *c;
165                 LDAPControl **tctrls;
166
167                 c = ch_calloc( 1, sizeof(LDAPControl) );
168
169 #if 0
170                 if( c == NULL ) {
171                         ldap_controls_free(op->o_ctrls);
172                         op->o_ctrls = NULL;
173
174                         rc = LDAP_NO_MEMORY;
175                         errmsg = "no memory";
176                         goto return_results;
177                 }
178 #endif
179
180                 /* allocate pointer space for current controls (nctrls)
181                  * + this control + extra NULL
182                  */
183                 tctrls = ch_realloc( op->o_ctrls,
184                         (nctrls+2) * sizeof(LDAPControl *));
185
186 #if 0
187                 if( tctrls == NULL ) {
188                         ch_free( c );
189                         ldap_controls_free(op->o_ctrls);
190                         op->o_ctrls = NULL;
191
192                         rc = LDAP_NO_MEMORY;
193                         errmsg = "no memory";
194                         goto return_results;
195                 }
196 #endif
197                 op->o_ctrls = tctrls;
198
199                 op->o_ctrls[nctrls++] = c;
200                 op->o_ctrls[nctrls] = NULL;
201
202                 tag = ber_scanf( ber, "{a" /*}*/, &c->ldctl_oid );
203
204                 if( tag == LBER_ERROR ) {
205 #ifdef NEW_LOGGING
206                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
207                                 "get_ctrls: conn %lu get OID failed.\n",
208                                 conn->c_connid ));
209 #else
210                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
211                                 0, 0, 0 );
212 #endif
213                         ldap_controls_free( op->o_ctrls );
214                         op->o_ctrls = NULL;
215                         rc = SLAPD_DISCONNECT;
216                         errmsg = "decoding controls error";
217                         goto return_results;
218                 }
219
220                 tag = ber_peek_tag( ber, &len );
221
222                 if( tag == LBER_BOOLEAN ) {
223                         ber_int_t crit;
224                         tag = ber_scanf( ber, "b", &crit );
225
226                         if( tag == LBER_ERROR ) {
227 #ifdef NEW_LOGGING
228                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
229                                         "get_ctrls: conn %lu get crit failed.\n",
230                                         conn->c_connid ));
231 #else
232                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
233                                         0, 0, 0 );
234 #endif
235                                 ldap_controls_free( op->o_ctrls );
236                                 op->o_ctrls = NULL;
237                                 rc = SLAPD_DISCONNECT;
238                                 errmsg = "decoding controls error";
239                                 goto return_results;
240                         }
241
242                         c->ldctl_iscritical = (crit != 0);
243                         tag = ber_peek_tag( ber, &len );
244                 }
245
246                 if( tag == LBER_OCTETSTRING ) {
247                         tag = ber_scanf( ber, "o", &c->ldctl_value );
248
249                         if( tag == LBER_ERROR ) {
250 #ifdef NEW_LOGGING
251                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO, "get_ctrls: conn %lu: "
252                                         "%s (%scritical): get value failed.\n",
253                                         conn->c_connid,
254                                         c->ldctl_oid ? c->ldctl_oid : "(NULL)",
255                                         c->ldctl_iscritical ? "" : "non" ));
256 #else
257                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
258                                         "%s (%scritical): get value failed.\n",
259                                         conn->c_connid,
260                                         c->ldctl_oid ? c->ldctl_oid : "(NULL)",
261                                         c->ldctl_iscritical ? "" : "non" );
262 #endif
263                                 ldap_controls_free( op->o_ctrls );
264                                 op->o_ctrls = NULL;
265                                 rc = SLAPD_DISCONNECT;
266                                 errmsg = "decoding controls error";
267                                 goto return_results;
268                         }
269                 }
270
271 #ifdef NEW_LOGGING
272                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
273                         "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n",
274                         conn->c_connid,
275                         c->ldctl_oid ? c->ldctl_oid : "(NULL)",
276                         c->ldctl_iscritical ? "" : "non" ));
277 #else
278                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: oid=\"%s\" (%scritical)\n",
279                         c->ldctl_oid ? c->ldctl_oid : "(NULL)",
280                         c->ldctl_iscritical ? "" : "non",
281                         0 );
282 #endif
283
284                 sc = find_ctrl( c->ldctl_oid );
285                 if( sc != NULL ) {
286                         /* recognized control */
287                         slap_mask_t tagmask;
288                         switch( op->o_tag ) {
289                         case LDAP_REQ_ADD:
290                                 tagmask = SLAP_CTRL_ADD;
291                                 break;
292                         case LDAP_REQ_BIND:
293                                 tagmask = SLAP_CTRL_BIND;
294                                 break;
295                         case LDAP_REQ_COMPARE:
296                                 tagmask = SLAP_CTRL_COMPARE;
297                                 break;
298                         case LDAP_REQ_DELETE:
299                                 tagmask = SLAP_CTRL_DELETE;
300                                 break;
301                         case LDAP_REQ_MODIFY:
302                                 tagmask = SLAP_CTRL_MODIFY;
303                                 break;
304                         case LDAP_REQ_RENAME:
305                                 tagmask = SLAP_CTRL_RENAME;
306                                 break;
307                         case LDAP_REQ_SEARCH:
308                                 tagmask = SLAP_CTRL_SEARCH;
309                                 break;
310                         case LDAP_REQ_UNBIND:
311                                 tagmask = SLAP_CTRL_UNBIND;
312                                 break;
313                         case LDAP_REQ_EXTENDED:
314                                 /* FIXME: check list of extended operations */
315                                 tagmask = ~0U;
316                                 break;
317                         default:
318                                 rc = LDAP_OTHER;
319                                 errmsg = "controls internal error";
320                                 goto return_results;
321                         }
322
323                         if (( sc->sc_mask & tagmask ) == tagmask ) {
324                                 /* available extension */
325
326                                 if( !sc->sc_parse ) {
327                                         rc = LDAP_OTHER;
328                                         errmsg = "not yet implemented";
329                                         goto return_results;
330                                 }
331
332                                 rc = sc->sc_parse( conn, op, c, &errmsg );
333
334                                 if( rc != LDAP_SUCCESS ) goto return_results;
335
336                                 if( sc->sc_mask & SLAP_CTRL_FRONTEND ) {
337                                         /* kludge to disable backend_control() check */
338                                         c->ldctl_iscritical = 0;
339                                 }
340
341                         } else if( c->ldctl_iscritical ) {
342                                 /* unavailable CRITICAL control */
343                                 rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
344                                 errmsg = "critical extension is unavailable";
345                                 goto return_results;
346                         }
347
348                 } else if( c->ldctl_iscritical ) {
349                         /* unrecognized CRITICAL control */
350                         rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
351                         errmsg = "critical extension is not recognized";
352                         goto return_results;
353                 }
354         }
355
356 return_results:
357 #ifdef NEW_LOGGING
358         LDAP_LOG(( "operation", LDAP_LEVEL_RESULTS,
359                 "get_ctrls: conn=%lu    n=%d rc=%d err=%s\n",
360                 conn->c_connid, nctrls, rc, errmsg ? errmsg : "" ));
361 #else
362         Debug( LDAP_DEBUG_TRACE, "<= get_ctrls: n=%d rc=%d err=%s\n",
363                 nctrls, rc, errmsg ? errmsg : "");
364 #endif
365
366         if( sendres && rc != LDAP_SUCCESS ) {
367                 if( rc == SLAPD_DISCONNECT ) {
368                         send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, errmsg );
369                 } else {
370                         send_ldap_result( conn, op, rc,
371                                 NULL, errmsg, NULL, NULL );
372                 }
373         }
374
375         return rc;
376 }
377
378 static int parseManageDSAit (
379         Connection *conn,
380         Operation *op,
381         LDAPControl *ctrl,
382         const char **text )
383 {
384         if ( op->o_managedsait != SLAP_NO_CONTROL ) {
385                 *text = "manageDSAit control specified multiple times";
386                 return LDAP_PROTOCOL_ERROR;
387         }
388
389         if ( ctrl->ldctl_value.bv_len ) {
390                 *text = "manageDSAit control value not empty";
391                 return LDAP_PROTOCOL_ERROR;
392         }
393
394         op->o_managedsait = ctrl->ldctl_iscritical
395                 ? SLAP_CRITICAL_CONTROL
396                 : SLAP_NONCRITICAL_CONTROL;
397
398         return LDAP_SUCCESS;
399 }
400
401 #ifdef LDAP_CONTROL_SUBENTRIES
402 static int parseSubentries (
403         Connection *conn,
404         Operation *op,
405         LDAPControl *ctrl,
406         const char **text )
407 {
408         if ( op->o_subentries != SLAP_NO_CONTROL ) {
409                 *text = "subentries control specified multiple times";
410                 return LDAP_PROTOCOL_ERROR;
411         }
412
413         /* FIXME: should use BER library */
414         if( ( ctrl->ldctl_value.bv_len != 3 )
415                 && ( ctrl->ldctl_value.bv_val[0] != 0x01 )
416                 && ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
417         {
418                 *text = "subentries control value encoding is bogus";
419                 return LDAP_PROTOCOL_ERROR;
420         }
421
422         op->o_subentries = ctrl->ldctl_iscritical
423                 ? SLAP_CRITICAL_CONTROL
424                 : SLAP_NONCRITICAL_CONTROL;
425
426         op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
427
428         return LDAP_SUCCESS;
429 }
430 #endif
431
432 #ifdef LDAP_CONTROL_NOOP
433 static int parseNoOp (
434         Connection *conn,
435         Operation *op,
436         LDAPControl *ctrl,
437         const char **text )
438 {
439         if ( op->o_noop != SLAP_NO_CONTROL ) {
440                 *text = "noop control specified multiple times";
441                 return LDAP_PROTOCOL_ERROR;
442         }
443
444         if ( ctrl->ldctl_value.bv_len ) {
445                 *text = "noop control value not empty";
446                 return LDAP_PROTOCOL_ERROR;
447         }
448
449         op->o_noop = ctrl->ldctl_iscritical
450                 ? SLAP_CRITICAL_CONTROL
451                 : SLAP_NONCRITICAL_CONTROL;
452
453         return LDAP_SUCCESS;
454 }
455 #endif
456
457 #ifdef LDAP_CONTROL_PAGEDRESULTS_REQUEST
458 static int parsePagedResults (
459         Connection *conn,
460         Operation *op,
461         LDAPControl *ctrl,
462         const char **text )
463 {
464         ber_tag_t tag;
465         ber_int_t size;
466         BerElement *ber;
467         struct berval cookie = { 0, NULL };
468
469         if ( op->o_pagedresults != SLAP_NO_CONTROL ) {
470                 *text = "paged results control specified multiple times";
471                 return LDAP_PROTOCOL_ERROR;
472         }
473
474         if ( ctrl->ldctl_value.bv_len == 0 ) {
475                 *text = "paged results control value is empty";
476                 return LDAP_PROTOCOL_ERROR;
477         }
478
479         /* Parse the control value
480          *      realSearchControlValue ::= SEQUENCE {
481          *              size    INTEGER (0..maxInt),
482          *                              -- requested page size from client
483          *                              -- result set size estimate from server
484          *              cookie  OCTET STRING
485          */
486         ber = ber_init( &ctrl->ldctl_value );
487         if( ber == NULL ) {
488                 *text = "internal error";
489                 return LDAP_OTHER;
490         }
491
492         tag = ber_scanf( ber, "{im}", &size, &cookie );
493         (void) ber_free( ber, 1 );
494
495         if( tag == LBER_ERROR ) {
496                 *text = "paged results control could not be decoded";
497                 return LDAP_PROTOCOL_ERROR;
498         }
499
500         if( size <= 0 ) {
501                 *text = "paged results control size invalid";
502                 return LDAP_PROTOCOL_ERROR;
503         }
504
505         if( cookie.bv_len ) {
506                 PagedResultsCookie reqcookie;
507                 if( cookie.bv_len != sizeof( reqcookie ) ) {
508                         /* bad cookie */
509                         *text = "paged results cookie is invalid";
510                         return LDAP_PROTOCOL_ERROR;
511                 }
512
513                 AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
514
515                 if( reqcookie > op->o_pagedresults_state.ps_cookie ) {
516                         /* bad cookie */
517                         *text = "paged results cookie is invalid";
518                         return LDAP_PROTOCOL_ERROR;
519
520                 } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) {
521                         *text = "paged results cookie is invalid or old";
522                         return LDAP_UNWILLING_TO_PERFORM;
523                 }
524         }
525
526         op->o_pagedresults_state.ps_cookie = op->o_opid;
527         op->o_pagedresults_size = size;
528
529         op->o_pagedresults = ctrl->ldctl_iscritical
530                 ? SLAP_CRITICAL_CONTROL
531                 : SLAP_NONCRITICAL_CONTROL;
532
533         return LDAP_SUCCESS;
534 }
535 #endif
536
537 #ifdef LDAP_CONTROL_VALUESRETURNFILTER
538 int parseValuesReturnFilter (
539         Connection *conn,
540         Operation *op,
541         LDAPControl *ctrl,
542         const char **text )
543 {
544         int             rc;
545         BerElement      *ber;
546         struct berval   fstr = { 0, NULL };
547         const char *err_msg = "";
548
549         if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
550                 *text = "valuesreturnfilter control specified multiple times";
551                 return LDAP_PROTOCOL_ERROR;
552         }
553
554         ber = ber_init( &(ctrl->ldctl_value) );
555         if (ber == NULL) {
556                 *text = "internal error";
557                 return LDAP_OTHER;
558         }
559         
560         rc = get_vrFilter( conn, ber, &(op->vrFilter), &err_msg);
561
562         if( rc != LDAP_SUCCESS ) {
563                 text = &err_msg;
564                 if( rc == SLAPD_DISCONNECT ) {
565                         send_ldap_disconnect( conn, op,
566                                 LDAP_PROTOCOL_ERROR, *text );
567                 } else {
568                         send_ldap_result( conn, op, rc,
569                                 NULL, *text, NULL, NULL );
570                 }
571                 if( fstr.bv_val != NULL) free( fstr.bv_val );
572                 if( op->vrFilter != NULL) vrFilter_free( op->vrFilter ); 
573
574         } else {
575                 vrFilter2bv( op->vrFilter, &fstr );
576         }
577
578 #ifdef NEW_LOGGING
579         LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
580                 "parseValuesReturnFilter: conn %d       vrFilter: %s\n", conn->c_connid,
581                 fstr.bv_len ? fstr.bv_val : "empty" ));
582 #else
583         Debug( LDAP_DEBUG_ARGS, "       vrFilter: %s\n",
584                 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
585 #endif
586
587         op->o_valuesreturnfilter = ctrl->ldctl_iscritical
588                 ? SLAP_CRITICAL_CONTROL
589                 : SLAP_NONCRITICAL_CONTROL;
590
591         return LDAP_SUCCESS;
592 }
593 #endif