/* $NetBSD: denyop.c,v 1.3 2021/08/14 16:14:51 christos Exp $ */
/* denyop.c - Denies operations */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2004-2021 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was initially developed by Pierangelo Masarati for inclusion in
* OpenLDAP Software.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: denyop.c,v 1.3 2021/08/14 16:14:51 christos Exp $");
#include "portable.h"
#ifdef SLAPD_OVER_DENYOP
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
/* This overlay provides a quick'n'easy way to deny selected operations
* for a database whose backend implements the operations. It is intended
* to be less expensive than ACLs because its evaluation occurs before
* any backend specific operation is actually even initiated.
*/
enum {
denyop_add = 0,
denyop_bind,
denyop_compare,
denyop_delete,
denyop_extended,
denyop_modify,
denyop_modrdn,
denyop_search,
denyop_unbind
} denyop_e;
typedef struct denyop_info {
int do_op[denyop_unbind + 1];
} denyop_info;
static int
denyop_func( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
denyop_info *oi = (denyop_info *)on->on_bi.bi_private;
int deny = 0;
switch( op->o_tag ) {
case LDAP_REQ_BIND:
deny = oi->do_op[denyop_bind];
break;
case LDAP_REQ_ADD:
deny = oi->do_op[denyop_add];
break;
case LDAP_REQ_DELETE:
deny = oi->do_op[denyop_delete];
break;
case LDAP_REQ_MODRDN:
deny = oi->do_op[denyop_modrdn];
break;
case LDAP_REQ_MODIFY:
deny = oi->do_op[denyop_modify];
break;
case LDAP_REQ_COMPARE:
deny = oi->do_op[denyop_compare];
break;
case LDAP_REQ_SEARCH:
deny = oi->do_op[denyop_search];
break;
case LDAP_REQ_EXTENDED:
deny = oi->do_op[denyop_extended];
break;
case LDAP_REQ_UNBIND:
deny = oi->do_op[denyop_unbind];
break;
}
if ( !deny ) {
return SLAP_CB_CONTINUE;
}
op->o_bd->bd_info = (BackendInfo *)on->on_info;
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"operation not allowed within namingContext" );
return 0;
}
static int
denyop_over_init(
BackendDB *be, ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
denyop_info *oi;
oi = (denyop_info *)ch_malloc(sizeof(denyop_info));
memset(oi, 0, sizeof(denyop_info));
on->on_bi.bi_private = oi;
return 0;
}
static int
denyop_config(
BackendDB *be,
const char *fname,
int lineno,
int argc,
char **argv
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
denyop_info *oi = (denyop_info *)on->on_bi.bi_private;
if ( strcasecmp( argv[0], "denyop" ) == 0 ) {
char *op;
if ( argc != 2 ) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"operation list missing in "
"\"denyop <op-list>\" line.\n",
fname, lineno );
return( 1 );
}
/* The on->on_bi.bi_private pointer can be used for
* anything this instance of the overlay needs.
*/
op = argv[1];
do {
char *next = strchr( op, ',' );
if ( next ) {
next[0] = '\0';
next++;
}
if ( strcmp( op, "add" ) == 0 ) {
oi->do_op[denyop_add] = 1;
} else if ( strcmp( op, "bind" ) == 0 ) {
oi->do_op[denyop_bind] = 1;
} else if ( strcmp( op, "compare" ) == 0 ) {
oi->do_op[denyop_compare] = 1;
} else if ( strcmp( op, "delete" ) == 0 ) {
oi->do_op[denyop_delete] = 1;
} else if ( strcmp( op, "extended" ) == 0 ) {
oi->do_op[denyop_extended] = 1;
} else if ( strcmp( op, "modify" ) == 0 ) {
oi->do_op[denyop_modify] = 1;
} else if ( strcmp( op, "modrdn" ) == 0 ) {
oi->do_op[denyop_modrdn] = 1;
} else if ( strcmp( op, "search" ) == 0 ) {
oi->do_op[denyop_search] = 1;
} else if ( strcmp( op, "unbind" ) == 0 ) {
oi->do_op[denyop_unbind] = 1;
} else {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"unknown operation \"%s\" at "
"\"denyop <op-list>\" line.\n",
fname, lineno, op );
return( 1 );
}
op = next;
} while ( op );
} else {
return SLAP_CONF_UNKNOWN;
}
return 0;
}
static int
denyop_destroy(
BackendDB *be, ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
denyop_info *oi = (denyop_info *)on->on_bi.bi_private;
if ( oi ) {
ch_free( oi );
}
return 0;
}
/* This overlay is set up for dynamic loading via moduleload. For static
* configuration, you'll need to arrange for the slap_overinst to be
* initialized and registered by some other function inside slapd.
*/
static slap_overinst denyop;
int
denyop_initialize( void )
{
memset( &denyop, 0, sizeof( slap_overinst ) );
denyop.on_bi.bi_type = "denyop";
denyop.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
denyop.on_bi.bi_db_init = denyop_over_init;
denyop.on_bi.bi_db_config = denyop_config;
denyop.on_bi.bi_db_destroy = denyop_destroy;
denyop.on_bi.bi_op_bind = denyop_func;
denyop.on_bi.bi_op_search = denyop_func;
denyop.on_bi.bi_op_compare = denyop_func;
denyop.on_bi.bi_op_modify = denyop_func;
denyop.on_bi.bi_op_modrdn = denyop_func;
denyop.on_bi.bi_op_add = denyop_func;
denyop.on_bi.bi_op_delete = denyop_func;
denyop.on_bi.bi_extended = denyop_func;
denyop.on_bi.bi_op_unbind = denyop_func;
denyop.on_response = NULL /* denyop_response */ ;
return overlay_register( &denyop );
}
#if SLAPD_OVER_DENYOP == SLAPD_MOD_DYNAMIC
int
init_module( int argc, char *argv[] )
{
return denyop_initialize();
}
#endif /* SLAPD_OVER_DENYOP == SLAPD_MOD_DYNAMIC */
#endif /* defined(SLAPD_OVER_DENYOP) */