20 Commits
0.1.3 ... 0.2.2

Author SHA1 Message Date
63e52b8c3e ding client with -c <CONFIGFILE> option 2020-05-03 01:58:54 +02:00
4622833ff5 systemd example file 2020-05-02 20:29:52 +02:00
57fb2f7b99 Using actual ConfigParser call; dingd has -c for config file 2020-05-02 20:24:16 +02:00
3e7f23ccd1 Removing trailing spaces No 7 >:( 2018-04-04 17:20:17 +02:00
abf6a0f563 Removing trailing spaces No 6 2018-04-04 17:06:35 +02:00
6687604446 Removing trailing spaces No 5 2018-04-04 16:59:19 +02:00
1a3e532b29 Removing trailing spaces No 4 2018-04-04 16:51:26 +02:00
36dd610965 Merge branch 'master' of github.com:Bandie/ding 2018-04-04 16:44:39 +02:00
2141418097 Removing trailing whitespaces No 3 2018-04-04 16:44:09 +02:00
6d24484430 Merge pull request #4 from Bandie/preMerge
Removing trailing whitespaces No 2
2018-04-04 16:40:22 +02:00
9b03d6f928 Removing trailing whitespaces No 2 2018-04-04 16:39:23 +02:00
dc027362f0 Merge pull request #3 from Bandie/preMerge
Removing trailing whitespaces
2018-04-04 16:34:27 +02:00
406accc716 Removing trailing whitespaces 2018-04-04 16:33:36 +02:00
72c68cabde Merge pull request #2 from Bandie/preMerge
Improvement™
2018-04-04 16:26:08 +02:00
a7d27c5ee9 Improvement™ 2018-04-04 16:24:52 +02:00
600524809c Renaming 2018-03-29 00:58:36 +02:00
ae3043b1de Structure 2018-02-06 00:01:53 +01:00
b17e6c9353 Beware of the shell history! 2018-02-05 23:58:30 +01:00
aef87bed4a Readability 2018-02-02 12:18:32 +01:00
4a09411676 ' 2018-02-01 22:14:32 +01:00
10 changed files with 130 additions and 79 deletions

View File

@ -1,28 +1,28 @@
#!/bin/bash #!/bin/bash
## Server private key ## Server private key
echo -n "Where to save your server's key file? ($PWD/ding_server.key): " echo -n "Where to save your server's key file? ($PWD/dingd.key): "
read temp read temp
if [ -n "$temp" ] if [ -n "$temp" ]
then then
save=$temp save=$temp
else else
save="$PWD/ding_server.key" save="$PWD/dingd.key"
fi fi
key=$save key=$save
openssl genrsa -out $save 4096 openssl genrsa -out $save 4096
## CSR ## CSR
echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding_server.csr): " echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/dingd.csr): "
read temp read temp
if [ -n "$temp" ] if [ -n "$temp" ]
then then
save=$temp save=$temp
else else
save="$PWD/ding_server.csr" save="$PWD/dingd.csr"
fi fi
csr=$save csr=$save
echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's INFORMATION.\033[00m" echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's INFORMATION.\033[00m"
@ -50,14 +50,14 @@ else
loadCAkey="$PWD/CA.key" loadCAkey="$PWD/CA.key"
fi fi
echo -n "Where to save your signed server certificate? ($PWD/ding_server.crt): " echo -n "Where to save your signed server certificate? ($PWD/dingd.crt): "
read temp read temp
if [ -n "$temp" ] if [ -n "$temp" ]
then then
save=$temp save=$temp
else else
save="$PWD/ding_server.crt" save="$PWD/dingd.crt"
fi fi
echo -n "How many days should the certificate be valid? (365): " echo -n "How many days should the certificate be valid? (365): "

View File

@ -1,28 +1,28 @@
#!/bin/bash #!/bin/bash
## Server private key ## Server private key
echo -n "Where to save your client's key file? ($PWD/ding_client.key): " echo -n "Where to save your client's key file? ($PWD/ding.key): "
read temp read temp
if [ -n "$temp" ] if [ -n "$temp" ]
then then
save=$temp save=$temp
else else
save="$PWD/ding_client.key" save="$PWD/ding.key"
fi fi
key=$save key=$save
openssl genrsa -out $save 4096 openssl genrsa -out $save 4096
## CSR ## CSR
echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding_client.csr): " echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding.csr): "
read temp read temp
if [ -n "$temp" ] if [ -n "$temp" ]
then then
save=$temp save=$temp
else else
save="$PWD/ding_client.csr" save="$PWD/ding.csr"
fi fi
csr=$save csr=$save
echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's AND SERVER's INFORMATION.\033[00m" echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's AND SERVER's INFORMATION.\033[00m"
@ -50,14 +50,14 @@ else
loadCAkey="$PWD/CA.key" loadCAkey="$PWD/CA.key"
fi fi
echo -n "Where to save your signed client certificate? ($PWD/ding_client.crt): " echo -n "Where to save your signed client certificate? ($PWD/ding.crt): "
read temp read temp
if [ -n "$temp" ] if [ -n "$temp" ]
then then
save=$temp save=$temp
else else
save="$PWD/ding_client.crt" save="$PWD/ding.crt"
fi fi
echo -n "How many days should the certificate be valid? (365): " echo -n "How many days should the certificate be valid? (365): "

View File

@ -1,20 +1,25 @@
# ding # ding
## What is ding? ## What is ding?
ding is a client-server thing written in python3. Its aim is to execute a set of commands remotely, which commands can be set in the server's config file. ding is a client-server thing written in python3. Its aim is to execute a set of commands remotely. The commands can be set in the server's config file.
## How does it work? ## How does it work?
The server will wait for a command to be sent by a client. If the command is present within the servers config file it will then execute the command, else nothing will happen. The server will wait for a command to be sent by a client. If the command is present within the server's config file it will then execute the command, else nothing will happen.
## What about ding's security? ## What about ding's security?
The authentication is done via a SSL Client Certificate signed by an (self generated) Certificate Authority. The scripts for generating a CA and signing the Server/Client Certificates are also included to make it (relatively) easy. [ This involves typing in a few certificate details and entering a previously defined CA password. ] The authentication is done via a SSL Client Certificate signed by an (self generated) Certificate Authority. The scripts for generating a CA and signing the Server/Client Certificates are also included to make it (relatively) easy. [ This involves typing in a few certificate details and entering a previously defined CA password. ]
## Pic or didn't happen ## Pic or didn't happen
![Screenshot of ding](/img/dingScreenshot.png) ![Screenshot of ding](/img/dingScreenshot.png)
[Can't read a thing?](https://raw.githubusercontent.com/Bandie/ding/master/img/dingScreenshot.png) [Can't read a thing?](https://raw.githubusercontent.com/Bandie/ding/master/img/dingScreenshot.png)
## Requirements ## Requirements
* Install python3 on your target computers. * Install python3 on your target computers.
## Installation ## Installation
At every step please read carefully what the generate certificates scripts want from you. The information on the certificates doesn't need to be true and can be totally random. They only need to be different from one another. At every step please read carefully what the generate certificates scripts want from you. The information on the certificates doesn't need to be true and can be totally random. They only need to be different from one another.
@ -23,22 +28,26 @@ Step 1 to 3 can only be run on UNIX or GNU/Linux.
1. Run `./1_generateCA.sh` to generate a CA. 1. Run `./1_generateCA.sh` to generate a CA.
2. Run `./2_generateServCert.sh` to generate a signed Server Certificate. 2. Run `./2_generateServCert.sh` to generate a signed Server Certificate.
3. Run `./3_generateClientCert.sh` to generate a signed Client Certificate. 3. Run `./3_generateClientCert.sh` to generate a signed Client Certificate.
4. Move `ding_client`, `ding_client.cfg`, `ding_client.crt`, `ding_client.key` and `CA.crt` to the computer which should be able to send commands to the server. 4. Move `ding`, `ding.cfg`, `ding.crt`, `ding.key` and `CA.crt` to the computer which should be able to send commands to the server.
* UNIX or GNU/Linux: Also move `ding_client.cfg` to that computer. * UNIX or GNU/Linux: Also move `ding.cfg` to that computer.
* Windows: Also move `ding_client.win.cfg` to that computer. * Windows: Also move `ding.win.cfg` to that computer.
5. Do some configuration on the server and client (ding\_server.cfg, ding\_client.cfg or ding\_server.win.cfg, ding\_client.win.cfg on Windows). 5. Do some configuration on the server and client (`dingd.cfg`, `ding.cfg` or `dingd.win.cfg`, `ding.win.cfg` on Windows).
6. Start the server using `./ding_server` or `python .\ding_server` on Windows. (You may want to put this in a tmux session. [Ctrl+B, D] ;) ). 6. Start the server using `./dingd` or `python .\dingd` on Windows. (You may want to put this in a tmux session. [Ctrl+B, D] ;) ).
7. Try out the client using `./ding_client <command>` òr `python .\ding_client <command>` on Windows. 7. Try out the client using `./ding <command>` òr `python .\ding <command>` on Windows.
## Optional: Cleartext password with timeout ## Optional: Cleartext password with timeout
If you want to be sure that this power won't be abused by bad people using your computer, you may want to add a password (saved in cleartext). If you want to be sure that this power won't be abused by bad people using your computer, you may want to add a password (saved in cleartext).
The password will be sent inside the TLS connection. The password will be sent inside the TLS connection.
To do so: ### Warning! Beware of the shell history!
You might want to do something like `$ history -c` after sending the password via the client or play around with bash's HISTCONTROL variable.
1. Open your `ding_server.cfg` or `ding_server.win.cfg`. ### How to enable the password
1. Open your `dingd.cfg` or `dingd.win.cfg`.
2. Set `pw_on=true`. 2. Set `pw_on=true`.
3. Set a password, like `password=abc def`. 3. Set a password, like `password=abc def`.
4. Set a password timeout: `pwtimeout=10` for 10 seconds. 4. Set a password timeout: `pwtimeout=10` for 10 seconds.
If you have a password with special characters as in spaces and the like, you may want to use quotation marks around your password. `./ding_client "abc def"` or `python .\ding_client "abc def"` on Windows. If you have a password with special characters as in spaces and the like, you may want to use quotation marks around your password. `./ding "abc def"` or `python .\ding "abc def"` on Windows.

