Commit 2d48b5dc authored by Hallvard Furuseth's avatar Hallvard Furuseth
Browse files

Handle full syntax of Generalized Time and UTC Time.

No longer accept initial and trailing spaces in these syntaxes.
parent 281627d8
......@@ -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" },
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment