openldap/servers/slapd/extended.c
Kurt Zeilenga 82fad7d0c8 First stable an implementing latest namedref specification.
Includes rewriting of URLs where the DN of the referral object
and the DN of the ref attribute attribute are not the same.
Also, always returns explicit DN and scope.
Currently, back-ldbm only.  Needs to be ported to back-bdb.
2001-10-26 02:05:14 +00:00

284 lines
6.2 KiB
C

/* $OpenLDAP$ */
/*
* Copyright 1999-2000 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted only
* as authorized by the OpenLDAP Public License. A copy of this
* license is available at http://www.OpenLDAP.org/license.html or
* in file LICENSE in the top-level directory of the distribution.
*/
/*
* LDAPv3 Extended Operation Request
* ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
* requestName [0] LDAPOID,
* requestValue [1] OCTET STRING OPTIONAL
* }
*
* LDAPv3 Extended Operation Response
* ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
* COMPONENTS OF LDAPResult,
* responseName [10] LDAPOID OPTIONAL,
* response [11] OCTET STRING OPTIONAL
* }
*
*/
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include "slap.h"
#define MAX_OID_LENGTH 128
typedef struct extop_list_t {
struct extop_list_t *next;
char *oid;
SLAP_EXTOP_MAIN_FN ext_main;
} extop_list_t;
extop_list_t *supp_ext_list = NULL;
/* this list of built-in extops is for extops that are not part
* of backends or in external modules. essentially, this is
* just a way to get built-in extops onto the extop list without
* having a separate init routine for each built-in extop.
*/
struct {
char *oid;
SLAP_EXTOP_MAIN_FN ext_main;
} builtin_extops[] = {
#ifdef HAVE_TLS
{ LDAP_EXOP_START_TLS, starttls_extop },
#endif
{ LDAP_EXOP_X_MODIFY_PASSWD, passwd_extop },
{ NULL, NULL }
};
static extop_list_t *find_extop( extop_list_t *list, char *oid );
char *
get_supported_extop (int index)
{
extop_list_t *ext;
/* linear scan is slow, but this way doesn't force a
* big change on root_dse.c, where this routine is used.
*/
for (ext = supp_ext_list; ext != NULL && --index >= 0; ext = ext->next) ;
if (ext == NULL)
return(NULL);
return(ext->oid);
}
int
do_extended(
Connection *conn,
Operation *op
)
{
int rc = LDAP_SUCCESS;
char* reqoid;
struct berval *reqdata;
ber_tag_t tag;
ber_len_t len;
extop_list_t *ext;
const char *text;
struct berval **refs;
char *rspoid;
struct berval *rspdata;
LDAPControl **rspctrls;
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
"do_extended: conn %d\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
#endif
reqoid = NULL;
reqdata = NULL;
if( op->o_protocol < LDAP_VERSION3 ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
"do_extended: protocol version (%d) too low.\n", op->o_protocol ));
#else
Debug( LDAP_DEBUG_ANY, "do_extended: protocol version (%d) too low\n",
op->o_protocol, 0 ,0 );
#endif
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "requires LDAPv3" );
rc = -1;
goto done;
}
if ( ber_scanf( op->o_ber, "{a" /*}*/, &reqoid ) == LBER_ERROR ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
"do_extended: conn %d ber_scanf failed\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
#endif
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto done;
}
if( !(ext = find_extop(supp_ext_list, reqoid)) ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
"do_extended: conn %d unsupported operation \"%s\"\n",
conn->c_connid, reqoid ));
#else
Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n",
reqoid, 0 ,0 );
#endif
send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
NULL, "unsupported extended operation", NULL, NULL );
goto done;
}
tag = ber_peek_tag( op->o_ber, &len );
if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) {
if( ber_scanf( op->o_ber, "O", &reqdata ) == LBER_ERROR ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
"do_extended: conn %d ber_scanf failed\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
#endif
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto done;
}
}
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
"do_extended: conn %d get_ctrls failed\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 );
#endif
return rc;
}
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
"do_extended: conn %d oid=%d\n.", conn->c_connid, reqoid ));
#else
Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n", reqoid, 0 ,0 );
#endif
rspoid = NULL;
rspdata = NULL;
rspctrls = NULL;
text = NULL;
refs = NULL;
rc = (ext->ext_main)( conn, op,
reqoid, reqdata,
&rspoid, &rspdata, &rspctrls, &text, &refs );
if( rc != SLAPD_ABANDON ) {
if ( rc == LDAP_REFERRAL && refs == NULL ) {
refs = referral_rewrite( default_referral,
NULL, NULL, LDAP_SCOPE_DEFAULT );
}
send_ldap_extended( conn, op, rc, NULL, text, refs,
rspoid, rspdata, rspctrls );
ber_bvecfree( refs );
}
if ( rspoid != NULL ) {
free( rspoid );
}
if ( rspdata != NULL )
ber_bvfree( rspdata );
done:
if ( reqdata != NULL ) {
ber_bvfree( reqdata );
}
if ( reqoid != NULL ) {
free( reqoid );
}
return rc;
}
int
load_extop(
const char *ext_oid,
SLAP_EXTOP_MAIN_FN ext_main )
{
extop_list_t *ext;
if( ext_oid == NULL || *ext_oid == '\0' ) return -1;
if(!ext_main) return -1;
ext = ch_calloc(1, sizeof(extop_list_t));
if (ext == NULL)
return(-1);
ext->oid = ch_strdup( ext_oid );
if (ext->oid == NULL) {
free(ext);
return(-1);
}
ext->ext_main = ext_main;
ext->next = supp_ext_list;
supp_ext_list = ext;
return(0);
}
int
extops_init (void)
{
int i;
for (i = 0; builtin_extops[i].oid != NULL; i++) {
load_extop(builtin_extops[i].oid, builtin_extops[i].ext_main);
}
return(0);
}
int
extops_kill (void)
{
extop_list_t *ext;
/* we allocated the memory, so we have to free it, too. */
while ((ext = supp_ext_list) != NULL) {
supp_ext_list = ext->next;
if (ext->oid != NULL)
ch_free(ext->oid);
ch_free(ext);
}
return(0);
}
static extop_list_t *
find_extop( extop_list_t *list, char *oid )
{
extop_list_t *ext;
for (ext = list; ext; ext = ext->next) {
if (strcmp(ext->oid, oid) == 0)
return(ext);
}
return(NULL);
}