OpenNDS option login_option_enabled '3' Login Loop

Hi all.

I am using OpenWrt 24.10.0 and got OpenNDS to run with the hint: opennds.@opennds[0].use_outdated_mhd='1' option login_option_enabled '1' option login_option_enabled '2' working for me.

option login_option_enabled '3' the captive portal appears and when I try to log in with username and password I am redirected to the next page and click on the Continue button. When I do this, it takes me back to the first page. So I can't get on the network.

Can someone look at my problem?

/etc/config/opennds

opennds.@opennds[0]=opennds
opennds.@opennds[0].enabled='1'
opennds.@opennds[0].debuglevel='2'
opennds.@opennds[0].login_option_enabled='3'
opennds.@opennds[0].themespec_path='/usr/lib/opennds/ThemeSpec.sh'
opennds.@opennds[0].use_outdated_mhd='1'
opennds.@opennds[0].gatewayinterface='phy1-ap1'
opennds.@opennds[0].gatewayname='Wlan'
opennds.@opennds[0].binauth='/usr/lib/opennds/my_binauth_script.sh'
opennds.@opennds[0].faskey='b094b9692a41c9e7d4e87913d7bec09adf029b9e83db2a0fb14dce5e913343a6'

/usr/lib/opennds/my_binauth_script.sh
#!/bin/sh

# Pfad zur Benutzerdatei
USER_FILE="/etc/opennds/users.list"

# Lese die vom Client übermittelten Daten (werden von openNDS als Umgebungsvariablen bereitgestellt)
CLIENT_USER="$AUTH_USER"
CLIENT_PASS="$AUTH_PASS"
CLIENT_MAC="$CLIENTMAC" # Nur zur Info/Logging, falls gewünscht

# Debugging-Ausgabe (optional, nützlich bei Problemen)
# logger -t binauth "Login attempt: User='$CLIENT_USER', Pass='******', MAC='$CLIENT_MAC'"

# Prüfe, ob Benutzername und Passwort übergeben wurden
if [ -z "$CLIENT_USER" ] || [ -z "$CLIENT_PASS" ]; then
    # logger -t binauth "Login failed: Empty username or password. MAC: $CLIENT_MAC"
    exit 1 # Fehlschlag
fi

# Suche den Benutzer in der Datei und prüfe das Passwort
# Format in users.list: username:password
EXPECTED_PASS=$(grep "^${CLIENT_USER}:" "$USER_FILE" | cut -d':' -f2)

if [ -n "$EXPECTED_PASS" ] && [ "$CLIENT_PASS" = "$EXPECTED_PASS" ]; then
    # Passwort stimmt überein
    # logger -t binauth "Login successful: User='$CLIENT_USER', MAC='$CLIENT_MAC'"
    exit 0 # Erfolg -> openNDS gewährt Zugang
else
    # Falscher Benutzername oder falsches Passwort
    # logger -t binauth "Login failed: Invalid credentials for User='$CLIENT_USER'. MAC: $CLIENT_MAC"
    exit 1 # Fehlschlag -> openNDS verweigert Zugang
fi
/usr/lib/opennds/ThemeSpec.sh
#!/bin/sh

# Lese Variablen von openNDS (optional, aber nützlich)
gatewayname="$GATEWAYNAME"
clientip="$CLIENTIP"
clientmac="$CLIENTMAC"
authaction="$AUTH_ACTION" # Die URL, an die das Formular gesendet werden muss

