X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fconstraint.c;h=8ce8a0fc6aa722812b1aa0008d5b55336dd52cfb;hb=76754855e81c68071d79e7f06978c4f394ca4228;hp=18a3078077b14dfa7aceccc9429767240d6e36db;hpb=6e8f1b9b257990fa47729b61f6cbc86ddabe856f;p=openldap diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c index 18a3078077..8ce8a0fc6a 100644 --- a/servers/slapd/overlays/constraint.c +++ b/servers/slapd/overlays/constraint.c @@ -1,7 +1,8 @@ +/* $OpenLDAP$ */ /* constraint.c - Overlay to constrain attributes to certain values */ /* - * * Copyright 2003-2004 Hewlett-Packard Company + * Copyright 2007 Emmanuel Dreyfus * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -13,7 +14,8 @@ * . */ /* - * Author: Neil Dunbar + * Authors: Neil Dunbar + * Emmannuel Dreyfus */ #include "portable.h" @@ -25,7 +27,9 @@ #include #include +#include "lutil.h" #include "slap.h" +#include "config.h" /* * This overlay limits the values which can be placed into an @@ -35,6 +39,9 @@ * control the add and modify value mods of a modify) */ +#define REGEX_STR "regex" +#define URI_STR "uri" + /* * Linked list of attribute constraints which we should enforce. * This is probably a sub optimal structure - some form of sorted @@ -42,244 +49,534 @@ * likely to be much bigger than 4 or 5. We stick with a list for * the moment. */ + typedef struct constraint { - struct constraint *ap_next; - AttributeDescription *ap; - regex_t *re; + struct constraint *ap_next; + AttributeDescription *ap; + regex_t *re; + LDAPURLDesc *lud; + AttributeDescription **attrs; + struct berval val; /* constraint value */ + struct berval dn; + struct berval filter; } constraint; +enum { + CONSTRAINT_ATTRIBUTE = 1 +}; + +static ConfigDriver constraint_cf_gen; + +static ConfigTable constraintcfg[] = { + { "constraint_attribute", "attribute> (regex|uri) re) { + regfree(cp->re); + ch_free(cp->re); + } + if (!BER_BVISNULL(&cp->val)) + ch_free(cp->val.bv_val); + if (cp->lud) + ldap_free_urldesc(cp->lud); + if (cp->attrs) + ch_free(cp->attrs); + ch_free(cp); +} + +static int +constraint_cf_gen( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)(c->bi); + constraint *cn = on->on_bi.bi_private, *cp; + struct berval bv; + int i, rc = 0; + constraint ap = { NULL, NULL, NULL }, *a2 = NULL; + const char *text = NULL; + + switch ( c->op ) { + case SLAP_CONFIG_EMIT: + switch (c->type) { + case CONSTRAINT_ATTRIBUTE: + for (cp=cn; cp; cp=cp->ap_next) { + int len; + char *s; + char *tstr = NULL; + + len = cp->ap->ad_cname.bv_len + 3; + if (cp->re) { + len += STRLENOF(REGEX_STR); + tstr = REGEX_STR; + } else if (cp->lud) { + len += STRLENOF(URI_STR); + tstr = URI_STR; + } + len += cp->val.bv_len; + + s = ch_malloc(len); + + bv.bv_len = snprintf(s, len, "%s %s %s", cp->ap->ad_cname.bv_val, + tstr, cp->val.bv_val); + bv.bv_val = s; + rc = value_add_one( &c->rvalue_vals, &bv ); + if (rc) return rc; + rc = value_add_one( &c->rvalue_nvals, &bv ); + if (rc) return rc; + ch_free(s); + } + break; + default: + abort(); + break; + } + break; + case LDAP_MOD_DELETE: + switch (c->type) { + case CONSTRAINT_ATTRIBUTE: + if (!cn) break; /* nothing to do */ + + if (c->valx < 0) { + /* zap all constraints */ + while (cn) { + cp = cn->ap_next; + constraint_free( cn ); + cn = cp; + } + + on->on_bi.bi_private = NULL; + } else { + constraint **cpp; + + /* zap constraint numbered 'valx' */ + for(i=0, cp = cn, cpp = &cn; + (cp) && (ivalx); + i++, cpp = &cp->ap_next, cp = *cpp); + + if (cp) { + /* zap cp, and join cpp to cp->ap_next */ + *cpp = cp->ap_next; + constraint_free( cp ); + } + on->on_bi.bi_private = cn; + } + break; + + default: + abort(); + break; + } + break; + case SLAP_CONFIG_ADD: + case LDAP_MOD_ADD: + switch (c->type) { + case CONSTRAINT_ATTRIBUTE: + if ( slap_str2ad( c->argv[1], &ap.ap, &text ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s <%s>: %s\n", c->argv[0], c->argv[1], text ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return( ARG_BAD_CONF ); + } + + if ( strcasecmp( c->argv[2], REGEX_STR ) == 0) { + int err; + + ap.re = ch_malloc( sizeof(regex_t) ); + if ((err = regcomp( ap.re, + c->argv[3], REG_EXTENDED )) != 0) { + char errmsg[1024]; + + regerror( err, ap.re, errmsg, sizeof(errmsg) ); + ch_free(ap.re); + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s %s: Illegal regular expression \"%s\": Error %s", + c->argv[0], c->argv[1], c->argv[3], errmsg); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + ap.re = NULL; + return( ARG_BAD_CONF ); + } + ber_str2bv( c->argv[3], 0, 1, &ap.val ); + } else if ( strcasecmp( c->argv[2], URI_STR ) == 0) { + int err; + + err = ldap_url_parse(c->argv[3], &ap.lud); + if ( err != LDAP_URL_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s %s: Invalid URI \"%s\"", + c->argv[0], c->argv[1], c->argv[3]); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return( ARG_BAD_CONF ); + } + + if (ap.lud->lud_host != NULL) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s %s: unsupported hostname in URI \"%s\"", + c->argv[0], c->argv[1], c->argv[3]); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + + ldap_free_urldesc(ap.lud); + + return( ARG_BAD_CONF ); + } + + for ( i=0; ap.lud->lud_attrs[i]; i++); + /* FIXME: This is worthless without at least one attr */ + if ( i ) { + ap.attrs = ch_malloc( (i+1)*sizeof(AttributeDescription *)); + for ( i=0; ap.lud->lud_attrs[i]; i++) { + ap.attrs[i] = NULL; + if ( slap_str2ad( ap.lud->lud_attrs[i], &ap.attrs[i], &text ) ) { + ch_free( ap.attrs ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s <%s>: %s\n", c->argv[0], ap.lud->lud_attrs[i], text ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return( ARG_BAD_CONF ); + } + } + ap.attrs[i] = NULL; + } + + if (ap.lud->lud_dn == NULL) + ap.lud->lud_dn = ch_strdup(""); + + if (ap.lud->lud_filter == NULL) + ap.lud->lud_filter = ch_strdup("objectClass=*"); + + ber_str2bv( c->argv[3], 0, 1, &ap.val ); + } else { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s %s: Unknown constraint type: %s", + c->argv[0], c->argv[1], c->argv[2] ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return ( ARG_BAD_CONF ); + } + + a2 = ch_calloc( sizeof(constraint), 1 ); + a2->ap_next = on->on_bi.bi_private; + a2->ap = ap.ap; + a2->re = ap.re; + a2->val = ap.val; + a2->lud = ap.lud; + if ( a2->lud ) { + ber_str2bv(a2->lud->lud_dn, 0, 0, &a2->dn); + ber_str2bv(a2->lud->lud_filter, 0, 0, &a2->filter); + } + a2->attrs = ap.attrs; + on->on_bi.bi_private = a2; + break; + default: + abort(); + break; + } + break; + default: + abort(); + } + + return rc; +} + static int -constraint_violation( constraint *c, struct berval *bv ) +constraint_uri_cb( Operation *op, SlapReply *rs ) { - if ((!c) || (!bv)) return 0; - - if ((c->re) && - (regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH)) - - return 1; /* regular expression violation */ - - return 0; + if(rs->sr_type == REP_SEARCH) { + int *foundp = op->o_callback->sc_private; + + *foundp = 1; + + Debug(LDAP_DEBUG_TRACE, "==> constraint_uri_cb <%s>\n", + rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); + } + return 0; +} + +static int +constraint_violation( constraint *c, struct berval *bv, Operation *op, SlapReply *rs) +{ + if ((!c) || (!bv)) return 0; + + if ((c->re) && + (regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH)) + return 1; /* regular expression violation */ + + if (c->lud) { + Operation nop = *op; + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + slap_callback cb; + SlapReply nrs = { REP_RESULT }; + int i; + int found; + int rc; + size_t len; + struct berval filterstr; + char *ptr; + + found = 0; + + nrs.sr_entry = NULL; + nrs.sr_nentries = 0; + + cb.sc_next = NULL; + cb.sc_response = constraint_uri_cb; + cb.sc_cleanup = NULL; + cb.sc_private = &found; + + nop.o_protocol = LDAP_VERSION3; + nop.o_tag = LDAP_REQ_SEARCH; + nop.o_time = slap_get_time(); + if (c->lud->lud_dn) { + struct berval dn; + + ber_str2bv(c->lud->lud_dn, 0, 0, &dn); + nop.o_req_dn = dn; + nop.o_req_ndn = dn; + nop.o_bd = select_backend(&nop.o_req_ndn, 1 ); + if (!nop.o_bd || !nop.o_bd->be_search) { + return 1; /* unexpected error */ + } + } else { + nop.o_req_dn = nop.o_bd->be_nsuffix[0]; + nop.o_req_ndn = nop.o_bd->be_nsuffix[0]; + nop.o_bd = on->on_info->oi_origdb; + } + nop.o_do_not_cache = 1; + nop.o_callback = &cb; + + nop.ors_scope = c->lud->lud_scope; + nop.ors_deref = LDAP_DEREF_NEVER; + nop.ors_slimit = SLAP_NO_LIMIT; + nop.ors_tlimit = SLAP_NO_LIMIT; + nop.ors_limit = NULL; + + nop.ors_attrsonly = 0; + nop.ors_attrs = slap_anlist_no_attrs; + + len = STRLENOF("(&(") + + c->filter.bv_len + + STRLENOF(")(|"); + + for (i = 0; c->attrs[i]; i++) { + len += STRLENOF("(") + + c->attrs[i]->ad_cname.bv_len + + STRLENOF("=") + + bv->bv_len + + STRLENOF(")"); + } + + len += STRLENOF("))"); + filterstr.bv_len = len; + filterstr.bv_val = op->o_tmpalloc(len + 1, op->o_tmpmemctx); + + ptr = filterstr.bv_val + + snprintf(filterstr.bv_val, len, "(&(%s)(|", c->lud->lud_filter); + for (i = 0; c->attrs[i]; i++) { + *ptr++ = '('; + ptr = lutil_strcopy( ptr, c->attrs[i]->ad_cname.bv_val ); + *ptr++ = '='; + ptr = lutil_strcopy( ptr, bv->bv_val ); + *ptr++ = ')'; + } + *ptr++ = ')'; + *ptr++ = ')'; + + Debug(LDAP_DEBUG_TRACE, + "==> constraint_violation uri filter = %s\n", + filterstr.bv_val, 0, 0); + + nop.ors_filterstr = filterstr; + nop.ors_filter = str2filter_x(&nop, filterstr.bv_val); + + rc = nop.o_bd->be_search( &nop, &nrs ); + + op->o_tmpfree(filterstr.bv_val, op->o_tmpmemctx); + Debug(LDAP_DEBUG_TRACE, + "==> constraint_violation uri rc = %d, found = %d\n", + rc, found, 0); + + if((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_OBJECT)) { + send_ldap_error(op, rs, rc, + "constraint_violation uri search failed"); + return 1; /* unexpected error */ + } + + if (!found) + return 1; /* constraint violation */ + + } + + return 0; } static char * -print_message( const char *fmt, AttributeDescription *a ) +print_message( struct berval *errtext, AttributeDescription *a ) { - char *ret; - int sz; - - sz = strlen(fmt) + a->ad_cname.bv_len + 1; - ret = ch_malloc(sz); - snprintf( ret, sz, fmt, a->ad_cname.bv_val ); - return ret; + char *ret; + int sz; + + sz = errtext->bv_len + sizeof(" on ") + a->ad_cname.bv_len; + ret = ch_malloc(sz); + snprintf( ret, sz, "%s on %s", errtext->bv_val, a->ad_cname.bv_val ); + return ret; } static int constraint_add( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; - Attribute *a; - constraint *c = on->on_bi.bi_private, *cp; - BerVarray b = NULL; - int i; - const char *rsv = "add breaks regular expression constraint on %s"; - char *msg; - - if ((a = op->ora_e->e_attrs) == NULL) { - op->o_bd->bd_info = (BackendInfo *)(on->on_info); - send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, - "constraint_add() got null op.ora_e.e_attrs"); - return(rs->sr_err); - } - - for(; a; a = a->a_next ) { - /* we don't constrain operational attributes */ - - if (is_at_operational(a->a_desc->ad_type)) continue; - - for(cp = c; cp; cp = cp->ap_next) { - if (cp->ap != a->a_desc) continue; - if ((b = a->a_vals) == NULL) continue; - - for(i=0; b[i].bv_val; i++) { - int cv = constraint_violation( cp, &b[i]); - - if (cv) { - /* regex violation */ - op->o_bd->bd_info = (BackendInfo *)(on->on_info); - msg = print_message( rsv, a->a_desc ); - send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); - ch_free(msg); - return (rs->sr_err); - } - } - } - } + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + Attribute *a; + constraint *c = on->on_bi.bi_private, *cp; + BerVarray b = NULL; + int i; + struct berval rsv = BER_BVC("add breaks constraint"); + char *msg; + + if ((a = op->ora_e->e_attrs) == NULL) { + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, + "constraint_add() got null op.ora_e.e_attrs"); + return(rs->sr_err); + } + + for(; a; a = a->a_next ) { + /* we don't constrain operational attributes */ + if (is_at_operational(a->a_desc->ad_type)) continue; + + for(cp = c; cp; cp = cp->ap_next) { + if (cp->ap != a->a_desc) continue; + if ((b = a->a_vals) == NULL) continue; + + for(i=0; b[i].bv_val; i++) { + int cv = constraint_violation( cp, &b[i], op, rs); + + if (cv) { + /* violation */ + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + msg = print_message( &rsv, a->a_desc ); + send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); + ch_free(msg); + return (rs->sr_err); + } + } + } + } /* Default is to just fall through to the normal processing */ - return SLAP_CB_CONTINUE; + return SLAP_CB_CONTINUE; } static int constraint_modify( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; - constraint *c = on->on_bi.bi_private, *cp; - Modifications *m; - BerVarray b = NULL; - int i; - const char *rsv = "modify breaks regular expression constraint on %s"; - char *msg; - - if ((m = op->orm_modlist) == NULL) { - op->o_bd->bd_info = (BackendInfo *)(on->on_info); - send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, - "constraint_modify() got null orm_modlist"); - return(rs->sr_err); - } - - for(;m; m = m->sml_next) { - if (is_at_operational( m->sml_desc->ad_type )) continue; - if ((( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_ADD) && - (( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_REPLACE)) - continue; - /* we only care about ADD and REPLACE modifications */ - if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL)) - continue; - - for(cp = c; cp; cp = cp->ap_next) { - if (cp->ap != m->sml_desc) continue; - - for(i=0; b[i].bv_val; i++) { - int cv = constraint_violation( cp, &b[i]); - - if (cv) { - /* regex violation */ - op->o_bd->bd_info = (BackendInfo *)(on->on_info); - msg = print_message( rsv, m->sml_desc ); - send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); - ch_free(msg); - return (rs->sr_err); - } - } - } - } - - return SLAP_CB_CONTINUE; -} + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + constraint *c = on->on_bi.bi_private, *cp; + Modifications *m; + BerVarray b = NULL; + int i; + struct berval rsv = BER_BVC("modify breaks constraint"); + char *msg; + + if ((m = op->orm_modlist) == NULL) { + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, + "constraint_modify() got null orm_modlist"); + return(rs->sr_err); + } -static int constraint_config( - BackendDB *be, - const char *fname, - int lineno, - int argc, - char **argv - ) -{ - slap_overinst *on = (slap_overinst *) be->bd_info; - constraint ap = { NULL, NULL, NULL }, *a2 = NULL; - regmatch_t rm[2]; - - if ( strcasecmp( argv[0], "constraint_attribute" ) == 0 ) { - const char *text; - - if ( argc != 4 ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "wrong number of parameters in" - "\"constraint_attribute \" line.\n", - fname, lineno, 0 ); - return( 1 ); - } - if ( slap_str2ad( argv[1], &ap.ap, &text ) ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "attribute description unknown \"constraint_attribute\" line: %s.\n", - fname, lineno, text ); - return( 1 ); - } - - if ( strcasecmp( argv[2], "regex" ) == 0) { - int err; - - ap.re = ch_malloc( sizeof(regex_t) ); - if ((err = regcomp( ap.re, argv[3], REG_EXTENDED )) != 0) { - const char *fmt = "%s: line %d: Illegal regular expression \"%s\": Error %s\n"; - char errmsg[1024], *msg; - int i, l, msgsize; - - msgsize = regerror( err, ap.re, errmsg, sizeof(errmsg) ); - msgsize += strlen(fmt) + strlen(argv[3]) + strlen(fname); - for(l=lineno; l>0; l/=10, msgsize++); - msgsize++; - - msg = ch_malloc( msgsize + 1 ); - snprintf( msg, msgsize, fmt, fname, lineno, argv[3], errmsg ); - ch_free(ap.re); - Debug( LDAP_DEBUG_ANY, msg, 0, 0, 0); - ch_free(msg); - ap.re = NULL; - return(1); - } - } else - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "Unknown constraint type: %s", - fname, lineno, argv[2] ); - - - a2 = ch_malloc( sizeof(constraint) ); - a2->ap_next = on->on_bi.bi_private; - a2->ap = ap.ap; - a2->re = ap.re; - on->on_bi.bi_private = a2; - } else { - return SLAP_CONF_UNKNOWN; - } - - return 0; + for(;m; m = m->sml_next) { + if (is_at_operational( m->sml_desc->ad_type )) continue; + if ((( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_ADD) && + (( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_REPLACE)) + continue; + /* we only care about ADD and REPLACE modifications */ + if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL)) + continue; + + for(cp = c; cp; cp = cp->ap_next) { + if (cp->ap != m->sml_desc) continue; + + for(i=0; b[i].bv_val; i++) { + int cv = constraint_violation( cp, &b[i], op, rs); + + if (cv) { + /* violation */ + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + msg = print_message( &rsv, m->sml_desc ); + send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); + ch_free(msg); + return (rs->sr_err); + } + } + } + } + + return SLAP_CB_CONTINUE; } static int constraint_close( - BackendDB *be - ) + BackendDB *be, + ConfigReply *cr ) { - slap_overinst *on = (slap_overinst *) be->bd_info; - constraint *ap, *a2; - - for ( ap = on->on_bi.bi_private; ap; ap = a2 ) { - a2 = ap->ap_next; - if (ap->re) { - regfree( ap->re ); - ch_free( ap->re ); - } - - ch_free( ap ); - } - - return 0; + slap_overinst *on = (slap_overinst *) be->bd_info; + constraint *ap, *a2; + + for ( ap = on->on_bi.bi_private; ap; ap = a2 ) { + a2 = ap->ap_next; + constraint_free( ap ); + } + + return 0; } static slap_overinst constraint_ovl; -/* 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. - */ - #if SLAPD_OVER_CONSTRAINT == SLAPD_MOD_DYNAMIC static #endif int constraint_initialize( void ) { - constraint_ovl.on_bi.bi_type = "constraint"; - constraint_ovl.on_bi.bi_db_config = constraint_config; - constraint_ovl.on_bi.bi_db_close = constraint_close; - constraint_ovl.on_bi.bi_op_add = constraint_add; - constraint_ovl.on_bi.bi_op_modify = constraint_modify; + int rc; + + constraint_ovl.on_bi.bi_type = "constraint"; + constraint_ovl.on_bi.bi_db_close = constraint_close; + constraint_ovl.on_bi.bi_op_add = constraint_add; + constraint_ovl.on_bi.bi_op_modify = constraint_modify; - return overlay_register( &constraint_ovl ); + constraint_ovl.on_bi.bi_private = NULL; + + constraint_ovl.on_bi.bi_cf_ocs = constraintocs; + rc = config_register_schema( constraintcfg, constraintocs ); + if (rc) return rc; + + return overlay_register( &constraint_ovl ); } #if SLAPD_OVER_CONSTRAINT == SLAPD_MOD_DYNAMIC int init_module(int argc, char *argv[]) { - return constraint_initialize(); + return constraint_initialize(); } #endif