]> git.sur5r.net Git - openldap/commitdiff
Handle full syntax of Generalized Time and UTC Time.
authorHallvard Furuseth <hallvard@openldap.org>
Wed, 13 Aug 2003 20:04:59 +0000 (20:04 +0000)
committerHallvard Furuseth <hallvard@openldap.org>
Wed, 13 Aug 2003 20:04:59 +0000 (20:04 +0000)
No longer accept initial and trailing spaces in these syntaxes.

servers/slapd/schema_init.c

index 43bad4b5522d703fd9f96fa07f4561cf957ca6ba..056e085d0dd16f34d82317e3d89f97ac1a7f66ee 100644 (file)
@@ -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" },