diff options
author | Nathan Kinder <nkinder@redhat.com> | 2009-05-08 09:14:42 -0700 |
---|---|---|
committer | Nathan Kinder <nkinder@redhat.com> | 2009-05-08 09:14:42 -0700 |
commit | d19eafcd211d89cffdac1b2c3432087443e7d122 (patch) | |
tree | 26d2b7f956c2ceaa3f605a42552a113e156b5b30 /ldap/servers/slapd | |
parent | 5d3d883251dd15cf719181e33fb6954454869822 (diff) | |
download | ds-d19eafcd211d89cffdac1b2c3432087443e7d122.tar.gz ds-d19eafcd211d89cffdac1b2c3432087443e7d122.tar.xz ds-d19eafcd211d89cffdac1b2c3432087443e7d122.zip |
Added capability to validate syntax of values being added to the database. Also added numericstring syntax support.
For more details, see the design doc at http://directory.fedoraproject.org/wiki/Syntax_Validation_Design
Diffstat (limited to 'ldap/servers/slapd')
-rw-r--r-- | ldap/servers/slapd/add.c | 10 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/import-threads.c | 22 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/ldbm_add.c | 9 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/ldbm_modify.c | 14 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 11 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldif/add.c | 7 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldif/modify.c | 7 | ||||
-rw-r--r-- | ldap/servers/slapd/config.c | 34 | ||||
-rw-r--r-- | ldap/servers/slapd/dse.c | 23 | ||||
-rw-r--r-- | ldap/servers/slapd/fedse.c | 11 | ||||
-rw-r--r-- | ldap/servers/slapd/libglobs.c | 59 | ||||
-rw-r--r-- | ldap/servers/slapd/pblock.c | 12 | ||||
-rw-r--r-- | ldap/servers/slapd/plugin.c | 16 | ||||
-rw-r--r-- | ldap/servers/slapd/plugin_syntax.c | 177 | ||||
-rw-r--r-- | ldap/servers/slapd/proto-slap.h | 4 | ||||
-rw-r--r-- | ldap/servers/slapd/schema.c | 4 | ||||
-rw-r--r-- | ldap/servers/slapd/slap.h | 22 | ||||
-rw-r--r-- | ldap/servers/slapd/slapi-plugin.h | 6 |
18 files changed, 416 insertions, 32 deletions
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c index b69da2e5..6607eff9 100644 --- a/ldap/servers/slapd/add.c +++ b/ldap/servers/slapd/add.c @@ -800,6 +800,16 @@ static void handle_fast_add(Slapi_PBlock *pb, Slapi_Entry *entry) return; } + /* syntax check */ + if (slapi_entry_syntax_check(pb, entry, 0) != 0) { + char *errtext; + LDAPDebug(LDAP_DEBUG_TRACE, "entry failed syntax check\n", 0, 0, 0); + slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext); + send_ldap_result(pb, LDAP_INVALID_SYNTAX, NULL, errtext, 0, NULL); + slapi_entry_free(entry); + return; + } + /* Check if the entry being added is a Tombstone. Could be if we are * doing a replica init. */ if (slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c index 7a1bcba1..7cde2bfc 100644 --- a/ldap/servers/slapd/back-ldbm/import-threads.c +++ b/ldap/servers/slapd/back-ldbm/import-threads.c @@ -534,9 +534,27 @@ void import_producer(void *param) "violates schema, ending line %d of file " "\"%s\"", escape_string(slapi_entry_get_dn(e), ebuf), curr_lineno, curr_filename); - if (e) + if (e) { + slapi_entry_free(e); + } + + job->skipped++; + continue; + } + + /* Check attribute syntax */ + if (slapi_entry_syntax_check(NULL, e, 0) != 0) + { + char ebuf[BUFSIZ]; + import_log_notice(job, "WARNING: skipping entry \"%s\" which " + "violates attribute syntax, ending line %d of " + "file \"%s\"", escape_string(slapi_entry_get_dn(e), ebuf), + curr_lineno, curr_filename); + if (e) { slapi_entry_free(e); - job->skipped++; + } + + job->skipped++; continue; } diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c index 764cff99..b9f573a7 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_add.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c @@ -305,6 +305,15 @@ ldbm_back_add( Slapi_PBlock *pb ) goto error_return; } + /* Check attribute syntax */ + if (slapi_entry_syntax_check(pb, e, 0) != 0) + { + LDAPDebug(LDAP_DEBUG_TRACE, "entry failed syntax check\n", 0, 0, 0); + ldap_result_code = LDAP_INVALID_SYNTAX; + slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); + goto error_return; + } + opcsn = operation_get_csn (operation); if(is_resurect_operation) { diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c index c169e9ed..1cbe92de 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c @@ -188,6 +188,7 @@ ldbm_back_modify( Slapi_PBlock *pb ) struct backentry *e, *ec = NULL; Slapi_Entry *postentry = NULL; LDAPMod **mods; + Slapi_Mods smods; back_txn txn; back_txnid parent_txn; int retval = -1; @@ -279,11 +280,10 @@ ldbm_back_modify( Slapi_PBlock *pb ) slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); /* The Plugin may have messed about with some of the PBlock parameters... ie. mods */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); + slapi_mods_init_byref(&smods,mods); { - Slapi_Mods smods; CSN *csn = operation_get_csn(operation); - slapi_mods_init_byref(&smods,mods); if ( (change_entry = mods_have_effect (ec->ep_entry, &smods)) ) { ldap_result_code = entry_apply_mods_wsi(ec->ep_entry, &smods, csn, operation_is_flag_set(operation,OP_FLAG_REPLICATED)); /* @@ -301,7 +301,6 @@ ldbm_back_modify( Slapi_PBlock *pb ) slapi_pblock_set ( pb, SLAPI_ENTRY_POST_OP, postentry ); postentry = NULL; /* avoid removal/free in error_return code */ } - slapi_mods_done(&smods); if ( !change_entry || ldap_result_code != 0 ) { /* change_entry == 0 is not an error, but we need to free lock etc */ goto error_return; @@ -340,6 +339,14 @@ ldbm_back_modify( Slapi_PBlock *pb ) goto error_return; } + /* check attribute syntax for the new values */ + if (slapi_mods_syntax_check(pb, mods, 0) != 0) + { + ldap_result_code = LDAP_INVALID_SYNTAX; + slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); + goto error_return; + } + /* * make sure the entry contains all values in the RDN. * if not, the modification must have removed them. @@ -506,6 +513,7 @@ error_return: common_return: + slapi_mods_done(&smods); if (ec_in_cache) { diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c index 1cb35ab8..c71dd8ee 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c @@ -530,6 +530,17 @@ ldbm_back_modrdn( Slapi_PBlock *pb ) goto error_return; } + /* Check attribute syntax if any new values are being added for the new RDN */ + if (slapi_mods_get_num_mods(&smods_operation_wsi)>0) + { + if (slapi_mods_syntax_check(pb, smods_generated_wsi.mods, 0) != 0) + { + ldap_result_code = LDAP_INVALID_SYNTAX; + slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); + goto error_return; + } + } + /* * Update the DN CSN of the entry. */ diff --git a/ldap/servers/slapd/back-ldif/add.c b/ldap/servers/slapd/back-ldif/add.c index 231f5483..27799973 100644 --- a/ldap/servers/slapd/back-ldif/add.c +++ b/ldap/servers/slapd/back-ldif/add.c @@ -92,6 +92,13 @@ ldif_back_add( Slapi_PBlock *pb ) return( -1 ); } + /* Check if the attribute values in the entry obey the syntaxes */ + if ( slapi_entry_syntax_check( pb, e, 0 ) != 0 ) { + LDAPDebug( LDAP_DEBUG_TRACE, "entry failed syntax_check\n", 0, 0, 0 ); + slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, NULL, 0, NULL ); + return( -1 ); + } + prev = NULL; /*Lock the database*/ diff --git a/ldap/servers/slapd/back-ldif/modify.c b/ldap/servers/slapd/back-ldif/modify.c index 58229ecc..7fff0670 100644 --- a/ldap/servers/slapd/back-ldif/modify.c +++ b/ldap/servers/slapd/back-ldif/modify.c @@ -140,6 +140,13 @@ ldif_back_modify( Slapi_PBlock *pb ) PR_Unlock( db->ldif_lock ); goto error_return; } + + /* Check if the attribute values in the mods obey the syntaxes */ + if ( slapi_mods_syntax_check( pb, mods, 0 ) != 0 ) { + slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + goto error_return; + } /* Check for abandon again */ if ( slapi_op_abandoned( pb ) ) { diff --git a/ldap/servers/slapd/config.c b/ldap/servers/slapd/config.c index 9cf56ddd..1af1b77b 100644 --- a/ldap/servers/slapd/config.c +++ b/ldap/servers/slapd/config.c @@ -239,11 +239,13 @@ slapd_bootstrap_config(const char *configdir) char _localuser[BUFSIZ]; char logenabled[BUFSIZ]; char schemacheck[BUFSIZ]; + char syntaxcheck[BUFSIZ]; + char syntaxlogging[BUFSIZ]; Slapi_DN plug_dn; workpath[0] = loglevel[0] = maxdescriptors[0] = '\0'; - val[0] = logenabled[0] = schemacheck[0] = '\0'; - _localuser[0] = '\0'; + val[0] = logenabled[0] = schemacheck[0] = syntaxcheck[0] = '\0'; + syntaxlogging[0] = _localuser[0] = '\0'; /* Convert LDIF to entry structures */ slapi_sdn_init_dn_byref(&plug_dn, PLUGIN_BASE_DN); @@ -460,6 +462,34 @@ slapd_bootstrap_config(const char *configdir) } } + /* see if we need to enable syntax checking */ + if (!syntaxcheck[0] && + entry_has_attr_and_value(e, CONFIG_SYNTAXCHECK_ATTRIBUTE, + syntaxcheck, sizeof(syntaxcheck))) + { + if (config_set_syntaxcheck(CONFIG_SYNTAXCHECK_ATTRIBUTE, + syntaxcheck, errorbuf, CONFIG_APPLY) + != LDAP_SUCCESS) + { + LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, + CONFIG_SYNTAXCHECK_ATTRIBUTE, errorbuf); + } + } + + /* see if we need to enable syntax warnings */ + if (!syntaxlogging[0] && + entry_has_attr_and_value(e, CONFIG_SYNTAXLOGGING_ATTRIBUTE, + syntaxlogging, sizeof(syntaxlogging))) + { + if (config_set_syntaxlogging(CONFIG_SYNTAXLOGGING_ATTRIBUTE, + syntaxlogging, errorbuf, CONFIG_APPLY) + != LDAP_SUCCESS) + { + LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, + CONFIG_SYNTAXLOGGING_ATTRIBUTE, errorbuf); + } + } + /* see if we need to expect quoted schema values */ if (entry_has_attr_and_value(e, CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, val, sizeof(val))) diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c index 4d593500..956c29d4 100644 --- a/ldap/servers/slapd/dse.c +++ b/ldap/servers/slapd/dse.c @@ -1864,6 +1864,17 @@ dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from thi return dse_modify_return( -1, ec, ecc ); } + /* Check if the attribute values in the mods obey the syntaxes */ + if ( slapi_mods_syntax_check( pb, mods, 0 ) != 0 ) + { + char *errtext; + + slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext); + slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, errtext, 0, NULL ); + slapi_sdn_done(&sdn); + return dse_modify_return( -1, ec, ecc ); + } + /* Change the entry itself both on disk and in the AVL tree */ /* dse_replace_entry free's the existing entry. */ if (dse_replace_entry( pdse, ecc, !dont_write_file, DSE_USE_LOCK )!=0 ) @@ -1941,6 +1952,18 @@ dse_add(Slapi_PBlock *pb) /* JCM There should only be one exit point from this f return error; } + /* Check if the attribute values in the entry obey the syntaxes */ + if ( slapi_entry_syntax_check( pb, e, 0 ) != 0 ) + { + char *errtext; + LDAPDebug( SLAPI_DSE_TRACELEVEL, + "dse_add: entry failed syntax check\n", 0, 0, 0 ); + slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext); + slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, errtext, 0, NULL ); + slapi_sdn_done(&sdn); + return error; + } + /* * Attempt to find this dn. */ diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c index f71b7fdd..beec7d5c 100644 --- a/ldap/servers/slapd/fedse.c +++ b/ldap/servers/slapd/fedse.c @@ -143,14 +143,7 @@ static const char *internal_entries[] = "objectclass:top\n" "objectclass:nsSNMP\n" "cn:SNMP\n" - "nsSNMPEnabled:on\n" - "nsSNMPName:\n" - "nsSNMPOrganization:\n" - "nsSNMPLocation:\n" - "nsSNMPContact:\n" - "nsSNMPDescription:\n" - "nsSNMPMasterHost:\n" - "nsSNMPMasterPort:\n" + "nsSNMPEnabled: on\n" "aci:(target=\"ldap:///cn=SNMP,cn=config\")(targetattr !=\"aci\")(version 3.0;acl \"snmp\";allow (read, search, compare)(userdn = \"ldap:///anyone\");)\n", }; @@ -161,7 +154,7 @@ static char *easter_egg_entry= "1E14405A150F47341F0E09191B0A1F5A3E13081F190E1508035A2E1F1B1756191447171514" "130E1508701518101F190E39161B0909405A0E150A701518101F190E39161B0909405A1508" "1D1B1413001B0E1315141B162F14130E701518101F190E39161B0909405A1E13081F190E15" -"0803040E1F1B17041F020E1F14091318161F041518101F190E70150F405A341F0E09191B0A" +"0803570E1F1B17571F020E1F14091318161F571518101F190E70150F405A341F0E09191B0A" "1F5A291F190F08130E035A2915160F0E1315140970150F405A341F0E09191B0A1F5A3E1308" "1F190E1508035A2E1F1B17701E1F091908130A0E131514405A3E1B0C131E5A3815081F121B" "17565A301B190B0F1F1613141F5A3815081F121B17565A3B140E121514035A3C15020D1508" diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index e473663c..30ad5f3a 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -321,6 +321,12 @@ static struct config_get_and_set { {CONFIG_SCHEMACHECK_ATTRIBUTE, config_set_schemacheck, NULL, 0, (void**)&global_slapdFrontendConfig.schemacheck, CONFIG_ON_OFF, NULL}, + {CONFIG_SYNTAXCHECK_ATTRIBUTE, config_set_syntaxcheck, + NULL, 0, + (void**)&global_slapdFrontendConfig.syntaxcheck, CONFIG_ON_OFF, NULL}, + {CONFIG_SYNTAXLOGGING_ATTRIBUTE, config_set_syntaxlogging, + NULL, 0, + (void**)&global_slapdFrontendConfig.syntaxlogging, CONFIG_ON_OFF, NULL}, {CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, config_set_ds4_compatible_schema, NULL, 0, (void**)&global_slapdFrontendConfig.ds4_compatible_schema, @@ -891,6 +897,8 @@ FrontendConfig_init () { cfg->sizelimit = SLAPD_DEFAULT_SIZELIMIT; cfg->timelimit = SLAPD_DEFAULT_TIMELIMIT; cfg->schemacheck = LDAP_ON; + cfg->syntaxcheck = LDAP_OFF; + cfg->syntaxlogging = LDAP_OFF; cfg->ds4_compatible_schema = LDAP_OFF; cfg->enquote_sup_oc = LDAP_OFF; cfg->lastmod = LDAP_ON; @@ -2422,6 +2430,33 @@ config_set_schemacheck( const char *attrname, char *value, char *errorbuf, int a return retVal; } +int +config_set_syntaxcheck( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + retVal = config_set_onoff ( attrname, + value, + &(slapdFrontendConfig->syntaxcheck), + errorbuf, + apply); + + return retVal; +} + +int +config_set_syntaxlogging( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + retVal = config_set_onoff ( attrname, + value, + &(slapdFrontendConfig->syntaxlogging), + errorbuf, + apply); + + return retVal; +} int config_set_ds4_compatible_schema( const char *attrname, char *value, char *errorbuf, int apply ) { @@ -4034,6 +4069,30 @@ config_get_schemacheck() { } int +config_get_syntaxcheck() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->syntaxcheck; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int +config_get_syntaxlogging() { + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->syntaxlogging; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int config_get_ds4_compatible_schema() { slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); int retVal; diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c index 6ac6aa8e..062a87f8 100644 --- a/ldap/servers/slapd/pblock.c +++ b/ldap/servers/slapd/pblock.c @@ -1072,6 +1072,12 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value ) case SLAPI_SYNTAX_SUBSTRLENS: (*(int **)value) = pblock->pb_substrlens; break; + case SLAPI_PLUGIN_SYNTAX_VALIDATE: + if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) { + return( -1 ); + } + (*(int *)value) = pblock->pb_plugin->plg_syntax_validate; + break; /* controls we know about */ case SLAPI_MANAGEDSAIT: @@ -2314,6 +2320,12 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value ) case SLAPI_SYNTAX_SUBSTRLENS: pblock->pb_substrlens = (int *) value; break; + case SLAPI_PLUGIN_SYNTAX_VALIDATE: + if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) { + return( -1 ); + } + pblock->pb_plugin->plg_syntax_validate = (IFP) value; + break; case SLAPI_ENTRY_PRE_OP: pblock->pb_pre_op_entry = (Slapi_Entry *) value; break; diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c index a7ad7dff..5ae63564 100644 --- a/ldap/servers/slapd/plugin.c +++ b/ldap/servers/slapd/plugin.c @@ -1878,35 +1878,37 @@ plugin_add_descriptive_attributes( Slapi_Entry *e, struct slapdplugin *plugin ) if ( NULL == plugin ) { + /* This can happen for things such as disabled syntax plug-ins. We + * just treat this as a warning to allow the description attributes + * to be set to a default value to avoid an objectclass violation. */ LDAPDebug(LDAP_DEBUG_PLUGIN, - "Error: failed to add descriptive values for plugin %s" - " (could not find plugin entry)\n", + "Warning: couldn't find plugin %s in global list. " + "Adding default descriptive values.\n", slapi_entry_get_dn_const(e), 0, 0 ); - return 1; /* failure */ } } if (add_plugin_description(e, ATTR_PLUGIN_PLUGINID, - plugin->plg_desc.spd_id)) + plugin ? plugin->plg_desc.spd_id : NULL)) { status = 1; } if (add_plugin_description(e, ATTR_PLUGIN_VERSION, - plugin->plg_desc.spd_version)) + plugin ? plugin->plg_desc.spd_version : NULL)) { status = 1; } if (add_plugin_description(e, ATTR_PLUGIN_VENDOR, - plugin->plg_desc.spd_vendor)) + plugin ? plugin->plg_desc.spd_vendor: NULL)) { status = 1; } if (add_plugin_description(e, ATTR_PLUGIN_DESC, - plugin->plg_desc.spd_description)) + plugin ? plugin->plg_desc.spd_description : NULL)) { status = 1; } diff --git a/ldap/servers/slapd/plugin_syntax.c b/ldap/servers/slapd/plugin_syntax.c index cb3cde9f..3290a954 100644 --- a/ldap/servers/slapd/plugin_syntax.c +++ b/ldap/servers/slapd/plugin_syntax.c @@ -261,6 +261,183 @@ plugin_call_syntax_filter_sub_sv( return( rc ); } +/* Checks if the values of all attributes in an entry are valid for the + * syntax specified for the attribute in question. Setting override to + * 1 will force syntax checking to be performed, even if syntax checking + * is disabled in the config. Setting override to 0 will obey the config + * settings. + * + * Returns 1 if there is a syntax violation and sets the error message + * appropriately. Returns 0 if everything checks out fine. + */ +int +slapi_entry_syntax_check( + Slapi_PBlock *pb, Slapi_Entry *e, int override +) +{ + int ret = 0; + int i = 0; + int is_replicated_operation = 0; + int badval = 0; + int syntaxcheck = config_get_syntaxcheck(); + int syntaxlogging = config_get_syntaxlogging(); + Slapi_Attr *prevattr = NULL; + Slapi_Attr *a = NULL; + char errtext[ BUFSIZ ]; + char *errp = &errtext[0]; + size_t err_remaining = sizeof(errtext); + + if (pb != NULL) { + slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation); + } + + /* If syntax checking and logging are off, or if this is a + * replicated operation, just return that the syntax is OK. */ + if (((syntaxcheck == 0) && (syntaxlogging == 0) && (override == 0)) || + is_replicated_operation) { + goto exit; + } + + i = slapi_entry_first_attr(e, &a); + + while ((-1 != i) && a && (a->a_plugin != NULL)) { + /* If no validate function is available for this type, just + * assume that the value is valid. */ + if ( a->a_plugin->plg_syntax_validate != NULL ) { + int numvals = 0; + + slapi_attr_get_numvalues(a, &numvals); + if ( numvals > 0 ) { + Slapi_Value *val = NULL; + const struct berval *bval = NULL; + int hint = slapi_attr_first_value(a, &val); + + /* iterate through each value to check if it's valid */ + while (val != NULL) { + bval = slapi_value_get_berval(val); + if ((a->a_plugin->plg_syntax_validate( bval )) != 0) { + if (syntaxlogging) { + slapi_log_error( SLAPI_LOG_FATAL, "Syntax Check", + "\"%s\": (%s) value #%d invalid per syntax\n", + slapi_entry_get_dn(e), a->a_type, hint ); + } + + if (syntaxcheck || override) { + if (pb) { + /* Append new text to any existing text. */ + errp += PR_snprintf( errp, err_remaining, + "%s: value #%d invalid per syntax\n", a->a_type, hint ); + err_remaining -= errp - &errtext[0]; + } + ret = 1; + } + } + + hint = slapi_attr_next_value(a, hint, &val); + } + } + } + + prevattr = a; + i = slapi_entry_next_attr(e, prevattr, &a); + } + + /* See if we need to set the error text in the pblock. */ + if (errp != &errtext[0]) { + slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext ); + } + +exit: + return( ret ); +} + +/* Checks if the values of all attributes being added in a Slapi_Mods + * are valid for the syntax specified for the attribute in question. + * The new values in an add or replace modify operation and the newrdn + * value for a modrdn operation will be checked. + * Returns 1 if there is a syntax violation and sets the error message + * appropriately. Returns 0 if everything checks out fine. + */ +int +slapi_mods_syntax_check( + Slapi_PBlock *pb, LDAPMod **mods, int override +) +{ + int ret = 0; + int i, j = 0; + int is_replicated_operation = 0; + int badval = 0; + int syntaxcheck = config_get_syntaxcheck(); + int syntaxlogging = config_get_syntaxlogging(); + char errtext[ BUFSIZ ]; + char *errp = &errtext[0]; + size_t err_remaining = sizeof(errtext); + char *dn = NULL; + LDAPMod *mod = NULL; + + if (mods == NULL) { + ret = 1; + goto exit; + } + + if (pb != NULL) { + slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation); + slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn); + } + + /* If syntax checking and logging are off, or if this is a + * replicated operation, just return that the syntax is OK. */ + if (((syntaxcheck == 0) && (syntaxlogging == 0) && (override == 0)) || + is_replicated_operation) { + goto exit; + } + + /* Loop through mods */ + for (i = 0; mods[i] != NULL; i++) { + mod = mods[i]; + + /* We only care about replace and add modify operations that + * are truly adding new values to the entry. */ + if ((SLAPI_IS_MOD_REPLACE(mod->mod_op) || SLAPI_IS_MOD_ADD(mod->mod_op)) && + (mod->mod_bvalues != NULL)) { + struct slapdplugin *syntax_plugin = NULL; + + /* Find the plug-in for this type, then call it's + * validate function.*/ + slapi_attr_type2plugin(mod->mod_type, (void **)&syntax_plugin); + if ((syntax_plugin != NULL) && (syntax_plugin->plg_syntax_validate != NULL)) { + /* Loop through the values and validate each one */ + for (j = 0; mod->mod_bvalues[j] != NULL; j++) { + if (syntax_plugin->plg_syntax_validate(mod->mod_bvalues[j]) != 0) { + if (syntaxlogging) { + slapi_log_error( SLAPI_LOG_FATAL, "Syntax Check", "\"%s\": (%s) value #%d invalid per syntax\n", + dn ? dn : "NULL", mod->mod_type, j ); + } + + if (syntaxcheck || override) { + if (pb) { + /* Append new text to any existing text. */ + errp += PR_snprintf( errp, err_remaining, + "%s: value #%d invalid per syntax\n", mod->mod_type, j ); + err_remaining -= errp - &errtext[0]; + } + ret = 1; + } + } + } + } + } + } + + /* See if we need to set the error text in the pblock. */ + if (errp != &errtext[0]) { + slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext ); + } + +exit: + return( ret ); +} + SLAPI_DEPRECATED int slapi_call_syntax_values2keys( /* JCM SLOW FUNCTION */ void *vpi, diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 7c25b18d..c561196d 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -264,6 +264,8 @@ int config_set_accesscontrol( const char *attrname, char *value, char *errorbuf, int config_set_security( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_readonly( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_schemacheck( const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_syntaxcheck( const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_syntaxlogging( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_ds4_compatible_schema( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_schema_ignore_trailing_spaces( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_rootdn( const char *attrname, char *value, char *errorbuf, int apply ); @@ -406,6 +408,8 @@ int config_get_return_exact_case(); int config_get_result_tweak(); int config_get_security(); int config_get_schemacheck(); +int config_get_syntaxcheck(); +int config_get_syntaxlogging(); int config_get_ds4_compatible_schema(); int config_get_schema_ignore_trailing_spaces(); char *config_get_rootdn(); diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c index 04b13d09..e331a946 100644 --- a/ldap/servers/slapd/schema.c +++ b/ldap/servers/slapd/schema.c @@ -3415,7 +3415,9 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, schema_errprefix_at, first_attr_name, "Missing parent attribute syntax OID"); status = invalid_syntax_error; - } else { + /* We only want to use the parent syntax if a SYNTAX + * wasn't explicitly specified for this attribute. */ + } else if (NULL == pSyntax) { char *pso = plugin_syntax2oid(asi_parent->asi_plugin); if (pso) { diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index ceeb11e9..cec186f9 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -287,8 +287,8 @@ typedef void (*VFP0)(); #define SLAPD_SCHEMA_DN "cn=schema" #define SLAPD_CONFIG_DN "cn=config" -#define EGG_OBJECT_CLASS "directory~team~extensible~object" -#define EGG_FILTER "(objectclass=directory~team~extensible~object)" +#define EGG_OBJECT_CLASS "directory-team-extensible-object" +#define EGG_FILTER "(objectclass=directory-team-extensible-object)" #define BE_LIST_SIZE 100 /* used by mapping tree code to hold be_list stuff */ @@ -501,16 +501,17 @@ typedef int (*SyntaxEnumFunc)(char **names, Slapi_PluginDesc *plugindesc, /* OIDs for some commonly used syntaxes */ #define BINARY_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.5" -#define BOOLEAN_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.7" +#define BOOLEAN_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.7" #define COUNTRYSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.11" #define DN_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.12" #define DIRSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.15" #define GENERALIZEDTIME_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.24" #define IA5STRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.26" #define INTEGER_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.27" -#define JPEG_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.28" +#define JPEG_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.28" +#define NUMERICSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.36" +#define OID_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.38" #define OCTETSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.40" -#define OID_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.38" #define POSTALADDRESS_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.41" #define TELEPHONE_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.50" #define SPACE_INSENSITIVE_STRING_SYNTAX_OID "2.16.840.1.113730.3.7.1" @@ -967,6 +968,7 @@ struct slapdplugin { char **plg_un_syntax_names; char *plg_un_syntax_oid; IFP plg_un_syntax_compare; + IFP plg_un_syntax_validate; } plg_un_syntax; #define plg_syntax_filter_ava plg_un.plg_un_syntax.plg_un_syntax_filter_ava #define plg_syntax_filter_sub plg_un.plg_un_syntax.plg_un_syntax_filter_sub @@ -976,7 +978,8 @@ struct slapdplugin { #define plg_syntax_flags plg_un.plg_un_syntax.plg_un_syntax_flags #define plg_syntax_names plg_un.plg_un_syntax.plg_un_syntax_names #define plg_syntax_oid plg_un.plg_un_syntax.plg_un_syntax_oid -#define plg_syntax_compare plg_un.plg_un_syntax.plg_un_syntax_compare +#define plg_syntax_compare plg_un.plg_un_syntax.plg_un_syntax_compare +#define plg_syntax_validate plg_un.plg_un_syntax.plg_un_syntax_validate struct plg_un_acl_struct { IFP plg_un_acl_init; @@ -1519,6 +1522,9 @@ typedef struct daemon_ports_s { /* Definition for plugin syntax compare routine */ typedef int (*value_compare_fn_type)(const struct berval *,const struct berval *); +/* Definition for plugin syntax validate routine */ +typedef int (*value_validate_fn_type)(const struct berval *); + #include "pw.h" #include "proto-slap.h" @@ -1631,6 +1637,8 @@ typedef struct _slapdEntryPoints { #define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass" #define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute" #define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck" +#define CONFIG_SYNTAXCHECK_ATTRIBUTE "nsslapd-syntaxcheck" +#define CONFIG_SYNTAXLOGGING_ATTRIBUTE "nsslapd-syntaxlogging" #define CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE "nsslapd-ds4-compatible-schema" #define CONFIG_SCHEMA_IGNORE_TRAILING_SPACES "nsslapd-schema-ignore-trailing-spaces" #define CONFIG_SCHEMAREPLACE_ATTRIBUTE "nsslapd-schemareplace" @@ -1846,6 +1854,8 @@ typedef struct _slapdFrontendConfig { int readonly; int reservedescriptors; int schemacheck; + int syntaxcheck; + int syntaxlogging; int ds4_compatible_schema; int schema_ignore_trailing_spaces; int secureport; diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 3c0cf72d..70556e98 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -280,6 +280,8 @@ int slapi_entry_next_attr( const Slapi_Entry *e, Slapi_Attr *prevattr, Slapi_Att const char *slapi_entry_get_uniqueid( const Slapi_Entry *e ); void slapi_entry_set_uniqueid( Slapi_Entry *e, char *uniqueid ); int slapi_entry_schema_check( Slapi_PBlock *pb, Slapi_Entry *e ); +int slapi_entry_syntax_check( Slapi_PBlock *pb, Slapi_Entry *e, int override ); +int slapi_mods_syntax_check( Slapi_PBlock *pb, LDAPMod **mods, int override ); int slapi_entry_rdn_values_present( const Slapi_Entry *e ); int slapi_entry_add_rdn_values( Slapi_Entry *e ); int slapi_entry_attr_delete( Slapi_Entry *e, const char *type ); @@ -1702,9 +1704,9 @@ typedef struct slapi_plugindesc { #define SLAPI_PLUGIN_SYNTAX_OID 706 #define SLAPI_PLUGIN_SYNTAX_FLAGS 707 #define SLAPI_PLUGIN_SYNTAX_COMPARE 708 - /* user defined substrlen; not stored in slapdplugin, but pblock itself */ -#define SLAPI_SYNTAX_SUBSTRLENS 709 +#define SLAPI_SYNTAX_SUBSTRLENS 709 +#define SLAPI_PLUGIN_SYNTAX_VALIDATE 710 /* ACL plugin functions and arguments */ #define SLAPI_PLUGIN_ACL_INIT 730 |