summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xclient/client.py64
-rwxr-xr-xpam/pam.py40
-rwxr-xr-xserver/mfad.py73
3 files changed, 143 insertions, 34 deletions
diff --git a/client/client.py b/client/client.py
index b2429b6..1c7e155 100755
--- a/client/client.py
+++ b/client/client.py
@@ -4,6 +4,7 @@ import socket
4import time 4import time
5import argparse 5import argparse
6import sys 6import sys
7import os
7 8
8HEADER_LENGTH = 64 9HEADER_LENGTH = 64
9KEY_LENGTH = 64 10KEY_LENGTH = 64
@@ -11,6 +12,7 @@ DISCONNECT_LENGTH = ACK_LENGTH = 3
11ACK_MESSAGE = "ACK" 12ACK_MESSAGE = "ACK"
12DISCONNECT_MESSAGE = "BYE" 13DISCONNECT_MESSAGE = "BYE"
13FORMAT = "utf-8" 14FORMAT = "utf-8"
15import configparser
14 16
15def parse_arguments(): 17def parse_arguments():
16 parser = argparse.ArgumentParser() 18 parser = argparse.ArgumentParser()
@@ -18,7 +20,7 @@ def parse_arguments():
18 parser.add_argument("--port",type=int,help="Port to connect to") 20 parser.add_argument("--port",type=int,help="Port to connect to")
19 parser.add_argument("--config",type=str,help="Path to config file",\ 21 parser.add_argument("--config",type=str,help="Path to config file",\
20 default="/etc/mfa/mfa.conf") 22 default="/etc/mfa/mfa.conf")
21 parser.add_argument("--key",type=str,help="Client connection key",required=True) 23 parser.add_argument("--key",type=str,help="Client connection key")
22 return parser.parse_args() 24 return parser.parse_args()
23 25
24def prompt_user(prompt): 26def prompt_user(prompt):
@@ -53,32 +55,48 @@ def init_connection(mfa_server, client_port, client_key):
53 55
54 56
55def read_config(config_file): 57def read_config(config_file):
56 # Read config file for server and port info 58 parser = configparser.ConfigParser(inline_comment_prefixes="#")
57 # Return tuple (server,port) 59 parser.read(config_file)
58 server = "" 60 return parser
59 port = 0 61
60 with open(config_file) as conf: 62
61 line = None 63def get_vars(args,confparser):
62 while line != "": 64 if not os.path.exists(args.config):
63 line = conf.readline() 65 print("Unable to open config file")
64 if line.startswith("server ="): 66 sys.exit(1)
65 server = line.split("=")[1].strip() 67
66 if line.startswith("port ="): 68 server = None
67 port = int(line.split("=")[1].strip()) 69 port = None
68 return (server,port) 70 key = None
71
72 # Set values from config file first
73 if confparser.has_section("client"):
74 server = confparser.get("client","server",fallback=None)
75 port = confparser.get("client","port",fallback=None)
76 key = confparser.get("client","key",fallback=None)
77
78 # Let command line args overwrite any values
79 if args.server:
80 server = args.server
81 if args.port:
82 port = args.port
83 if args.key:
84 key = args.key
85
86 # Exit if any value is null
87 if None in [server,port,key]:
88 print("error: one or more items unspecified")
89 sys.exit(1)
90
91 return server,port,key
92
69 93
70def main(): 94def main():
71 # Get arguments, exit if unable to connect 95 # Get arguments, exit if unable to connect
72 args = parse_arguments() 96 args = parse_arguments()
73 client_key = args.key 97 confparser = read_config(args.config)
74 98
75 # Read server and port from config file but allow command line options 99 mfa_server,client_port,client_key = get_vars(args,confparser)
76 # to override those settings
77 mfa_server, client_port = read_config(args.config)
78 if args.server != None:
79 mfa_server = args.server
80 if args.port != None:
81 client_port = args.port
82 100
83 # Exit if invalid key is provided 101 # Exit if invalid key is provided
84 if len(client_key) != KEY_LENGTH: 102 if len(client_key) != KEY_LENGTH:
diff --git a/pam/pam.py b/pam/pam.py
index 5a2fee8..5cb9f4d 100755
--- a/pam/pam.py
+++ b/pam/pam.py
@@ -3,6 +3,8 @@ import socket
3import argparse 3import argparse
4import time 4import time
5import sys 5import sys
6import configparser
7import os
6 8
7# Sends authentication request to MFA server 9# Sends authentication request to MFA server
8# Receive either pass or fail response from MFA server 10# Receive either pass or fail response from MFA server
@@ -40,7 +42,6 @@ def init_connection(mfa_server, pam_port):
40 while connection == None and timeout < timeout_length: 42 while connection == None and timeout < timeout_length:
41 try: 43 try:
42 connection = socket.create_connection((mfa_server,pam_port)) 44 connection = socket.create_connection((mfa_server,pam_port))
43 print("connected to mfa server")
44 return connection 45 return connection
45 except (ConnectionError,ConnectionRefusedError): 46 except (ConnectionError,ConnectionRefusedError):
46 time.sleep(sleep_length) 47 time.sleep(sleep_length)
@@ -63,19 +64,54 @@ def read_config(config_file):
63 port = int(line.split("=")[1].strip()) 64 port = int(line.split("=")[1].strip())
64 return (server,port) 65 return (server,port)
65 66
67
68def read_config(config_file):
69 parser = configparser.ConfigParser(inline_comment_prefixes="#")
70 parser.read(config_file)
71 return parser
72
73
74def get_vars(args,confparser):
75 if not os.path.exists(args.config):
76 print("Unable to open config file")
77 sys.exit(1)
78
79 server = None
80 port = None
81
82 # Set values from config file first
83 if confparser.has_section("pam"):
84 server = confparser.get("pam","server",fallback=None)
85 port = confparser.get("pam","port",fallback=None)
86
87 # Let command line args overwrite any values
88 if args.server:
89 server = args.server
90 if args.port:
91 port = args.port
92
93 # Exit if any value is null
94 if None in [server,port]:
95 print("error: one or more items unspecified")
96 sys.exit(1)
97
98 return server,port
99
100
66def main(): 101def main():
67 authed = "0" 102 authed = "0"
68 failed = "1" 103 failed = "1"
69 104
70 # Get arguments 105 # Get arguments
71 args = parse_arguments() 106 args = parse_arguments()
107 confparser = read_config(args.config)
108 mfa_server,pam_port = get_vars(args,confparser)
72 user = args.user 109 user = args.user
73 service = args.service 110 service = args.service
74 111
75 # Compile data to send to server 112 # Compile data to send to server
76 # Read server and port from config file but allow command line options 113 # Read server and port from config file but allow command line options
77 # to override those settings 114 # to override those settings
78 mfa_server, pam_port = read_config(args.config)
79 if args.server != None: 115 if args.server != None:
80 mfa_server = args.server 116 mfa_server = args.server
81 if args.port != None: 117 if args.port != None:
diff --git a/server/mfad.py b/server/mfad.py
index d045e14..46fc0cc 100755
--- a/server/mfad.py
+++ b/server/mfad.py
@@ -7,6 +7,8 @@ import threading
7import pyotp 7import pyotp
8import sqlite3 8import sqlite3
9import re 9import re
10import configparser
11import argparse
10 12
11## Listens for authentication request from PAM module 13## Listens for authentication request from PAM module
12## Recevies connection from client 14## Recevies connection from client
@@ -16,7 +18,7 @@ import re
16## Return pass or fail response to PAM moudle 18## Return pass or fail response to PAM moudle
17 19
18 20
19DB_NAME = "mfa.db" 21DB_NAME = ""
20HEADER_LENGTH = 64 22HEADER_LENGTH = 64
21KEY_LENGTH = 64 23KEY_LENGTH = 64
22DISCONNECT_LENGTH = ACK_LENGTH = 3 24DISCONNECT_LENGTH = ACK_LENGTH = 3
@@ -41,6 +43,22 @@ CLIENT_SECRET_INDEX = 2
41# key and a tuple of (socket,(addr,port)) as the value 43# key and a tuple of (socket,(addr,port)) as the value
42client_connections = dict() 44client_connections = dict()
43 45
46def parse_arguments():
47 parser = argparse.ArgumentParser()
48 parser.add_argument("--address",type=str,help="Bind Address")
49 parser.add_argument("--pam-port",type=int,help="Port to listen for PAM requests")
50 parser.add_argument("--client-port",type=int,help="Port for client connections")
51 parser.add_argument("--database",type=str,help="Path to alternate database file")
52 parser.add_argument("--config",type=str,help="Alternate config file location",\
53 default="/etc/mfa/mfa.conf")
54 return parser.parse_args()
55
56
57def read_config(config):
58 parser = configparser.ConfigParser(inline_comment_prefixes="#")
59 parser.read(config)
60 return parser
61
44 62
45def eval_mfa(client_key, mfa_methods, client_response): 63def eval_mfa(client_key, mfa_methods, client_response):
46 print("response: " + client_response) 64 print("response: " + client_response)
@@ -228,14 +246,14 @@ def listen_pam(addr, port):
228 246
229################################################################################ 247################################################################################
230 248
231def create_db(): 249def create_db(db):
232 with sqlite3.connect(DB_NAME) as conn: 250 with sqlite3.connect(db) as conn:
233 c = conn.cursor() 251 c = conn.cursor()
234 c.execute("""CREATE TABLE applications ( 252 c.execute("""CREATE TABLE applications (
235 username text, 253 username text,
236 hostname text, 254 hostname text,
237 service text, 255 service text,
238 client_key text, 256 alias text,
239 mfa_methods text 257 mfa_methods text
240 )""") 258 )""")
241 c.execute("""CREATE TABLE clients ( 259 c.execute("""CREATE TABLE clients (
@@ -243,16 +261,53 @@ def create_db():
243 key text, 261 key text,
244 totp_secret text 262 totp_secret text
245 )""") 263 )""")
264 conn.commit()
265
266
267def get_vars(args,confparser):
268 if not os.path.exists(args.config):
269 print("Unable to open config file")
270 sys.exit(1)
271
272 bind_addr = None
273 client_port = None
274 pam_port = None
275 database = None
276
277 # Set values from config file first
278 if confparser.has_section("mfad"):
279 bind_addr = confparser.get("mfad","address",fallback=None)
280 client_port = confparser.get("mfad","client-port",fallback=None)
281 pam_port = confparser.get("mfad","pam-port",fallback=None)
282 database = confparser.get("mfad","database",fallback=None)
283
284 # Let command line args overwrite any values
285 if args.address:
286 bind_addr = args.address
287 if args.client_port:
288 client_port = args.client_port
289 if args.pam_port:
290 pam_port = args.pam_port
291 if args.database:
292 database = args.database
293
294 # Exit if any value is null
295 if None in [bind_addr,client_port,pam_port,database]:
296 print("error: one or more items unspecified")
297 sys.exit(1)
298
299 return bind_addr, int(client_port), int(pam_port), database
246 300
247 301
248def main(): 302def main():
249 global connection_list 303 args = parse_arguments()
250 bind_addr = "127.0.0.1" 304 confparser = read_config(args.config)
251 pam_port = 8000 305
252 client_port = 8001 306 bind_addr, client_port, pam_port, DB_NAME = get_vars(args,confparser)
253 307
254 if not os.path.exists(DB_NAME): 308 if not os.path.exists(DB_NAME):
255 create_db() 309 print("Creating DB")
310 create_db(DB_NAME)
256 311
257 clients = threading.Thread(target=listen_client,args=(bind_addr,client_port)) 312 clients = threading.Thread(target=listen_client,args=(bind_addr,client_port))
258 pam = threading.Thread(target=listen_pam,args=(bind_addr,pam_port)) 313 pam = threading.Thread(target=listen_pam,args=(bind_addr,pam_port))