Difference between revisions of "Login with Roaming Profiles"

From ComputerCraft Wiki
Jump to: navigation, search
(Undo revision 3179 by 188.223.251.127 (talk))
m (Moved to tutorials category)
 
(22 intermediate revisions by 11 users not shown)
Line 5: Line 5:
  
 
== Setting Up ==
 
== Setting Up ==
As I'm sure you're aware, writing code directly into the computer terminal can be difficult, slow, and therefore annoying. I highly recommend writing/copying the following code into a Lua editor and then using FTP to transfer the documents across to the computer or disk. Please ensure you do not add the .lua extension.
+
First of all, you must know how to craft a [[Wireless_Modem|wireless modem]] and a [[Computer|computer]]. You need to craft at least 2 wireless modems and 2 computers if you want to have a practical use for this system. Then, attach 1 modem to each computer you want to add to the system.
  
First craft two or more computers. One will act as your password server, any others will be connecting to that computer. Find the computer ID of your password server. This is important as we don't want to broadcast password requests and replies. In the following code I have also locked the requests to certain computers to ensure security but it is not a needed component of the code. If you decide to take the security as well, make a note of all of the ID's of the client computers. I found it useful to give each computer a label and then search for labels.txt on the server to map it out easily.
+
Second, since typing on normal computers is relatively slow and annoying, I recommend to write the programs in [[Advanced Computer|Advanced Computers]]because in advanced computers you can click to move the cursor around, and there are colors to distinguis between different statements), copying them into a [[Floppy Disk]] and moving them into each computer you want to include(with their respective programs of course). Alternatively, if you are the server owner(this tutorial assumes you are in Multiplayer because this system does not have any practical use in Singleplayer), you can go into the world folder and write copy/paste the source code into the folders of each computer you want to use. The folders you should use are the named the IDs of the computers(so if you have 3 computers, with the IDs 5, 7 and 9, you should copy them into the folders 5, 7 and 9).  
  
Each computer you craft needs a [[modem|rednet modem]].
+
It does not matter wether you are using Normal or Advanced computers for this tutorial. I recommend to use Normal ones for the server.
  
== The Code ==
+
When writing the programs, I HIGHLY recommend using a [[Disk_Drive|disk drive]] like stated above, so you dont have to write in prograns for every computer you add.
 +
Remember to read the text behind the --. These are comments, and you can safely leave them in the code.
 +
 
 +
== Server ==
 +
print("Initializing...")
 +
local validSender = false
 +
valid = false
 +
tserved, vserved, dserved = 0
 +
 +
print("Loading startup settings...")
 +
count = true -- If you dont want the server to count request statics, set the value of this variable to "false" without qoutes.
 +
modemSide = "left" -- change to the side of the computer your modem is on
 +
whitelist = true -- If you dont want to use a whitelist, change the value to "false" without quotes. This is not recommended on Multiplayer, but it does not make any difference on a Singleplayer World.
 +
 +
print("Loading user database...")
 +
users = {"username1", "username2" } -- Change this to the names for the users you want to have. Make sure the usernames are in the same order as in the password table. Changing the order is fine, but you must maintain the same order in both the users and passwords tables. Incorrect orders WILL cause 2 or more users not being able to log in!
 +
passwords = {"password1", "password2" } -- Change this to the passwords for the users defined in the variable above. Again, make sure the passwords for users are in the same order as the usernames.
 +
senders = { 1, 2, 3, 4 } -- change this to the ID's of the all computers you want to accept requests from if you use a whitelist. If you do not use a whitelist, DO NOT REMOVE THIS LINE! Doing so will cause the program to crash everytime it is run, even though the variable is not used.
 +
 +
print("Loading core functions...")
 +
function clear()
 +
term.clear()
 +
term.setCursorPos(1, 1)
 +
print("CCLS Server 1.0 for CC 1.53")
 +
print("There is no user interaction here. Please contact your system administrator for assistance regarding the system.")
 +
if count == true then
 +
  print(tserved.." total requests received this session.")
 +
  print(vserved.." requests completed this session.")
 +
  print(dserved.." requests denied this session.")
 +
elseif count == false then
 +
  print("Request statics have been disabled.")
 +
