If statement is not evaluated consistently - freeradius

Here is the code snippet I have deployed in copy-acct-to-home-server. Which basically checks if the username has "#" sign... if yes then it extracts huntgroup from mysql table comparing NAS-IP-Address. And finally if the result from the query is not null then it updates Proxy-to-Realm.
if(request:User-Name =~ /#/){
update control {
SQLQueryResult := "%{sql:SELECT `groupname` FROM `radhuntgroup` WHERE nasipaddress='%{NAS-IP-Address}'}" }
if( %{control:SQLQueryResult} != '') {
update control {
Proxy-To-Realm := SQLQueryResult } }
}
This code is not working as I would expect. Here is the debug message snippet outcome for both true and false conditions
When some value is extracted from the database the proxy-to-realm should have been assigned the proper value (but it's not working)
Acct-Session-Id = "5CD8CA8B-0012B000"
Framed-IP-Address = host.ip.address.local
Acct-Multi-Session-Id = "24c9a18012b85c514f44f9715cd8ca8b085b"
Acct-Link-Count = 1
Acct-Status-Type = Start
Acct-Authentic = RADIUS
User-Name = "user#domain.com"
NAS-IP-Address = some.ip.add.NAS
NAS-Identifier = "CustomNASID"
.........
--> user#domain.com
(6) SQL-User-Name set to 'user#domain.com'
rlm_sql (sql): Reserved connection (5)
(6) EXPAND /var/log/freeradius/sqllog.sql
(6) --> /var/log/freeradius/sqllog.sql
(6) Executing select query: SELECT `groupname` FROM `radhuntgroup` WHERE nasipaddress='some.ip.add.NAS'
rlm_sql (sql): Released connection (5)
(6) EXPAND %{sql:SELECT `groupname` FROM `radhuntgroup` WHERE nasipaddress='%{NAS-IP-Address}'}
(6) --> customRealm
(6) SQLQueryResult := customRealm
(6) } # update control = noop
(6) if ( %{control:SQLQueryResult} != '') {
(6) if ( %{control:SQLQueryResult} != '') -> TRUE
(6) if ( %{control:SQLQueryResult} != '') {
(6) update control {
(6) No attributes updated
(6) } # update control = noop
(6) } # if ( %{control:SQLQueryResult} != '') = noop
(6) } # if (request:User-Name =~ /#/) = noop
(6) } # preacct = ok
As could be seen from the log it is not updating the attribute proxy-to-realm with the value fetched from the database even though both the if conditions are true (the username contains # and SQLQueryResult is not null)
If condition seems to be true even when there is no value fetched from the database. Here is the log snippet.
Acct-Session-Id = "5CD8C9F7-C1DA2D04"
Framed-IP-Address = host.ip.address.local
Acct-Multi-Session-Id = "441e98b16388185680b4a7355cd8c9f7000a"
Acct-Link-Count = 5
Acct-Status-Type = Interim-Update
Acct-Authentic = RADIUS
User-Name = "user#somedomain"
NAS-IP-Address = some.ip.address.nas
...........
Executing section preacct from file /etc/freeradius/3.0/sites-enabled/copy-acct-to-home-server
(8) preacct {
(8) [preprocess] = ok
(8) if (request:User-Name =~ /#/){
(8) if (request:User-Name =~ /#/) -> TRUE
(8) if (request:User-Name =~ /#/) {
(8) update control {
(8) EXPAND %{User-Name}
(8) --> user#domain.com
(8) SQL-User-Name set to 'user#domain.com'
rlm_sql (sql): Reserved connection (6)
(8) EXPAND /var/log/freeradius/sqllog.sql
(8) --> /var/log/freeradius/sqllog.sql
(8) Executing select query: SELECT `groupname` FROM `radhuntgroup` WHERE nasipaddress='nas.ip.address.local'
(8) SQL query returned no results
rlm_sql (sql): Released connection (6)
(8) EXPAND %{sql:SELECT `groupname` FROM `radhuntgroup` WHERE nasipaddress='%{NAS-IP-Address}'}
(8) -->
(8) SQLQueryResult :=
(8) } # update control = noop
(8) if ( %{control:SQLQueryResult} != '') {
(8) if ( %{control:SQLQueryResult} != '') -> TRUE
(8) if ( %{control:SQLQueryResult} != '') {
(8) update control {
(8) No attributes updated
(8) } # update control = noop
(8) } # if ( %{control:SQLQueryResult} != '') = noop
(8) } # if (request:User-Name =~ /#/) = noop
(8) } # preacct = ok
The strange thing is although it is not fetching any value from the db
second if condition is being evaluated as true if (SQLQueryResult != '') should have been false in this case.
the attribute SQLQueryResult has been defined in the dictionary as string.
I am not sure what I am missing here... seems to be straightforward logic. Requesting help from the experts.

There are a couple of issues here.
First, closing braces of sections should always be on a new line. The config parser isn't great, and that might be tripping it up.
Second you're mixing attribute reference and expansion syntax.
if( %{control:SQLQueryResult} != '') {
The above isn't valid. Honestly I'm surprised the expression parser isn't throwing an error. It's probably because there are no spaces in %{control:SQLQueryResult} so it's treating it a string literal, and then comparing the string literal to an empty string.
You either need to wrap the expansion in double quotes
if ("%{control:SQLQueryResult}" != '') {
or use the attribute reference form
if (&control:SQLQueryResult != '') {
I'm fairly certain that's what's causing your issue.

Related

How to check this sequence element is equal to that sequence element in Dafny

I have 2 sequences a:seq and b:seq, I wonder if we use the function, how we can determine that the element at this index in seq a is equal to element at this index in seq b
function test(s:seq<nat>, u:seq<nat>): nat
ensures |s|>0
ensures |u|>0
ensures |s| == |u|
{
// Code
}
method Testing()
{
var sys:seq<nat> := [4,2,9,3,1];
var usr:seq<nat> := [1,2,3,4,5];
assert test(sys, usr) == 1
// The element at the index 2 of sys and usr are equal, so it have 1 element that match in both 2 sequence
}
Because of the function I could not create a while loop, so I can not do the basic logic on that, so I wonder if there's something that fit the requirement.
After researching and working by Python to find the recursion in Python, finally I found the answer for this:
function bullspec(s:seq<nat>, u:seq<nat>): nat
requires |s| > 0
requires |u| > 0
requires |s| == |u|
{
var index:=0;
if |s| == 1 then (
if s[0]==u[0]
then 1 else 0
) else (
if s[index] != u[index]
then bullspec(s[index+1..],u[index+1..])
else 1+bullspec(s[index+1..],u[index+1..])
)
}
This is a wonderful problem to solve with Dafny.
Let me state the problem in clear:
Given two sequences of the same length, find the first index at which these sequences are equal. Otherwise return the length of the sequences.
That formulation makes it possible to not require that sequences are non-empty.
Thus, we can start with the following definition
function bullspec(s:seq<nat>, u:seq<nat>): (r: nat)
requires |s| == |u|
// Ensures r is either a sequence index or the sequence length
ensures r <= |s|
// All the elements before r are different
ensures forall i: nat | i < r :: s[i] != u[i]
// Either r is the sequence length or the elements at index r are equal
ensures r == |s| || s[r] == u[r]
{
Now, if you manage to prove this function, you will have prove that this function does what you want it to do.
To obtain the body of the function, you usually have to check whether the sequence if empty. In our case, we can return 0, which is the length of the sequence.
if |s| == 0 then 0 else
If the sequence is not empty, then we can compare the first elements. If they are equal, then we return the index 0
if s[0] == u[0] then 0 else
Otherwise, what happens if we recurse into bullspec(s[1..],u[1..])? We will obtain an index that is offset by 1 ! So we only need to add 1 to it.
1 + bullspec(s[1..],u[1..])
}
With this, you can verify that your function does exactly what you intended it to do.

Checking for Out Links with DOORS DXL

I am trying to write a simple DXL that checks for out links. More specifically, I want to look through every requirement in a formal module and return the number of items missing an out link:
Module m = current
Object o = null
string objType = ""
Link outLink
int noOutLinkCount = 0
for o in m do {
objType = o."Object Type"
for outLink in o -> "*" do {
if objType == "Req" or objType = "Obj" and outLink == null then noOutLinkCount++
}
}
print "No Out Link Count = " noOutLinkCount""
For the life of me, I cannot figure out how to do this. The condition
outLink == null
does not seem to work.
Note: Checking to make sure the object is of type "Req" (Requirement) or "Obj" (Objective Requirement) is necessary as I do not care about missing links on Headers, images, text objects, etc.
This loop:
for outLink in o -> "*" do {
}
Will execute for each outlink. It will not execute at all if there are 0 outlinks.
I would structure the code like so:
Module m = current
Object o = null
string objType = ""
Link outLink
int noOutLinkCount = 0
for o in m do {
objType = o."Object Type" ""
// Check if the type is right
if ( ( objType == "Req" ) || ( objType == "Obj" ) ) {
// Check for any outlinks at all
bool no_outlink_flag = true
for outLink in o -> "*" do {
// If this executes, at least 1 outlink- flag and break
no_outlink_flag = false
break
}
// If we didn't flag any outlinks, increment
if ( no_outlink_flag ) {
noOutLinkCount++
}
}
}
print "No Out Link Count = " noOutLinkCount""
That should work. Let me know if it does!

What is the function of square brackets around table keys in lua?

I came across tables that have square brackets around keys:
local commands_json =
{
["request"] = {
["application"] = PW_APPLICATION,
["push_token"] = deviceToken
}
}
Can the square brackets be omitted?
It's simply the long form of specifying keys in a table. You can put any value between the [] (except nil. And floating-point NaNs). Whereas without them, you can only use identifiers.
For example:
tbl =
{
key name = 5,
}
That's a compile error, since "key name" isn't an identifier (due to the space). This works:
tbl =
{
["key name"] = 5,
}
And this:
tbl =
{
"key name" = 5,
}
Is also a compile error. If Lua sees a naked value like this, it thinks you're trying to add to the array part of the table. That is, it confuses it with:
tbl =
{
"key name",
}
Which creates a 1-element array, with tbl[1] equal to "key name". By using [], the compiler can easily tell that you meant for something to be a key rather than the value of an array element.
The long form also lets you distinguish between:
local name = "a name";
tbl =
{
["name"] = 5,
[name] = 7,
}
The second part means to evaluate the expression name, the result of which will be the key. So this table has the keys "name" and "a name".
You cannot omit the brackets
> x = { 'a' = 1 }
stdin:1: '}' expected near '='
the correct code is
> x = { ['a'] = 1 }
> print(x['a'])
1
or
> x = { a = 1 }
> print(x['a'])
1
However, the second one has its limitations. What if you want to have a key called "-"?
> x = { - = 1 }
stdin:1: unexpected symbol near '='
> x = { '-' = 1 }
stdin:1: '}' expected near '='
again the correct way is to use brackets
> x = { ['-'] = 1 }
> print(x['-'])
1
Or you want to create a field of name which is contained in a variable called a?
> a = 'cat'
> x = { [a] = 1 }
> print(x['cat'])
1
Brackets are used as a general form of key creation, they give you ability to put any hashable object as a key - not only strings.

How to parse text in Groovy

I need to parse a text (output from a svn command) in order to retrieve a number (svn revision).
This is my code. Note that I need to retrieve all the output stream as a text to do other operations.
def proc = cmdLine.execute() // Call *execute* on the strin
proc.waitFor() // Wait for the command to finish
def output = proc.in.text
//other stuff happening here
output.eachLine {
line ->
def revisionPrefix = "Last Changed Rev: "
if (line.startsWith(revisionPrefix)) res = new Integer(line.substring(revisionPrefix.length()).trim())
}
This code is working fine, but since I'm still a novice in Groovy, I'm wondering if there were a better idiomatic way to avoid the ugly if...
Example of svn output (but of course the problem is more general)
Path: .
Working Copy Root Path: /svn
URL: svn+ssh://svn.company.com/opt/svnserve/repos/project/trunk
Repository Root: svn+ssh://svn.company.com/opt/svnserve/repos
Repository UUID: 516c549e-805d-4d3d-bafa-98aea39579ae
Revision: 25447
Node Kind: directory
Schedule: normal
Last Changed Author: ubi
Last Changed Rev: 25362
Last Changed Date: 2012-11-22 10:27:00 +0000 (Thu, 22 Nov 2012)
I've got inspiration from the answer below and I solved using find(). My solution is:
def revisionPrefix = "Last Changed Rev: "
def line = output.readLines().find { line -> line.startsWith(revisionPrefix) }
def res = new Integer(line?.substring(revisionPrefix.length())?.trim()?:"0")
3 lines, no if, very clean
One possible alternative is:
def output = cmdLine.execute().text
Integer res = output.readLines().findResult { line ->
(line =~ /^Last Changed Rev: (\d+)$/).with { m ->
if( m.matches() ) {
m[ 0 ][ 1 ] as Integer
}
}
}
Not sure it's better or not. I'm sure others will have different alternatives
Edit:
Also, beware of using proc.text. if your proc outputs a lot of stuff, then you could end up blocking when the inputstream gets full...
Here is a heavily commented alternative, using consumeProcessOutput:
// Run the command
String output = cmdLine.execute().with { proc ->
// Then, with a StringWriter
new StringWriter().with { sw ->
// Consume the output of the process
proc.consumeProcessOutput( sw, System.err )
// Make sure we worked
assert proc.waitFor() == 0
// Return the output (goes into `output` var)
sw.toString()
}
}
// Extract the version from by looking through all the lines
Integer version = output.readLines().findResult { line ->
// Pass the line through a regular expression
(line =~ /Last Changed Rev: (\d+)/).with { m ->
// And if it matches
if( m.matches() ) {
// Return the \d+ part as an Integer
m[ 0 ][ 1 ] as Integer
}
}
}

Advanced query range

How to make a query in Ax with advanced filtering (with x++):
I want to make such filter criteria On SalesTable form to show SalesTable.SalesId == "001" || SalesLine.LineAmount == 100.
So result should show SalesOrder 001 AND other salesOrders which has at least one SalesLine with LineAmount = 100?
Jan's solution works fine if sales order '001' should only be selected if it has sales lines. If it doesn't have lines it won't appear in the output.
If it is important to you that sales order '001' should always appear in the output even if it doesn't have sales lines, you can do it via union as follows:
static void AdvancedFiltering(Args _args)
{
Query q;
QueryRun qr;
QueryBuildDataSource qbds;
SalesTable salesTable;
;
q = new Query();
q.queryType(QueryType::Union);
qbds = q.addDataSource(tablenum(SalesTable), identifierstr(SalesTable_1));
qbds.fields().dynamic(false);
qbds.fields().clearFieldList();
qbds.fields().addField(fieldnum(SalesTable, SalesId));
qbds.addRange(fieldnum(SalesTable, SalesId)).value(queryValue('001'));
qbds = q.addDataSource(tablenum(SalesTable), identifierstr(SalesTable_2), UnionType::Union);
qbds.fields().dynamic(false);
qbds.fields().clearFieldList();
qbds.fields().addField(fieldnum(SalesTable, SalesId));
qbds = qbds.addDataSource(tablenum(SalesLine));
qbds.relations(true);
qbds.joinMode(JoinMode::ExistsJoin);
qbds.addRange(fieldnum(SalesLine, LineAmount )).value(queryValue(100));
qr = new QueryRun(q);
while (qr.next())
{
salesTable = qr.get(tablenum(SalesTable));
info(salesTable.SalesId);
}
}
The AX select statement supports exists join such as:
while select salesTable
exits join salesLine
where salesLine.SalesId == salesTable.SalesId &&
salesLine.LineAmount == 100
X++ does not support exists clause as a subquery in the where clause. Therefore it is not possible to express the exists in combination with or.
However AX supports query expressions in a query.
Therefore your query should be possible to express like this:
static void TestQuery(Args _args)
{
SalesTable st;
QueryRun qr = new QueryRun(new Query());
QueryBuildDataSource qst = qr.query().addDataSource(tableNum(SalesTable));
QueryBuildDataSource qsl = qst.addDataSource(tableNum(SalesLine));
str qstr = strFmt('((%1.SalesId == "%2") || (%3.LineAmount == %4))',
qst.name(), queryValue("001"),
qsl.name(), queryValue(100));
qsl.relations(true); // Link on SalesId
qsl.joinMode(JoinMode::ExistsJoin);
qsl.addRange(fieldNum(SalesLine,RecId)).value(qstr);
info(qstr); // This is the query expression
info(qst.toString()); // This is the full query
while (qr.next())
{
st = qr.get(tableNum(SalesTable));
info(st.SalesId);
}
}
However, if sales order 001 does not contain lines, it will not be selected.
Other than that the output is as you requested:
((SalesTable_1.SalesId == "001") || (SalesLine_1.LineAmount == 100))
SELECT FIRSTFAST * FROM SalesTable
EXISTS JOIN FIRSTFAST * FROM SalesLine WHERE SalesTable.SalesId =
SalesLine.SalesId AND ((((SalesTable_1.SalesId == "001") ||
(SalesLine_1.LineAmount == 100))))
001
125
175

Resources