There it is.
This commit is contained in:
parent
e7d44a152e
commit
b524f113dc
43
1_generateCA.sh
Executable file
43
1_generateCA.sh
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "###################"
|
||||||
|
echo "# CA generation #"
|
||||||
|
echo -e "###################\n"
|
||||||
|
|
||||||
|
## CA Private key
|
||||||
|
echo -n "Where to save your CA key file? ($PWD/CA.key): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/CA.key"
|
||||||
|
fi
|
||||||
|
CAkey=$save
|
||||||
|
openssl genrsa -aes256 -out $save 8192
|
||||||
|
|
||||||
|
|
||||||
|
## CA Certificate
|
||||||
|
echo -n "Where to save your CA certificate? ($PWD/CA.crt): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/CA.crt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "How many days should the certificate be valid? (3650): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [[ $temp =~ ^[0-9]+$ ]]
|
||||||
|
then
|
||||||
|
days=$temp
|
||||||
|
else
|
||||||
|
days=3650
|
||||||
|
fi
|
||||||
|
echo -e "\033[01;33mPlease enter some information about the CA.\033[00m"
|
||||||
|
openssl req -new -x509 -days $days -key $CAkey -out $save
|
||||||
|
|
||||||
|
|
73
2_generateServCert.sh
Executable file
73
2_generateServCert.sh
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
## Server private key
|
||||||
|
echo -n "Where to save your server's key file? ($PWD/ding_server.key): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/ding_server.key"
|
||||||
|
fi
|
||||||
|
key=$save
|
||||||
|
openssl genrsa -out $save 4096
|
||||||
|
|
||||||
|
|
||||||
|
## CSR
|
||||||
|
echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding_server.csr): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/ding_server.csr"
|
||||||
|
fi
|
||||||
|
csr=$save
|
||||||
|
echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's INFORMATION.\033[00m"
|
||||||
|
openssl req -new -key $key -out $save -sha512
|
||||||
|
|
||||||
|
|
||||||
|
## Signing
|
||||||
|
echo -n "Path of your CA Certificate? ($PWD/CA.crt): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
loadCAcrt=$temp
|
||||||
|
else
|
||||||
|
loadCAcrt="$PWD/CA.crt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Path of your CA key? ($PWD/CA.key): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
loadCAkey=$temp
|
||||||
|
else
|
||||||
|
loadCAkey="$PWD/CA.key"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Where to save your signed server certificate? ($PWD/ding_server.crt): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/ding_server.crt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "How many days should the certificate be valid? (365): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
t=$temp
|
||||||
|
else
|
||||||
|
t=365
|
||||||
|
fi
|
||||||
|
openssl x509 -req -in $csr -CA $loadCAcrt -CAkey $loadCAkey -CAcreateserial -out $save -days $t -sha512
|
||||||
|
rm $csr
|
73
3_generateClientCert.sh
Executable file
73
3_generateClientCert.sh
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
## Server private key
|
||||||
|
echo -n "Where to save your client's key file? ($PWD/ding_client.key): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/ding_client.key"
|
||||||
|
fi
|
||||||
|
key=$save
|
||||||
|
openssl genrsa -out $save 4096
|
||||||
|
|
||||||
|
|
||||||
|
## CSR
|
||||||
|
echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding_client.csr): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/ding_client.csr"
|
||||||
|
fi
|
||||||
|
csr=$save
|
||||||
|
echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's AND SERVER's INFORMATION.\033[00m"
|
||||||
|
openssl req -new -key $key -out $save -sha512
|
||||||
|
|
||||||
|
|
||||||
|
## Signing
|
||||||
|
echo -n "Path of your CA Certificate? ($PWD/CA.crt): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
loadCAcrt=$temp
|
||||||
|
else
|
||||||
|
loadCAcrt="$PWD/CA.crt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Path of your CA key? ($PWD/CA.key): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
loadCAkey=$temp
|
||||||
|
else
|
||||||
|
loadCAkey="$PWD/CA.key"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Where to save your signed client certificate? ($PWD/ding_client.crt): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
save=$temp
|
||||||
|
else
|
||||||
|
save="$PWD/ding_client.crt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "How many days should the certificate be valid? (365): "
|
||||||
|
read temp
|
||||||
|
|
||||||
|
if [ -n "$temp" ]
|
||||||
|
then
|
||||||
|
t=$temp
|
||||||
|
else
|
||||||
|
t=365
|
||||||
|
fi
|
||||||
|
openssl x509 -req -in $csr -CA $loadCAcrt -CAkey $loadCAkey -CAcreateserial -out $save -days $t -sha512
|
||||||
|
rm $csr
|
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# ding
|
||||||
|
## What is ding?
|
||||||
|
ding is a client-server thing written in python. Its aim is to execute a set of commands remotely which can be set in the server's config file.
|
||||||
|
|
||||||
|
## How does it work?
|
||||||
|
The server awaits the client's commands. A command sent by the client must be defined in the server's config file, else the server won't do anything.
|
||||||
|
|
||||||
|
## What about ding's security?
|
||||||
|
The authentication is done by an SSL Client Certificate signed by an (own generated) Certificate Authority. The scripts for generating a CA and signing a Server/Client Certificate are also in here to make it (relatively) easy. [ You need only to press enter in the most cases, type in some certificate information and entering a previously defined CA password. ]
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
In all steps please read carefully, what the generating script want from you.
|
||||||
|
|
||||||
|
1. Run `./1_generateCA.sh` to generate a CA.
|
||||||
|
2. Run `./2_generateServCert.sh` to generate a signed Server 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 to the computer which should be able to send commands to the server.
|
||||||
|
5. Do some configuration on the server and client (ding\_server.cfg, ding\_client.cfg).
|
||||||
|
6. Start the server using `./ding_server`. You may want to put this in a tmux session ([Ctrl+B, D] ;) ).
|
||||||
|
7. Try out the client using `./ding_client <command>`.
|
||||||
|
|
||||||
|
|
82
ding_client
Executable file
82
ding_client
Executable file
@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys, ssl, socket
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
CONFIG = "ding_client.cfg"
|
||||||
|
|
||||||
|
def readConfig():
|
||||||
|
cfg = configparser.SafeConfigParser()
|
||||||
|
try:
|
||||||
|
cfg.read(CONFIG)
|
||||||
|
|
||||||
|
global host, port, cafile, certfile, keyfile
|
||||||
|
|
||||||
|
host = cfg.get("Client", "host")
|
||||||
|
port = int(cfg.get("Client", "port"))
|
||||||
|
|
||||||
|
cafile = cfg.get("Client", "cafile")
|
||||||
|
certfile = cfg.get("Client", "certfile")
|
||||||
|
keyfile = cfg.get("Client", "keyfile")
|
||||||
|
except configparser.NoSectionError:
|
||||||
|
print("No suitable config found. Expecting some config in", CONFIG)
|
||||||
|
quit(3)
|
||||||
|
|
||||||
|
|
||||||
|
def send(conn, cmd):
|
||||||
|
|
||||||
|
global exitcode
|
||||||
|
|
||||||
|
conn.connect((host, port))
|
||||||
|
buf = conn.recv(1024)
|
||||||
|
if(buf == b"OK 1337\n"):
|
||||||
|
conn.sendall(cmd)
|
||||||
|
buf = conn.recv(1024)
|
||||||
|
if(buf == b"OK CMD"):
|
||||||
|
exitcode = 0
|
||||||
|
elif(buf == b"ERR NO_CMD"):
|
||||||
|
print("Error. Server said: The command doesn't exist/isn't set.", file=sys.stderr)
|
||||||
|
exitcode = 1
|
||||||
|
elif(buf == b"ERR CMD_ERR"):
|
||||||
|
print("Error. Server said: The command doesn't work because the file doesn't exist on the server.")
|
||||||
|
exitcode = 2
|
||||||
|
|
||||||
|
else:
|
||||||
|
conn.sendall(b"NO.")
|
||||||
|
print("The server seems to be crazy. Nothing sent.", file=sys.stderr)
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||||
|
context.verify_mode = ssl.CERT_REQUIRED
|
||||||
|
context.load_verify_locations(cafile)
|
||||||
|
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
print(e)
|
||||||
|
print("Please check your paths in the config file. (Have you forgotten to generate the Certificates?)", sep="", file=sys.stderr)
|
||||||
|
quit(2)
|
||||||
|
|
||||||
|
conn = context.wrap_socket(socket.socket())
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
send(conn, bytes(sys.argv[1], sys.stdin.encoding))
|
||||||
|
except IndexError:
|
||||||
|
print(sys.argv[0], ": Missing argument.\nSyntax: ", sys.argv[0], " <COMMAND>", file=sys.stderr)
|
||||||
|
except ConnectionRefusedError:
|
||||||
|
print("Connection refused.", file=sys.stderr)
|
||||||
|
quit(1)
|
||||||
|
except ssl.SSLError:
|
||||||
|
print("Wrong certificate.", file=sys.stderr);
|
||||||
|
quit(3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(__name__ == "__main__"):
|
||||||
|
readConfig()
|
||||||
|
main()
|
||||||
|
quit(exitcode)
|
||||||
|
|
10
ding_client.cfg
Normal file
10
ding_client.cfg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[Client]
|
||||||
|
host=localhost
|
||||||
|
port=13573
|
||||||
|
|
||||||
|
|
||||||
|
cafile=CA.crt
|
||||||
|
#Client Certificate/key signed by the CA above
|
||||||
|
certfile=ding_client.crt
|
||||||
|
keyfile=ding_client.key
|
||||||
|
|
127
ding_server
Executable file
127
ding_server
Executable file
@ -0,0 +1,127 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import ssl, socket, subprocess, time
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
CONFIG = "ding_server.cfg"
|
||||||
|
|
||||||
|
def getTimestamp():
|
||||||
|
t = "[" + time.strftime("%Y-%m-%d %H:%M:%S") + "]"
|
||||||
|
return t
|
||||||
|
|
||||||
|
def execFromConfig(option):
|
||||||
|
cfg = configparser.SafeConfigParser()
|
||||||
|
cfg.read(CONFIG)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cmd = cfg.get("Commands", option).replace("\"", "").replace("\'", "")
|
||||||
|
cmd = cmd.split(" ")
|
||||||
|
try:
|
||||||
|
subprocess.Popen(cmd)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(getTimestamp(), "Can't execute", cmd, ". File not found.")
|
||||||
|
return 2
|
||||||
|
|
||||||
|
except configparser.NoOptionError:
|
||||||
|
print(getTimestamp(), "No execution set:", option)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
while True:
|
||||||
|
newsocket, fromaddr = bindsocket.accept()
|
||||||
|
try:
|
||||||
|
connstream = context.wrap_socket(newsocket, server_side=True)
|
||||||
|
print(getTimestamp(), "Incoming connection:", fromaddr[0])
|
||||||
|
connstream.send(b"OK 1337\n")
|
||||||
|
|
||||||
|
con_loop = True
|
||||||
|
while con_loop:
|
||||||
|
try:
|
||||||
|
buf = connstream.recv(1024)
|
||||||
|
if not buf: break
|
||||||
|
buf = buf.decode("utf-8").upper()
|
||||||
|
except ssl.SSLEOFError:
|
||||||
|
print(getTimestamp(), "SSL-EOF-Error.")
|
||||||
|
con_loop = False
|
||||||
|
except ConnectionResetError:
|
||||||
|
print(getTimestamp(), "Connection reset.")
|
||||||
|
serve()
|
||||||
|
|
||||||
|
print(getTimestamp(), " ", fromaddr[0], ": ", buf, sep="")
|
||||||
|
|
||||||
|
retval = execFromConfig(buf)
|
||||||
|
if(retval == 0):
|
||||||
|
connstream.send(b"OK CMD")
|
||||||
|
elif(retval == 1):
|
||||||
|
connstream.send(b"ERR NO_CMD")
|
||||||
|
elif(retval == 2):
|
||||||
|
connstream.send(b"ERR CMD_ERR")
|
||||||
|
|
||||||
|
|
||||||
|
except ssl.SSLError as e:
|
||||||
|
print(getTimestamp(), e)
|
||||||
|
|
||||||
|
except EOFError:
|
||||||
|
print(getTimestamp(), "EOF")
|
||||||
|
|
||||||
|
def init():
|
||||||
|
|
||||||
|
global host, port, cafile, certfile, keyfile, context, bindsocket
|
||||||
|
|
||||||
|
cfg = configparser.SafeConfigParser()
|
||||||
|
cfg.read(CONFIG)
|
||||||
|
|
||||||
|
try:
|
||||||
|
host=cfg.get("Server", "host").replace("\"","").replace("\'","")
|
||||||
|
port=int(cfg.get("Server", "port").replace("\"","").replace("\'",""))
|
||||||
|
cafile=cfg.get("Security", "cafile").replace("\"","").replace("\'","")
|
||||||
|
certfile=cfg.get("Security", "certfile").replace("\"","").replace("\'","")
|
||||||
|
keyfile=cfg.get("Security", "keyfile").replace("\"","").replace("\'","")
|
||||||
|
except configparser.NoOptionError as e:
|
||||||
|
print("Error in configuration file:", e)
|
||||||
|
quit(1)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=cafile)
|
||||||
|
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
||||||
|
context.verify_mode = ssl.CERT_REQUIRED
|
||||||
|
context.load_verify_locations(cafile=cafile)
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
print(e)
|
||||||
|
print("Please check your paths in the config file. (Have you forgotten to generate the Certificates?)")
|
||||||
|
quit(2)
|
||||||
|
|
||||||
|
try:
|
||||||
|
bindsocket = socket.socket()
|
||||||
|
bindsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
bindsocket.bind((host, port))
|
||||||
|
bindsocket.listen(5)
|
||||||
|
except socket.gaierror:
|
||||||
|
print("Error: Hostname error. Name or service not known.")
|
||||||
|
quit(1)
|
||||||
|
except PermissionError:
|
||||||
|
print("Error: Can't bind for port number ", port, ". Permission denied.", sep="")
|
||||||
|
quit(1)
|
||||||
|
|
||||||
|
print("Running ding server on ", host, ":", port,
|
||||||
|
"\nCAFile: ", cafile,
|
||||||
|
"\nCertfile: ", certfile,
|
||||||
|
"\nKeyfile: ", keyfile,
|
||||||
|
"\n===========",
|
||||||
|
sep="")
|
||||||
|
|
||||||
|
|
||||||
|
if(__name__ == "__main__"):
|
||||||
|
|
||||||
|
try:
|
||||||
|
init()
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\r\rServer stopped.")
|
||||||
|
|
19
ding_server.cfg
Normal file
19
ding_server.cfg
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[Server]
|
||||||
|
host=localhost
|
||||||
|
port=13573
|
||||||
|
|
||||||
|
[Security]
|
||||||
|
# Certificate of the OWN CA
|
||||||
|
cafile=CA.crt
|
||||||
|
|
||||||
|
# Server's certificate [signed by the CA above]
|
||||||
|
certfile=ding_server.crt
|
||||||
|
|
||||||
|
# Server's private key
|
||||||
|
keyfile=ding_server.key
|
||||||
|
|
||||||
|
|
||||||
|
[Commands]
|
||||||
|
# Syntax:
|
||||||
|
# SERVER_COMMAND: Command --which --should_be --executed
|
||||||
|
lock: xscreensaver-command -lock
|
Loading…
Reference in New Issue
Block a user