# Generiere den HTML-Code
cat << EOF
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Willkommen bei $gatewayname</title>
    <style>
        body {
            font-family: sans-serif;
            background-color: #f4f4f4;
            margin: 0;
            padding: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }
        .container {
            background-color: #fff;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            max-width: 500px;
            width: 100%;
            text-align: center;
        }
        h1 {
            color: #333;
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            color: #555;
            text-align: left;
        }
        input[type="text"], input[type="password"] {
            width: calc(100% - 22px); /* Adjust for padding/border */
            padding: 10px;
            margin-bottom: 15px;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        button {
            background-color: #5cb85c;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
        }
        button:hover {
            background-color: #4cae4c;
        }
        .info, .disclaimer {
            margin-top: 25px;
            font-size: 0.9em;
            color: #666;
            text-align: left;
            padding-top: 15px;
            border-top: 1px solid #eee;
        }
        .disclaimer {
            font-size: 0.8em;
            color: #888;
        }
        .price-info {
            font-weight: bold;
            color: #337ab7; /* Blue color for emphasis */
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Willkommen bei "$gatewayname"</h1>
        <p>Bitte melden Sie sich an, um das Internet zu nutzen.</p>

        <form method="POST" action="$authaction">
            <div>
                <label for="auth_user">Benutzername:</label>
                <input type="text" id="auth_user" name="auth_user" required>
            </div>
            <div>
                <label for="auth_pass">Passwort:</label>
                <input type="password" id="auth_pass" name="auth_pass" required>
            </div>
            <button type="submit">Anmelden</button>
        </form>

        <div class="info">
            <p class="price-info">Dieser WLAN-Zugang wird für 20€ pro Monat angeboten.</p>
            <p>Kontaktieren Sie den Betreiber für Zugangsdaten.</p>
            </div>

        <div class="disclaimer">
            <h2>Haftungsausschluss</h2>
            <p>Die Nutzung dieses WLAN-Zugangs erfolgt auf eigene Gefahr. Der Betreiber übernimmt keine Haftung für Schäden, die durch die Nutzung entstehen. Es ist untersagt, rechtswidrige Handlungen vorzunehmen (z. B. Urheberrechtsverletzungen). Der Betreiber speichert keine personenbezogenen Daten und behält sich vor, bei Verdacht auf Missbrauch den Zugang zu sperren.</p>
        </div>

        </div>
</body>
</html>
EOF

exit 0
/etc/opennds/users.list

user1:123456748
kundeA:passwortXYZ
gast123:geheim456

ThemeSpec Path

ThemeSpec Path
Default: None

Required when when login_option_enabled is set to ‘3’

Note: /usr/lib/opennds/theme_click-to-continue.sh is used for login_option_enabled ‘1’

and: /usr/lib/opennds/theme_user_email_login.sh is used for login_option_enabled ‘2’

Sets the ThemeSpec file path to be used when login_option_enabled ‘3’

The ThemeSpec script makes use of lists of custom parameters, custom variables, custom image urls and custom files and is used to generate the dynamic splash page sequence.

The ThemeSpec file will normally reside in /usr/lib/opennds/ but can be anywhere accessible to openNDS.

The file must be flagged as executable and have the correct shebang for the default shell.
Default: None

Required when when login_option_enabled is set to ‘3’

Note: /usr/lib/opennds/theme_click-to-continue.sh is used for login_option_enabled ‘1’

and: /usr/lib/opennds/theme_user_email_login.sh is used for login_option_enabled ‘2’

Sets the ThemeSpec file path to be used when login_option_enabled ‘3’

The ThemeSpec script makes use of lists of custom parameters, custom variables, custom image urls and custom files and is used to generate the dynamic splash page sequence.

The ThemeSpec file will normally reside in /usr/lib/opennds/ but can be anywhere accessible to openNDS.

The file must be flagged as executable and have the correct shebang for the default shell.

You are not authenticating anywhere, so yes you will go into a login loop.

Authentication is done in the ThemeSpec script, but your ThemeSpec.sh is just some html.

In addition, you have replaced the standard binauth script with something that does not do what is required.

Authentication is achieved by calling the auth_log () library function provided by openNDS.

Look in detail at the example ThemeSpec theme_user-email-login-basic.sh.
You can find this in /usr/lib/opennds. This is almost what you need as it asks for username and email address. A small edit would give you username and password. You could add a bit of script to check against your users.list file for credential verification before calling auth_log ().

Replacing binauth without knowing what the standard version does is a very bad idea and will break things. You can add custom functionality to binauth by adding to the placeholder file /usr/lib/opennds/custombinauth.sh, but really, I don't see that you need to.

Thank you for your detailed explanation. I've now changed the login_option_enabled to '2' and attempted to replace the username and email address fields with username and password. However, I'm still unable to access the network after entering my credentials. I'm still experiencing the login loop.

I appreciate your continued support in helping me resolve this issue.

/usr/lib/opennds/theme_user-email-login-basic.sh
#!/bin/sh
# Copyright (C) The openNDS Contributors 2004-2022
# Copyright (C) BlueWave Projects and Services 2015-2024
# This software is released under the GNU GPL license.
#
# Modifiziert für Benutzername/Passwort-Authentifizierung mit users.list
#
# Warnung - Shebang sh ist für Kompatibilität mit busybox ash (z.B. auf OpenWrt)
#

title="theme_user-password-login"
USER_LIST_FILE="/etc/opennds/users.list"
login_error_msg=""

# URL-Decoding für Benutzername und Passwort hinzufügen
# Assuming openNDS sets these variables based on query parameters
# We need to handle the case where they might not be set on the first load
safe_username=$(echo "$username" | sed 's/%\([0-9A-F][0-9A-F]\)/\\\x\1/g' | xargs -0 printf "%b" 2>/dev/null || true)
safe_password=$(echo "$password" | sed 's/%\([0-9A-F][0-9A-F]\)/\\\x\1/g' | xargs -0 printf "%b" 2>/dev/null || true)

# --- Function Definitions ---

generate_splash_sequence() {
    # Use the decoded variables within this function's scope
    local current_user="$safe_username"
    local current_pass="$safe_password"

    # Only attempt validation if both username and password seem to be provided
    if [ -n "$current_user" ] && [ -n "$current_pass" ]; then
        validate_credentials "$current_user" "$current_pass"
    else
        # If no credentials submitted, just show the login form
        login_form
    fi
}

header() {
    # Make sure gatewayurl is properly escaped for HTML context if needed
    # The original printf approach might be okay, but consider potential issues
    local safe_gatewayurl=$(printf "${gatewayurl//%/\\x}") # Original approach
    # Alternative: Basic check if it looks like a URL
    # local safe_gatewayurl="$gatewayurl" # Simpler if no special chars expected

    echo "<!DOCTYPE html>
        <html>
        <head>
        <meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\">
        <meta http-equiv=\"Pragma\" content=\"no-cache\">
        <meta http-equiv=\"Expires\" content=\"0\">
        <meta charset=\"utf-8\">
        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
        <link rel=\"shortcut icon\" href=\"$safe_gatewayurl/images/splash.jpg\" type=\"image/x-icon\">
        <link rel=\"stylesheet\" type=\"text/css\" href=\"$safe_gatewayurl/splash.css\">
        <title>$gatewayname</title>
        </head>
        <body>
        <div class=\"offset\">
        <med-blue>$gatewayname</med-blue>
        <div class=\"insert\" style=\"max-width:100%;\">"
}

footer() {
    local year=$(date +'%Y')
    local safe_gatewayurl=$(printf "${gatewayurl//%/\\x}") # Repeat safe URL handling if needed
    local safe_imagepath="$imagepath" # Assuming imagepath is safe

    echo "</div>
        <hr>
        <div style=\"font-size:0.5em;\">
            <br>
            <img style=\"height:60px; float:left;\" src=\"$safe_gatewayurl$safe_imagepath\" alt=\"Splash Page\">
            &copy; BlueWave Projects and Services 2015 - $year<br>
            Portal Version: $version
        </div>
        </div>
        </body>
        </html>"
    # It's generally better practice for the calling logic to exit, not the function
    # exit 0
}

# Function to display terms (assuming it exists elsewhere or needs to be added)
read_terms() {
    # Placeholder: Add logic to display terms and conditions if needed
    # This might involve a link or button handled by openNDS parameters
    echo "<p><small>By clicking 'Anmelden', you agree to the terms and conditions.</small></p>" # Example
}

# Function to display the actual terms page (assuming it exists elsewhere)
display_terms() {
    echo "<h2>Terms and Conditions</h2>"
    echo "<p>Please read and accept our terms...</p>"
    # Add a button/form to accept terms, which redirects back setting a parameter like 'terms=accepted'
    echo "<form action=\"/opennds_preauth/\" method=\"get\">"
    echo "  <input type=\"hidden\" name=\"fas\" value=\"$fas\">"
    # Pass other necessary parameters if needed
    echo "  <input type=\"hidden\" name=\"terms\" value=\"accepted\">" # Indicate terms accepted
    echo "  <input type=\"submit\" value=\"Accept Terms\">"
    echo "</form>"
}

# Function for the landing page after successful login
landing_page() {
    local user="$1"
    echo "<h2>Login Successful!</h2>"
    echo "<p>Welcome, $user!</p>"
    echo "<p>You are now connected to the internet.</p>"
    # Optionally, add a continue button or redirect information
    # NDS usually handles the redirect automatically after auth
}


validate_credentials() {
    local input_user="$1"
    local input_pass="$2"
    local is_valid=0
    local debug_log="/tmp/opennds_debug.log"

    # Clear or initialize debug log for this attempt
    echo "=== Validation Attempt Start: $(date) ===" > "$debug_log"
    echo "Script location: $(pwd)" >> "$debug_log"
    echo "Received User (decoded): [$input_user]" >> "$debug_log"
    # Be cautious logging passwords, even to temporary files
    echo "Received Pass (decoded): [REDACTED]" >> "$debug_log" # Avoid logging password directly
    # echo "Received Pass (decoded): [$input_pass]" >> "$debug_log" # Uncomment only for temporary, secure debugging
    echo "Users.list path: [$USER_LIST_FILE]" >> "$debug_log"

    # Check file existence
    if [ ! -f "$USER_LIST_FILE" ]; then
        echo "ERROR: Users list file not found at [$USER_LIST_FILE]" >> "$debug_log"
        login_error_msg="<br><b style='color:red;'>Fehler: Benutzerliste nicht gefunden ($USER_LIST_FILE)</b>"
        login_form
        return # Exit validation function
    fi
    echo "File Check: [$USER_LIST_FILE] exists." >> "$debug_log"

    # Check file readability (by the script's user)
    if [ ! -r "$USER_LIST_FILE" ]; then
        echo "ERROR: Cannot read users list file at [$USER_LIST_FILE]. Check permissions." >> "$debug_log"
        ls -l "$USER_LIST_FILE" >> "$debug_log" 2>&1 # Log permissions
        login_error_msg="<br><b style='color:red;'>Fehler: Kein Leserecht für Benutzerliste</b>"
        login_form
        return # Exit validation function
    fi
    echo "File Check: [$USER_LIST_FILE] is readable." >> "$debug_log"
    echo "File Permissions:" >> "$debug_log"
    ls -l "$USER_LIST_FILE" >> "$debug_log" 2>&1

    echo "--- Reading User List ---" >> "$debug_log"
    # Read the user list file line by line
    while IFS=: read -r user pass || [ -n "$user" ]; do # Handle last line without newline if necessary
        # Trim leading/trailing whitespace (optional but good practice)
        user=$(echo "$user" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
        pass=$(echo "$pass" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

        # Ignore comments and empty lines
        [ -z "$user" ] && continue
        echo "$user" | grep -q "^#" && continue

        echo "Checking against: User=[$user], Pass=[REDACTED]" >> "$debug_log"
        # Compare submitted credentials with current line from file
        if [ "$input_user" = "$user" ] && [ "$input_pass" = "$pass" ]; then
            echo "MATCH FOUND: User=[$user]" >> "$debug_log"
            is_valid=1
            break # Exit loop once match is found
        fi
    done < "$USER_LIST_FILE"
    echo "--- Finished Reading User List ---" >> "$debug_log"


    # Log validation result
    echo "Validation Result (0=Fail, 1=Success): $is_valid" >> "$debug_log"
    echo "=== Validation Attempt End ===" >> "$debug_log"

    if [ "$is_valid" -eq 1 ]; then
        # If valid, call the landing page function
        landing_page "$input_user"
    else
        # If invalid, set error message and show login form again
        login_error_msg="<br><b style='color:red;'>Ungültige Anmeldedaten</b>"
        login_form
    fi
}


login_form() {
    # Ensure variables like client_zone and fas are available
    # These should be passed by openNDS environment or query string

    echo "<big-red>Willkommen!</big-red><br>
        <med-blue>Client-Zone: $client_zone</med-blue><br>
        <italic-black>Bitte Anmeldedaten eingeben</italic-black>
        ${login_error_msg:-""}  # Display error message if set, otherwise nothing
        <hr>
        <form action=\"/opennds_preauth/\" method=\"get\">
            <input type=\"hidden\" name=\"fas\" value=\"$fas\">
            Username: <input type=\"text\" name=\"username\" placeholder=\"Benutzername\" required autofocus>
            <br>
            Password: <input type=\"password\" name=\"password\" placeholder=\"Passwort\" required>
            <br><br>
            <input type=\"submit\" value=\"Anmelden\">
        </form>"
    # Call read_terms function if you want terms info below the form
    read_terms
}

# --- Main Logic ---

# Call header function to output HTML head and start body
header

# Determine which page to show based on openNDS parameters
# These parameters ($terms, $landing) should be set by openNDS in the environment
# or parsed from $QUERY_STRING if necessary.

# Example assuming openNDS sets environment variables:
if [ "$terms" = "yes" ]; then
    display_terms
# elif [ "$landing" = "yes" ]; then # NDS usually handles the landing redirect after auth, this might not be needed here
#    landing_page "$safe_username" # Need username if showing landing page directly
else
    # Default action: Show login form or validate credentials if submitted
    generate_splash_sequence
fi

# Call footer function to close HTML
footer

# Exit after footer is printed
exit 0

uci show opennds
opennds.@opennds[0]=opennds
opennds.@opennds[0].enabled='1'
opennds.@opennds[0].debuglevel='3'
opennds.@opennds[0].login_option_enabled='2'
opennds.@opennds[0].use_outdated_mhd='1'
opennds.@opennds[0].gatewayinterface='phy1-ap1'
opennds.@opennds[0].gatewayname='WLAN Portal'
opennds.@opennds[0].sessiontimeout='5'
opennds.@opennds[0].faskey='3974b28b56956a0f334430e26f07389b7a82208ba4090f6b6a9393332a5a0418'

There are lots of things wrong here.

1.You still have a login loop because you are still not calling auth_log () anywhere as far as I can see.
2. Let me say that it is bad practice to actually modify the themespec example, instead you should have made a copy and edited the copy instead, keeping login_option_enabled set to 3.
3. opennds.@opennds[0].gatewayinterface='phy1-ap1' implies you are attempting to bind opennds directly to a wireless interface. This can lead to indeterminate results, if it works at all. A wireless interface is usually added to a bridge device and openNDS is bound to that bridge.

Note that in the example themespec scripts, the login sequence consists of the following pages:

  1. Login Form - the form where the client/user enters credentials.
  2. Thankyou Page - displayed if the credentials are valid. Clicking continue is interpreted as acceptance of the ToS and Privacy statement (very important in the EU as it passes legal responsibility for usage of the Internet feed to the client/user.)
  3. Landing Page - This page calls auth_log () and informs the client that Internet access is granted. On most modern devices this page is automatically closed and maybe so quickly it is not even seen, by the client device operating system (part of the standard CPD process).

Note: You would add your credential validation against your users.list in the themespec function name_email_login().
All you need to change to get username/password instead of username/email_address is the login form text. You don't actually need to change function names etc to make it work, such changes would be cosmetic in nature.

I would suggest:

  1. you restore all the standard scripts. The best and quickest way to do this is to force reinstall openNDS.
  2. Also fix the gatewayinterface binding issue I mentioned by adding the wireless interface to a bridge device.
  3. Then test with theme_user-email-login-basic.sh (login_option_enabled='2') to make sure it all works as standard with username and email address.
  4. Copy theme_user-email-login-basic.sh to your new `ThemeSpec.sh' file.
  5. Set opennds.@opennds[0].login_option_enabled='3'
  6. Set opennds.@opennds[0].themespec_path='/usr/lib/opennds/ThemeSpec.sh'
  7. Do service opennds restart
  8. Test if it still works with username/emailaddress
  9. Edit your `ThemeSpec.sh' and test again.

Hi @bluewavenet,

Thank you very much for your detailed suggestions in post #4. I've been following your steps carefully.

Now I've arrived at step 9: "Edit your ThemeSpec.sh [in my case, /etc/opennds/ThemeSpec_Guest_Password.sh] and test again."

This is where I'm running into trouble. I tried to modify the copied script (/etc/opennds/ThemeSpec_Guest_Password.sh) according to your notes: changing the login form text to ask for Username and Password, and adding the credential validation against /etc/opennds/users.list (using username:password format) within the name_email_login() function.

The modified script does show the Username and Password fields correctly on the login page. However, when I enter valid credentials from my /etc/opennds/users.list file and click "Login", it doesn't proceed to the "Thank You" page. It seems the validation part within the name_email_login function isn't working as intended in my modification, and I just get the login form again (sometimes with an error message, sometimes just reloaded).

Unfortunately, my shell scripting/programming skills are quite limited, and despite several attempts (including trying different code snippets found online or generated), I haven't been able to get the validation against the users.list file working correctly within the structure of the theme_user-email-login-basic.sh script.

Would you perhaps be able to provide the necessary code modifications for the name_email_login() function (and the corresponding changes in login_form()) within the copied ThemeSpec_Guest_Password.sh file to correctly validate username:password credentials against /etc/opennds/users.list?

I would be very grateful for your help in getting this final step working.

Thanks again for your support!

uci show opennds
opennds.@opennds[0]=opennds
opennds.@opennds[0].enabled='1'
opennds.@opennds[0].debuglevel='2'
opennds.@opennds[0].login_option_enabled='3'
opennds.@opennds[0].use_outdated_mhd='1'
opennds.@opennds[0].gatewayinterface='br-guest'
opennds.@opennds[0].gatewayname='WLAN Portal'
opennds.@opennds[0].sessiontimeout='3'
opennds.@opennds[0].faskey='0365bcf201f355c1b84c35d90f0b836ce61ae50d2e6a4b476142f9cec8718ce4'
opennds.@opennds[0].themespec_path='/etc/opennds/ThemeSpec_Guest_Password.sh'

/etc/opennds/ThemeSpec_Guest_Password.sh
root@Openwrt:~# cat /etc/opennds/ThemeSpec_Guest_Password.sh
#!/bin/sh
#Copyright (C) The openNDS Contributors 2004-2022
#Copyright (C) BlueWave Projects and Services 2015-2024
#This software is released under the GNU GPL license.
# MINIMALLY MODIFIED for Username/Password Validation based on theme_user-email-login-basic.sh

# Define path to user list file (ADDED)
USER_LIST_FILE="/etc/opennds/users.list"

# Title of this theme:
title="theme_user-password-login-minimal" # CHANGED title slightly

# --- Standard Functions (mostly unchanged) ---

generate_splash_sequence() {
        # Calls name_email_login - the function NAME remains the same,
        # but its *logic* will be modified for password validation.
        name_email_login
}

# --- header() function (unchanged from original) ---
header() {
        gatewayurl=$(printf "${gatewayurl//%/\\x}")
        echo "<!DOCTYPE html>
                <html>
                <head>
                <meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\">
                <meta http-equiv=\"Pragma\" content=\"no-cache\">
                <meta http-equiv=\"Expires\" content=\"0\">
                <meta charset=\"utf-8\">
                <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
                <link rel=\"shortcut icon\" href=\"$gatewayurl/images/splash.jpg\" type=\"image/x-icon\">
                <link rel=\"stylesheet\" type=\"text/css\" href=\"$gatewayurl/splash.css\">
                <title>$gatewayname</title>
                </head>
                <body>
                <div class=\"offset\">
                <med-blue>
                        $gatewayname <br>
                </med-blue>
                <div class=\"insert\" style=\"max-width:100%;\">
        "
}

# --- footer() function (unchanged from original) ---
footer() {
        year=$(date +'%Y')
        echo "
                <hr>
                <div style=\"font-size:0.5em;\">
                        <br>
                        <img style=\"height:60px; float:left;\" src=\"$gatewayurl""$imagepath\" alt=\"Splash Page: For access to the Internet.\">
                        © Portal: BlueWave Projects and Services 2015 - $year<br>
                        <br>
                        Portal Version: $version
                        <br><br><br><br>
                </div>
                </div>
                </div>
                </body>
                </html>
        "
        exit 0
}

# --- Core Logic Change Area ---

name_email_login() {
        # Function name is kept. Logic changed for password validation.

        # Check if *both* username and password parameters were received from the form submission
        # Assumes $username and $password are populated by openNDS/libopennds.sh from query string
        if [ ! -z "$username" ] && [ ! -z "$password" ]; then
                # BOTH fields submitted, attempt validation

                if [ ! -f "$USER_LIST_FILE" ]; then
                    logger -p daemon.error -t "opennds[$$]" "ThemeSpec Error: User list file not found at $USER_LIST_FILE"
                    login_form "Login System Error (ULNF)." "$username"
                    footer
                elif [ ! -r "$USER_LIST_FILE" ]; then
                    logger -p daemon.error -t "opennds[$$]" "ThemeSpec Error: Cannot read user list file at $USER_LIST_FILE"
                    login_form "Login System Error (ULNR)." "$username"
                    footer
                fi

                credential_line="${username}:${password}"

                logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Checking credential line [$credential_line] in $USER_LIST_FILE" # Keep this debug log

                if grep -qFx "$credential_line" "$USER_LIST_FILE"; then
                    # Credentials VALID
                    logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Credentials VALID. Calling thankyou_page." # Keep this debug log
                    thankyou_page
                    footer
                else
                    # Credentials INVALID
                    logger -p daemon.notice -t "opennds[$$]" "Login Failed: Invalid credentials for user '$username' from $clientip" # Keep this log
                    login_form "Invalid Username or Password." "$username"
                    footer
                fi
        fi

        # If the above 'if' was false (no username/password found)
        # Show the initial login form.
        login_form "" "$username" # Pass username back if it was submitted alone
        footer
}

login_form() {
        # MODIFIED to ask for Password instead of Email

        error_msg="$1"
        preset_username="$2"

        # Simple encode function for reflecting values safely in HTML
        encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }

        if [ -n "$error_msg" ]; then
                echo "<p style=\"color:red; font-weight:bold;\">Error: $(encode "$error_msg")</p>"
        fi

        echo "
                <big-red>Welcome!</big-red><br>
                <med-blue>You are connected to <br>$(encode "$client_zone")</med-blue><br>
                <italic-black>
                        <!-- Text CHANGED -->
                        To access the Internet you must enter your Username and Password then click Login.
                </italic-black>
                <hr>
                <form action=\"/opennds_preauth/\" method=\"get\">
                        <input type=\"hidden\" name=\"fas\" value=\"$fas\">
                        <!-- Username Input (unchanged from original) -->
                        <input type=\"text\" name=\"username\" value=\"$(encode "$preset_username")\" autocomplete=\"on\" required autofocus ><br>Username<br><br>

                        <!-- Email Input CHANGED to Password Input -->
                        <input type=\"password\" name=\"password\" value=\"\" autocomplete=\"current-password\" required ><br>Password<br><br>

                        <!-- Submit Button Text CHANGED -->
                        <input type=\"submit\" value=\"Login\" >
                </form>
                <br>
        "
        read_terms
}

thankyou_page () {
        # Page shown after successful validation.
        # MODIFIED: Removed references to emailaddress.

        # Simple encode function
        encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }

        echo "
                <big-red>
                        Thankyou for using this service.<br>Please click Continue for access.
                </big-red>
                <br>
                <b>Welcome $(encode "$username")</b>
                <br>
                <med-blue>You are connected to $(encode "$client_zone")</med-blue><br>
        "
        echo "
                <br>
                <italic-black>
                        Your News or Advertising could be here...
                </italic-black>
        "
        # Continue button form - triggers landing_page()
        # MODIFIED: Removed hidden emailaddress field
        echo "
                <form action=\"/opennds_preauth/\" method=\"get\">
                        <input type=\"hidden\" name=\"fas\" value=\"$fas\">
                        <input type=\"hidden\" name=\"username\" value=\"$(encode "$username")\">
                        <input type=\"hidden\" name=\"landing\" value=\"yes\"> <!-- Flag for landing_page -->
                        <input type=\"submit\" value=\"Continue\" >
                </form>
                <br>
        "
        read_terms
}

landing_page() {
        # Page triggered by "Continue" button. Calls auth_log.
        # MODIFIED: userinfo string for log

        # Simple encode function
        encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }

        # Prepare user info string for the log (MODIFIED: removed email)
        userinfo_log="theme=$title, user=$(encode "$username")"

        # CRITICAL: Authenticate the client using openNDS library function
        export clientip clientmac userinfo_log quotas fas
        logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Calling libopennds.sh auth_log for $clientip $clientmac User: $(encode "$username")" # Keep this debug log
        if [ -x "/usr/lib/opennds/libopennds.sh" ]; then
            auth_log_result=$(/usr/lib/opennds/libopennds.sh auth_log)
            ndsstatus=$(echo "$auth_log_result" | grep -o 'authenticated\|denied')
        else
            logger -p daemon.error -t "opennds[$$]" "ThemeSpec: libopennds.sh not found or not executable in landing_page!"
            ndsstatus="denied"
        fi
        logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: libopennds.sh auth_log returned status [$ndsstatus]" # Keep this debug log

        auth_success="<p><big-red>Access Granted!</big-red><hr>Welcome, $(encode "$username")! You are now connected.<br>(Requested: $(encode "$originurl"))</p><form><input type=\"button\" VALUE=\"Continue\" onClick=\"location.href='$gatewayurl'\" ></form><hr>"
        auth_fail="<p><big-red>Authentication Failed!</big-red><hr>Could not grant access. Please try again.</p><form><input type=\"button\" VALUE=\"Try Again\" onClick=\"location.href='http://$(encode "$gatewayfqdn")'\" ></form><hr>"

        if [ "$ndsstatus" = "authenticated" ]; then echo "$auth_success"; else logger -p daemon.warn -t "opennds[$$]" "Landing Page: Authentication failed or status unknown for '$(encode "$username")'. NDSStatus: [$ndsstatus]"; echo "$auth_fail"; fi
        read_terms
}

# --- read_terms() function (unchanged) ---
read_terms() {
    echo "<form action=\"/opennds_preauth/\" method=\"get\"><input type=\"hidden\" name=\"fas\" value=\"$fas\"><input type=\"hidden\" name=\"terms\" value=\"yes\"><input type=\"submit\" value=\"Read Terms of Service\"></form>"
}

# --- display_terms() function (unchanged, using placeholder) ---
display_terms() {
    # Simple encode function
    encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }
    echo "<h2>Terms of Service</h2><p>...(Full Terms Text Should Be Here)...</p><hr><form><input type=\"button\" VALUE=\"Go Back\" onClick=\"history.go(-1);return true;\"></form>"
}

