Prev: Compiling
Next: "open" issue in a new defined namespace
From: Don Pich on 1 Mar 2010 12:43 I'm trying to compose a tcl script to read a username for our radius server, and modify if it matches a couple of conditions. First off, here is a typical username that I would want to modify: 0900000023000003780a2202fc0000229f This is a hex string returned from a dslam. The issue is that the last 8 characters of the string can change on a whim. So I can't use it for authentication data. So I'll need to hack them off. Character's 19 through 26 contain the IP address of the device. So 0a2202fc equals the IP address 10.34.2.252. I will have a list of all the devices I will need to compare against. So here is my plan: 1) Read the username 2) If the length of the username equals 34, send it into an if/else a) Read characters 19~26 b) Comapre them to a(n) external file/array that has 300+ objects - Need help here c) If the value retrieved from 19~26 matches a 8 digit hex string stored in array/external file, truncate the last 8 characters of the username and store it as NEW_username. i.e. 0900000023000003780a2202fc0000229f will be modified to 0900000023000003780a2202fc 3) ELSE - do nothing and send the username through as presented. With my elementary knowledge of tcl, I got a start with this. proc ProcessBASIP {request response environ} { set username [ $request get User-Name ] if { [ string length $username ] == 34} { string equal string trimright # SETUP NEW USERNAME $environ put User-Name $NEW_username } else { $environ put User-Name $username } That's as far as I have gotten. I understand some computer languages, but regular expressions and tcl are a bit above me. Any help you can give me would be appreciated. Thanks, Don
From: Richard Owlett on 1 Mar 2010 16:55 The OP states at end of post that he is a newbie, so being a relative newbie myself, I'm perhaps going to be more verbose than most.[especially my variable names and comments ;] Don Pich wrote: > I'm trying to compose a tcl script to read a username for our radius > server, and modify if it matches a couple of conditions. > > First off, here is a typical username that I would want to modify: > 0900000023000003780a2202fc0000229f 0123456789012345678901234567890123 111111111122222222223333 Note that Tcl uses 0 {not 1} as index of list/array/vector/... > > This is a hex string returned from a dslam. The issue is that the last 8 > characters of the string can change on a whim. So I can't use it for > authentication data. So I'll need to hack them off. Character's 19 > through 26 contain the IP address of the device. So 0a2202fc equals the > IP address 10.34.2.252. I will have a list of all the devices I will > need to compare against. > > So here is my plan: > > 1) Read the username > 2) If the length of the username equals 34, send it into an if/else > a) Read characters 19~26 > b) Comapre them to a(n) external file/array that has 300+ objects - > Need help here > c) If the value retrieved from 19~26 matches a 8 digit hex string > stored in array/external file, truncate the last 8 characters of the > username and store it as NEW_username. > i.e. 0900000023000003780a2202fc0000229f will be modified to > 0900000023000003780a2202fc > 3) ELSE - do nothing and send the username through as presented. > > With my elementary knowledge of tcl, I got a start with this. > > proc ProcessBASIP {request response environ} { > set username [ $request get User-Name ] > > if { [ string length $username ] == 34} { > string equal > string trimright > # SETUP NEW USERNAME > $environ put User-Name $NEW_username > } > else { > $environ put User-Name $username > } > > That's as far as I have gotten. I understand some computer languages, > but regular expressions and tcl are a bit above me. > > Any help you can give me would be appreciated. > > Thanks, > Don proc EditUserName {username file_of_users} { # file_of_users is name of file containing known # IP addresses # if { [ string length $username ] <> 34} { return $username ;# return original user id } else { set a [split $username {}] ;# convert string to list set b [lrange $a 18 25] ;# b now has user IP set f [open $file_of_users] set u [read $f] ;# u has the all known users set u [split $u {}] close $f set flag [lsearch -exact $u $g] ;# -1 if no match if {[$flag > -1]} { return [lrange $a 0 25] ;# return truncated user id } else { return $username ;# return original user id } } }
From: Don Pich on 1 Mar 2010 17:26 Hello Richard, Thanks for the attempt. I have one question. Is $g a globally defined variable, or is there a bit missing? Can you use a file location for the filename? (i.e. /var/file_of_users)? proc EditUserName {username file_of_users} { # file_of_users is name of file containing known # IP addresses # if { [ string length $username ] <> 34} { return $username ;# return original user id } else { set a [split $username {}] ;# convert string to list set b [lrange $a 18 25] ;# b now has user IP set f [open $file_of_users] set u [read $f] ;# u has the all known users set u [split $u {}] close $f set flag [lsearch -exact $u $g] ;# -1 if no match if {[$flag > -1]} { return [lrange $a 0 25] ;# return truncated user id } else { return $username ;# return original user id } } }
From: Richard Owlett on 1 Mar 2010 18:05 Don Pich wrote: > Hello Richard, > > Thanks for the attempt. I have one question. > > Is $g a globally defined variable, or is there a bit missing? The $g was a typo. It should have been $b . [One of the reasons I tend to use long variable names. It makes some typos very obvious to be typos.] > Can you use a file location for the filename? (i.e. /var/file_of_users)? Anything the open command accepts. I'm strictly a Windows(tm) user without any familiarity with C or Linux conventions. So when I post code I assume all problem specific information is stored in a variable. I've reformatted my code to solve the line wrap garbling that occurred - There were tab characters in my post (probably not good idea). Convention in this group is to intersperse comments in quoted text and/or to bottom post. HTH > > > proc EditUserName {username file_of_users} { > # file_of_users is name of file containing known > # IP addresses > # > if { [ string length $username ] <> 34} { > return $username ;# return original user id > } > else { > set a [split $username {}] ;# convert string to list > set b [lrange $a 18 25] ;# b now has user IP > set f [open $file_of_users] > set u [read $f] ;# u has all known users > set u [split $u {}] > close $f > set flag [lsearch -exact $u $b] ;# -1 if no match > if {[$flag > -1]} { > return [lrange $a 0 25] ;# return truncated user id > } > else { > return $username ;# return original user id > } > } > } > >
From: Aric Bills on 1 Mar 2010 19:26
Let's pretend there's a text file at /var/file_of_users that contains the IP addresses of interest, in hexidecimal format, where the addresses are separated by some kind of whitespace (spaces, tabs, and/ or newlines). Let's read the contents of that file and put them in a global variable called "user_list". We'll use a regular expression that recognizes strings of non-space characters. proc read_user_list {filename} { variable user_list set filehandle [open $filename r] set contents [read $filehandle] close $filehandle set user_list [regexp -all -inline {\S+} $contents] } read_user_list /var/file_of_users Now let's pretend the argument $username contains a user name as you have described. Pretend $username is sanitized and that you've already populated $user_list before calling the following procedure. This procedure will return the first 26 characters of $username if $username is 34 characters long and contains an IP address that is listed in $user_list; otherwise it will return $username unchanged, whether it was 34 characters long or not. proc check_username {username} { variable user_list if {[string length $username] == 34} { set ip_address [string range $username 18 25] if {$ip_address in $user_list} { return [string range $string 0 end-8] } } return $username } If you're using an earlier version of Tcl than 8.5, then {$ip_address in $user_list} won't work. Instead, use {[lsearch -exact $user_list $ip_address] != -1}. |