3 * Copyright 1999-2003 The OpenLDAP Foundation.
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.
15 #include <ac/string.h>
16 #include <ac/socket.h>
20 #include "../../libraries/liblber/lber-int.h"
22 #define SLAP_CTRL_FRONTEND 0x80000000U
23 #define SLAP_CTRL_FRONTEND_SEARCH 0x01000000U /* for NOOP */
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
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)
41 typedef int (SLAP_CTRL_PARSE_FN) LDAP_P((
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;
53 #ifdef LDAP_CONTROL_SUBENTRIES
54 static SLAP_CTRL_PARSE_FN parseSubentries;
56 #ifdef LDAP_CLIENT_UPDATE
57 static SLAP_CTRL_PARSE_FN parseClientUpdate;
60 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
62 static char *proxy_authz_extops[] = {
63 LDAP_EXOP_MODIFY_PASSWD,
68 static struct slap_control {
71 char **sc_extendedops;
72 SLAP_CTRL_PARSE_FN *sc_parse;
74 } supportedControls[] = {
75 { LDAP_CONTROL_PROXY_AUTHZ,
76 SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops,
78 { LDAP_CONTROL_MANAGEDSAIT,
79 SLAP_CTRL_ACCESS, NULL,
82 SLAP_CTRL_ACCESS, NULL,
84 { LDAP_CONTROL_PAGEDRESULTS,
85 SLAP_CTRL_SEARCH, NULL,
87 { LDAP_CONTROL_VALUESRETURNFILTER,
88 SLAP_CTRL_SEARCH, NULL,
89 parseValuesReturnFilter },
90 #ifdef LDAP_CONTROL_SUBENTRIES
91 { LDAP_CONTROL_SUBENTRIES,
92 SLAP_CTRL_SEARCH, NULL,
95 #ifdef LDAP_CLIENT_UPDATE
96 { LDAP_CONTROL_CLIENT_UPDATE,
97 SLAP_CTRL_SEARCH, NULL,
99 #endif /* LDAP_CLIENT_UPDATE */
104 get_supported_ctrl(int index)
106 return supportedControls[index].sc_oid;
110 get_supported_ctrl_mask(int index)
112 return supportedControls[index].sc_mask;
115 static struct slap_control *
116 find_ctrl( const char *oid )
119 for( i=0; supportedControls[i].sc_oid; i++ ) {
120 if( strcmp( oid, supportedControls[i].sc_oid ) == 0 ) {
121 return &supportedControls[i];
136 BerElement *ber = op->o_ber;
137 struct slap_control *sc;
138 int rc = LDAP_SUCCESS;
139 const char *errmsg = NULL;
141 len = ber_pvt_ber_remaining(ber);
149 if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
150 if( tag == LBER_ERROR ) {
151 rc = SLAPD_DISCONNECT;
152 errmsg = "unexpected data in PDU";
159 LDAP_LOG( OPERATION, ENTRY,
160 "get_ctrls: conn %lu\n", conn->c_connid, 0, 0 );
162 Debug( LDAP_DEBUG_TRACE,
163 "=> get_ctrls\n", 0, 0, 0 );
166 if( op->o_protocol < LDAP_VERSION3 ) {
167 rc = SLAPD_DISCONNECT;
168 errmsg = "controls require LDAPv3";
172 /* one for first control, one for termination */
173 op->o_ctrls = ch_malloc( 2 * sizeof(LDAPControl *) );
176 if( op->ctrls == NULL ) {
178 errmsg = "no memory";
183 op->o_ctrls[nctrls] = NULL;
185 /* step through each element */
186 for( tag = ber_first_element( ber, &len, &opaque );
188 tag = ber_next_element( ber, &len, opaque ) )
191 LDAPControl **tctrls;
193 c = ch_calloc( 1, sizeof(LDAPControl) );
197 ldap_controls_free(op->o_ctrls);
201 errmsg = "no memory";
206 /* allocate pointer space for current controls (nctrls)
207 * + this control + extra NULL
209 tctrls = ch_realloc( op->o_ctrls,
210 (nctrls+2) * sizeof(LDAPControl *));
213 if( tctrls == NULL ) {
215 ldap_controls_free(op->o_ctrls);
219 errmsg = "no memory";
223 op->o_ctrls = tctrls;
225 op->o_ctrls[nctrls++] = c;
226 op->o_ctrls[nctrls] = NULL;
228 tag = ber_scanf( ber, "{a" /*}*/, &c->ldctl_oid );
230 if( tag == LBER_ERROR ) {
232 LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu get OID failed.\n",
233 conn->c_connid, 0, 0 );
235 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
239 ldap_controls_free( op->o_ctrls );
241 rc = SLAPD_DISCONNECT;
242 errmsg = "decoding controls error";
245 } else if( c->ldctl_oid == NULL ) {
247 LDAP_LOG( OPERATION, INFO,
248 "get_ctrls: conn %lu got emtpy OID.\n",
249 conn->c_connid, 0, 0 );
251 Debug( LDAP_DEBUG_TRACE,
252 "get_ctrls: conn %lu got emtpy OID.\n",
253 conn->c_connid, 0, 0 );
256 ldap_controls_free( op->o_ctrls );
258 rc = LDAP_PROTOCOL_ERROR;
259 errmsg = "OID field is empty";
263 tag = ber_peek_tag( ber, &len );
265 if( tag == LBER_BOOLEAN ) {
267 tag = ber_scanf( ber, "b", &crit );
269 if( tag == LBER_ERROR ) {
271 LDAP_LOG( OPERATION, INFO,
272 "get_ctrls: conn %lu get crit failed.\n",
273 conn->c_connid, 0, 0 );
275 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
278 ldap_controls_free( op->o_ctrls );
280 rc = SLAPD_DISCONNECT;
281 errmsg = "decoding controls error";
285 c->ldctl_iscritical = (crit != 0);
286 tag = ber_peek_tag( ber, &len );
289 if( tag == LBER_OCTETSTRING ) {
290 tag = ber_scanf( ber, "o", &c->ldctl_value );
292 if( tag == LBER_ERROR ) {
294 LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu: "
295 "%s (%scritical): get value failed.\n",
296 conn->c_connid, c->ldctl_oid,
297 c->ldctl_iscritical ? "" : "non" );
299 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
300 "%s (%scritical): get value failed.\n",
301 conn->c_connid, c->ldctl_oid,
302 c->ldctl_iscritical ? "" : "non" );
304 ldap_controls_free( op->o_ctrls );
306 rc = SLAPD_DISCONNECT;
307 errmsg = "decoding controls error";
313 LDAP_LOG( OPERATION, INFO,
314 "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n",
315 conn->c_connid, c->ldctl_oid, c->ldctl_iscritical ? "" : "non" );
317 Debug( LDAP_DEBUG_TRACE,
318 "=> get_ctrls: oid=\"%s\" (%scritical)\n",
319 c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
322 sc = find_ctrl( c->ldctl_oid );
324 /* recognized control */
326 switch( op->o_tag ) {
328 tagmask = SLAP_CTRL_ADD;
331 tagmask = SLAP_CTRL_BIND;
333 case LDAP_REQ_COMPARE:
334 tagmask = SLAP_CTRL_COMPARE;
336 case LDAP_REQ_DELETE:
337 tagmask = SLAP_CTRL_DELETE;
339 case LDAP_REQ_MODIFY:
340 tagmask = SLAP_CTRL_MODIFY;
342 case LDAP_REQ_RENAME:
343 tagmask = SLAP_CTRL_RENAME;
345 case LDAP_REQ_SEARCH:
346 tagmask = SLAP_CTRL_SEARCH;
348 case LDAP_REQ_UNBIND:
349 tagmask = SLAP_CTRL_UNBIND;
351 case LDAP_REQ_ABANDON:
352 tagmask = SLAP_CTRL_ABANDON;
354 case LDAP_REQ_EXTENDED:
356 assert( op->o_extendedop != NULL );
357 if( sc->sc_extendedops != NULL ) {
359 for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
360 if( strcmp( op->o_extendedop, sc->sc_extendedops[i] )
371 errmsg = "controls internal error";
375 if (( sc->sc_mask & tagmask ) == tagmask ) {
376 /* available extension */
378 if( !sc->sc_parse ) {
380 errmsg = "not yet implemented";
384 rc = sc->sc_parse( conn, op, c, &errmsg );
386 if( rc != LDAP_SUCCESS ) goto return_results;
388 if ( sc->sc_mask & SLAP_CTRL_FRONTEND ) {
389 /* kludge to disable backend_control() check */
390 c->ldctl_iscritical = 0;
392 } else if ( tagmask == SLAP_CTRL_SEARCH &&
393 sc->sc_mask & SLAP_CTRL_FRONTEND_SEARCH )
395 /* kludge to disable backend_control() check */
396 c->ldctl_iscritical = 0;
399 } else if( c->ldctl_iscritical ) {
400 /* unavailable CRITICAL control */
401 rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
402 errmsg = "critical extension is unavailable";
406 } else if( c->ldctl_iscritical ) {
407 /* unrecognized CRITICAL control */
408 rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
409 errmsg = "critical extension is not recognized";
416 LDAP_LOG( OPERATION, RESULTS,
417 "get_ctrls: n=%d rc=%d err=\"%s\"\n",
418 nctrls, rc, errmsg ? errmsg : "" );
420 Debug( LDAP_DEBUG_TRACE,
421 "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
422 nctrls, rc, errmsg ? errmsg : "");
425 if( sendres && rc != LDAP_SUCCESS ) {
426 if( rc == SLAPD_DISCONNECT ) {
427 send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, errmsg );
429 send_ldap_result( conn, op, rc,
430 NULL, errmsg, NULL, NULL );
437 static int parseManageDSAit (
443 if ( op->o_managedsait != SLAP_NO_CONTROL ) {
444 *text = "manageDSAit control specified multiple times";
445 return LDAP_PROTOCOL_ERROR;
448 if ( ctrl->ldctl_value.bv_len ) {
449 *text = "manageDSAit control value not empty";
450 return LDAP_PROTOCOL_ERROR;
453 op->o_managedsait = ctrl->ldctl_iscritical
454 ? SLAP_CRITICAL_CONTROL
455 : SLAP_NONCRITICAL_CONTROL;
460 static int parseProxyAuthz (
469 if ( op->o_proxy_authz != SLAP_NO_CONTROL ) {
470 *text = "proxy authorization control specified multiple times";
471 return LDAP_PROTOCOL_ERROR;
474 op->o_proxy_authz = ctrl->ldctl_iscritical
475 ? SLAP_CRITICAL_CONTROL
476 : SLAP_NONCRITICAL_CONTROL;
479 LDAP_LOG( OPERATION, ARGS,
480 "parseProxyAuthz: conn %d authzid=\"%s\"\n",
482 ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous",
485 Debug( LDAP_DEBUG_ARGS,
486 "parseProxyAuthz: conn %d authzid=\"%s\"\n",
488 ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous",
492 if( ctrl->ldctl_value.bv_len == 0 ) {
494 LDAP_LOG( OPERATION, RESULTS,
495 "parseProxyAuthz: conn=%d anonymous\n",
496 conn->c_connid, 0, 0 );
498 Debug( LDAP_DEBUG_TRACE,
499 "parseProxyAuthz: conn=%d anonymous\n",
500 conn->c_connid, 0, 0 );
504 free( op->o_dn.bv_val );
506 op->o_dn.bv_val = ch_strdup( "" );
508 free( op->o_ndn.bv_val );
509 op->o_ndn.bv_len = 0;
510 op->o_ndn.bv_val = ch_strdup( "" );
515 rc = slap_sasl_getdn( conn,
516 ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len,
517 NULL, &dn, SLAP_GETDN_AUTHZID );
519 if( rc != LDAP_SUCCESS || !dn.bv_len ) {
520 *text = "authzId mapping failed";
521 return LDAP_PROXY_AUTHZ_FAILURE;
525 LDAP_LOG( OPERATION, RESULTS,
526 "parseProxyAuthz: conn=%d \"%s\"\n",
528 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
530 Debug( LDAP_DEBUG_TRACE,
531 "parseProxyAuthz: conn=%d \"%s\"\n",
533 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
536 rc = slap_sasl_authorized( conn, &op->o_ndn, &dn );
539 ch_free( dn.bv_val );
540 *text = "not authorized to assume identity";
541 return LDAP_PROXY_AUTHZ_FAILURE;
544 ch_free( op->o_dn.bv_val );
545 ch_free( op->o_ndn.bv_val );
547 op->o_dn.bv_val = NULL;
549 ber_dupbv( &op->o_dn, &dn );
554 static int parseNoOp (
560 if ( op->o_noop != SLAP_NO_CONTROL ) {
561 *text = "noop control specified multiple times";
562 return LDAP_PROTOCOL_ERROR;
565 if ( ctrl->ldctl_value.bv_len ) {
566 *text = "noop control value not empty";
567 return LDAP_PROTOCOL_ERROR;
570 op->o_noop = ctrl->ldctl_iscritical
571 ? SLAP_CRITICAL_CONTROL
572 : SLAP_NONCRITICAL_CONTROL;
577 static int parsePagedResults (
586 struct berval cookie = { 0, NULL };
588 if ( op->o_pagedresults != SLAP_NO_CONTROL ) {
589 *text = "paged results control specified multiple times";
590 return LDAP_PROTOCOL_ERROR;
593 if ( ctrl->ldctl_value.bv_len == 0 ) {
594 *text = "paged results control value is empty (or absent)";
595 return LDAP_PROTOCOL_ERROR;
598 /* Parse the control value
599 * realSearchControlValue ::= SEQUENCE {
600 * size INTEGER (0..maxInt),
601 * -- requested page size from client
602 * -- result set size estimate from server
603 * cookie OCTET STRING
605 ber = ber_init( &ctrl->ldctl_value );
607 *text = "internal error";
611 tag = ber_scanf( ber, "{im}", &size, &cookie );
612 (void) ber_free( ber, 1 );
614 if( tag == LBER_ERROR ) {
615 *text = "paged results control could not be decoded";
616 return LDAP_PROTOCOL_ERROR;
620 *text = "paged results control size invalid";
621 return LDAP_PROTOCOL_ERROR;
624 if( cookie.bv_len ) {
625 PagedResultsCookie reqcookie;
626 if( cookie.bv_len != sizeof( reqcookie ) ) {
628 *text = "paged results cookie is invalid";
629 return LDAP_PROTOCOL_ERROR;
632 AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
634 if( reqcookie > op->o_pagedresults_state.ps_cookie ) {
636 *text = "paged results cookie is invalid";
637 return LDAP_PROTOCOL_ERROR;
639 } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) {
640 *text = "paged results cookie is invalid or old";
641 return LDAP_UNWILLING_TO_PERFORM;
644 /* Initial request. Initialize state. */
645 op->o_pagedresults_state.ps_cookie = 0;
646 op->o_pagedresults_state.ps_id = NOID;
649 op->o_pagedresults_size = size;
651 op->o_pagedresults = ctrl->ldctl_iscritical
652 ? SLAP_CRITICAL_CONTROL
653 : SLAP_NONCRITICAL_CONTROL;
658 int parseValuesReturnFilter (
666 struct berval fstr = { 0, NULL };
667 const char *err_msg = "";
669 if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
670 *text = "valuesReturnFilter control specified multiple times";
671 return LDAP_PROTOCOL_ERROR;
674 if ( ctrl->ldctl_value.bv_len == 0 ) {
675 *text = "valuesReturnFilter control value is empty (or absent)";
676 return LDAP_PROTOCOL_ERROR;
679 ber = ber_init( &(ctrl->ldctl_value) );
681 *text = "internal error";
685 rc = get_vrFilter( conn, ber, &(op->vrFilter), &err_msg);
687 if( rc != LDAP_SUCCESS ) {
689 if( rc == SLAPD_DISCONNECT ) {
690 send_ldap_disconnect( conn, op,
691 LDAP_PROTOCOL_ERROR, *text );
693 send_ldap_result( conn, op, rc,
694 NULL, *text, NULL, NULL );
696 if( fstr.bv_val != NULL) free( fstr.bv_val );
697 if( op->vrFilter != NULL) vrFilter_free( op->vrFilter );
700 vrFilter2bv( op->vrFilter, &fstr );
704 LDAP_LOG( OPERATION, ARGS,
705 "parseValuesReturnFilter: conn %d vrFilter: %s\n",
706 conn->c_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
708 Debug( LDAP_DEBUG_ARGS, " vrFilter: %s\n",
709 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
712 op->o_valuesreturnfilter = ctrl->ldctl_iscritical
713 ? SLAP_CRITICAL_CONTROL
714 : SLAP_NONCRITICAL_CONTROL;
719 #ifdef LDAP_CONTROL_SUBENTRIES
720 static int parseSubentries (
726 if ( op->o_subentries != SLAP_NO_CONTROL ) {
727 *text = "subentries control specified multiple times";
728 return LDAP_PROTOCOL_ERROR;
731 /* FIXME: should use BER library */
732 if( ( ctrl->ldctl_value.bv_len != 3 )
733 && ( ctrl->ldctl_value.bv_val[0] != 0x01 )
734 && ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
736 *text = "subentries control value encoding is bogus";
737 return LDAP_PROTOCOL_ERROR;
740 op->o_subentries = ctrl->ldctl_iscritical
741 ? SLAP_CRITICAL_CONTROL
742 : SLAP_NONCRITICAL_CONTROL;
744 op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
750 #ifdef LDAP_CLIENT_UPDATE
751 static int parseClientUpdate (
762 struct berval scheme = { 0, NULL };
763 struct berval cookie = { 0, NULL };
765 if ( op->o_clientupdate != SLAP_NO_CONTROL ) {
766 *text = "LCUP client update control specified multiple times";
767 return LDAP_PROTOCOL_ERROR;
770 if ( ctrl->ldctl_value.bv_len == 0 ) {
771 *text = "LCUP client update control value is empty (or absent)";
772 return LDAP_PROTOCOL_ERROR;
775 /* Parse the control value
776 * ClientUpdateControlValue ::= SEQUENCE {
777 * updateType ENUMERATED {
778 * synchronizeOnly {0},
779 * synchronizeAndPersist {1},
781 * sendCookieInterval INTEGER OPTIONAL,
782 * cookie LCUPCookie OPTIONAL
786 ber = ber_init( &ctrl->ldctl_value );
788 *text = "internal error";
792 if ( (tag = ber_scanf( ber, "{i" /*}*/, &type )) == LBER_ERROR ) {
793 *text = "LCUP client update control : decoding error";
794 return LDAP_PROTOCOL_ERROR;
798 case LDAP_CUP_SYNC_ONLY:
799 type = SLAP_LCUP_SYNC;
801 case LDAP_CUP_SYNC_AND_PERSIST:
802 type = SLAP_LCUP_SYNC_AND_PERSIST;
804 case LDAP_CUP_PERSIST_ONLY:
805 type = SLAP_LCUP_PERSIST;
808 *text = "LCUP client update control : unknown update type";
809 return LDAP_PROTOCOL_ERROR;
812 if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) {
813 *text = "LCUP client update control : decoding error";
814 return LDAP_PROTOCOL_ERROR;
817 if ( tag == LDAP_TAG_INTERVAL ) {
818 if ( (tag = ber_scanf( ber, "i", &interval )) == LBER_ERROR ) {
819 *text = "LCUP client update control : decoding error";
820 return LDAP_PROTOCOL_ERROR;
823 if ( interval <= 0 ) {
824 /* server chooses interval */
825 interval = LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL;
829 /* server chooses interval */
830 interval = LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL;
833 if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) {
834 *text = "LCUP client update control : decoding error";
835 return LDAP_PROTOCOL_ERROR;
838 if ( tag == LDAP_TAG_COOKIE ) {
839 if ( (tag = ber_scanf( ber, /*{*/ "{mm}}",
840 &scheme, &cookie )) == LBER_ERROR ) {
841 *text = "LCUP client update control : decoding error";
842 return LDAP_PROTOCOL_ERROR;
846 /* TODO : Cookie Scheme Validation */
848 if ( lcup_cookie_scheme_validate(scheme) != LDAP_SUCCESS ) {
849 *text = "Unsupported LCUP cookie scheme";
850 return LCUP_UNSUPPORTED_SCHEME;
853 if ( lcup_cookie_validate(scheme, cookie) != LDAP_SUCCESS ) {
854 *text = "Invalid LCUP cookie";
855 return LCUP_INVALID_COOKIE;
859 ber_dupbv( &op->o_clientupdate_state, &cookie );
861 (void) ber_free( ber, 1 );
863 op->o_clientupdate_type = (char) type;
864 op->o_clientupdate_interval = interval;
866 op->o_clientupdate = ctrl->ldctl_iscritical
867 ? SLAP_CRITICAL_CONTROL
868 : SLAP_NONCRITICAL_CONTROL;
872 #endif /* LDAP_CLIENT_UPDATE */