#### end of functions ####

#################################################
# Main entry point - Script Execution Starts Here
#################################################

# Parameters expected from openNDS ($ndsparamlist) - Unchanged
ndscustomparams=""; ndscustomimages=""; ndscustomfiles=""
ndsparamlist="$ndsparamlist $ndscustomparams $ndscustomimages $ndscustomfiles"

# FAS Variables used in this script (MODIFIED)
additionalthemevars="username password landing terms" # CHANGED
fasvarlist="$fasvarlist $additionalthemevars"

# User info string for logs
userinfo="$title"

# --- Assume openNDS calls generate_splash_sequence after setting environment ---
# Check if libopennds.sh exists (basic check)
if [ ! -f "/usr/lib/opennds/libopennds.sh" ]; then
    echo "Content-Type: text/html"; echo ""; echo "Error: /usr/lib/opennds/libopennds.sh not found."
    logger -p daemon.error -t "opennds[$$]" "ThemeSpec: libopennds.sh not found!"
    exit 1
fi

# Call the main sequence generator function
# Assumes $username, $password, $landing, $terms etc. are populated from $nds_query_string by openNDS/libopennds.sh
# We also assume $clientip, $fas etc are available from $ndsparamlist
logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Calling generate_splash_sequence." # Keep this debug log
generate_splash_sequence

