Added variable olcDelayChecks that forces some syntax checks to be postponed until...
authorNadezhda Ivanova <nivanova@symas.com>
Fri, 28 Feb 2014 15:06:47 +0000 (17:06 +0200)
committerNadezhda Ivanova <nivanova@symas.com>
Sat, 19 Jul 2014 20:07:15 +0000 (23:07 +0300)
contrib/slapd-modules/samba4/Makefile
contrib/slapd-modules/samba4/syntax_checks.c [new file with mode: 0644]
servers/slapd/add.c
servers/slapd/bconfig.c
servers/slapd/modify.c
servers/slapd/proto-slap.h
servers/slapd/slap.h

index a7cf7cbc32fe26778c1192951711f2c4155d4f1c..01ef3fd93cf784281d777dbd66cbd26366e56c73 100644 (file)
@@ -24,11 +24,13 @@ OPT = -g -O2 -Wall
 DEFS = -DSLAPD_OVER_RDNVAL=SLAPD_MOD_DYNAMIC \
        -DSLAPD_OVER_PGUID=SLAPD_MOD_DYNAMIC \
        -DSLAPD_OVER_VERNUM=SLAPD_MOD_DYNAMIC \
-       -DSLAPD_OVER_INSTANCETYPE=SLAPD_MOD_DYNAMIC
+       -DSLAPD_OVER_INSTANCETYPE=SLAPD_MOD_DYNAMIC \
+       -DSLAPD_OVER_SYNTAXCHECKS=SLAPD_MOD_DYNAMIC
+
 INCS = $(LDAP_INC)
 LIBS = $(LDAP_LIB)
 
-PROGRAMS = pguid.la rdnval.la vernum.la instancetype.la
+PROGRAMS = pguid.la rdnval.la vernum.la instancetype.la syntax_checks.la
 LTVER = 0:0:0
 
 prefix=/usr/local
@@ -62,6 +64,11 @@ instancetype.la: instancetype.lo
        $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
        -rpath $(moduledir) -module -o $@ $? $(LIBS)
 
+syntax_checks.la: syntax_checks.lo
+       $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
+       -rpath $(moduledir) -module -o $@ $? $(LIBS)
+
+
 clean:
        rm -rf *.o *.lo *.la .libs
 
diff --git a/contrib/slapd-modules/samba4/syntax_checks.c b/contrib/slapd-modules/samba4/syntax_checks.c
new file mode 100644 (file)
index 0000000..77ce1f5
--- /dev/null
@@ -0,0 +1,71 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2013 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>.
+ */
+
+/* This is a simple overlay to perform the syntax checks usually
+   performed before the request is passed to the frontend.
+   This is necessary so the overlays above could handle errors and
+   return required non-standard error codes */
+
+#include "portable.h"
+
+#ifdef SLAPD_OVER_SYNTAXCHECKS
+
+#include <stdio.h>
+
+#include "ac/string.h"
+#include "ac/socket.h"
+
+#include "slap.h"
+#include "config.h"
+
+#include "lutil.h"
+#include "ldap_rq.h"
+
+static slap_overinst           syntax_checks;
+
+
+static int syntax_checks_do_check( Operation *op, SlapReply *rs )
+{
+       char            textbuf[ SLAP_TEXT_BUFLEN ];
+       size_t          textlen = sizeof( textbuf );
+       if (SLAP_DB_DELAY_CHECKS(op->o_bd)) {
+               rs->sr_err = slap_mods_final_check( op, op->ora_modlist,
+                                                   textbuf, textlen, NULL );
+               if (rs->sr_err != LDAP_SUCCESS) {
+                       send_ldap_error( op, rs, rs->sr_err, textbuf );
+                       return rs->sr_err;
+               }
+       }
+       return SLAP_CB_CONTINUE;
+}
+
+int syntax_checks_initialize(void)
+{
+        syntax_checks.on_bi.bi_type = "syntax_checks";
+       syntax_checks.on_bi.bi_op_add = syntax_checks_do_check;
+       syntax_checks.on_bi.bi_op_modify = syntax_checks_do_check;
+       Debug(LDAP_DEBUG_TRACE, ("syntax_checks_initialize\n"),0,0,0);
+       return overlay_register(&syntax_checks);
+}
+
+
+#if SLAPD_OVER_SYNTAXCHECKS == SLAPD_MOD_DYNAMIC
+int init_module( int argc, char *argv[] )
+{
+       return syntax_checks_initialize();
+}
+#endif /* SLAPD_OVER_SYNTAXCHECKS == SLAPD_MOD_DYNAMIC */
+
+#endif /*SLAPD_OVER_SYNTAXCHECKS*/
index 41ae59cf180ce4d90f13d3754721c4221f92bc12..afeba33a64c222e44199f71687e6e4cb4f1dee39 100644 (file)
@@ -22,7 +22,6 @@
  * software without specific prior written permission. This software
  * is provided ``as is'' without express or implied warranty.
  */
