diff --git a/src/LdifDotNet/RfcGrammar.cs b/src/LdifDotNet/RfcGrammar.cs index 3a615f8..204f435 100644 --- a/src/LdifDotNet/RfcGrammar.cs +++ b/src/LdifDotNet/RfcGrammar.cs @@ -15,7 +15,15 @@ internal static class RfcGrammar /// internal static readonly UTF8Encoding StrictUtf8 = new(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); - /// RFC 4512 numericoid / RFC 2849 ldap-oid: 1*DIGIT *("." 1*DIGIT). + /// + /// Numeric OID, deliberately the looser RFC 2849 ldap-oid grammar + /// (1*DIGIT *("." 1*DIGIT)) rather than RFC 4512's numericoid: leading-zero + /// arcs and single-arc OIDs are accepted. Correct per spec on every LDIF + /// boundary, and matched to slapd on the schema boundary — slaptest 2.6 + /// accepts 01.2.3.4.5, 1.02.3, and bare 1 in attributetype directives, so + /// tightening this would reject files slapd loads. Pinned by tests; do not + /// "fix" toward RFC 4512 without re-probing slapd. + /// internal static bool IsNumericOid(string text) { bool expectDigit = true; diff --git a/tests/LdifDotNet.Tests/AttributeDescriptionTests.cs b/tests/LdifDotNet.Tests/AttributeDescriptionTests.cs index b4c8309..748dca6 100644 --- a/tests/LdifDotNet.Tests/AttributeDescriptionTests.cs +++ b/tests/LdifDotNet.Tests/AttributeDescriptionTests.cs @@ -26,6 +26,7 @@ public void HasOption_matches_whole_options_case_insensitively(string descriptio [Theory] [InlineData("cn", true)] [InlineData("2.5.4.3", true)] + [InlineData("01.2.3", true)] // RFC 2849 ldap-oid allows leading zeros — deliberate, see RfcGrammar.IsNumericOid [InlineData("userCertificate;binary", true)] [InlineData("cn;lang-en;binary", true)] [InlineData("", false)] diff --git a/tests/LdifDotNet.Tests/SchemaParserTests.cs b/tests/LdifDotNet.Tests/SchemaParserTests.cs index 6cde7cc..4e0e63b 100644 --- a/tests/LdifDotNet.Tests/SchemaParserTests.cs +++ b/tests/LdifDotNet.Tests/SchemaParserTests.cs @@ -12,6 +12,23 @@ public static TheoryData SchemaFiles() return data; } + [Theory] + [InlineData("01.2.3.4.5")] // leading-zero arc — illegal per RFC 4512 numericoid + [InlineData("1.02.3")] // interior leading zero + [InlineData("1")] // single arc — RFC 4512 requires at least two + public void Oid_leniency_matches_slapd_not_rfc4512(string oid) + { + // Deliberate: IsNumericOid implements RFC 2849's looser ldap-oid, and + // slapd is exactly as loose — slaptest (OpenLDAP 2.6.10, 2026-08-03) + // accepted attributetype directives with every OID shape below. + // Tightening to RFC 4512's numericoid would reject schema files slapd + // loads, breaking the tolerant-reader / slapd-compatibility invariant. + var schema = LdapSchema.Parse( + $"attributetype ( {oid} NAME 'probeAttr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )\n"); + + Assert.Equal(oid, schema.AttributeTypes[0].Oid); + } + [Fact] public void Ldapsyntax_directive_parses_in_file_mode() {