From 2d48b5dc9905bbc48d16363a15cc236dce82e18c Mon Sep 17 00:00:00 2001 From: Hallvard Furuseth Date: Wed, 13 Aug 2003 20:04:59 +0000 Subject: [PATCH] Handle full syntax of Generalized Time and UTC Time. No longer accept initial and trailing spaces in these syntaxes. --- servers/slapd/schema_init.c | 303 +++++++++++++++++++++--------------- 1 file changed, 177 insertions(+), 126 deletions(-) diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 43bad4b552..056e085d0d 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -1996,172 +1996,189 @@ certificateExactNormalize( #endif /* HAVE_TLS */ +#ifndef SUPPORT_OBSOLETE_UTC_SYNTAX +/* slight optimization - does not need the start parameter */ +#define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f) +enum { start = 0 }; +#endif + static int check_time_syntax (struct berval *val, int start, - int *parts) + int *parts, + struct berval *fraction) { - static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 }; - static int mdays[2][12] = { + /* + * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) + * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM] + * GeneralizedTime supports leap seconds, UTCTime does not. + */ + static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 }; + static const int mdays[2][12] = { /* non-leap years */ - { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }, + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, /* leap years */ - { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 } + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; char *p, *e; - int part, c, tzoffset, leapyear = 0 ; - - if( val->bv_len == 0 ) { - return LDAP_INVALID_SYNTAX; - } + int part, c, c1, c2, tzoffset, leapyear = 0; - p = (char *)val->bv_val; + p = val->bv_val; e = p + val->bv_len; - /* Ignore initial whitespace */ - while ( ( p < e ) && ASCII_SPACE( *p ) ) { - p++; - } - - if (e - p < 13 - (2 * start)) { - return LDAP_INVALID_SYNTAX; - } - - for (part = 0; part < 9; part++) { - parts[part] = 0; - } - - for (part = start; part < 7; part++) { - c = *p; - if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) { - part++; +#ifdef SUPPORT_OBSOLETE_UTC_SYNTAX + parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */ +#endif + for (part = start; part < 7 && p < e; part++) { + c1 = *p; + if (!ASCII_DIGIT(c1)) { break; } p++; - c -= '0'; if (p == e) { return LDAP_INVALID_SYNTAX; } - if (c < 0 || c > 9) { - return LDAP_INVALID_SYNTAX; - } - parts[part] = c; - - c = *p++ - '0'; - if (p == e) { + c = *p++; + if (!ASCII_DIGIT(c)) { return LDAP_INVALID_SYNTAX; } - if (c < 0 || c > 9) { - return LDAP_INVALID_SYNTAX; - } - parts[part] *= 10; - parts[part] += c; - - if (part == 2 || part == 3) { - parts[part]--; - } - if (parts[part] < 0) { - return LDAP_INVALID_SYNTAX; + c += c1 * 10 - '0' * 11; + if ((part | 1) == 3) { + --c; + if (c < 0) { + return LDAP_INVALID_SYNTAX; + } } - if (parts[part] > ceiling[part]) { - return LDAP_INVALID_SYNTAX; + if (c >= ceiling[part]) { + if (! (c == 60 && part == 6 && start == 0)) + return LDAP_INVALID_SYNTAX; } + parts[part] = c; + } + if (part < 5 + start) { + return LDAP_INVALID_SYNTAX; + } + for (; part < 9; part++) { + parts[part] = 0; } /* leapyear check for the Gregorian calendar (year>1581) */ - if (((parts[1] % 4 == 0) && (parts[1] != 0)) || - ((parts[0] % 4 == 0) && (parts[1] == 0))) + if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) { leapyear = 1; } - if (parts[3] > mdays[leapyear][parts[2]]) { + if (parts[3] >= mdays[leapyear][parts[2]]) { return LDAP_INVALID_SYNTAX; } - - c = *p++; - if (c == 'Z') { - tzoffset = 0; /* UTC */ - } else if (c != '+' && c != '-') { - return LDAP_INVALID_SYNTAX; - } else { - if (c == '-') { - tzoffset = -1; - } else /* c == '+' */ { - tzoffset = 1; - } - - if (p > e - 4) { - return LDAP_INVALID_SYNTAX; - } - - for (part = 7; part < 9; part++) { - c = *p++ - '0'; - if (c < 0 || c > 9) { - return LDAP_INVALID_SYNTAX; - } - parts[part] = c; - c = *p++ - '0'; - if (c < 0 || c > 9) { - return LDAP_INVALID_SYNTAX; - } - parts[part] *= 10; - parts[part] += c; - if (parts[part] < 0 || parts[part] > ceiling[part]) { + if (start == 0) { + fraction->bv_val = p; + fraction->bv_len = 0; + if (p < e && (*p == '.' || *p == ',')) { + char *end_num; + while (++p < e && ASCII_DIGIT(*p)) + ; + if (p - fraction->bv_val == 1) { return LDAP_INVALID_SYNTAX; } + for (end_num = p; end_num[-1] == '0'; --end_num) + ; + c = end_num - fraction->bv_val; + if (c != 1) + fraction->bv_len = c; } } - /* Ignore trailing whitespace */ - while ( ( p < e ) && ASCII_SPACE( *p ) ) { - p++; - } - if (p != e) { - return LDAP_INVALID_SYNTAX; + if (p == e) { + /* no time zone */ + return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS; } - switch ( tzoffset ) { - case -1: /* negativ offset to UTC, ie west of Greenwich */ - parts[4] += parts[7]; - parts[5] += parts[8]; - for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */ - if (part != 3) { - c = ceiling[part]; - } else { - c = mdays[leapyear][parts[2]]; + tzoffset = *p++; + switch (tzoffset) { + default: + return LDAP_INVALID_SYNTAX; + case 'Z': + /* UTC */ + break; + case '+': + case '-': + for (part = 7; part < 9 && p < e; part++) { + c1 = *p; + if (!ASCII_DIGIT(c1)) { + break; + } + p++; + if (p == e) { + return LDAP_INVALID_SYNTAX; + } + c2 = *p++; + if (!ASCII_DIGIT(c2)) { + return LDAP_INVALID_SYNTAX; } - if (parts[part] > c) { - parts[part] -= c + 1; - parts[part - 1]++; + parts[part] = c1 * 10 + c2 - '0' * 11; + if (parts[part] >= ceiling[part]) { + return LDAP_INVALID_SYNTAX; } } - break; - case 1: /* positive offset to UTC, ie east of Greenwich */ - parts[4] -= parts[7]; - parts[5] -= parts[8]; - for (part = 6; --part > 0; ) { - if (part != 3) { - c = ceiling[part]; - } else { - /* first arg to % needs to be non negativ */ - c = mdays[leapyear][(parts[2] - 1 + 12) % 12]; + if (part < 8 + start) { + return LDAP_INVALID_SYNTAX; + } + + if (tzoffset == '-') { + /* negative offset to UTC, ie west of Greenwich */ + parts[4] += parts[7]; + parts[5] += parts[8]; + /* offset is just hhmm, no seconds */ + for (part = 6; --part >= 0; ) { + if (part != 3) { + c = ceiling[part]; + } else { + c = mdays[leapyear][parts[2]]; + } + if (parts[part] >= c) { + if (part == 0) { + return LDAP_INVALID_SYNTAX; + } + parts[part] -= c; + parts[part - 1]++; + continue; + } else if (part != 5) { + break; + } } - if (parts[part] < 0) { - parts[part] += c + 1; - parts[part - 1]--; + } else { + /* positive offset to UTC, ie east of Greenwich */ + parts[4] -= parts[7]; + parts[5] -= parts[8]; + for (part = 6; --part >= 0; ) { + if (parts[part] < 0) { + if (part == 0) { + return LDAP_INVALID_SYNTAX; + } + if (part != 3) { + c = ceiling[part]; + } else { + /* make first arg to % non-negative */ + c = mdays[leapyear][(parts[2] - 1 + 12) % 12]; + } + parts[part] += c; + parts[part - 1]--; + continue; + } else if (part != 5) { + break; + } } } - break; - case 0: /* already UTC */ - break; } - return LDAP_SUCCESS; + return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS; } #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX + +#if 0 static int xutcTimeNormalize( Syntax *syntax, @@ -2170,7 +2187,7 @@ xutcTimeNormalize( { int parts[9], rc; - rc = check_time_syntax(val, 1, parts); + rc = check_time_syntax(val, 1, parts, NULL); if (rc != LDAP_SUCCESS) { return rc; } @@ -2187,6 +2204,7 @@ xutcTimeNormalize( return LDAP_SUCCESS; } +#endif /* 0 */ static int utcTimeValidate( @@ -2194,9 +2212,10 @@ utcTimeValidate( struct berval *in ) { int parts[9]; - return check_time_syntax(in, 1, parts); + return check_time_syntax(in, 1, parts, NULL); } -#endif + +#endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */ static int generalizedTimeValidate( @@ -2204,7 +2223,8 @@ generalizedTimeValidate( struct berval *in ) { int parts[9]; - return check_time_syntax(in, 0, parts); + struct berval fraction; + return check_time_syntax(in, 0, parts, &fraction); } static int @@ -2217,25 +2237,56 @@ generalizedTimeNormalize( void *ctx ) { int parts[9], rc; + unsigned int len; + struct berval fraction; - rc = check_time_syntax(val, 0, parts); + rc = check_time_syntax(val, 0, parts, &fraction); if (rc != LDAP_SUCCESS) { return rc; } - normalized->bv_val = sl_malloc( sizeof("YYYYmmddHHMMSSZ"), ctx ); + len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len; + normalized->bv_val = sl_malloc( len + 1, ctx ); if ( normalized->bv_val == NULL ) { return LBER_ERROR_MEMORY; } - sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ", + sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d", parts[0], parts[1], parts[2] + 1, parts[3] + 1, parts[4], parts[5], parts[6] ); - normalized->bv_len = 15; + if ( fraction.bv_len ) { + memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2, + fraction.bv_val, fraction.bv_len ); + normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.'; + } + strcpy( normalized->bv_val + len-1, "Z" ); + normalized->bv_len = len; return LDAP_SUCCESS; } +static int +generalizedTimeOrderingMatch( + int *matchp, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *value, + void *assertedValue ) +{ + struct berval *asserted = (struct berval *) assertedValue; + ber_len_t v_len = value->bv_len; + ber_len_t av_len = asserted->bv_len; + + /* ignore trailing 'Z' when comparing */ + int match = memcmp( value->bv_val, asserted->bv_val, + (v_len < av_len ? v_len : av_len) - 1 ); + if ( match == 0 ) match = v_len - av_len; + + *matchp = match; + return LDAP_SUCCESS; +} + static int nisNetgroupTripleValidate( Syntax *syntax, @@ -2781,7 +2832,7 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", SLAP_MR_ORDERING, NULL, - NULL, generalizedTimeNormalize, octetStringOrderingMatch, + NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch, NULL, NULL, "generalizedTimeMatch" }, -- 2.39.5