View File

@ -3,26 +3,32 @@
# Author: Bandie Canis # Author: Bandie Canis
# License: 2-Clause BSD License # License: 2-Clause BSD License
import sys, ssl, socket, os import sys, ssl, socket, os, getopt
import configparser import configparser
global exitcode host = None
port = 0
cafile = None
certfile = None
keyfile = None
exitcode = 1 exitcode = 1
def readConfig(): def init(conf):
if(os.name == 'nt'): if(conf == None):
CONFIG = "ding_client.win.cfg" if(os.name == 'nt'):
CONFIG = "ding.win.cfg"
else:
CONFIG = "ding.cfg"
else: else:
CONFIG = "ding_client.cfg" CONFIG = conf
cfg = configparser.SafeConfigParser() cfg = configparser.ConfigParser()
try: try:
cfg.read(CONFIG) cfg.read(CONFIG)
global host, port, cafile, certfile, keyfile global host, port, cafile, certfile, keyfile
host = cfg.get("Client", "host") host = cfg.get("Client", "host")
port = int(cfg.get("Client", "port")) port = int(cfg.get("Client", "port"))
@ -30,7 +36,7 @@ def readConfig():
certfile = cfg.get("Client", "certfile") certfile = cfg.get("Client", "certfile")
keyfile = cfg.get("Client", "keyfile") keyfile = cfg.get("Client", "keyfile")
except configparser.NoSectionError: except configparser.NoSectionError:
print("No suitable config found. Expecting some config in", CONFIG) print("No suitable config found. Expecting some config in", CONFIG, file=sys.stderr)
quit(3) quit(3)
@ -38,7 +44,7 @@ def send(conn, cmd):
conn.connect((host, port)) conn.connect((host, port))
buf = conn.recv(1024) buf = conn.recv(1024)
if(buf == b"OK 1337\n"): if(buf == b"OK 1337\n"):
conn.sendall(cmd) conn.sendall(cmd)
buf = conn.recv(1024) buf = conn.recv(1024)
if(buf == b"OK CMD"): if(buf == b"OK CMD"):
@ -47,10 +53,10 @@ def send(conn, cmd):
print("Error. Server said: The command isn't set on the server.", file=sys.stderr) print("Error. Server said: The command isn't set on the server.", file=sys.stderr)
exitcode = 1 exitcode = 1
elif(buf == b"ERR CMD_ERR"): elif(buf == b"ERR CMD_ERR"):
print("Error. Server said: The command doesn't work because the file doesn't exist on the server.") print("Error. Server said: The command doesn't work because the file doesn't exist on the server.", file=sys.stderr)
exitcode = 2 exitcode = 2
elif(buf == b"ERR PW"): elif(buf == b"ERR PW"):
print("Error. Password required. The password was wrong.") print("Error. Password required. The password was wrong.", file=sys.stderr)
exitcode = 4 exitcode = 4
elif(b"OK PW" in buf): elif(b"OK PW" in buf):
bufr=str(buf.decode('utf-8')) bufr=str(buf.decode('utf-8'))
@ -61,10 +67,10 @@ def send(conn, cmd):
print("The server seems to be crazy. Nothing sent.", file=sys.stderr) print("The server seems to be crazy. Nothing sent.", file=sys.stderr)
conn.close() conn.close()
quit(exitcode)
def main(arg):
def main():
try: try:
context = ssl.SSLContext(ssl.PROTOCOL_TLS) context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_REQUIRED context.verify_mode = ssl.CERT_REQUIRED
@ -82,7 +88,7 @@ def main():
try: try:
send(conn, bytes(sys.argv[1], sys.stdin.encoding)) send(conn, bytes(arg[0], sys.stdin.encoding))
except IndexError: except IndexError:
print(sys.argv[0], ": Missing argument.\nSyntax: ", sys.argv[0], " <COMMAND>", file=sys.stderr) print(sys.argv[0], ": Missing argument.\nSyntax: ", sys.argv[0], " <COMMAND>", file=sys.stderr)
except ConnectionRefusedError: except ConnectionRefusedError:
@ -95,7 +101,16 @@ def main():
if(__name__ == "__main__"): if(__name__ == "__main__"):
readConfig() try:
main() conf = None
quit(exitcode) opts, args = getopt.getopt(sys.argv[1:], "c:")
for o, a in opts:
if o == "-c":
conf = a
init(conf)
main(args)
except getopt.GetoptError as e:
print("Error using options. Allowed options:\n-c [FILE] - Config file\n")
quit(2)
quit(exitcode)

