]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9358 Fix reqStart normalizer
authorHoward Chu <hyc@openldap.org>
Tue, 29 Sep 2020 07:22:55 +0000 (08:22 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Wed, 30 Sep 2020 15:51:14 +0000 (15:51 +0000)
Don't truncate trailing zeroes in reqStart/reqEnd timestamps

servers/slapd/overlays/accesslog.c

index 78657dac39502fa78841840792b18160bf065e64..77e9ada6dc3d2c274dc664bced0ef9effd3beb69 100644 (file)
@@ -2296,9 +2296,167 @@ accesslog_db_open(
        return 0;
 }
 
+enum { start = 0 };
+
+static int
+check_rdntime_syntax (struct berval *val,
+       int *parts,
+       struct berval *fraction)
+{
+       /*
+        * GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
+        * 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 */
+               { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+               /* leap years */
+               { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+       };
+       char *p, *e;
+       int part, c, c1, c2, tzoffset, leapyear = 0;
+
+       p = val->bv_val;
+       e = p + val->bv_len;
+
+       for (part = start; part < 7 && p < e; part++) {
+               c1 = *p;
+               if (!ASCII_DIGIT(c1)) {
+                       break;
+               }
+               p++;
+               if (p == e) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               c = *p++;
+               if (!ASCII_DIGIT(c)) {
+                       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;
+       }
+       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[parts[1] == 0 ? 0 : 1] % 4 == 0) {
+               leapyear = 1;
+       }
+
+       if (parts[3] >= mdays[leapyear][parts[2]]) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       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)) {
+                               /* EMPTY */;
+                       }
+                       if (p - fraction->bv_val == 1) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+#if 0          /* don't truncate trailing zeros */
+                       for (end_num = p; end_num[-1] == '0'; --end_num) {
+                               /* EMPTY */;
+                       }
+                       c = end_num - fraction->bv_val;
+#else
+                       c = p - fraction->bv_val;
+#endif
+                       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) {
+       case 'Z':
+               /* UTC */
+               break;
+       default:
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
+}
+
+static int
+rdnTimestampValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       int parts[9];
+       struct berval fraction;
+       return check_rdntime_syntax(in, parts, &fraction);
+}
+
+static int
+rdnTimestampNormalize(
+       slap_mask_t usage,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *val,
+       struct berval *normalized,
+       void *ctx )
+{
+       int parts[9], rc;
+       unsigned int len;
+       struct berval fraction;
+
+       rc = check_rdntime_syntax(val, parts, &fraction);
+       if (rc != LDAP_SUCCESS) {
+               return rc;
+       }
+
+       len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
+       normalized->bv_val = slap_sl_malloc( len + 1, ctx );
+       if ( BER_BVISNULL( normalized ) ) {
+               return LBER_ERROR_MEMORY;
+       }
+
+       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] );
+       if ( !BER_BVISEMPTY( &fraction ) ) {
+               memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
+                       fraction.bv_val, fraction.bv_len );
+               normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
+       }
+       strcpy( normalized->bv_val + len-1, "Z" );
+       normalized->bv_len = len;
+
+       return LDAP_SUCCESS;
+}
+
+
 int accesslog_initialize()
 {
        int i, rc;
+       Syntax *rdnTimestampSyntax;
+       MatchingRule *rdnTimestampMatch;
 
        accesslog.on_bi.bi_type = "accesslog";
        accesslog.on_bi.bi_db_init = accesslog_db_init;
@@ -2365,6 +2523,25 @@ int accesslog_initialize()
 #endif
        }
 
+       /* Inject custom normalizer for reqStart/reqEnd */
+       rdnTimestampMatch = ch_malloc( sizeof( MatchingRule ));
+       rdnTimestampSyntax = ch_malloc( sizeof( Syntax ));
+       *rdnTimestampMatch = *ad_reqStart->ad_type->sat_equality;
+       rdnTimestampMatch->smr_normalize = rdnTimestampNormalize;
+       *rdnTimestampSyntax = *ad_reqStart->ad_type->sat_syntax;
+       rdnTimestampSyntax->ssyn_validate = rdnTimestampValidate;
+       ad_reqStart->ad_type->sat_equality = rdnTimestampMatch;
+       ad_reqStart->ad_type->sat_syntax = rdnTimestampSyntax;
+
+       rdnTimestampMatch = ch_malloc( sizeof( MatchingRule ));
+       rdnTimestampSyntax = ch_malloc( sizeof( Syntax ));
+       *rdnTimestampMatch = *ad_reqStart->ad_type->sat_equality;
+       rdnTimestampMatch->smr_normalize = rdnTimestampNormalize;
+       *rdnTimestampSyntax = *ad_reqStart->ad_type->sat_syntax;
+       rdnTimestampSyntax->ssyn_validate = rdnTimestampValidate;
+       ad_reqEnd->ad_type->sat_equality = rdnTimestampMatch;
+       ad_reqEnd->ad_type->sat_syntax = rdnTimestampSyntax;
+
        for ( i=0; locs[i].ot; i++ ) {
                int code;