Commit f2869fb5 authored by Quanah Gibson-Mount's avatar Quanah Gibson-Mount
Browse files

ITS#5663

parent 273ba695
......@@ -20,6 +20,7 @@ OpenLDAP 2.4.12 Engineering
Fixed slapd spurious text output (ITS#5688)
Fixed slapd socket closing on Windows (ITS#5606)
Fixed slapd sortvals comparison (ITS#5578)
Added slapd substitute syntax support (ITS#5663)
Fixed slapd syncrepl contextCSN detection (ITS#5675)
Fixed slapd syncrepl error logging (ITS#5618)
Fixed slapd-bdb entry return if attr not present (ITS#5650)
......
......@@ -508,6 +508,37 @@ changing these settings will generally require deleting any indices that
depend on these parameters and recreating them with
.BR slapindex (8).
.HP
.hy 0
.B ldapsyntax "(\ <oid>\
[DESC\ <description>]\
[X-SUBST <substitute\-syntax>]\ )"
.RS
Specify an LDAP syntax using the LDAPv3 syntax defined in RFC 4512.
The slapd parser extends the RFC 4512 definition by allowing string
forms as well as numeric OIDs to be used for the syntax OID.
(See the
.B objectidentifier
description.)
The slapd parser also honors the
.B X-SUBST
extension (an OpenLDAP-specific extension), which allows to use the
.B ldapsyntax
statement to define a non-implemented syntax along with another syntax,
the extension value
.IR substitute\-syntax ,
as its temporary replacement.
The
.I substitute\-syntax
must be defined.
This allows to define attribute types that make use of non-implemented syntaxes
using the correct syntax OID.
Unless
.B X-SUBST
is used, this configuration statement would result in an error,
since no handlers would be associated to the resulting syntax structure.
.RE
.TP
.B localSSF <SSF>
Specifies the Security Strength Factor (SSF) to be given local LDAP sessions,
......
......@@ -63,6 +63,7 @@ typedef struct ConfigFile {
ContentRule *c_cr_head, *c_cr_tail;
ObjectClass *c_oc_head, *c_oc_tail;
OidMacro *c_om_head, *c_om_tail;
Syntax *c_syn_head, *c_syn_tail;
BerVarray c_dseFiles;
} ConfigFile;
......@@ -87,7 +88,7 @@ static struct berval cfdir;
/* Private state */
static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
*cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om;
*cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax;
static ConfigFile *cfn;
......@@ -97,9 +98,11 @@ static Avlnode *CfOcTree;
extern AttributeType *at_sys_tail; /* at.c */
extern ObjectClass *oc_sys_tail; /* oc.c */
extern OidMacro *om_sys_tail; /* oidm.c */
extern Syntax *syn_sys_tail; /* syntax.c */
static AttributeType *cf_at_tail;
static ObjectClass *cf_oc_tail;
static OidMacro *cf_om_tail;
static Syntax *cf_syn_tail;
static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
SlapReply *rs, int *renumber, Operation *op );
......@@ -180,6 +183,7 @@ enum {
CFG_SERVERID,
CFG_SORTVALS,
CFG_IX_INTLEN,
CFG_SYNTAX,
CFG_LAST
};
......@@ -381,6 +385,13 @@ static ConfigTable config_back_cf_table[] = {
{ "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
&config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' "
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ "ldapsyntax", "syntax", 2, 0, 0,
ARG_PAREN|ARG_MAGIC|CFG_SYNTAX,
&config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
"DESC 'OpenLDAP ldapSyntax' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
NULL, NULL },
{ "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
&config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
"EQUALITY caseIgnoreMatch "
......@@ -732,13 +743,13 @@ static ConfigOCs cf_ocs[] = {
"olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ "
"olcTLSCRLFile $ olcToolThreads $ "
"olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
"olcDitContentRules ) )", Cft_Global },
"olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
{ "( OLcfgGlOc:2 "
"NAME 'olcSchemaConfig' "
"DESC 'OpenLDAP schema object' "
"SUP olcConfig STRUCTURAL "
"MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ "
"olcObjectClasses $ olcDitContentRules ) )",
"olcObjectClasses $ olcDitContentRules $ olcLdapSyntaxes ) )",
Cft_Schema, NULL, cfAddSchema },
{ "( OLcfgGlOc:3 "
"NAME 'olcBackendConfig' "
......@@ -927,6 +938,17 @@ config_generic(ConfigArgs *c) {
rc = 1;
}
break;
case CFG_SYNTAX: {
ConfigFile *cf = c->ca_private;
if ( !cf )
syn_unparse( &c->rvalue_vals, NULL, NULL, 1 );
else if ( cf->c_syn_head )
syn_unparse( &c->rvalue_vals, cf->c_syn_head,
cf->c_syn_tail, 0 );
if ( !c->rvalue_vals )
rc = 1;
}
break;
case CFG_DIT: {
ConfigFile *cf = c->ca_private;
if ( !cf )
......@@ -1277,6 +1299,44 @@ config_generic(ConfigArgs *c) {
}
}
break;
case CFG_SYNTAX: {
CfEntryInfo *ce;
/* Can be NULL when undoing a failed add */
if ( c->ca_entry ) {
ce = c->ca_entry->e_private;
/* can't modify the hardcoded schema */
if ( ce->ce_parent->ce_type == Cft_Global )
return 1;
}
}
cfn = c->ca_private;
if ( c->valx < 0 ) {
Syntax *syn;
for( syn = cfn->c_syn_head; syn; syn_next( &syn )) {
syn_delete( syn );
if ( syn == cfn->c_syn_tail )
break;
}
cfn->c_syn_head = cfn->c_syn_tail = NULL;
} else {
Syntax *syn, *prev = NULL;
for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) {
prev = syn;
syn_next( &syn );
}
syn_delete( syn );
if ( cfn->c_syn_tail == syn ) {
cfn->c_syn_tail = prev;
}
if ( cfn->c_syn_head == syn ) {
syn_next( &syn );
cfn->c_syn_head = syn;
}
}
break;
case CFG_SORTVALS:
if ( c->valx < 0 ) {
ADlist *sv;
......@@ -1503,6 +1563,38 @@ config_generic(ConfigArgs *c) {
}
break;
case CFG_SYNTAX: {
Syntax *syn, *prev;
if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
cfn = c->ca_private;
if ( c->valx < 0 ) {
prev = cfn->c_syn_tail;
} else {
prev = NULL;
/* If adding anything after the first, prev is easy */
if ( c->valx ) {
int i;
for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) {
prev = syn;
syn_next( &syn );
}
} else
/* If adding the first, and head exists, find its prev */
if (cfn->c_syn_head) {
for ( syn_start( &syn ); syn != cfn->c_syn_head; ) {
prev = syn;
syn_next( &syn );
}
}
/* else prev is NULL, append to end of global list */
}
if ( parse_syn( c, &syn, prev ) ) return(1);
if ( !cfn->c_syn_head ) cfn->c_syn_head = syn;
if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn;
}
break;
case CFG_DIT: {
ContentRule *cr;
......@@ -4062,6 +4154,13 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs,
ct = config_find_table( colst, nocs, ad, ca );
config_del_vals( ct, ca );
}
if ( cfn->c_syn_head ) {
struct berval bv = BER_BVC("olcLdapSyntaxes");
ad = NULL;
slap_bv2ad( &bv, &ad, &text );
ct = config_find_table( colst, nocs, ad, ca );
config_del_vals( ct, ca );
}
if ( cfn->c_om_head ) {
struct berval bv = BER_BVC("olcObjectIdentifier");
ad = NULL;
......@@ -5556,7 +5655,7 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
for (; cf; cf=cf->c_sibs, c->depth++) {
if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head &&
!cf->c_om_head ) continue;
!cf->c_om_head && !cf->c_syn_head ) continue;
c->value_dn.bv_val = c->log;
LUTIL_SLASHPATH( cf->c_file.bv_val );
bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]);
......@@ -5685,6 +5784,21 @@ config_check_schema(Operation *op, CfBackInfo *cfb)
ber_bvarray_free( bv );
cf_oc_tail = oc_sys_tail;
}
if ( cf_syn_tail != syn_sys_tail ) {
a = attr_find( e->e_attrs, cfAd_syntax );
if ( a ) {
if ( a->a_nvals != a->a_vals )
ber_bvarray_free( a->a_nvals );
ber_bvarray_free( a->a_vals );
a->a_vals = NULL;
a->a_nvals = NULL;
a->a_numvals = 0;
}
syn_unparse( &bv, NULL, NULL, 1 );
attr_merge_normalize( e, cfAd_syntax, bv, NULL );
ber_bvarray_free( bv );
cf_syn_tail = syn_sys_tail;
}
} else {
SlapReply rs = {REP_RESULT};
c.ca_private = NULL;
......@@ -5698,6 +5812,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb)
cf_at_tail = at_sys_tail;
cf_oc_tail = oc_sys_tail;
cf_om_tail = om_sys_tail;
cf_syn_tail = syn_sys_tail;
}
return 0;
}
......@@ -5789,6 +5904,7 @@ config_back_db_open( BackendDB *be, ConfigReply *cr )
cf_at_tail = at_sys_tail;
cf_oc_tail = oc_sys_tail;
cf_om_tail = om_sys_tail;
cf_syn_tail = syn_sys_tail;
/* Create schema nodes for included schema... */
if ( cfb->cb_config->c_kids ) {
......@@ -6222,6 +6338,7 @@ static struct {
{ "backend", &cfAd_backend },
{ "database", &cfAd_database },
{ "include", &cfAd_include },
{ "ldapsyntax", &cfAd_syntax },
{ "objectclass", &cfAd_oc },
{ "objectidentifier", &cfAd_om },
{ "overlay", &cfAd_overlay },
......
......@@ -1699,6 +1699,8 @@ LDAP_SLAPD_F (int) parse_at LDAP_P((
LDAP_SLAPD_F (char *) scherr2str LDAP_P((int code)) LDAP_GCCATTR((const));
LDAP_SLAPD_F (int) dscompare LDAP_P(( const char *s1, const char *s2del,
char delim ));
LDAP_SLAPD_F (int) parse_syn LDAP_P((
struct config_args_s *ca, Syntax **sat, Syntax *prev ));
/*
* sessionlog.c
......@@ -1758,7 +1760,10 @@ LDAP_SLAPD_F (Syntax *) syn_find_desc LDAP_P((
const char *syndesc, int *slen ));
LDAP_SLAPD_F (int) syn_add LDAP_P((
LDAPSyntax *syn,
int user,
slap_syntax_defs_rec *def,
Syntax **ssyn,
Syntax *prev,
const char **err ));
LDAP_SLAPD_F (void) syn_destroy LDAP_P(( void ));
......@@ -1767,6 +1772,13 @@ LDAP_SLAPD_F (int) register_syntax LDAP_P((
LDAP_SLAPD_F (int) syn_schema_info( Entry *e );
LDAP_SLAPD_F (int) syn_start LDAP_P(( Syntax **at ));
LDAP_SLAPD_F (int) syn_next LDAP_P(( Syntax **at ));
LDAP_SLAPD_F (void) syn_delete LDAP_P(( Syntax *at ));
LDAP_SLAPD_F (void) syn_unparse LDAP_P((
BerVarray *bva, Syntax *start, Syntax *end, int system ));
/*
* user.c
*/
......
......@@ -331,3 +331,68 @@ done:;
return code;
}
static void
syn_usage( void )
{
fprintf( stderr, "%s",
"SyntaxDescription = \"(\" whsp\n"
" numericoid whsp ; object identifier\n"
" [ whsp \"DESC\" whsp qdstring ] ; description\n"
" extensions whsp \")\" ; extensions\n"
" whsp \")\"\n");
}
int
parse_syn(
struct config_args_s *c,
Syntax **ssyn,
Syntax *prev )
{
LDAPSyntax *syn;
slap_syntax_defs_rec def = { 0 };
int code;
const char *err;
char *line = strchr( c->line, '(' );
syn = ldap_str2syntax( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
if ( !syn ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
c->argv[0], ldap_scherr2str(code), err );
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s %s\n", c->log, c->cr_msg, 0 );
syn_usage();
return 1;
}
if ( syn->syn_oid == NULL ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
c->argv[0] );
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s %s\n", c->log, c->cr_msg, 0 );
syn_usage();
code = 1;
goto done;
}
code = syn_add( syn, 1, &def, ssyn, prev, &err );
if ( code ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
c->argv[0], scherr2str(code), err);
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s %s\n", c->log, c->cr_msg, 0 );
code = 1;
goto done;
}
done:;
if ( code ) {
ldap_syntax_free( syn );
} else {
ldap_memfree( syn );
}
return code;
}
......@@ -415,6 +415,7 @@ struct Syntax {
#else
#define SLAP_SYNTAX_HIDE 0x8000U /* hide (do not publish) */
#endif
#define SLAP_SYNTAX_HARDCODE 0x10000U /* This is hardcoded schema */
Syntax **ssyn_sups;
......@@ -431,7 +432,7 @@ struct Syntax {
struct ComponentDesc* ssync_comp_syntax;
#endif
LDAP_SLIST_ENTRY(Syntax) ssyn_next;
LDAP_STAILQ_ENTRY(Syntax) ssyn_next;
};
#define slap_syntax_is_flag(s,flag) ((int)((s)->ssyn_flags & (flag)) ? 1 : 0)
......
......@@ -30,8 +30,11 @@ struct sindexrec {
};
static Avlnode *syn_index = NULL;
static LDAP_SLIST_HEAD(SyntaxList, Syntax) syn_list
= LDAP_SLIST_HEAD_INITIALIZER(&syn_list);
static LDAP_STAILQ_HEAD(SyntaxList, Syntax) syn_list
= LDAP_STAILQ_HEAD_INITIALIZER(syn_list);
/* Last hardcoded attribute registered */
Syntax *syn_sys_tail;
static int
syn_index_cmp(
......@@ -68,7 +71,7 @@ syn_find_desc( const char *syndesc, int *len )
{
Syntax *synp;
LDAP_SLIST_FOREACH(synp, &syn_list, ssyn_next) {
LDAP_STAILQ_FOREACH(synp, &syn_list, ssyn_next) {
if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{' /*'}'*/ ))) {
return synp;
}
......@@ -111,9 +114,9 @@ syn_destroy( void )
Syntax *s;
avl_free( syn_index, ldap_memfree );
while( !LDAP_SLIST_EMPTY( &syn_list ) ) {
s = LDAP_SLIST_FIRST( &syn_list );
LDAP_SLIST_REMOVE_HEAD( &syn_list, ssyn_next );
while( !LDAP_STAILQ_EMPTY( &syn_list ) ) {
s = LDAP_STAILQ_FIRST( &syn_list );
LDAP_STAILQ_REMOVE_HEAD( &syn_list, ssyn_next );
if ( s->ssyn_sups ) {
SLAP_FREE( s->ssyn_sups );
}
......@@ -123,14 +126,13 @@ syn_destroy( void )
static int
syn_insert(
Syntax *ssyn,
const char **err
)
Syntax *ssyn,
Syntax *prev,
const char **err )
{
struct sindexrec *sir;
LDAP_SLIST_NEXT( ssyn, ssyn_next ) = NULL;
LDAP_SLIST_INSERT_HEAD( &syn_list, ssyn, ssyn_next );
LDAP_STAILQ_NEXT( ssyn, ssyn_next ) = NULL;
if ( ssyn->ssyn_oid ) {
sir = (struct sindexrec *)
......@@ -150,19 +152,36 @@ syn_insert(
/* FIX: temporal consistency check */
syn_find(sir->sir_name);
}
if ( ssyn->ssyn_flags & SLAP_AT_HARDCODE ) {
prev = syn_sys_tail;
syn_sys_tail = ssyn;
}
if ( prev ) {
LDAP_STAILQ_INSERT_AFTER( &syn_list, prev, ssyn, ssyn_next );
} else {
LDAP_STAILQ_INSERT_TAIL( &syn_list, ssyn, ssyn_next );
}
return 0;
}
int
syn_add(
LDAPSyntax *syn,
slap_syntax_defs_rec *def,
const char **err
)
LDAPSyntax *syn,
int user,
slap_syntax_defs_rec *def,
Syntax **ssynp,
Syntax *prev,
const char **err )
{
Syntax *ssyn;
int code = 0;
if ( ssynp != NULL ) {
*ssynp = NULL;
}
ssyn = (Syntax *) SLAP_CALLOC( 1, sizeof(Syntax) );
if ( ssyn == NULL ) {
Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 );
......@@ -171,7 +190,7 @@ syn_add(
AC_MEMCPY( &ssyn->ssyn_syn, syn, sizeof(LDAPSyntax) );
LDAP_SLIST_NEXT(ssyn,ssyn_next) = NULL;
LDAP_STAILQ_NEXT(ssyn,ssyn_next) = NULL;
/*
* note: ssyn_bvoid uses the same memory of ssyn_syn.syn_oid;
......@@ -213,9 +232,11 @@ syn_add(
}
}
if ( code == 0 ) {
code = syn_insert( ssyn, err );
if ( !user )
ssyn->ssyn_flags |= SLAP_SYNTAX_HARDCODE;
if ( code == 0 ) {
code = syn_insert( ssyn, prev, err );
}
if ( code != 0 && ssyn != NULL ) {
......@@ -223,6 +244,11 @@ syn_add(
SLAP_FREE( ssyn->ssyn_sups );
}
SLAP_FREE( ssyn );
ssyn = NULL;
}
if (ssynp ) {
*ssynp = ssyn;
}
return code;
......@@ -244,7 +270,7 @@ register_syntax(
return( -1 );
}
code = syn_add( syn, def, &err );
code = syn_add( syn, 0, def, NULL, NULL, &err );
if ( code ) {
Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
......@@ -267,7 +293,7 @@ syn_schema_info( Entry *e )
struct berval val;
struct berval nval;
LDAP_SLIST_FOREACH(syn, &syn_list, ssyn_next ) {
LDAP_STAILQ_FOREACH(syn, &syn_list, ssyn_next ) {
if ( ! syn->ssyn_validate ) {
/* skip syntaxes without validators */
continue;
......@@ -297,3 +323,92 @@ syn_schema_info( Entry *e )
return 0;
}
void
syn_delete( Syntax *syn )
{
LDAP_STAILQ_REMOVE(&syn_list, syn, Syntax, ssyn_next);
}
int
syn_start( Syntax **syn )
{
assert( syn != NULL );
*syn = LDAP_STAILQ_FIRST(&syn_list);
return (*syn != NULL);
}
int
syn_next( Syntax **syn )
{
assert( syn != NULL );
#if 0 /* pedantic check: don't use this */
{
Syntax *tmp = NULL;
LDAP_STAILQ_FOREACH(tmp,&syn_list,ssyn_next) {
if ( tmp == *syn ) {
break;
}
}
assert( tmp != NULL );
}
#endif
*syn = LDAP_STAILQ_NEXT(*syn,ssyn_next);
return (*syn != NULL);
}
void
syn_unparse( BerVarray *res, Syntax *start, Syntax *end, int sys )
{
Syntax *syn;
int i, num;
struct berval bv, *bva = NULL, idx;
char ibuf[32];
if ( !start )
start = LDAP_STAILQ_FIRST( &syn_list );
/* count the result size */
i = 0;
for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) {
if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break;
i++;
if ( syn == end ) break;
}
if ( !i ) return;
num = i;
bva = ch_malloc( (num+1) * sizeof(struct berval) );
BER_BVZERO( bva );
idx.bv_val = ibuf;
if ( sys ) {
idx.bv_len = 0;
ibuf[0] = '\0';
}
i = 0;
for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) {
if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break;
if ( ldap_syntax2bv( &syn->ssyn_syn, &bv ) == NULL ) {
ber_bvarray_free( bva );
}