1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

TomatoVPN and Auth-Passwd

Discussion in 'Tomato Firmware' started by Dagger, Jun 30, 2010.

  1. Dagger

    Dagger Networkin' Nut Member

    I'd like to add username/password authentication to my WL-500gP running TomatoUSB w/VPN...

    I've seen the OpenVPN solutions using a perl script or PAM plugin... but I'm not sure if Tomato has PAM and I'm not too fond of the perl script approach.

    I did find another plugin that simply checks the local systems passwd/shadow file. Here are some links:

    http://sourceforge.net/projects/auth-passwd/files/
    http://freshmeat.net/projects/openvpn-auth-passwd/

    I haven't worked with Linux in years, and I'm new to using Tomato... so I was hoping someone could point me in the right direction to getting this plugin setup. What I'm guessing would work is using JFFS2 space to store the plugin.... but the plugin needs to be compiled and I'm not sure how to do that in Tomato.

    Here is another link showing the process on a NAS:

    http://blog.deadcode.net/2009/05/19...-openvpn-client-and-ds101j-openvpn-client/15/

    I'm sure this would be super easy to implement if someone could make a pre-compiled version of the plugin available... with TomatoVPN specific edits in the make file (OpenVPN path, passwd or shadow, etc...)

    Any ideas?
     
  2. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    No, Tomato does not have PAM. Easier than the module you speak of, though, would be a simple script (not perl, Tomato doesn't support that).

    I plan to include such support in the next release, so your post has triggered me to try and come up with such a script (this is untested and just a 5 minute attempt, so it may have some bugs):
    Code:
    #!/bin/sh
    authfile=/tmp/openvpn-auth
    i=2
    size=`cat $authfile | wc -l`
    while expr $i "<=" $size
    do
    	if cat $authfile | head -n $i | tail -n 2 | cmp -s $1
    	then
    		exit 0
    	fi
    	i=`expr $i + 2`
    done
    exit 1
    
    Give that a shot, with "auth-user-pass-verify /path/to/that/script via-file" in your server custom config and /tmp/openvpn-auth being a file with the following format:
    Code:
    user1
    pass1
    user2
    pass2
    ...
    
     
  3. Dagger

    Dagger Networkin' Nut Member

    I see... so OpenVPN is only looking for a 0 or 1 to be returned from the script? I'm in Afghanistan behind a NAT I don't control so I'll have to setup a little workbench network to test it... but I'll get to work on that, I have a second router I can use. I'll be home (Kentucky) in August and I'm trying to prep this Asus so I can access my home network from Afghanistan.

    In the meantime... would this line work?

    while expr $i "<" `wc -l $authfile`

    wc -l should only return the number of lines in the file. If so, would it better than having to call awk? Maybe a little faster, maybe use less memory?
     
  4. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Yes, exactly.

    Well, the wc included in Tomato prints the line number and filename, so you wouldn't be any better off using -l (unless you use a pipe so it doesn't know the filename).

    It either has to be:
    Code:
    while expr $i "<=" `wc -l $authfile | awk '{print $1}'`
    or
    Code:
    while expr $i "<=" `cat $authfile | wc -l`
    I've updated my previous post with (a variant of) the second version, as you're right; it would be more efficient.
     
  5. Dagger

    Dagger Networkin' Nut Member

    Nice changes... I especially like the new "size" variable. Now the number of lines in the file is only counted once.
     
  6. Dagger

    Dagger Networkin' Nut Member

    I'm not 100% sure about the syntax, might be missing a " here and there, but what do you think about this?

    Code:
    #!/bin/sh
    authfile=/tmp/openvpn-auth
    awk '$1==$username {pass=$2}' $authfile
    if [$pass=$password]
    then
       exit 0
    fi
    exit 1
    The idea is to use via-env for the auth-user-pass-verify method instead of via-file. With via-env OpenVPN calls the script and assigns the $username and $password variables for the process. This way the env variables pop smoke when the process ends and no temporary argument file is ever created...

    Awk reads the authfile one line at a time until it finds the record matching the supplied username, then reads the stored password. This way the file only needs to be read once...

    A simple IF statement compares the stored password with the supplied password and exits with 0 if it matches...

    Otherwise the script did not find the username or a matching password and exits with 1...

    The stored authfile for this approach would contain one username/password pair on each line seperated by at least one space...

    Code:
    user1 pass1
    user2 pass2
    user3 pass3
    Obviously, you could not have duplicate usernames in the file... otherwise awk would only authenticate the last instance of a duplicate username in the file...

    You want to avoid duplicate usernames anyway... because if you want to support auth-user-pass-verify only (no certs) then you want to set username-as-common-name so the authenticated username is substituted as a unique common name instead of the common name from a cert.
     
  7. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Well, for what I'll end up using, I'll be pulling things out of NVRAM instead of a file, so I was planning on using via-env.

    A few things about your last script:
    • The passwords are allowed to have spaces, so you need to be careful about field delimination.
    • I'm pretty sure you won't be able to set that shell variable from within awk (you could however have it print $2 and set the awk output to a variable)
    • if [...] syntax isn't supported in the ash shell, you'll need to use expr to evaluate things
    I like where you're going with it, though.
     
  8. Dagger

    Dagger Networkin' Nut Member

    Passwords - that's a tricky one... OpenVPN allows any printable character other than CR and LF... so there isn't anything left to use for a delimiter. I'd lean toward disallowing spaces in passwords... who uses spaces in passwords anyway? :)

    Awk - Good catch... how would I set awk output to a variable?

    if then - would this work instead ?

    Code:
    test $pass "=" $password && exit 0
     
  9. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Well, the delimiter between the username and password can still be a space, but you'll need to find a way to just use the remainder of the line as the password (or use a newline as the delimeter). I wouldn't want to disallow spaces in passwords, as passphrases are good practice and much harder to crack.
    Code:
    pass=`awk "\\\$1 ~ /$username/ {print \\\$2}" /tmp/openvpn-auth`
    But, then we still have the space issue to deal with.
    Just as long as $pass wasn't empty, it would. Even if you quoted your variable to make it work when $pass is empty, you'd be leaving a hole where a bad username and a null password would be authenticated. I'd probably go with something like:
    Code:
    test -n "$pass" && test "$pass" == "$password" && exit 0
    EDIT: The spaces problem could be gotten around with:
    Code:
    pass=`awk "\\\$1 ~ \"$username\" { print substr(\\\$0,length(\\\$1)+2) }" /tmp/openvpn-auth`
    To put it all together

    Code:
    #!/bin/sh
    pass=`awk "\\\$1 ~ \"$username\" { print substr(\\\$0,length(\\\$1)+2) }" /tmp/openvpn-auth`
    test -n "$pass" && test "$pass" == "$password" && exit 0
    exit 1
    
    Considerably better than what we started with. And it translates easily to what I'll use in the end. I'll just pipe the output of an nvram get to awk instead of reading it from a file. Thanks for sticking with this, working toward a better solution.
     
  10. Dagger

    Dagger Networkin' Nut Member

    Ok... thanks... assigning a variable from awk is easier than I thought it would be. The \\\'s are confusing me at the moment though... I'll have to look that up...(GriN)

    I like the test -n... that will also catch the "username not found" situations better than before...

    I have a concern about using ~ for matching $1 to $username though... I think that if user "Fran" was logging in and there was a user "Frank" in the authfile, then that record would be considered a match. Would it be better to use == here?
     
  11. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Because we want to expand the $username variable we have to use " instead of '. However, we don't want to expand $0 and $1 (we want it to show up exactly that way when awk sees it) so we have to escape the $ as \$. So, the " will evaluate that escape and we're back to just $0 and $1. Now, it's `'s turn and it still evaluates $0 and $1 before awk ever sees it. So, we have to escape the escape :wink:. Since things are evaluated twice here (" and `):
    \\\$ -> \$ -> $
    We only need one \ for " because only another " will try to parse it. The ` will leave it alone:
    \" -> \" -> "
    Yep, that's exactly what I was envisioning when I added that. If a username wasn't found then $pass will be empty. So, if someone gave a bogus username and an empty password, it would pass without that.
    Good point. I changed it to ~ because I wasn't able to get it to work with ==, and thought that maybe the version of awk in Tomato doesn't support it. However, I just tried it again and it worked. I was probably missing a set of ""s (around $username is my guess) when I tried it before, or something similar.
    Code:
    #!/bin/sh
    pass=`awk "\\\$1 == \"$username\" { print substr(\\\$0,length(\\\$1)+2) }" /tmp/openvpn-auth`
    test -n "$pass" && test "$pass" == "$password" && exit 0
    exit 1
    
     
  12. xenithorb

    xenithorb Networkin' Nut Member

    Thanks for you work on this topic. Scoured various forums and OpenVPN documentation looking for a solution for several hours on this topic. I had assumed that this was something rudimentary included within the system that I kept missing. Though I tried a very basic script, my lack of knowledge in the area precluded me from using it in a real-world scenario. Out of curiosity, was this not something that the firmware makers thought would be necessary? I'm not particularly partial to swapping keys, especially because the shiny "OpenVPN Client" doesn't appear to support anything but user/pass combos (which is how this started). My intent is for dynamic connections from my netbook at various hotspots, not a solid static tunnel between businesses, so something more "portable" in nature seemes to be necessary. I realize that I could probably easily do this with an internal computer, yet for some reason fancy running such a thing on the gateway anyway. Above all, glad to see (and rather surprised to see) the current date-stamps on this thread. Good to know i'm not that far behind the power curve. Thanks for your help and support, looking forward to seeing what you guys can whip up.
     
  13. Dagger

    Dagger Networkin' Nut Member

    Thanks for explaining the escapes... it makes a lot more sense now.

    So the Tomato GUI will store the usernames/password in NVRAM and you'll use a get to pass the data to awk... I like it.

    In the meantime... what if I echoed this script to a file from the Tomato GUI?

    Code:
    echo '#!/bin/sh
    user1="user1name"
    pass1="user1pass"
    user2="user2name"
    pass2="user2pass"
    user3="user3name"
    pass3="user3pass"
    test "$user1" = "$username" && "$pass1" = "$password" && exit 0
    test "$user2" = "$username" && "$pass2" = "$password" && exit 0
    test "$user3" = "$username" && "$pass3" = "$password" && exit 0
    exit 1' > /tmp/quickAuth.script
    Then set the following on the server:
    --auth-user-pass-verify /tmp/quickAuth.script via-env

    Set the following on the client:
    --auth-user-pass

    Would that work? Is that the correct way to echo a file from the GUI?


    Xenithorb - Keep in mind that if you disable cert authentication with client-cert-not-required and username-as-common-name... the server still requires a CA and CERT... and the client would still need the common CA. Still a lot simpler than dealing with CERTs and KEYs on the clients.
     
  14. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Yes. If you put that first bit in your init script (not in the VPN custom config), that should work.
     
  15. Dagger

    Dagger Networkin' Nut Member

    Init Script:
    Code:
    echo '#!/bin/sh
    user1="user1name"
    pass1="user1pass"
    test "$user1" = "$username" && "$pass1" = "$password" && exit 0
    exit 1' > /tmp/quickAuth.sh
    chmod 755 /tmp/quickAuth.sh
    VPN Server Custom Configuration:
    Code:
    --script-security 2
    --auth-user-pass-verify /tmp/quickAuth.sh via-env
    VPN Client Configuration:
    Code:
    auth-user-pass
    I've almost got this working, but there seems to be a script problem. Username/Password fails unless I change "exit 1" in the quickAuth.sh to "exit 0"...

    Any idea what's wrong with the logic/syntax in the quickAuth.sh script?
     
  16. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    You're missing "test" on your password test.
     
  17. Dagger

    Dagger Networkin' Nut Member

    Code:
    echo '#!/bin/sh
    user1="user1name"
    pass1="user1pass"
    test "$user1" = "$username" && test "$pass1" = "$password" && exit 0
    exit 1' > /tmp/quickAuth.sh
    chmod 755 /tmp/quickAuth.sh
    I changed the init script to the above, and rebooted... but user/pass authentication still fails. I really thought that was it though :(
     
  18. Dagger

    Dagger Networkin' Nut Member

    Code:
    echo '#!/bin/sh
    user1="user1name"
    pass1="user1pass"
    test "$user1" = "${username}" && test "$pass1" = "${password}" && exit 0
    exit 1' > /tmp/quickAuth.sh
    chmod 755 /tmp/quickAuth.sh
    Figured it out...

    Contrary to what the OpenVPN manual says... the USERNAME and PASSWORD variables are not set as environment variables when the script is called, rather they are passed parameters... at least the way I understand it.

    That being the case if you reference them with the ${parameter} syntax it works fine. :)

    Oh, and you have to use --script-security 3 and not --script-security 2, otherwise OpenVPN only passes USERNAME and not PASSWORD.
     
  19. kenyloveg

    kenyloveg LI Guru Member

    Well, SGT and Dagger
    Thanks for the great conversation, as I'm a watcher.
    This authentication way maybe solves my problem (RouterOS 4.11 as Server, Tomato as cliet), but I have to give a try. Cuz Router OS insists to auth user name and password as a requirement (with cert or not). I'm keeping getting "unknow auth alg" or "TLS failed" message from Router OS.
    I'll let you know once it can be done without problems.
     
  20. kenyloveg

    kenyloveg LI Guru Member

    one question for SGT, did you compiled openvpn client/server with the "--enable-password-save" configure option? or would it be a problem to this script?
    Thanks.
     
  21. kenyloveg

    kenyloveg LI Guru Member

    Well, Dagger
    After putting these in Script->Init

    Code:
    echo '#!/bin/sh
    user1="ppp1"
    pass1="123456"
    test "$user1" = "${username}" && test "$pass1" = "${password}" && exit 0
    exit 1' > /tmp/quickAuth.sh
    chmod 755 /tmp/quickAuth.sh
    and this in custom configuration in client 1

    Code:
    auth-user-pass
    I'm getting this error when i click

    Code:
    Aug 17 13:50:24 ? daemon.err openvpn[381]: ERROR: could not read Auth username from stdin
    Aug 17 13:50:24 ? daemon.notice openvpn[381]: Exiting
    Aug 17 13:50:24 ? user.info init[1]: VPN_LOG_ERROR: 311: Starting OpenVPN failed...
    
    Did you have the same problem, or can you help me to solve this?
    Thanks.
     
  22. kenyloveg

    kenyloveg LI Guru Member

    Can we just create a file with username/password in 2 lines, and store it in /tmp or /etc every time when Tomato boot?
    Then put "auth-user-pass /tmp/openvpn-auth" in client custom configuration to let opvn invoke the username and password?

    Thanks.
     
  23. kenyloveg

    kenyloveg LI Guru Member

    I've tried following script in Script->Init

    ether
    Code:
    echo '
    ppp1
    123456
    ' > /tmp/openvpn-auth
    or

    Code:
    echo '
    ppp1 123456
    ' > /tmp/openvpn-auth
    but all get

    Code:
    Aug 17 16:02:42 ? daemon.notice openvpn[300]: OpenVPN 2.1.1 mipsel-unknown-linux-gnu [SSL] [LZO2] built on Jan 31 2010
    Aug 17 16:02:42 ? daemon.warn openvpn[300]: WARNING: file '/tmp/openvpn-auth' is group or others accessible
    Aug 17 16:02:42 ? daemon.err openvpn[300]: ERROR: username from Auth authfile '/tmp/openvpn-auth' is empty
    Aug 17 16:02:42 ? daemon.notice openvpn[300]: Exiting
    Aug 17 16:02:42 ? user.info init[1]: VPN_LOG_ERROR: 311: Starting OpenVPN failed...
    
    kind of driving me crazy....
     
  24. Dagger

    Dagger Networkin' Nut Member

  25. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Yes, it is compiled with --enable-password-save.
     
  26. kenyloveg

    kenyloveg LI Guru Member

    Hi, Dagger
    Thanks for your replay.
    But, please consider my Tomato VPN MOD is only a client, RouterOS is the server side. Which means i can't let ROS authenticate through /tmp/quickAuth.sh but the RouterOS way.
    What i need is to create a simple file contains user name and password, which can be invoked in client custom configuration "auth-user-pass userpassfile".
     
  27. kenyloveg

    kenyloveg LI Guru Member

    Hi, guys
    Still getting confused after reading the openvpn 2.1 manual

    If SGT compiled with "enable-password-save" config, then no username will be invoked by Tomato, when ROS insist username and password?
    Also, does "up is a file containing username/password on 2 lines" means this file must be named to "up", and 2 lines means
    Code:
    ppp1 123456
    or
    Code:
    ppp1
    123456
    ?
     
  28. rhester72

    rhester72 Network Guru Member

    The file can be named whatever you like, but needs to have the user name on the first line and the password on the second as in your second example.

    Rodney
     
  29. kenyloveg

    kenyloveg LI Guru Member

    Well, finally got through it with
    Code:
    echo 'ppp1
    123456' > /tmp/up
    Now researching on TLS-Auth/HMAC stuff...
     
  30. kenyloveg

    kenyloveg LI Guru Member

  31. Dagger

    Dagger Networkin' Nut Member

    I'm not at all familiar with RouterOS's implementation of OpenVPN... so I have no idea... :(
     
  32. SgtPepperKSU

    SgtPepperKSU Network Guru Member

    Are you sure your RouterOS server is configured to use static key, not TLS? From the error message, I'd think it's expecting TLS, but you're using static key. I don't know anything about RouterOS, so I don't know if that's a configurable option.
     

Share This Page