View File

@ -5,6 +5,6 @@ port=13573
cafile=CA.crt cafile=CA.crt
#Client Certificate/key signed by the CA above #Client Certificate/key signed by the CA above
certfile=ding_client.crt certfile=ding.crt
keyfile=ding_client.key keyfile=ding.key

View File

@ -5,6 +5,6 @@ port=13573
cafile=CA.crt cafile=CA.crt
#Client Certificate/key signed by the CA above #Client Certificate/key signed by the CA above
certfile=ding_client.crt certfile=ding.crt
keyfile=ding_client.key keyfile=ding.key

View File

@ -3,24 +3,37 @@
# Author: Bandie Canis # Author: Bandie Canis
# License: 2-Clause BSD license # License: 2-Clause BSD license
import ssl, socket, subprocess, time, os import ssl, socket, subprocess, time, os, sys, getopt
import configparser import configparser
CONFIG = None
host = None
port = 0
cafile = None
certfile = None
keyfile = None
pw_on = None
password = None
pwtimeout = 30
tmppw_on = None
context = None
bindsocket = None
def getTimestamp(): def getTimestamp():
t = "[" + time.strftime("%Y-%m-%d %H:%M:%S") + "]" t = "[" + time.strftime("%Y-%m-%d %H:%M:%S") + "]"
return t return t
def execFromConfig(option, pw=False): def execFromConfig(option, pw=False):
cfg = configparser.SafeConfigParser() cfg = configparser.ConfigParser()
cfg.read(CONFIG) cfg.read(CONFIG)
if(pw): if(pw):
if(option == password): if(option == password):
return 4 return 4
else: else:
return 5 return 5
else: else:
@ -39,16 +52,14 @@ def execFromConfig(option, pw=False):
print(getTimestamp(), "No execution set:", option) print(getTimestamp(), "No execution set:", option)
return 1 return 1
def main(): def main():
while True: while True:
newsocket, fromaddr = bindsocket.accept() newsocket, fromaddr = bindsocket.accept()
try: try:
connstream = context.wrap_socket(newsocket, server_side=True) connstream = context.wrap_socket(newsocket, server_side=True)
print(getTimestamp(), "Incoming connection:", fromaddr[0]) print(getTimestamp(), "Incoming connection:", fromaddr[0])
connstream.send(b"OK 1337\n") connstream.send(b"OK 1337\n")
con_loop = True con_loop = True
while con_loop: while con_loop:
global tmppw_on, pw_on, pwtimeout global tmppw_on, pw_on, pwtimeout
@ -56,7 +67,7 @@ def main():
del timeout del timeout
tmppw_on=pw_on tmppw_on=pw_on
print(getTimestamp(), "Locked.") print(getTimestamp(), "Locked.")
try: try:
buf = connstream.recv(1024) buf = connstream.recv(1024)
if not buf: break if not buf: break
@ -67,9 +78,7 @@ def main():
except ConnectionResetError: except ConnectionResetError:
print(getTimestamp(), "Connection reset.") print(getTimestamp(), "Connection reset.")
serve() serve()
if(tmppw_on): if(tmppw_on):
retval = execFromConfig(buf, True) retval = execFromConfig(buf, True)
if(retval == 5): if(retval == 5):
@ -81,7 +90,7 @@ def main():
connstream.send(bytes(pwokstr, "utf-8")) connstream.send(bytes(pwokstr, "utf-8"))
timeout=time.time() + pwtimeout timeout=time.time() + pwtimeout
tmppw_on = False tmppw_on = False
else: else:
print(getTimestamp(), " ", fromaddr[0], ": ", buf, sep="") print(getTimestamp(), " ", fromaddr[0], ": ", buf, sep="")
retval = execFromConfig(buf) retval = execFromConfig(buf)
@ -91,7 +100,6 @@ def main():
connstream.send(b"ERR NO_CMD") connstream.send(b"ERR NO_CMD")
elif(retval == 2): elif(retval == 2):
connstream.send(b"ERR CMD_ERR") connstream.send(b"ERR CMD_ERR")
except ssl.SSLError as e: except ssl.SSLError as e:
print(getTimestamp(), e) print(getTimestamp(), e)
@ -99,16 +107,19 @@ def main():
except EOFError: except EOFError:
print(getTimestamp(), "EOF") print(getTimestamp(), "EOF")
def init(): def init(cfg=None):
global CONFIG, host, port, cafile, certfile, keyfile, pw_on, password, pwtimeout, tmppw_on, context, bindsocket global CONFIG, host, port, cafile, certfile, keyfile, pw_on, password, pwtimeout, tmppw_on, context, bindsocket
if(os.name == 'nt'):
CONFIG = "ding_server.win.cfg"
else:
CONFIG = "ding_server.cfg"
cfg = configparser.SafeConfigParser() if(cfg==None):
if(os.name == 'nt'):
CONFIG = "dingd.win.cfg"
else:
CONFIG = "dingd.cfg"
else:
CONFIG = cfg
cfg = configparser.ConfigParser()
cfg.read(CONFIG) cfg.read(CONFIG)
try: try:
@ -125,11 +136,10 @@ def init():
else: else:
pw_on = False pw_on = False
tmppw_on=pw_on tmppw_on=pw_on
except configparser.NoOptionError as e: except configparser.NoSectionError as e:
print("Error in configuration file:", e) print("Error in configuration file:", e, file=sys.stderr)
quit(1) quit(1)
try: try:
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=cafile) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=cafile)
context.load_cert_chain(certfile=certfile, keyfile=keyfile) context.load_cert_chain(certfile=certfile, keyfile=keyfile)
@ -155,11 +165,11 @@ def init():
except PermissionError: except PermissionError:
print("Error: Can't bind for port number ", port, ". Permission denied.", sep="") print("Error: Can't bind for port number ", port, ". Permission denied.", sep="")
quit(1) quit(1)
print("Running ding server on ", host, ":", port, print("Running dingd on ", host, ":", port,
"\nConfig: ", CONFIG, "\nConfig: ", CONFIG,
"\nCAFile: ", cafile, "\nCAFile: ", cafile,
"\nCertfile: ", certfile, "\nCertfile: ", certfile,
"\nKeyfile: ", keyfile, "\nKeyfile: ", keyfile,
"\nPassword lock: ", pw_on, "\nPassword lock: ", pw_on,
"\nPassword timeout: ", pwtimeout, "\nPassword timeout: ", pwtimeout,
@ -169,10 +179,17 @@ def init():
if(__name__ == "__main__"): if(__name__ == "__main__"):
try: try:
init() conf = None
opts, args = getopt.getopt(sys.argv[1:], "c:")
for o, a in opts:
if o == "-c":
conf = a
init(conf)
main() main()
except getopt.GetoptError as e:
print("Error using options. Allowed options:\n-c [FILE] - Config file\n")
quit(2)
except KeyboardInterrupt: except KeyboardInterrupt:
print("\r\rServer stopped.") print("\r\rServer stopped.")

View File

@ -7,10 +7,10 @@ port=13573
cafile=CA.crt cafile=CA.crt
# Server's certificate [signed by the CA above] # Server's certificate [signed by the CA above]
certfile=ding_server.crt certfile=dingd.crt
# Server's private key # Server's private key
keyfile=ding_server.key keyfile=dingd.key
## Optional cleartext password ## Optional cleartext password
# To unlock the commands you need to send the password before sending the command. # To unlock the commands you need to send the password before sending the command.

View File

@ -7,10 +7,10 @@ port=13573
cafile=CA.crt cafile=CA.crt
# Server's certificate [signed by the CA above] # Server's certificate [signed by the CA above]
certfile=ding_server.crt certfile=dingd.crt
# Server's private key # Server's private key
keyfile=ding_server.key keyfile=dingd.key
## Optional cleartext password ## Optional cleartext password
# To unlock the commands you need to send the password before sending the command. # To unlock the commands you need to send the password before sending the command.

10
systemd/dingd.service Normal file
View File

@ -0,0 +1,10 @@
[Unit]
Description=dingd Service
[Service]
ExecStart=/root/ding/dingd -c /path/to/config/file/dingd.cfg
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=default.target