-
 #include "portable.h"
 
 #include <stdio.h>
@@ -49,7 +48,7 @@ do_add( Operation *op, SlapReply *rs )
        int             rc = 0;
        int             freevals = 1;
        OpExtraDB oex;
-
+       BackendDB *t_db = NULL;
        Debug( LDAP_DEBUG_TRACE, "%s do_add\n",
                op->o_log_prefix, 0, 0 );
 
@@ -165,14 +164,19 @@ do_add( Operation *op, SlapReply *rs )
                goto done;
        }
 
-       rs->sr_err = slap_mods_check( op, modlist, &rs->sr_text,
-               textbuf, textlen, NULL );
+       t_db = select_backend( &op->o_req_dn, 0 );
+       if (t_db && SLAP_DB_DELAY_CHECKS(t_db)) {
+               rs->sr_err = slap_mods_initial_check( op, modlist, &rs->sr_text,
+                       textbuf, textlen, NULL );
+       } else {
+               rs->sr_err = slap_mods_check( op, modlist, &rs->sr_text,
+                                                     textbuf, textlen, NULL );
+       }
 
        if ( rs->sr_err != LDAP_SUCCESS ) {
                send_ldap_result( op, rs );
                goto done;
        }
-
        /* temporary; remove if not invoking backend function */
        op->ora_modlist = modlist;
 
index ded66131b45b1d218114d15684c41e9da0495458..518e969b045af950baa2a8e4593efcad8af555d8 100644 (file)
@@ -200,6 +200,7 @@ enum {
        CFG_DISABLED,
        CFG_THREADQS,
        CFG_TLS_ECNAME,
+       CFG_DELAY_CHECKS,
 
        CFG_LAST
 };