else
 +
  rednet.close(modemSide)
 +
  term.clear()
 +
  term.setCursorPos(1, 1)
 +
  print("Error: Counter setting is not boolean and the server can not continue.")
 +
  print("The server program will exit automatically in 10 minutes. Or you can hold down Ctrl+T for 1 second.")
 +
  print("After that, please set the variable \"count\" in the source code to either \"true\" or \"false\" WITHOUT QUOTATION MARKS. Doing this with quotation marks will cause the same error.")
 +
  sleep(600)
 +
  shell.exit()
 +
end
 +
 +
print("Starting up...")
 +
rednet.open(modemSide) -- Opens the modem to wait for incoming login requests
 +
 +
clear()
 +
 +
while true do
 +
  validSender = false
 +
  senderId, message, distance = rednet.receive()
 +
  for i,v in ipairs(senders) do
 +
  tserved = tserved + 1
 +
  if v == senderId then
 +
    validSender = true
 +
    break
 +
  else
 +
    rednet.send(senderId, "301", true) -- Send response code 301 - which means Not Whitelisted.
 +
    dserved = dserved + 1
 +
    clear()
 +
  end
 +
  end
 +
  if validSender then
 +
  for i,v in ipairs(users) do
 +
    if message == v then
 +
  password = passwords[i]
 +
  rednet.send(senderId, password, true)
 +
  vserved = vserved + 1
 +
  clear()
 +
  break
 +
    else
 +
  rednet.send(senderId, "300", true) -- Send response code 300 - which means Bad Auth.
 +
  dserved = dserved + 1
 +
  clear()
 +
    end
 +
  end
 +
  end
 +
end
  
=== Server Code ===
+
 
 +
== Client ==
 +
<!-- Latias1290, you should remove the branding part, it's a tutorial, not a publish program place. You should also explain everything -->
 +
os.pullEvent = os.pullEventRaw
 +
local failed = true
 +
busr = "nsliq" -- If you ever happen to be unable to log in for some reason, you can use this username as a backup.
 +
bpass = "zuFUkVEjQKjkLQhTdpFMheNF" -- If you ever happen to be unable to log in for some reason, you can use this password as a backup.
 +
 +
password_server = 0 -- change to the ID of your password server computer
 +
rednet.open("left") -- change to the side your rednet modem is on
 +
while true do
 +
term.clear()
 +
term.setCursorPos(1,1)
 +
print("Welcome to CCLS 1.0 by Latias1290.")
 +
print("Please select an option.")
 +
print("[1] Login")
 +
print("[2] Shutdown")
 +
write("> ")
 +
input = read()
 +
if input == "2" then
 +
  os.shutdown()
 +
elseif input == "1" then
 +
  print("Please login.")
 +
  write("Username: ")
 +
  username = read()
 +
  write("Password: ")
 +
  password = read("*")
 +
  if username == busr then
 +
  if password == bpass then
 +
print("Access granted")
 +
break
 +
  end
 +
  end
 +
  rednet.send(password_server, username, true)
 +
  senderId, message, distance = rednet.receive(5)
 +
  if message == "300" then
 +
  print("Invalid Username or Password.")
 +
  sleep(3)
 +
  elseif password == message then
 +
  failed = false
 +
  term.clear()
 +
  term.setCursorPos(1,1)
 +
  print("Welcome ", username)
 +
  break;
 +
  else
 +
  print("Invalid Username or Password.")
 +
  sleep(3)
 +
  end
 +
else
 +
  print("Invalid Command.")
 +
  sleep(2)
 +
end
 +
end
 +
 
 +
== Flaws ==
 +
The above login system has several flaws and vulnerabilities.
 +
=== Credentials stored on volatile memory (Storage flaw) ===
 +
The login credentials are stored in a table. Since tables are stored on volatile memory, the computer requires to be on at all times in order for the server to retain login credentials. Computers are automatically restarted on server reload or world reload, rendering this login system inefficient for long-term usage.
 +
