# # Tests for parsing conditional expressions. # # $Id$ # # # A bunch of errors, in the order that the error strings # appear in parser.c # # All IP address literals should be parsed as prefixes condition ("foo\ data ERROR offset 6 End of string after escape condition ("foo data ERROR offset 2 Unterminated string condition () data ERROR offset 1 Empty string is invalid condition (!) data ERROR offset 2 Empty string is invalid condition (foo == bar data ERROR offset 11 No closing brace at end of string condition (|| b) data ERROR offset 1 Empty string is invalid condition ((ok || handled) foo) data ERROR offset 17 Unexpected text after condition # escapes in names are illegal condition (ok\ foo || handled) data ERROR offset 3 Unexpected escape condition (ok FOO handled) data ERROR offset 4 Invalid text. Expected comparison operator condition (ok !x handled) data ERROR offset 4 Invalid operator condition (ok =x handled) data ERROR offset 4 Invalid operator condition (ok =~ handled) data ERROR offset 7 Expected regular expression condition (ok == /foo/) data ERROR offset 7 Unexpected regular expression condition (ok == handled"foo") data ERROR offset 14 Unexpected start of string # And now we have a bunch of VALID conditions we want to parse. # sillyness is OK condition ((((((ok)))))) data ok # # Extra braces get squashed # condition (&User-Name == &User-Password) data &User-Name == &User-Password condition (!ok) data !ok condition !(ok) data !ok condition !!ok data ERROR offset 1 Double negation is invalid condition !(!ok) data ok # # These next two are identical after normalization # condition (&User-Name == &User-Password || &Filter-Id == &Reply-Message) data &User-Name == &User-Password || &Filter-Id == &Reply-Message condition ((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) data &User-Name == &User-Password || &Filter-Id == &Reply-Message condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) data !&User-Name == &User-Password || &Filter-Id == &Reply-Message # different from the previous ones. condition (!((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))) data !(&User-Name == &User-Password || &Filter-Id == &Reply-Message) condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)) data !&User-Name == &User-Password || &Filter-Id == &Reply-Message condition ((a == b) || (c == d))) data ERROR offset 22 Unexpected closing brace condition (handled && (Response-Packet-Type == Access-Challenge)) data handled && &Response-Packet-Type == Access-Challenge # This is OK, without the braces condition handled && &Response-Packet-Type == Access-Challenge data handled && &Response-Packet-Type == Access-Challenge # and this, though it's not a good idea. condition handled &&&Response-Packet-Type == Access-Challenge data handled && &Response-Packet-Type == Access-Challenge condition /foo/ =~ bar data ERROR offset 0 Conditional check cannot begin with a regular expression condition reply == request data ERROR offset 0 Cannot use list references in condition condition reply == "hello" data ERROR offset 0 Cannot use list references in condition condition "hello" == reply data ERROR offset 0 Cannot use list references in condition condition request:User-Name == reply:User-Name data &User-Name == &reply:User-Name # # Convert !~ to !(COND) for regex # condition foo =~ /bar/ data foo =~ /bar/ condition foo !~ /bar/ data !foo =~ /bar/ condition !foo !~ /bar/ data foo =~ /bar/ # # Convert != to !(COND) for normal checks # condition &User-Name == &User-Password data &User-Name == &User-Password condition &User-Name != &User-Password data !&User-Name == &User-Password condition !&User-Name != &User-Password data &User-Name == &User-Password condition foo data ERROR offset 0 Cannot do cast for existence check condition Filter-Id == &Framed-IP-Address data &Filter-Id == &Framed-IP-Address condition Filter-Id == &Framed-IP-Address data ERROR offset 21 Unnecessary cast condition Filter-Id == &Framed-IP-Address data ERROR offset 21 Cannot cast to a different data type condition Filter-Id == &Framed-IP-Address data ERROR offset 22 Invalid data type in cast # # Normalize things # condition Filter-Id == "127.0.0.1" data &Filter-Id == '127.0.0.1' condition 127.0.0.1 < &Framed-IP-Address data &Framed-IP-Address > 127.0.0.1 # =* and !* are only for attrs / lists condition "foo" !* bar data ERROR offset 6 Cannot use !* on a string condition "foo" =* bar data ERROR offset 6 Cannot use =* on a string # existence checks don't need the RHS condition User-Name =* bar data &User-Name condition User-Name !* bar data !&User-Name condition !User-Name =* bar data !&User-Name condition !User-Name !* bar data &User-Name # redundant casts get squashed condition Framed-IP-Address == 127.0.0.1 data &Framed-IP-Address == 127.0.0.1 condition Framed-IP-Address <= 192.168.0.0/16 data &Framed-IP-Address <= 192.168.0.0/16 # All IP address literals should be parsed as prefixes condition Framed-IP-Address <= 192.168.0.0/16 data &Framed-IP-Address <= 192.168.0.0/16 # string attributes must be string condition User-Name == "bob" data &User-Name == "bob" condition User-Name == `bob` data &User-Name == `bob` condition User-Name == 'bob' data &User-Name == 'bob' condition User-Name == bob data ERROR offset 13 Must have string as value for attribute # Integer (etc.) types must be "bare" condition Session-Timeout == 10 data &Session-Timeout == 10 condition Session-Timeout == '10' data ERROR offset 19 Value must be an unquoted string # Except for dates, which can be humanly readable! # This one is be an expansion, so it's left as-is. condition Event-Timestamp == "January 1, 2012 %{blah}" data &Event-Timestamp == "January 1, 2012 %{blah}" # This one is NOT an expansion, so it's parsed into normal form condition Event-Timestamp == 'January 1, 2012' #data &Event-Timestamp == 'Jan 1 2012 00:00:00 EST' # literals are parsed when the conditions are parsed condition X == 1 data ERROR offset 9 Failed to parse field condition NAS-Port == X data ERROR offset 12 Failed to parse value for attribute # # The RHS is a static string, so this gets mashed to a literal, # and then statically evaluated. # condition 127.0.0.1 == "127.0.0.1" data true condition 127.0.0.1 == "%{sql: 127.0.0.1}" data 127.0.0.1 == "%{sql: 127.0.0.1}" condition 00:11:22:33:44:55 == "00:11:22:33:44:55" data true condition 00:11:22:33:44:55 == "ff:11:22:33:44:55" data false condition 00:11:22:33:44:55 == "%{sql:00:11:22:33:44:55}" data 00:11:22:33:44:55 == "%{sql:00:11:22:33:44:55}" condition 00:XX:22:33:44:55 == 00:11:22:33:44:55 data ERROR offset 8 Failed to parse field # # Tests for boolean data types. # condition true data true condition 1 data true condition false data false condition 0 data false condition true && (User-Name == "bob") data &User-Name == "bob" condition false && (User-Name == "bob") data false condition false || (User-Name == "bob") data &User-Name == "bob" condition true || (User-Name == "bob") data true # # Both sides static data with a cast: evaluate at parse time. # condition 20 < 100 data true # # Both sides literal: evaluate at parse time # condition ('foo' == 'bar') data false condition ('foo' < 'bar') data false condition ('foo' > 'bar') data true condition ('foo' == 'foo') data true # # Double-quotes strings without expansions are literals # condition ("foo" == "%{sql: foo}") data foo == "%{sql: foo}" condition ("foo bar" == "%{sql: foo}") data "foo bar" == "%{sql: foo}" condition ("foo" == "bar") data false condition ("foo" == 'bar') data false # # The RHS gets parsed as a VPT_TYPE_DATA, which is # a double-quoted string. Except that there's no '%' # in it, so it reverts back to a literal. # condition (&User-Name == "bob") data &User-Name == "bob" condition (&User-Name == "%{sql: blah}") data &User-Name == "%{sql: blah}" condition 127.0.0.1 == 2130706433 data true # /32 suffix should be trimmed for this type condition 127.0.0.1/32 == 127.0.0.1 data true condition 127.0.0.1/327 == 127.0.0.1 data ERROR offset 8 Failed to parse field condition 127.0.0.1/32 == 127.0.0.1 data true condition (/foo/) data ERROR offset 1 Conditional check cannot begin with a regular expression # # Tests for (FOO). # condition (1) data true condition (0) data false condition (true) data true condition (false) data false condition ('') data false condition ("") data false # # Integers are true, as are non-zero strings # condition (4) data true condition ('a') data true condition (a) data ERROR offset 1 Expected a module return code # # Module return codes are OK # condition (ok) data ok condition (handled) data handled condition (fail) data fail condition ("a") data true condition (`a`) data `a` condition (User-name) data &User-Name # # Forbidden data types in cast # condition ("foo" == &User-Name) data ERROR offset 2 Forbidden data type in cast # # Must have attribute references on the LHS of a condition. # condition ("foo" == &User-Name) data ERROR offset 1 Cannot use attribute reference on right side of condition # # If the LHS is a cast to a type, and the RHS is an attribute # of the same type, then re-write it so that the attribute # is on the LHS of the condition. # condition "foo" == &User-Name data &User-Name == "foo" condition "%{expr: 1 + 1}" < &NAS-Port data &NAS-Port > "%{expr: 1 + 1}" condition &Filter-Id == &Framed-IP-Address data ERROR offset 0 Attribute comparisons must be of the same data type condition 127.0.0.1 == &Filter-Id data ERROR offset 0 Attribute comparisons must be of the same data type condition &Tmp-Integer64-0 == &request:Foo-Stuff-Bar data &Tmp-Integer64-0 == &Foo-Stuff-Bar condition &Tmp-Integer64-0 == &reply:Foo-Stuff-Bar data &Tmp-Integer64-0 == &reply:Foo-Stuff-Bar # # Casting attributes of different size # condition &Tmp-Integer64-0 == &Framed-IP-Address data ERROR offset 0 Cannot cast to attribute of incompatible size condition &PMIP6-Home-IPv4-HoA == &Framed-IP-Address data ERROR offset 0 Cannot cast to attribute of incompatible size # but these are allowed condition &Tmp-Integer64-0 == "%{module: foo}" data &Tmp-Integer64-0 == "%{module: foo}" condition &Filter-Id == &Framed-IP-Address data &Filter-Id == &Framed-IP-Address condition &Class == &Framed-IP-Address data &Class == &Framed-IP-Address # # Tags of zero mean restrict to attributes with no tag # condition &Tunnel-Password:0 == "Hello" data &Tunnel-Password:0 == "Hello" condition &Tunnel-Password:1 == "Hello" data &Tunnel-Password:1 == "Hello" # # Single quoted strings are left as-is # condition &Tunnel-Password:1 == 'Hello' data &Tunnel-Password:1 == 'Hello' # # zero offset into arrays get parsed and ignored # condition &User-Name[0] == "bob" data &User-Name[0] == "bob" condition &User-Name[1] == "bob" data &User-Name[1] == "bob" condition &User-Name[n] == "bob" data &User-Name[n] == "bob" condition &Tunnel-Password:1[0] == "Hello" data &Tunnel-Password:1[0] == "Hello" condition &Tunnel-Password:1[3] == "Hello" data &Tunnel-Password:1[3] == "Hello" # # This is allowed for pass2-fixups. Foo-Bar MAY be an attribute. # If so allow it so that pass2 can fix it up. Until then, # it's an unknown attribute # condition &Foo-Bar data &Foo-Bar # Same types are optimized # # FIXME: the tests don't currently run the "pass2" checks. # This test should really be: # # data &Acct-Input-Octets > &Session-Timeout # condition &Acct-Input-Octets > "%{Session-Timeout}" data &Acct-Input-Octets > "%{Session-Timeout}" # Separate types aren't optimized condition &Acct-Input-Octets-64 > "%{Session-Timeout}" data &Acct-Input-Octets-64 > "%{Session-Timeout}" # # Parse OIDs into known attributes, where possible. # condition &Attr-26.24757.84.9.5.4 == 0x1a99 data &WiMAX-PFDv2-Src-Port == 6809 # # This OID is known, but the data is malformed. # This is disallowed. Fix the configuration so that # it works. # condition &Attr-26.24757.84.9.5.7 == 0x1a99 data ERROR offset 27 Failed to parse value for attribute # This one is really unknown condition &Attr-26.24757.84.9.5.15 == 0x1a99 data &Attr-26.24757.84.9.5.15 == 0x1a99 # # Invalid array references. # condition &User-Name[a] == 'bob' data ERROR offset 11 Array index is not an integer condition &User-Name == &Filter-Id[a] data ERROR offset 25 Array index is not an integer # # This one is still wrong. # condition User-Name[a] == 'bob' data false # # Bounds checks... # condition &User-Name[1001] == 'bob' data ERROR offset 11 Invalid array reference '1001' (should be between 0-1000) condition &User-Name[-1] == 'bob' data ERROR offset 11 Invalid array reference '-1' (should be between 0-1000) # # Tags # condition &Tunnel-Private-Group-Id:10 == 'test' data &Tunnel-Private-Group-Id:10 == 'test' condition &User-Name:10 == 'test' data ERROR offset 10 Attribute 'User-Name' cannot have a tag # # Tags are always wrong for attributes which aren't tagged. # condition &User-Name:0 == 'test' data ERROR offset 10 Attribute 'User-Name' cannot have a tag # # Bounds checks... # condition &Tunnel-Private-Group-Id:32 == 'test' data ERROR offset 25 Invalid tag value '32' (should be between 0-31) condition &request:Tunnel-Private-Group-Id:-1 == 'test' data ERROR offset 33 Invalid tag value '-1' (should be between 0-31) # # Sometimes the attribute/condition parser needs to fallback to bare words # condition request:Foo == 'request:Foo' data true condition request:Foo+Bar == request:Foo+Bar data true condition &request:Foo+Bar == 'request:Foo+Bar' data ERROR offset 12 Unexpected text after unknown attr condition 'request:Foo+d' == &request:Foo+Bar data ERROR offset 31 Unexpected text after unknown attr # Attribute tags are not allowed for unknown attributes condition &request:FooBar:0 == &request:FooBar data ERROR offset 15 Unexpected text after unknown attr condition ¬-a-list:User-Name == ¬-a-list:User-Name data ERROR offset 1 Invalid list qualifier # . is a valid dictionary name attribute, so we can't error out in pass1 condition ¬-a-packet.User-Name == ¬-a-packet.User-Name data ¬-a-packet.User-Name == ¬-a-packet.User-Name # # The LHS is a string with ASCII 5C 30 30 30 inside of it. # condition ('i have scary embedded things\000 inside me' == "i have scary embedded things\000 inside me") data false # # 'Unknown' attributes which are defined in the main dictionary # should be resolved to their real names. condition &Attr-1 == 'bar' data &User-Name == 'bar' condition &Vendor-11344-Attr-1 == 127.0.0.1 data &FreeRADIUS-Proxied-To == 127.0.0.1 condition &FreeRADIUS-Attr-1 == 127.0.0.1 data &FreeRADIUS-Proxied-To == 127.0.0.1 # # Escape the backslashes correctly # And print them correctly # condition &User-Name =~ /@|\\/ data &User-Name =~ /@|\\/ condition &User-Name == '\\' data &User-Name == '\\' condition &User-Name !~ /^foo\nbar$/ data !&User-Name =~ /^foo\nbar$/ condition &User-Name == "@|\\" data &User-Name == "@|\\" condition &User-Name != "foo\nbar" data !&User-Name == "foo\nbar" condition User-Name =~ /^([^\\]*)\\(.*)$/ data &User-Name =~ /^([^\\]*)\\(.*)$/ # # We require explicit casts # condition 192.168.0.0/16 > 192.168.1.2 data false condition 192.168.0.0/16 > 192.168.1.2 data true condition &NAS-IP-Address == 192.168.0.0/24 data &NAS-IP-Address == 192.168.0.0/24 condition 192.168.0.0/24 > &NAS-IP-Address data 192.168.0.0/24 > &NAS-IP-Address # # We add casts to the LHS if necessary # condition &NAS-IP-Address < &PMIP6-Home-IPv4-HoA data &NAS-IP-Address < &PMIP6-Home-IPv4-HoA condition &NAS-IP-Address < 192.168/16 data &NAS-IP-Address < 192.168.0.0/16 condition &NAS-IP-Address < "%{echo: 192.168/16}" data &NAS-IP-Address < "%{echo: 192.168/16}" condition &NAS-IP-Address < `/bin/echo 192.168/16` data &NAS-IP-Address < `/bin/echo 192.168/16`