@@ -807,6 +808,9 @@ static ConfigTable config_back_cf_table[] = {
        { "writetimeout", "timeout", 2, 2, 0, ARG_INT,
                &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+       { "delay-checks", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_DELAY_CHECKS,
+               &config_generic, "( OLcfgDbAt:0.22 NAME 'olcDelayChecks' "
+                       "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
        { NULL, NULL, 0, 0, 0, ARG_IGNORED,
                NULL, NULL, NULL, NULL }
 };
@@ -896,7 +900,7 @@ static ConfigOCs cf_ocs[] = {
                 "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
                 "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ "
                 "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ "
-                "olcMonitoring $ olcExtraAttrs ) )",
+                "olcMonitoring $ olcExtraAttrs $ olcDelayChecks ) )",
                        Cft_Database, NULL, cfAddDatabase },
        { "( OLcfgGlOc:5 "
                "NAME 'olcOverlayConfig' "
@@ -1327,6 +1331,13 @@ config_generic(ConfigArgs *c) {
                        if ( !c->rvalue_vals ) rc = 1;
                        break;
 #endif
+               case CFG_DELAY_CHECKS:
+                       if ( SLAP_DB_DELAY_CHECKS( c->be )) {
+                               c->value_int = 1;
+                       } else {
+                               rc = 1;
+                       }
+                       break;
                default:
                        rc = 1;
                }
@@ -1648,6 +1659,9 @@ config_generic(ConfigArgs *c) {
                        }
                        break;
 
+               case CFG_DELAY_CHECKS:
+                       c->be->be_flags &= ~SLAP_DBFLAG_DELAYCHECKS;
+                       break;
                case CFG_ATOPT:
                        /* FIXME: there is no ad_option_free function */
                case CFG_ROOTDSE:
@@ -2370,7 +2384,12 @@ sortval_reject:
                        }
 #endif
 
-
+               case CFG_DELAY_CHECKS:
+                       if (c->value_int)
+                               SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_DELAYCHECKS;
+                       else
+                               SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_DELAYCHECKS;
+                       break;
                default:
                        Debug( LDAP_DEBUG_ANY,
                                "%s: unknown CFG_TYPE %d.\n",
index 8958a581dee382a9c235640d650c1cdcfc5e300e..c7c94d78835ce9c0b0ff73ca173dffb12bc9c679 100644 (file)
@@ -22,7 +22,6 @@
  * software without specific prior written permission. This software
  * is provided ``as is'' without express or implied warranty.
  */
-
 #include "portable.h"
 
 #include <stdio.h>
@@ -164,10 +163,13 @@ do_modify(
                }
        }
 #endif /* LDAP_DEBUG */
-
+       if (!SLAP_DB_DELAY_CHECKS(frontendDB)) {
        rs->sr_err = slap_mods_check( op, op->orm_modlist,
-               &rs->sr_text, textbuf, textlen, NULL );
-
+                       &rs->sr_text, textbuf, textlen, NULL );
+       } else {
+               rs->sr_err = slap_mods_initial_check( op, op->orm_modlist,
+                                                     &rs->sr_text, textbuf, textlen, NULL );
+       }
        if ( rs->sr_err != LDAP_SUCCESS ) {
                send_ldap_result( op, rs );
                goto cleanup;
@@ -456,7 +458,6 @@ int slap_mods_check(
        void *ctx )
 {
        int rc;
-
        for( ; ml != NULL; ml = ml->sml_next ) {
                AttributeDescription *ad = NULL;
 
@@ -668,6 +669,230 @@ int slap_mods_check(
        return LDAP_SUCCESS;
 }
 
+/* slap_mods_check divided in two parts,
+ * the checks that should return non-standard or module-specific error codes
+ * will be moved ot slap_mods_final_check and invoked in an overlay at the bottom of the stack
+ */
+int slap_mods_initial_check(
+       Operation *op,
+       Modifications *ml,
+       const char **text,
+       char *textbuf,
+       size_t textlen,
+       void *ctx )
+{
+       int rc;
+       for( ; ml != NULL; ml = ml->sml_next ) {
+               AttributeDescription *ad = NULL;
+
+               /* convert to attribute description */
+               if ( ml->sml_desc == NULL ) {
+                       rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
+                       if( rc != LDAP_SUCCESS ) {
+                               if ( get_no_schema_check( op )) {
+                                       rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc,
+                                               text, 0 );
+                               }
+                       }
+                       if( rc != LDAP_SUCCESS ) {
+                               snprintf( textbuf, textlen, "%s: %s",
+                                       ml->sml_type.bv_val, *text );
+                               *text = textbuf;
+                               return rc;
+                       }
+               }
+
+               ad = ml->sml_desc;
+
+               if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
+                       && !slap_ad_is_binary( ad ))
+               {
+                       /* attribute requires binary transfer */
+                       snprintf( textbuf, textlen,
+                               "%s: requires ;binary transfer",
+                               ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_UNDEFINED_TYPE;
+               }
+
+               if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
+                       && slap_ad_is_binary( ad ))
+               {
+                       /* attribute does not require binary transfer */
+                       snprintf( textbuf, textlen,
+                               "%s: disallows ;binary transfer",
+                               ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_UNDEFINED_TYPE;
+               }
+
+               if( slap_ad_is_tag_range( ad )) {
+                       /* attribute requires binary transfer */
+                       snprintf( textbuf, textlen,
+                               "%s: inappropriate use of tag range option",
+                               ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_UNDEFINED_TYPE;
+               }
+
+               if ( ml->sml_op == LDAP_MOD_INCREMENT &&
+#ifdef SLAPD_REAL_SYNTAX
+                       !is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) &&
+#endif
+                       !is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) )
+               {
+                       /*
+                        * attribute values must be INTEGER or REAL
+                        */
+                       snprintf( textbuf, textlen,
+                               "%s: attribute syntax inappropriate for increment",
+                               ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_CONSTRAINT_VIOLATION;
+               }
+
+               /*
+                * check values
+                */
+               if( ml->sml_values != NULL ) {
+                       ber_len_t nvals;
+                       slap_syntax_validate_func *validate =
+                               ad->ad_type->sat_syntax->ssyn_validate;
+                       slap_syntax_transform_func *pretty =
+                               ad->ad_type->sat_syntax->ssyn_pretty;
+
+                       if( !pretty && !validate ) {
+                               *text = "no validator for syntax";
+                               snprintf( textbuf, textlen,
+                                       "%s: no validator for syntax %s",
+                                       ml->sml_type.bv_val,
+                                       ad->ad_type->sat_syntax->ssyn_oid );
+                               *text = textbuf;
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+                       /*
+                        * check that each value is valid per syntax
+                        *      and pretty if appropriate
+                        */
+                       for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
+                               struct berval pval;
+
+                               if ( pretty ) {
+                                       rc = ordered_value_pretty( ad,
+                                               &ml->sml_values[nvals], &pval, ctx );
+                               } else {
+                                       rc = ordered_value_validate( ad,
+                                               &ml->sml_values[nvals], ml->sml_op );
+                               }
+
+                               if( rc != 0 ) {
+                                       snprintf( textbuf, textlen,
+                                               "%s: value #%ld invalid per syntax",
+                                               ml->sml_type.bv_val, (long) nvals );
+                                       *text = textbuf;
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+
+                               if( pretty ) {
+                                       ber_memfree_x( ml->sml_values[nvals].bv_val, ctx );
+                                       ml->sml_values[nvals] = pval;
+                               }
+                       }
+                       ml->sml_values[nvals].bv_len = 0;
+                       ml->sml_numvals = nvals;
+
+
+                       /* if the type has a normalizer, generate the
+                        * normalized values. otherwise leave them NULL.
+                        *
+                        * this is different from the rule for attributes
+                        * in an entry - in an attribute list, the normalized
+                        * value is set equal to the non-normalized value
+                        * when there is no normalizer.
+                        */
+                       if( nvals && ad->ad_type->sat_equality &&
+                               ad->ad_type->sat_equality->smr_normalize )
+                       {
+                               ml->sml_nvalues = ber_memalloc_x(
+                                       (nvals+1)*sizeof(struct berval), ctx );
+
+                               for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
+                                       rc = ordered_value_normalize(
+                                               SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+                                               ad,
+                                               ad->ad_type->sat_equality,
+                                               &ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
+                                       if ( rc ) {
+                                               Debug( LDAP_DEBUG_ANY,
+                                                       "<= str2entry NULL (ssyn_normalize %d)\n",
+                                                       rc, 0, 0 );
+                                               snprintf( textbuf, textlen,
+                                                       "%s: value #%ld normalization failed",
+                                                       ml->sml_type.bv_val, (long) nvals );
+                                               *text = textbuf;
+                                               BER_BVZERO( &ml->sml_nvalues[nvals] );
+                                               return rc;
+                                       }
+                               }
+
+                               BER_BVZERO( &ml->sml_nvalues[nvals] );
+                       }
+
+                       /* check for duplicates, but ignore Deletes.
+                        */
+                       if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
+                               int i;
+                               rc = slap_sort_vals( ml, text, &i, ctx );
+                               if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
+                                       /* value exists already */
+                                       snprintf( textbuf, textlen,
+                                               "%s: value #%d provided more than once",
+                                               ml->sml_desc->ad_cname.bv_val, i );
+                                       *text = textbuf;
+                               }
+                               if ( rc )
+                                       return rc;
+                       }
+               } else {
+                       ml->sml_numvals = 0;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+int slap_mods_final_check(
+       Operation *op,
+       Modifications *ml,
+       char *textbuf,
+       size_t textlen,
+       void *ctx )
+{
+       for( ; ml != NULL; ml = ml->sml_next ) {
+/*
+ * a rough single value check... an additional check is needed
+ * to catch add of single value to existing single valued attribute
+ */
+               if ( ml->sml_values != NULL ) {
+                       ber_len_t nvals = 0;
+                       while (!BER_BVISNULL( &ml->sml_values[nvals])) {
+                                       nvals++;
+                               }
+                       if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
+                           && nvals > 1 && is_at_single_value( ml->sml_desc->ad_type ))
+                       {
+                               snprintf( textbuf, textlen,
+                                         "%s: multiple values provided",
+                                         ml->sml_type.bv_val );
+                               return LDAP_CONSTRAINT_VIOLATION;
+                       }
+               }
+       }
+       return LDAP_SUCCESS;
+}
+
+
 /* Sort a set of values. An (Attribute *) may be used interchangeably here
  * instead of a (Modifications *) structure.
  *
index c112e2fbaab940a733bbfbd4b9341433ef743840..8b263b2470c70e725c72979c4505d99a4a806717 100644 (file)
@@ -1284,6 +1284,17 @@ LDAP_SLAPD_F( int ) slap_mods_check(
        const char **text,
        char *textbuf, size_t textlen, void *ctx );
 
+LDAP_SLAPD_F( int ) slap_mods_initial_check(
+       Operation *op,
+       Modifications *ml,
+       const char **text,
+       char *textbuf, size_t textlen, void *ctx );
+
+LDAP_SLAPD_F( int ) slap_mods_final_check(
+       Operation *op,
+       Modifications *ml,
+       char *textbuf, size_t textlen, void *ctx );
+
 LDAP_SLAPD_F( int ) slap_sort_vals(
        Modifications *ml,
        const char **text,
index 6ba87ca5d357ccbd787b8f0b3e2bd90406449732..1e0d0fd60170f4a6fc605b17db2049ff5abab811 100644 (file)
@@ -1854,6 +1854,7 @@ struct BackendDB {
 #define SLAP_DBFLAG_SYNC_SUBENTRY      0x40000U /* use subentry for context */
 #define SLAP_DBFLAG_MULTI_SHADOW       0x80000U /* uses mirrorMode/multi-master */
 #define SLAP_DBFLAG_DISABLED   0x100000U
+#define SLAP_DBFLAG_DELAYCHECKS                0x200000U /* delay some preliminary syntax checks till the bottom of overlay stack */
        slap_mask_t     be_flags;
 #define SLAP_DBFLAGS(be)                       ((be)->be_flags)
 #define SLAP_NOLASTMOD(be)                     (SLAP_DBFLAGS(be) & SLAP_DBFLAG_NOLASTMOD)
@@ -1882,6 +1883,7 @@ struct BackendDB {
 #define SLAP_DBCLEAN(be)                       (SLAP_DBFLAGS(be) & SLAP_DBFLAG_CLEAN)
 #define SLAP_DBACL_ADD(be)                     (SLAP_DBFLAGS(be) & SLAP_DBFLAG_ACL_ADD)
 #define SLAP_SYNC_SUBENTRY(be)                 (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SYNC_SUBENTRY)
+#define SLAP_DB_DELAY_CHECKS(be)               (SLAP_DBFLAGS(be) & SLAP_DBFLAG_DELAYCHECKS)
 
        slap_mask_t     be_restrictops;         /* restriction operations */
 #define SLAP_RESTRICT_OP_ADD           0x0001U