=== [[Network_Attacks#Identity_Spoof|Spoof Attack]] (Active Attack) ===
 +
Although this system is designed to protect a computer rather than a system, the login server is undeniably vulnerable to ID spoof, where a malicious user assumes the ID of a whitelisted computer, and defeats the purpose of an ID whitelist entirely. More details can be found on the [[Rednet_(API)|Rednet API]] page.
 +
=== [[Network_Attacks#Wiretapping|Wiretapping]] (Passive Attack) ===
 +
In this system, the username is sent to the server, which replies with the password for that username. A malicious user can intercept the username as it is being sent to the server, and intercept the password as it is being sent back to the client. The malicious user will be able to clearly read the username and password since no form of encryption is being used. More details can be found on the [[Rednet_(API)|Rednet API]] page.
 +
=== [[Network_Attacks#Forgery|Password Forgery]] (Active Attack) ===
 +
A malicious user can enter a random username and password on the target computer. He can then make another computer send the password he typed in to the target computer immediately after it sends the username. The target computer will recieve the forged password and compare it with the malicious user's password, and finding them to be equal, will grant the malicious user access to the computer.
 +
=== [[Network_Attacks#Forgery|Error code forgery]] (Active Attack) ===
 +
A malicious user can simply send the not whitelisted or invalid credentials error codes to the target computer before a legitamate error code appears, causing it to assume that the user is not whitelisted or has an invalid username every time the user tries to log in. This works because the target computer has no way of detecting whether the error code messages are forged or authentic.
 +
=== Program Terminate (Passive Attack) ===
 +
A malicious user can press and hold Ctrl+T on the computer to terminate the startup program and use the computer.
 +
=== Bypass username (Passive Attack) ===
 +
A malicious user can create a malicious floppy disk with a startup program that copies the computer's files to itself. A transfer the floppy disk to another computer and view the bypass credentials.
 +
 
 +
 
 +
== Alternative Server ==
  
 
  os.pullEvent = os.pullEventRaw
 
  os.pullEvent = os.pullEventRaw
Line 19: Line 167:
 
  term.setCursorPos(1,1)
 
  term.setCursorPos(1,1)
 
  print("This is a password server. There is no user interaction here.")
 
  print("This is a password server. There is no user interaction here.")
  print("Please find a computer and login there.")  
+
  print("Please find a computer and login there.")  
 
  local firstCycle = true
 
  local firstCycle = true
 
  local validSender = false
 
  local validSender = false
 
  local modemSide = "left" -- change to the side of the computer your modem is on
 
  local modemSide = "left" -- change to the side of the computer your modem is on
 
  local valid = false
 
  local valid = false
  users = { username1, username2 } --make sure users and passwords line up
+
  users = {"username1", "username2" } --make sure users and passwords line up
  passwords = { password1, password2 }
+
  passwords = {"password1", "password2" }
  senders = { 13, 14, 15, 17 } -- computer ID's of the computers you want to accept requests from
+
  senders = { 1, 2, 3, 4 } -- computer ID's of the computers you want to accept requests from
 
  function bootUp()
 
  function bootUp()
 
   rednet.open(modemSide)
 
   rednet.open(modemSide)
  end  
+
  end
 
  while true do  
 
  while true do  
 
   validSender = false
 
   validSender = false
Line 48: Line 196:
 
     valid = true
 
     valid = true
 
     password = passwords[i]
 
     password = passwords[i]
 +
    break
 
     else
 
     else
 
     valid = false
 
     valid = false
Line 53: Line 202:
 
   end
 
   end
 
   if valid then
 
   if valid then
     rednet.send(senderId, password)
+
     rednet.send(senderId, password, true)
 
   else
 
   else
     rednet.send(senderId, "Not Valid")
+
     rednet.send(senderId, "Not Valid", true)
 
   end
 
   end
 
   end
 
   end
 
  end
 
  end
  
=== Client Code ===
+
== Alternative Client ==
  
 
  os.pullEvent = os.pullEventRaw
 
  os.pullEvent = os.pullEventRaw
Line 66: Line 215:
 
  local failed = true
 
  local failed = true
 
  local attempted_login = true
 
  local attempted_login = true
  local password_server = 17 -- change to the ID of your password server computer
+
  local password_server = 0 -- change to the ID of your password server computer
 
  rednet.open("left") -- change to the side your rednet modem is on
 
  rednet.open("left") -- change to the side your rednet modem is on
 
  while locker do
 
  while locker do
Line 87: Line 236:
 
   write("Password: ")
 
   write("Password: ")
 
   local password = read("*")
 
   local password = read("*")
   rednet.send(password_server, username)
+
   rednet.send(password_server, username, true)
 
   senderId, message, distance = rednet.receive(5)
 
   senderId, message, distance = rednet.receive(5)
 
   if password == message then
 
   if password == message then
Line 96: Line 245:
 
     print("Welcome ", username)
 
     print("Welcome ", username)
 
   else
 
   else
     print("Not authorised.")
+
     print("Invalid Username or Password.")
     sleep(1)
+
     sleep(3)
 
   end
 
   end
 
   else
 
   else
Line 106: Line 255:
  
 
== Thoughts and Notes ==
 
== Thoughts and Notes ==
 +
 +
Although this may work very well as a login system, it is insecure by the flaw that a malicious sniffer can unnoticeably obtain a copy of the password while it is being sent as described on the [[Rednet_(API)|Rednet API]] page, and use the password to login.
 +
 
If you change the client code, to "startup" and put it in the root directory, it works very well as a login system.
 
If you change the client code, to "startup" and put it in the root directory, it works very well as a login system.
 
You may also want to put in the line  
 
You may also want to put in the line  
Line 113: Line 265:
 
If you have either Railcraft or Additional Pipes, find the 'World Anchor' or 'Teleport Tether' block. If your server can afford the resources, place the block within a 3x3 grid of your password server. It will ensure that even if you leave the chunk, the password server still is operational. Otherwise you may find that you cannot login because you've left the chunk and the password server is no longer dealing with requests.
 
If you have either Railcraft or Additional Pipes, find the 'World Anchor' or 'Teleport Tether' block. If your server can afford the resources, place the block within a 3x3 grid of your password server. It will ensure that even if you leave the chunk, the password server still is operational. Otherwise you may find that you cannot login because you've left the chunk and the password server is no longer dealing with requests.
  
 +
''Alternative version only:''
 
This is a minor security flaw but it is only if someone has access to a computer that is 'whitelisted' to access the password server. The security flaw is that if they use the password Not Valid on that computer they are allowed access;
 
This is a minor security flaw but it is only if someone has access to a computer that is 'whitelisted' to access the password server. The security flaw is that if they use the password Not Valid on that computer they are allowed access;
  
if valid then
+
if valid then
--send client password
+
  --send client password
else
+
else
--send client Not Valid
+
  --send client Not Valid
end
+
end
  
to fix remove the else statement
+
To fix this, remove the else statement.
  
  
[[Category:User Management]]
+
[[Category:Tutorials]]

Latest revision as of 07:46, 26 March 2014

This tutorial covers how to make a password server and a password client. The server will host a Lua table of usernames and passwords and the client will remotely connect each start up, ask the user for their username and password and compare it to that on the password server.

Setting Up

First of all, you must know how to craft a wireless modem and a computer. You need to craft at least 2 wireless modems and 2 computers if you want to have a practical use for this system. Then, attach 1 modem to each computer you want to add to the system.

Second, since typing on normal computers is relatively slow and annoying, I recommend to write the programs in Advanced Computersbecause in advanced computers you can click to move the cursor around, and there are colors to distinguis between different statements), copying them into a Floppy Disk and moving them into each computer you want to include(with their respective programs of course). Alternatively, if you are the server owner(this tutorial assumes you are in Multiplayer because this system does not have any practical use in Singleplayer), you can go into the world folder and write copy/paste the source code into the folders of each computer you want to use. The folders you should use are the named the IDs of the computers(so if you have 3 computers, with the IDs 5, 7 and 9, you should copy them into the folders 5, 7 and 9).

It does not matter wether you are using Normal or Advanced computers for this tutorial. I recommend to use Normal ones for the server.

When writing the programs, I HIGHLY recommend using a disk drive like stated above, so you dont have to write in prograns for every computer you add. Remember to read the text behind the --. These are comments, and you can safely leave them in the code.

Server

print("Initializing...")
local validSender = false
valid = false
tserved, vserved, dserved = 0

print("Loading startup settings...")
count = true -- If you dont want the server to count request statics, set the value of this variable to "false" without qoutes.
modemSide = "left" -- change to the side of the computer your modem is on
whitelist = true -- If you dont want to use a whitelist, change the value to "false" without quotes. This is not recommended on Multiplayer, but it does not make any difference on a Singleplayer World.

print("Loading user database...")
users = {"username1", "username2" } -- Change this to the names for the users you want to have. Make sure the usernames are in the same order as in the password table. Changing the order is fine, but you must maintain the same order in both the users and passwords tables. Incorrect orders WILL cause 2 or more users not being able to log in!
passwords = {"password1", "password2" } -- Change this to the passwords for the users defined in the variable above. Again, make sure the passwords for users are in the same order as the usernames.
senders = { 1, 2, 3, 4 } -- change this to the ID's of the all computers you want to accept requests from if you use a whitelist. If you do not use a whitelist, DO NOT REMOVE THIS LINE! Doing so will cause the program to crash everytime it is run, even though the variable is not used.

print("Loading core functions...")
function clear()
term.clear()
term.setCursorPos(1, 1)
print("CCLS Server 1.0 for CC 1.53") 
print("There is no user interaction here. Please contact your system administrator for assistance regarding the system.")
if count == true then
 print(tserved.." total requests received this session.")
 print(vserved.." requests completed this session.")
 print(dserved.." requests denied this session.")
elseif count == false then
 print("Request statics have been disabled.")
else
 rednet.close(modemSide)
 term.clear()
 term.setCursorPos(1, 1)
 print("Error: Counter setting is not boolean and the server can not continue.")
 print("The server program will exit automatically in 10 minutes. Or you can hold down Ctrl+T for 1 second.")
 print("After that, please set the variable \"count\" in the source code to either \"true\" or \"false\" WITHOUT QUOTATION MARKS. Doing this with quotation marks will cause the same error.")
 sleep(600)
 shell.exit()
end

print("Starting up...")
rednet.open(modemSide) -- Opens the modem to wait for incoming login requests

clear()

while true do 
 validSender = false
 senderId, message, distance = rednet.receive()
 for i,v in ipairs(senders) do
  tserved = tserved + 1
  if v == senderId then
   validSender = true
   break
  else
   rednet.send(senderId, "301", true) -- Send response code 301 - which means Not Whitelisted.
   dserved = dserved + 1
   clear()
  end
 end
 if validSender then
  for i,v in ipairs(users) do
   if message == v then
 password = passwords[i]
 rednet.send(senderId, password, true)
 vserved = vserved + 1
 clear()
 break
   else
 rednet.send(senderId, "300", true) -- Send response code 300 - which means Bad Auth.
 dserved = dserved + 1
 clear()
   end
  end
 end
end


Client

os.pullEvent = os.pullEventRaw
local failed = true
busr = "nsliq" -- If you ever happen to be unable to log in for some reason, you can use this username as a backup.
bpass = "zuFUkVEjQKjkLQhTdpFMheNF" -- If you ever happen to be unable to log in for some reason, you can use this password as a backup.

password_server = 0 -- change to the ID of your password server computer
rednet.open("left") -- change to the side your rednet modem is on
while true do
term.clear()
term.setCursorPos(1,1)
print("Welcome to CCLS 1.0 by Latias1290.")
print("Please select an option.")
print("[1] Login")
print("[2] Shutdown")
write("> ")
input = read()
if input == "2" then
 os.shutdown()
elseif input == "1" then
 print("Please login.")
 write("Username: ")
 username = read()
 write("Password: ")
 password = read("*")
 if username == busr then
 if password == bpass then
print("Access granted")
break
 end
 end
 rednet.send(password_server, username, true)
 senderId, message, distance = rednet.receive(5)
 if message == "300" then
 print("Invalid Username or Password.")
 sleep(3)
 elseif password == message then
 failed = false
 term.clear()
 term.setCursorPos(1,1)
 print("Welcome ", username)
 break;
 else
 print("Invalid Username or Password.")
 sleep(3)
 end
else
 print("Invalid Command.")
 sleep(2)
end
end

Flaws

The above login system has several flaws and vulnerabilities.

Credentials stored on volatile memory (Storage flaw)

The login credentials are stored in a table. Since tables are stored on volatile memory, the computer requires to be on at all times in order for the server to retain login credentials. Computers are automatically restarted on server reload or world reload, rendering this login system inefficient for long-term usage.

Spoof Attack (Active Attack)

Although this system is designed to protect a computer rather than a system, the login server is undeniably vulnerable to ID spoof, where a malicious user assumes the ID of a whitelisted computer, and defeats the purpose of an ID whitelist entirely. More details can be found on the Rednet API page.

Wiretapping (Passive Attack)

In this system, the username is sent to the server, which replies with the password for that username. A malicious user can intercept the username as it is being sent to the server, and intercept the password as it is being sent back to the client. The malicious user will be able to clearly read the username and password since no form of encryption is being used. More details can be found on the Rednet API page.

Password Forgery (Active Attack)

A malicious user can enter a random username and password on the target computer. He can then make another computer send the password he typed in to the target computer immediately after it sends the username. The target computer will recieve the forged password and compare it with the malicious user's password, and finding them to be equal, will grant the malicious user access to the computer.

Error code forgery (Active Attack)

A malicious user can simply send the not whitelisted or invalid credentials error codes to the target computer before a legitamate error code appears, causing it to assume that the user is not whitelisted or has an invalid username every time the user tries to log in. This works because the target computer has no way of detecting whether the error code messages are forged or authentic.

Program Terminate (Passive Attack)

A malicious user can press and hold Ctrl+T on the computer to terminate the startup program and use the computer.

Bypass username (Passive Attack)

A malicious user can create a malicious floppy disk with a startup program that copies the computer's files to itself. A transfer the floppy disk to another computer and view the bypass credentials.


Alternative Server

os.pullEvent = os.pullEventRaw
term.clear()
term.setCursorPos(1,1)
print("This is a password server. There is no user interaction here.")
print("Please find a computer and login there.") 
local firstCycle = true
local validSender = false
local modemSide = "left" -- change to the side of the computer your modem is on
local valid = false
users = {"username1", "username2" } --make sure users and passwords line up
passwords = {"password1", "password2" }
senders = { 1, 2, 3, 4 } -- computer ID's of the computers you want to accept requests from
function bootUp()
 rednet.open(modemSide)
end
while true do 
 validSender = false
 if firstCycle then
  bootUp()
  firstCycle = false
 end
 senderId, message, distance = rednet.receive()
 for i,v in ipairs(senders) do
  if v == senderId then
   validSender = true
   break
  end
 end
 if validSender then
  for i,v in ipairs(users) do
   if message == v then
    valid = true
    password = passwords[i]
    break
   else
    valid = false
   end
  end
  if valid then
   rednet.send(senderId, password, true)
  else
   rednet.send(senderId, "Not Valid", true)
  end
 end
end

Alternative Client

os.pullEvent = os.pullEventRaw
local locker = true
local failed = true
local attempted_login = true
local password_server = 0 -- change to the ID of your password server computer
rednet.open("left") -- change to the side your rednet modem is on
while locker do
 attempted_login = false
 term.clear()
 term.setCursorPos(1,1)
 print("Welcome to a USERS PC : Roaming Profile Enabled")
 print("What would you like to do?")
 print("[1] Login (*)")
 print("[2] Shutdown")
 write("> ")
 local input = read()
 if input == "2" then
  os.shutdown()
 elseif input == "1" then
  attempted_login = true
  print("Please login...")
  write("Username: ")
  local username = read()
  write("Password: ")
  local password = read("*")
  rednet.send(password_server, username, true)
  senderId, message, distance = rednet.receive(5)
  if password == message then
   failed = false
   locker = false
   term.clear()
   term.setCursorPos(1,1)
   print("Welcome ", username)
  else
   print("Invalid Username or Password.")
   sleep(3)
  end
 else
  print("Command not recognised...")
  sleep(2)
 end
end

Thoughts and Notes

Although this may work very well as a login system, it is insecure by the flaw that a malicious sniffer can unnoticeably obtain a copy of the password while it is being sent as described on the Rednet API page, and use the password to login.

If you change the client code, to "startup" and put it in the root directory, it works very well as a login system. You may also want to put in the line

os.pullEvent = os.pullEventRaw -- disables Ctrl+T

as if it doesn't work first time it can be difficult to get out of the program.

If you have either Railcraft or Additional Pipes, find the 'World Anchor' or 'Teleport Tether' block. If your server can afford the resources, place the block within a 3x3 grid of your password server. It will ensure that even if you leave the chunk, the password server still is operational. Otherwise you may find that you cannot login because you've left the chunk and the password server is no longer dealing with requests.

Alternative version only: This is a minor security flaw but it is only if someone has access to a computer that is 'whitelisted' to access the password server. The security flaw is that if they use the password Not Valid on that computer they are allowed access;

if valid then
 --send client password
else
 --send client Not Valid
end

To fix this, remove the else statement.