Handle full syntax of Generalized Time and UTC Time.

No longer accept initial and trailing spaces in these syntaxes.
This commit is contained in:
Hallvard Furuseth 2003-08-13 20:04:59 +00:00
parent 281627d81d
commit 2d48b5dc99

View file

@ -1996,172 +1996,189 @@ certificateExactNormalize(
#endif /* HAVE_TLS */ #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 static int
check_time_syntax (struct berval *val, check_time_syntax (struct berval *val,
int start, 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 */ /* 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 */ /* 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; char *p, *e;
int part, c, tzoffset, leapyear = 0 ; int part, c, c1, c2, tzoffset, leapyear = 0;
if( val->bv_len == 0 ) { p = val->bv_val;
return LDAP_INVALID_SYNTAX;
}
p = (char *)val->bv_val;
e = p + val->bv_len; e = p + val->bv_len;
/* Ignore initial whitespace */ #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
while ( ( p < e ) && ASCII_SPACE( *p ) ) { parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
p++; #endif
} for (part = start; part < 7 && p < e; part++) {
c1 = *p;
if (e - p < 13 - (2 * start)) { if (!ASCII_DIGIT(c1)) {
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++;
break; break;
} }
p++; p++;
c -= '0';
if (p == e) { if (p == e) {
return LDAP_INVALID_SYNTAX; return LDAP_INVALID_SYNTAX;
} }
if (c < 0 || c > 9) { c = *p++;
if (!ASCII_DIGIT(c)) {
return LDAP_INVALID_SYNTAX; return LDAP_INVALID_SYNTAX;
} }
c += c1 * 10 - '0' * 11;
if ((part | 1) == 3) {
--c;
if (c < 0) {
return LDAP_INVALID_SYNTAX;
}
}
if (c >= ceiling[part]) {
if (! (c == 60 && part == 6 && start == 0))
return LDAP_INVALID_SYNTAX;
}
parts[part] = c; parts[part] = c;
}
c = *p++ - '0'; if (part < 5 + start) {
if (p == e) { return LDAP_INVALID_SYNTAX;
return LDAP_INVALID_SYNTAX; }
} for (; part < 9; part++) {
if (c < 0 || c > 9) { parts[part] = 0;
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;
}
if (parts[part] > ceiling[part]) {
return LDAP_INVALID_SYNTAX;
}
} }
/* leapyear check for the Gregorian calendar (year>1581) */ /* leapyear check for the Gregorian calendar (year>1581) */
if (((parts[1] % 4 == 0) && (parts[1] != 0)) || if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0)
((parts[0] % 4 == 0) && (parts[1] == 0)))
{ {
leapyear = 1; leapyear = 1;
} }
if (parts[3] > mdays[leapyear][parts[2]]) { if (parts[3] >= mdays[leapyear][parts[2]]) {
return LDAP_INVALID_SYNTAX; 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) { 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;
}
}
if (p == e) {
/* no time zone */
return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
}
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;
}
parts[part] = c1 * 10 + c2 - '0' * 11;
if (parts[part] >= ceiling[part]) {
return LDAP_INVALID_SYNTAX;
}
}
if (part < 8 + start) {
return LDAP_INVALID_SYNTAX; return LDAP_INVALID_SYNTAX;
} }
for (part = 7; part < 9; part++) { if (tzoffset == '-') {
c = *p++ - '0'; /* negative offset to UTC, ie west of Greenwich */
if (c < 0 || c > 9) { parts[4] += parts[7];
return LDAP_INVALID_SYNTAX; 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;
}
} }
parts[part] = c; } else {
/* positive offset to UTC, ie east of Greenwich */
c = *p++ - '0'; parts[4] -= parts[7];
if (c < 0 || c > 9) { parts[5] -= parts[8];
return LDAP_INVALID_SYNTAX; for (part = 6; --part >= 0; ) {
} if (parts[part] < 0) {
parts[part] *= 10; if (part == 0) {
parts[part] += c; return LDAP_INVALID_SYNTAX;
if (parts[part] < 0 || parts[part] > ceiling[part]) { }
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;
}
} }
} }
} }
/* Ignore trailing whitespace */ return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
while ( ( p < e ) && ASCII_SPACE( *p ) ) {
p++;
}
if (p != e) {
return LDAP_INVALID_SYNTAX;
}
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]];
}
if (parts[part] > c) {
parts[part] -= c + 1;
parts[part - 1]++;
}
}
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 (parts[part] < 0) {
parts[part] += c + 1;
parts[part - 1]--;
}
}
break;
case 0: /* already UTC */
break;
}
return LDAP_SUCCESS;
} }
#ifdef SUPPORT_OBSOLETE_UTC_SYNTAX #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
#if 0
static int static int
xutcTimeNormalize( xutcTimeNormalize(
Syntax *syntax, Syntax *syntax,
@ -2170,7 +2187,7 @@ xutcTimeNormalize(
{ {
int parts[9], rc; int parts[9], rc;
rc = check_time_syntax(val, 1, parts); rc = check_time_syntax(val, 1, parts, NULL);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
return rc; return rc;
} }
@ -2187,6 +2204,7 @@ xutcTimeNormalize(
return LDAP_SUCCESS; return LDAP_SUCCESS;
} }
#endif /* 0 */
static int static int
utcTimeValidate( utcTimeValidate(
@ -2194,9 +2212,10 @@ utcTimeValidate(
struct berval *in ) struct berval *in )
{ {
int parts[9]; 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 static int
generalizedTimeValidate( generalizedTimeValidate(
@ -2204,7 +2223,8 @@ generalizedTimeValidate(
struct berval *in ) struct berval *in )
{ {
int parts[9]; int parts[9];
return check_time_syntax(in, 0, parts); struct berval fraction;
return check_time_syntax(in, 0, parts, &fraction);
} }
static int static int
@ -2217,25 +2237,56 @@ generalizedTimeNormalize(
void *ctx ) void *ctx )
{ {
int parts[9], rc; 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) { if (rc != LDAP_SUCCESS) {
return rc; 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 ) { if ( normalized->bv_val == NULL ) {
return LBER_ERROR_MEMORY; 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[0], parts[1], parts[2] + 1, parts[3] + 1,
parts[4], parts[5], parts[6] ); 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; 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 static int
nisNetgroupTripleValidate( nisNetgroupTripleValidate(
Syntax *syntax, Syntax *syntax,
@ -2781,7 +2832,7 @@ static slap_mrule_defs_rec mrule_defs[] = {
{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' " {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
SLAP_MR_ORDERING, NULL, SLAP_MR_ORDERING, NULL,
NULL, generalizedTimeNormalize, octetStringOrderingMatch, NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
NULL, NULL, NULL, NULL,
"generalizedTimeMatch" }, "generalizedTimeMatch" },