# Fallback exit (should be handled by footer)
logger -p daemon.error -t "opennds[$$]" "ThemeSpec: Reached end of script without explicit exit from footer!"
exit 1


Asking an AI/LLM to code it for you is not a good idea, but nice try :wink:

You have ended up with some nice looking, safe code that does not know about the underlying system, so it fails quietly without error... :man_facepalming:

Never mind, lets look at it.

Some points to note:

  1. openNDS sanitises all user input - you do not need to do any encoding. In addition, the query string is always b64 encoded.
  2. You do not need to write to logger directly, there is a library function to do this that takes into account the current debuglevel.
  3. You only needed to do simple changes, all the passing of variables etc is handled already by opnNDS.

Writing to syslog example:

syslogmessage="Hello World"
debugtype="info"
write_to_syslog

debugtype can be emerg, err, notice, warn, info and debug.

The check in the users.list database can be very simple indeed.
You should check if the username exists and if it does return the password. That way, when you generate the database file you can hash the password and even give users the option of changing their password, with it always stored as a hash.

You should do this as a new function in your themespec script.

For example, to check for a username and return the password, do:

stored_password=$(grep "$username" /etc/users.list 2>/dev/null | awk -F ":" 'NR==1 {printf "%s", $2}'')

This returns $stored_password as an empty string if the username does not exist.
If the username is duplicated, it returns the password of the last entry.

1 Like

Thank you very much for your answer:

Conclusion:

The problem is not in your validation script code itself, but in the fact that openNDS (or the underlying web server component) is not passing the data from the submitted form correctly to your script.

The most likely cause is the already identified outdated libmicrohttpd library:

Wed Apr 9 12:20:32 2025 daemon.err opennds[25927]: libmicrohttpd is out of date, please upgrade to version 0.9.71 or higher
Wed Apr 9 12:20:32 2025 daemon.err opennds[25927]: Attempting use of outdated MHD - Data may be corrupted or openNDS may fail...

After submitting the form

Wed Apr  9 12:20:53 2025 daemon.debug opennds[30720]: ThemeSpec: Calling generate_splash_sequence.
Wed Apr  9 12:20:53 2025 daemon.debug opennds[30720]: ThemeSpec: name_email_login called. Received username=[] password=[]

Here is the problem! Although you have entered username and password and clicked on ‘Login’, the variables $username and $password are still empty () in the script.

Follow in the script: Since the variables are empty, the condition if [ ! -z ‘$username’ ] && [ ! -z ‘$password’ ]; then fails. The script jumps over the entire validation block and calls login_form ‘’ ‘$username’ again at the end, which displays the empty login form again. It does not even try to check the users.list.

Debug-Logging
Wed Apr  9 12:20:05 2025 daemon.info opennds[16771]: Handler for termination caught signal 15
Wed Apr  9 12:20:05 2025 daemon.info opennds[16771]: Cleaning up and exiting
Wed Apr  9 12:20:05 2025 daemon.info opennds[16771]: Revert request sent
Wed Apr  9 12:20:12 2025 daemon.info opennds[16771]: Dnsmasq restarted
Wed Apr  9 12:20:12 2025 daemon.info opennds[16771]: Flushing firewall rules...
Wed Apr  9 12:20:13 2025 daemon.info opennds[16771]: Chain delete request sent
Wed Apr  9 12:20:13 2025 daemon.notice opennds[16771]: Exiting...
Wed Apr  9 12:20:13 2025 daemon.info opennds[25854]: openNDS is already running, status [ 1 ]. Retry later...
Wed Apr  9 12:20:28 2025 daemon.info opennds[25927]: option enabled is [ 1 ]
Wed Apr  9 12:20:28 2025 daemon.notice opennds[25927]: openNDS Version 10.3.0 is in startup
Wed Apr  9 12:20:28 2025 daemon.info opennds[25927]: openNDS Version 10.3.0 is in startup - Please wait....
Wed Apr  9 12:20:28 2025 daemon.info opennds[25927]: option gatewayname is [ WLAN%20Portal ]
Wed Apr  9 12:20:28 2025 daemon.notice opennds[25927]: The name of this gateway is WLAN Portal
Wed Apr  9 12:20:28 2025 daemon.info opennds[25927]: option gatewayfqdn is [ status.client ]
Wed Apr  9 12:20:28 2025 daemon.info opennds[25927]: option statuspath is [ /usr/lib/opennds/client_params.sh ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option gatewayinterface is [ br-guest ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option gateway_iprange is [ 0.0.0.0/0 ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option faskey is [ 0365bcf201f355c1b84c35d90f0b836ce61ae50d2e6a4b476142f9cec8718ce4 ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option log_mountpoint is [ /tmp ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option webroot is [ /etc/opennds/htdocs ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option authdir is [ opennds_auth ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option denydir is [ opennds_deny ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option preauthdir is [ opennds_preauth ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option ndsctl_sock is [ ndsctl.sock ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option authentication_mark is [ 0x00030000 ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option binauth is [ /usr/lib/opennds/binauth_log.sh ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option faspath is [ / ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option themespec_path is [ /etc/opennds/ThemeSpec_Guest_Password.sh ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option fasremoteip is [ disabled ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option fasremotefqdn is [ disabled ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option fas_ssl is [ wget ]
Wed Apr  9 12:20:29 2025 daemon.info opennds[25927]: option debuglevel is [ 2 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option sessiontimeout is [ 3 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option preauthidletimeout is [ 30 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option authidletimeout is [ 120 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option maxclients is [ 250 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option enable_serial_number_suffix is [ 1 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option dhcp_default_url_enable is [ 1 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option gatewayport is [ 2050 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option fasport is [ 0 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option login_option_enabled is [ 3 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option use_outdated_mhd is [ 1 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option max_page_size is [ 10240 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option max_log_entries is [ 100 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option allow_preemptive_authentication is [ 1 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option fas_secure_enabled is [ 1 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option remotes_refresh_interval is [ 0 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option checkinterval is [ 15 ]
Wed Apr  9 12:20:30 2025 daemon.info opennds[25927]: option ratecheckwindow is [ 2 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option uploadrate is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option downloadrate is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option download_bucket_ratio is [ 1 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option max_download_bucket_size is [ 250 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option download_unrestricted_bursting is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option upload_bucket_ratio is [ 1 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option max_upload_bucket_size is [ 250 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option upload_unrestricted_bursting is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option uploadquota is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option downloadquota is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option fup_upload_throttle_rate is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option fup_download_throttle_rate is [ 0 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option fw_mark_authenticated is [ 0x30000 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option fw_mark_auth_blocked is [ 0x30001 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: option fw_mark_trusted is [ 0x20000 ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: list trustedmac is [  ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: list fas_custom_parameters_list is [  ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: list fas_custom_images_list is [  ]
Wed Apr  9 12:20:31 2025 daemon.info opennds[25927]: Parsing list [] for Custom FAS Images
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: list fas_custom_files_list is [  ]
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: Parsing list [] for Custom FAS Files
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: Chain delete request sent
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: Pre-Setup request sent
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: Attempting to Bind to interface: br-guest
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: Interface br-guest is up
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: Interface br-guest is at 192.168.3.1 (ced8438f1457)
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: Revert request sent
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: tmpfs mountpoint is [/tmp]
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: MHD version is 1.0.1
Wed Apr  9 12:20:32 2025 daemon.err opennds[25927]: libmicrohttpd is out of date, please upgrade to version 0.9.71 or higher
Wed Apr  9 12:20:32 2025 daemon.err opennds[25927]: Attempting use of outdated MHD - Data may be corrupted or openNDS may fail...
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: Number of Upstream gateway(s) [ 1 ]
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: Upstream gateway(s) [ online:192.168.178.1,phy0-sta0  ]
Wed Apr  9 12:20:32 2025 daemon.notice opennds[25927]: Preemptive authentication is enabled
Wed Apr  9 12:20:32 2025 daemon.info opennds[25927]: Client status Page: Configured
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: RFC8910 support is enabled
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: Dnsmasq reloading
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Adding Serial Number suffix [ced8438f1457] to gatewayname
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: main: System Uptime is 81847 seconds
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: Setting started_time
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: MHD Handle [4392256]
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Created web server on 192.168.3.1:2050
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Maximum Html Page size is [ 10240 ] Bytes
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Socket access at /tmp/ndsctl.sock
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Login option is Enabled using mode 3.
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Preauth is Enabled - Overriding FAS configuration.
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: Preauth Script is /usr/lib/opennds/libopennds.sh
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: fas_secure_enabled is set to level 1
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: fasremoteip - 192.168.3.1 - is a valid IPv4 address...
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: sha256sum provider is available
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: FAS FQDN is: status.client
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Forwarding Authentication is Enabled.
Wed Apr  9 12:20:33 2025 daemon.notice opennds[25927]: Binauth is Enabled.
Wed Apr  9 12:20:33 2025 daemon.info opennds[25927]: Binauth Script is /usr/lib/opennds/binauth_log.sh
Wed Apr  9 12:20:33 2025 daemon.debug opennds[28519]: ThemeSpec: Calling generate_splash_sequence.
Wed Apr  9 12:20:33 2025 daemon.debug opennds[28519]: ThemeSpec: name_email_login called. Received username=[] password=[]
Wed Apr  9 12:20:35 2025 daemon.notice opennds[25927]: Externals flagged with debuglevel 2.
Wed Apr  9 12:20:35 2025 daemon.notice opennds[25927]: Initializing firewall rules
Wed Apr  9 12:20:35 2025 daemon.info opennds[25927]: fas_remotefqdn [ status.client ]
Wed Apr  9 12:20:36 2025 daemon.info opennds[25927]: Dnsmasq reloaded
Wed Apr  9 12:20:36 2025 daemon.info opennds[25927]: list users_to_router is [ allow%20udp%20port%2053 allow%20udp%20port%2067 allow%20tcp%20port%2022 allow%20tcp%20port%20443 ]
Wed Apr  9 12:20:37 2025 daemon.info opennds[25927]: list preauthenticated_users is [  ]
Wed Apr  9 12:20:37 2025 daemon.info opennds[25927]: list authenticated_users is [ allow%20all ]
Wed Apr  9 12:20:37 2025 daemon.info opennds[25927]: Walled Garden Setup Request sent
Wed Apr  9 12:20:37 2025 daemon.info opennds[25927]: Block List Setup Request sent
Wed Apr  9 12:20:37 2025 daemon.err opennds[25927]: Dnsmasq reload failed!
Wed Apr  9 12:20:37 2025 daemon.notice opennds[25927]: openNDS is now running.
Wed Apr  9 12:20:38 2025 daemon.notice opennds[25927]: Adding 192.168.3.175 ea:23:b8:fe:08:e2 token 6a7eac9f to client list
Wed Apr  9 12:20:39 2025 daemon.info opennds[25927]: Network Authentication Required - page_511 html generated for [192.168.3.175]
Wed Apr  9 12:20:41 2025 daemon.debug opennds[30455]: ThemeSpec: Calling generate_splash_sequence.
Wed Apr  9 12:20:41 2025 daemon.debug opennds[30455]: ThemeSpec: name_email_login called. Received username=[] password=[]
Wed Apr  9 12:20:41 2025 daemon.debug opennds[30591]: ThemeSpec: Calling generate_splash_sequence.
Wed Apr  9 12:20:41 2025 daemon.debug opennds[30591]: ThemeSpec: name_email_login called. Received username=[] password=[]
Wed Apr  9 12:20:41 2025 daemon.info opennds[25927]: Failed to get client connections for [ea:23:b8:fe:08:e2] - retrying
Wed Apr  9 12:20:53 2025 daemon.debug opennds[30720]: ThemeSpec: Calling generate_splash_sequence.
Wed Apr  9 12:20:53 2025 daemon.debug opennds[30720]: ThemeSpec: name_email_login called. Received username=[] password=[]
Wed Apr  9 12:20:53 2025 daemon.debug opennds[31088]: ThemeSpec: Calling generate_splash_sequence.
Wed Apr  9 12:20:53 2025 daemon.debug opennds[31088]: ThemeSpec: name_email_login called. Received username=[] password=[]

ThemeSpec_Guest_Password.sh
#!/bin/sh
#Copyright (C) The openNDS Contributors 2004-2022
#Copyright (C) BlueWave Projects and Services 2015-2024
#This software is released under the GNU GPL license.
# MINIMALLY MODIFIED for Username/Password Validation based on theme_user-email-login-basic.sh
# Incorporates specific suggestions from bluewavenet (grep/awk check and write_to_syslog example)

# Define path to user list file (ADDED)
USER_LIST_FILE="/etc/opennds/users.list" # Path used for user credentials

# Title of this theme:
title="theme_user-password-login-minimal" # CHANGED title slightly

# --- Standard Functions (mostly unchanged) ---

generate_splash_sequence() {
        # Calls name_email_login - the function NAME remains the same,
        # but its *logic* will be modified for password validation.
        name_email_login
}

# --- header() function (unchanged from original) ---
header() {
        gatewayurl=$(printf "${gatewayurl//%/\\x}") # Original printf line kept as per "no other changes" request
        echo "<!DOCTYPE html>
                <html>
                <head>
                <meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\">
                <meta http-equiv=\"Pragma\" content=\"no-cache\">
                <meta http-equiv=\"Expires\" content=\"0\">
                <meta charset=\"utf-8\">
                <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
                <link rel=\"shortcut icon\" href=\"$gatewayurl/images/splash.jpg\" type=\"image/x-icon\">
                <link rel=\"stylesheet\" type=\"text/css\" href=\"$gatewayurl/splash.css\">
                <title>$gatewayname</title>
                </head>
                <body>
                <div class=\"offset\">
                <med-blue>
                        $gatewayname <br>
                </med-blue>
                <div class=\"insert\" style=\"max-width:100%;\">
        "
}

# --- footer() function (unchanged from original) ---
footer() {
        year=$(date +'%Y')
        echo "
                <hr>
                <div style=\"font-size:0.5em;\">
                        <br>
                        <img style=\"height:60px; float:left;\" src=\"$gatewayurl""$imagepath\" alt=\"Splash Page: For access to the Internet.\">
                        © Portal: BlueWave Projects and Services 2015 - $year<br>
                        <br>
                        Portal Version: $version
                        <br><br><br><br>
                </div>
                </div>
                </div>
                </body>
                </html>
        "
        exit 0
}

# --- Core Logic Change Area ---

name_email_login() {
        # Function name is kept. Logic changed for password validation.

        # *** NEUES DEBUG LOGGING START ***
        logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: name_email_login called. Received username=[$username] password=[$password]"
        # *** NEUES DEBUG LOGGING END ***


        # Check if *both* username and password parameters were received from the form submission
        # Assumes $username and $password are populated by openNDS/libopennds.sh from query string
        if [ ! -z "$username" ] && [ ! -z "$password" ]; then
                # BOTH fields submitted, attempt validation
                logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Username and Password seem present. Proceeding with validation..." # Zusätzliches Log

                # File existence and readability checks (kept from original)
                if [ ! -f "$USER_LIST_FILE" ]; then
                    logger -p daemon.error -t "opennds[$$]" "ThemeSpec Error: User list file not found at $USER_LIST_FILE"
                    login_form "Login System Error (ULNF)." "$username"
                    footer
                elif [ ! -r "$USER_LIST_FILE" ]; then
                    logger -p daemon.error -t "opennds[$$]" "ThemeSpec Error: Cannot read user list file at $USER_LIST_FILE"
                    login_form "Login System Error (ULNR)." "$username"
                    footer
                fi

                # *** MODIFICATION START: Use grep/awk as suggested by bluewavenet ***
                # Fetch the stored password for the given username
                # Use anchored grep for exact username match at the beginning of the line
                logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Attempting to fetch password for user '$username' from $USER_LIST_FILE" # Keep this debug log
                stored_password=$(grep "^${username}:" "$USER_LIST_FILE" 2>/dev/null | awk -F ":" 'NR==1 {printf "%s", $2}')

                # Check if username was found (stored_password is not empty) and if the submitted password matches the stored one
                if [ ! -z "$stored_password" ] && [ "$password" = "$stored_password" ]; then
                # *** MODIFICATION END ***
                        # Credentials VALID
                        logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Credentials VALID for '$username'. Calling thankyou_page." # Keep this debug log

                        # *** ADDED: write_to_syslog example as requested ***
                        # Note: This assumes 'write_to_syslog' function is available from libopennds.sh in the execution environment
                        syslogmessage="User '$username' successfully validated credentials via ThemeSpec."
                        debugtype="info"
                        # Ensure libopennds.sh providing write_to_syslog is sourced or available in the environment
                        write_to_syslog
                        # *** END ADDED ***

                        thankyou_page
                        footer
                else
                        # Credentials INVALID (username not found or password mismatch)
                        # Original logger call kept
                        logger -p daemon.notice -t "opennds[$$]" "Login Failed: Invalid credentials for user '$username' from $clientip" # Keep this log
                        login_form "Invalid Username or Password." "$username"
                        footer
                fi
        fi

        # If the above 'if' was false (no username/password found in query string)
        # Show the initial login form. Original logic kept.
        login_form "" "$username" # Pass username back if it was submitted alone
        footer
}

# --- login_form() function (unchanged from user's provided script) ---
login_form() {
        error_msg="$1"
        preset_username="$2"

        # Simple encode function for reflecting values safely in HTML
        encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }

        if [ -n "$error_msg" ]; then
                echo "<p style=\"color:red; font-weight:bold;\">Error: $(encode "$error_msg")</p>"
        fi

        echo "
                <big-red>Welcome!</big-red><br>
                <med-blue>You are connected to <br>$(encode "$client_zone")</med-blue><br>
                <italic-black>
                        To access the Internet you must enter your Username and Password then click Login.
                </italic-black>
                <hr>
                <form action=\"/opennds_preauth/\" method=\"get\">
                        <input type=\"hidden\" name=\"fas\" value=\"$fas\">
                        <input type=\"text\" name=\"username\" value=\"$(encode "$preset_username")\" autocomplete=\"on\" required autofocus ><br>Username<br><br>

                        <input type=\"password\" name=\"password\" value=\"\" autocomplete=\"current-password\" required ><br>Password<br><br>

                        <input type=\"submit\" value=\"Login\" >
                </form>
                <br>
        "
        read_terms
}

# --- thankyou_page() function (unchanged from user's provided script) ---
thankyou_page () {
        # Page shown after successful validation.
        # MODIFIED: Removed references to emailaddress.

        # Simple encode function
        encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }

        echo "
                <big-red>
                        Thankyou for using this service.<br>Please click Continue for access.
                </big-red>
                <br>
                <b>Welcome $(encode "$username")</b>
                <br>
                <med-blue>You are connected to $(encode "$client_zone")</med-blue><br>
        "
        echo "
                <br>
                <italic-black>
                        Your News or Advertising could be here...
                </italic-black>
        "
        # Continue button form - triggers landing_page()
        # MODIFIED: Removed hidden emailaddress field
        echo "
                <form action=\"/opennds_preauth/\" method=\"get\">
                        <input type=\"hidden\" name=\"fas\" value=\"$fas\">
                        <input type=\"hidden\" name=\"username\" value=\"$(encode "$username")\">
                        <input type=\"hidden\" name=\"landing\" value=\"yes\"> <input type=\"submit\" value=\"Continue\" >
                </form>
                <br>
        "
        read_terms
}

# --- landing_page() function (unchanged from user's provided script) ---
landing_page() {
        # Page triggered by "Continue" button. Calls auth_log.
        # MODIFIED: userinfo string for log

        # Simple encode function
        encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }

        # Prepare user info string for the log (MODIFIED: removed email)
        userinfo_log="theme=$title, user=$(encode "$username")"

        # CRITICAL: Authenticate the client using openNDS library function
        export clientip clientmac userinfo_log quotas fas
        logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Calling libopennds.sh auth_log for $clientip $clientmac User: $(encode "$username")" # Keep this debug log
        if [ -x "/usr/lib/opennds/libopennds.sh" ]; then
            # Original direct call to libopennds.sh kept
            auth_log_result=$(/usr/lib/opennds/libopennds.sh auth_log)
            ndsstatus=$(echo "$auth_log_result" | grep -o 'authenticated\|denied')
        else
            logger -p daemon.error -t "opennds[$$]" "ThemeSpec: libopennds.sh not found or not executable in landing_page!"
            ndsstatus="denied"
        fi
        logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: libopennds.sh auth_log returned status [$ndsstatus]" # Keep this debug log

        auth_success="<p><big-red>Access Granted!</big-red><hr>Welcome, $(encode "$username")! You are now connected.<br>(Requested: $(encode "$originurl"))</p><form><input type=\"button\" VALUE=\"Continue\" onClick=\"location.href='$gatewayurl'\" ></form><hr>"
        auth_fail="<p><big-red>Authentication Failed!</big-red><hr>Could not grant access. Please try again.</p><form><input type=\"button\" VALUE=\"Try Again\" onClick=\"location.href='http://$(encode "$gatewayfqdn")'\" ></form><hr>"

        if [ "$ndsstatus" = "authenticated" ]; then echo "$auth_success"; else logger -p daemon.warn -t "opennds[$$]" "Landing Page: Authentication failed or status unknown for '$(encode "$username")'. NDSStatus: [$ndsstatus]"; echo "$auth_fail"; fi
        read_terms
}

# --- read_terms() function (unchanged from user's provided script) ---
read_terms() {
    echo "<form action=\"/opennds_preauth/\" method=\"get\"><input type=\"hidden\" name=\"fas\" value=\"$fas\"><input type=\"hidden\" name=\"terms\" value=\"yes\"><input type=\"submit\" value=\"Read Terms of Service\"></form>"
}

# --- display_terms() function (unchanged from user's provided script) ---
display_terms() {
    # Simple encode function
    encode() { echo "$1" | sed 's/[&<>"\x27]/\\&/g'; }
    echo "<h2>Terms of Service</h2><p>...(Full Terms Text Should Be Here)...</p><hr><form><input type=\"button\" VALUE=\"Go Back\" onClick=\"history.go(-1);return true;\"></form>"
}

#### end of functions ####

#################################################
# Main entry point - Script Execution Starts Here
#################################################

# Parameters expected from openNDS ($ndsparamlist) - Unchanged
ndscustomparams=""; ndscustomimages=""; ndscustomfiles=""
ndsparamlist="$ndsparamlist $ndscustomparams $ndscustomimages $ndscustomfiles"

# FAS Variables used in this script (MODIFIED) - Kept as in user's script
additionalthemevars="username password landing terms" # CHANGED
fasvarlist="$fasvarlist $additionalthemevars"

# User info string for logs - Kept as in user's script
userinfo="$title"

# --- Assume openNDS calls generate_splash_sequence after setting environment ---
# Check if libopennds.sh exists (basic check) - Kept as in user's script
if [ ! -f "/usr/lib/opennds/libopennds.sh" ]; then
    echo "Content-Type: text/html"; echo ""; echo "Error: /usr/lib/opennds/libopennds.sh not found."
    logger -p daemon.error -t "opennds[$$]" "ThemeSpec: libopennds.sh not found!"
    exit 1
fi

# Call the main sequence generator function - Kept as in user's script
# Assumes $username, $password, $landing, $terms etc. are populated from $nds_query_string by openNDS/libopennds.sh
# We also assume $clientip, $fas etc are available from $ndsparamlist
logger -p daemon.debug -t "opennds[$$]" "ThemeSpec: Calling generate_splash_sequence." # Keep this debug log
generate_splash_sequence

# Fallback exit (should be handled by footer) - Kept as in user's script
logger -p daemon.error -t "opennds[$$]" "ThemeSpec: Reached end of script without explicit exit from footer!"
exit 1

Sorry but that is a completely wrong answer from some LLM AI bot you have asked.

You confirmed earlier that it worked correctly with the standard themespec script, but does not work with your script.

My Conclusion:
Your customised themespec script does not work.

I have already given you pointers to where you are going wrong. Please re-read what I said.
And NO, I am NOT going to do your school project for you write it for you.

FYI: The version of MHD is not actually out of date. It is just that openNDS is miss-identifying the version. You have added opennds.@opennds[0].use_outdated_mhd='1' to tell openNDS to use the version of MHD that is installed and not to bother checking.

2 Likes

Hi @bluewavenet.

You were absolutely right, and thanks for pushing me in the right direction. The issue was indeed entirely within my custom themespec script, not with openNDS core or MHD.

After comparing the logic more closely with the standard themes and incorporating your earlier pointers (especially regarding variable handling via fasvarlist), I've now managed to get it working correctly. The login process completes successfully using the credentials from the users.list file and the modern design is applied.

Thank you very much for your support and patience!

And thanks also for the clarification regarding the use_outdated_mhd setting – that makes sense.

For anyone who might run into similar issues in the future, or just for reference, these are the key files I ended up with that are now working:

/etc/opennds/ThemeSpec_Guest_Password.sh
#!/bin/sh
#Copyright (C) The openNDS Contributors 2004-2022
#Copyright (C) BlueWave Projects and Services 2015-2024
#This software is released under the GNU GPL license.

# Title of this theme:
title="ThemeSpec_Guest_Password_UserFile_Modern"

# --- Configuration ---
USER_LIST_FILE="/etc/opennds/users.list"
# --- SECURITY WARNING: Passwords in USER_LIST_FILE are currently checked as plain text! ---
# ---------------------

# functions:

generate_splash_sequence() {
	name_password_login
}

header() {
# Modernized header
	gatewayurl=$(printf "${gatewayurl//%/\\x}")
	echo "<!DOCTYPE html>
		<html lang=\"en\">
		<head>
		<meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\">
		<meta http-equiv=\"Pragma\" content=\"no-cache\">
		<meta http-equiv=\"Expires\" content=\"0\">
		<meta charset=\"utf-8\">
		<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
		<link rel=\"shortcut icon\" href=\"$gatewayurl/images/splash.jpg\" type=\"image/x-icon\">
		<link rel=\"stylesheet\" type=\"text/css\" href=\"$gatewayurl/splash.css\">
		<title>$gatewayname Guest Access</title>
		</head>
		<body>
		<div class=\"container\">
			<div class=\"header\">
				<div class=\"gateway-name\">$gatewayname</div>
				<div class=\"client-zone\">Connected via: $client_zone</div>
			</div>"
	# Container div is opened here, closed in footer
}

footer() {
# Modernized footer
	year=$(date +'%Y')
	local logo_path=${logo:-"/images/splash.jpg"} # Use default splash if no custom logo
	echo "
			<div class=\"footer\">
				<img src=\"$gatewayurl""$logo_path\" alt=\"Logo\">
				<span>© Your Org Name $year<br>Portal Version: $version</span>
			</div>
		</div> <!-- Close container -->
		</body>
		</html>
	"
	exit 0
}

name_password_login() {
    # --- Logic to check credentials from USER_LIST_FILE (same as before) ---
	local error_msg=""
	local stored_password=""

	/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Checking credentials against '$USER_LIST_FILE'. Received username=[$username] password=[***]" "debug"

	if [ ! -z "$username" ] && [ ! -z "$password" ]; then
		if [ -r "$USER_LIST_FILE" ]; then
			stored_password=$(grep "^${username}:" "$USER_LIST_FILE" 2>/dev/null | awk -F ":" 'NR==1 {printf "%s", $2}')
			if [ ! -z "$stored_password" ]; then
				if [ "$password" = "$stored_password" ]; then # Plain text compare!
					/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Password MATCH for user [$username]." "info"
					thankyou_page; footer
				else
					/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Password MISMATCH for user [$username]." "warn"
					error_msg="Invalid password for user '$username'. Please try again."
				fi
			else
				/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Username [$username] NOT FOUND in '$USER_LIST_FILE'." "warn"
				error_msg="Username '$username' not found."
			fi
		else
			/usr/lib/opennds/libopennds.sh syslog "Theme '$title': User list file '$USER_LIST_FILE' not found or not readable." "err"
			error_msg="Server configuration error: Cannot access user database."
		fi
	else
		/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Username or password missing, serving login form." "debug"
	fi

	login_form "$error_msg" # Pass potential error message
	footer
}

login_form() {
# Modernized login form
	local error_display="$1"

	echo "
		<div class=\"message-welcome\">Welcome to Guest Access</div>
		<div class=\"message-info\">
			Please enter your assigned guest credentials and accept the Terms of Service below.
		</div>
		<hr>
	"
	# Display error message if provided
	if [ ! -z "$error_display" ]; then
		echo "<div class=\"message-error\">$error_display</div>"
	fi

	echo "
		<form action=\"/opennds_preauth/\" method=\"get\" class=\"login-form\">
			<input type=\"hidden\" name=\"fas\" value=\"$fas\">

			<div class=\"form-group\">
				<label for=\"username\" class=\"input-label\">Username</label>
				<input type=\"text\" id=\"username\" name=\"username\" value=\"$username\" autocomplete=\"username\" placeholder=\"Enter username\" required>
			</div>

			<div class=\"form-group\">
				<label for=\"password\" class=\"input-label\">Password</label>
				<input type=\"password\" id=\"password\" name=\"password\" value=\"\" autocomplete=\"current-password\" placeholder=\"Enter password\" required>
			</div>

			<!-- Include custom hidden inputs if needed -->
			$custom_passthrough

			<input type=\"submit\" value=\"Login & Accept Terms\" class=\"button\">
		</form>
	"
	# Terms of Service button/link
	read_terms
}

thankyou_page () {
# Modernized Thank You Page
	binauth_custom="login_method=$title username=$username"
	encode_custom
	customhtml=""
	if [ ! -z "$custom" ]; then customhtml="<input type=\"hidden\" name=\"custom\" value=\"$custom\">"; fi

	echo "
		<div class=\"message-thankyou\">Login Successful!</div>
		<div class=\"message-info\">Welcome, $username. Click Continue to access the internet.</div>
        <hr>"

	# Form to proceed to the actual authentication and landing page
	echo "
		<form action=\"/opennds_preauth/\" method=\"get\" class=\"continue-form\">
			<input type=\"hidden\" name=\"fas\" value=\"$fas\">
			<input type=\"hidden\" name=\"username\" value=\"$username\">
			$customhtml
			$custom_passthrough
			<input type=\"hidden\" name=\"landing\" value=\"yes\">
			<input type=\"submit\" value=\"Continue to Internet\" class=\"button\">
		</form>
	"
	read_terms # Display link to Terms of Service again
}

landing_page() {
# Modernized Landing Page
	originurl=$(printf "${originurl//%/\\x}")
	gatewayurl=$(printf "${gatewayurl//%/\\x}")

	configure_log_location
	. $mountpoint/ndscids/ndsinfo
	userinfo="$title (user: $username)"
	auth_log # Perform NDS authentication

	if [ "$ndsstatus" = "authenticated" ]; then
		/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Client MAC [$clientmac] IP [$clientip] successfully authenticated." "notice"
		auth_success="
			<div class=\"message-thankyou\">Authentication Complete!</div>
			<div class=\"message-info\">
				You are now logged in and have access to the Internet.<br>
				You can use your Browser, Email, and other network Apps as usual.
				<br><br>
				<small>(Your device originally requested: $originurl)</small>
			</div>
			<hr>
			<form class=\"continue-form\">
				<input type=\"button\" VALUE=\"View Account Status\" onClick=\"location.href='$gatewayurl'\" class=\"button button-secondary\">
			</form>"
		echo "$auth_success"
	else
		/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Client MAC [$clientmac] IP [$clientip] FAILED authentication. NDSCTL Status: [$ndsstatus], Output: [$authstat]" "err"
		auth_fail="
			<div class=\"message-error\">Authentication Failed!</div>
			<div class=\"message-info\">
				Sorry, there was a problem authenticating your session.<br>
				This might be due to a system issue or timeout.
			</div>
			<hr>
			<form class=\"continue-form\">
				<input type=\"button\" VALUE=\"Retry Login\" onClick=\"location.href='http://$gatewayaddress/'\" class=\"button\">
			</form>"
		echo "$auth_fail"
	fi
	read_terms
}

# --- Terms of Service Functions ---
read_terms() {
# Modernized ToS Button/Form
	echo "
		<hr>
		<form action=\"/opennds_preauth/\" method=\"get\" class=\"tos-form\">
			<input type=\"hidden\" name=\"fas\" value=\"$fas\">
			<input type=\"hidden\" name=\"username\" value=\"$username\">
			$custom_passthrough
			<input type=\"hidden\" name=\"terms\" value=\"yes\">
			<input type=\"submit\" value=\"Read Terms of Service\" class=\"button button-secondary\">
		</form>
	"
}

display_terms() {
# Modernized ToS Display
	echo "
		<div style=\"text-align: left; max-height: 400px; overflow-y: auto; border: 1px solid #e8eaed; padding: 15px; border-radius: 4px; margin-bottom: 20px;\">
			<h3 style=\"text-align: center; color: #1a73e8; margin-bottom: 15px;\">Terms of Service</h3>

			<h4 style=\"color: #d93025;\">Privacy</h4>
			<p>By logging in to the system, you grant your permission for this system to store any data you provide...</p>
			<hr style=\"margin: 15px 0;\">

			<h4 style=\"color: #d93025;\">Terms of Service for this Hotspot</h4>
			<p>Access is granted on a basis of trust...</p>
            <!-- Add the rest of your ToS sections here, using <p>, <h4>, <ol>, <li> etc. -->
			<hr style=\"margin: 15px 0;\">
            <h4>Proper Use</h4> <p>...</p> <ol><li>...</li></ol> <hr style=\"margin: 15px 0;\">
            <h4>Content Disclaimer</h4> <p>...</p> <hr style=\"margin: 15px 0;\">
            <h4>Limitation of Liability</h4> <p>...</p> <hr style=\"margin: 15px 0;\">
            <h4>Changes to Terms of Service...</h4> <p>...</p> <hr style=\"margin: 15px 0;\">
            <h4>Indemnity</h4> <p>...</p>

		</div>
		<form class=\"continue-form\">
			<input type=\"button\" VALUE=\"Back to Login\" onClick=\"history.go(-1);return true;\" class=\"button\">
		</form>
	"
	footer # Exit after displaying terms
}
# --- End Terms of Service Functions ---

#### end of functions ####

#################################################
# Initialization Block (Keep as before)
# 1. Quotas
session_length="0"; upload_rate="0"; download_rate="0"; upload_quota="0"; download_quota="0"
quotas="$session_length $upload_rate $download_rate $upload_quota $download_quota"
# 2. NDS Params
ndscustomparams=""; ndscustomimages=""; ndscustomfiles=""
ndsparamlist="$ndsparamlist $ndscustomparams $ndscustomimages $ndscustomfiles"
# 3. FAS Vars
additionalthemevars="username password"; fasvarlist="$fasvarlist $additionalthemevars"
# 4. BinAuth Custom String (dynamic)
# 5. User Info (dynamic)
userinfo="$title"
# 6. Log Location (optional override)
#################################################
/etc/config/opennds
config opennds
        option enabled '1'
        option debuglevel '2'
        option login_option_enabled '3'
        option use_outdated_mhd '1'
        option gatewayinterface 'br-guest'
        option gatewayname 'WLAN Portal'
        option faskey '0365bcf201f355c1b84c35d90f0b836ce61ae50d2e6a4b476142f9cec8718ce4'
        option themespec_path '/etc/opennds/ThemeSpec_Guest_Password.sh'

Why did you use grep "^${username}:" instead of grep "$username" ?

I gave an example of how to write to syslog from within a themespec script. I'll show it again:

But you have used the libopennds cli command instead:

/usr/lib/opennds/libopennds.sh syslog "Theme '$title': Password MATCH for user [$username]." "info"

Note that the themespec script is an include file for libopennds.sh so calling the internal function write_to_syslog () is many times faster than completely reloading another instance of libopennds.sh into memory for running the cli command.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.