From 6f0766e115d955143c5b7fa46628a7dace518852 Mon Sep 17 00:00:00 2001 From: maxliu2001 Date: Wed, 7 Jun 2023 16:03:53 +0000 Subject: [PATCH 1/4] expand results --- pscheduler-test-dot1x/dot1x/result-format | 4 + pscheduler-test-dot1x/dot1x/validate.py | 1 + pscheduler-tool-bssidscanner/bssidscanner/run | 183 ++++++++--------- pscheduler-tool-umichwpa/umichwpa/duration | 1 - pscheduler-tool-umichwpa/umichwpa/run | 184 ++++++++---------- 5 files changed, 182 insertions(+), 191 deletions(-) diff --git a/pscheduler-test-dot1x/dot1x/result-format b/pscheduler-test-dot1x/dot1x/result-format index aa24cb627e..0b22c6ae53 100755 --- a/pscheduler-test-dot1x/dot1x/result-format +++ b/pscheduler-test-dot1x/dot1x/result-format @@ -38,8 +38,12 @@ result = input["result"] # print(). if format == 'text/plain': + final = result["final"] # Print results of the test here, in plaintext print('Time: %s\n' % result['time']) + print('') + for each in final: + print(each) elif format == 'text/html': # Print results of the test here, in html diff --git a/pscheduler-test-dot1x/dot1x/validate.py b/pscheduler-test-dot1x/dot1x/validate.py index 2f4fbf7f4a..e25b83024f 100644 --- a/pscheduler-test-dot1x/dot1x/validate.py +++ b/pscheduler-test-dot1x/dot1x/validate.py @@ -126,6 +126,7 @@ def spec_is_valid(json): "succeeded": { "$ref": "#/pScheduler/Boolean" }, "Authenticated": { "$ref": "#/pScheduler/Boolean" }, "time": { "$ref": "#/pScheduler/Duration" }, + "final": { "type": "array", "items": { "$ref": "#/pScheduler/String" } } }, "required": [ "succeeded", diff --git a/pscheduler-tool-bssidscanner/bssidscanner/run b/pscheduler-tool-bssidscanner/bssidscanner/run index f1c8423f30..75a74d682a 100755 --- a/pscheduler-tool-bssidscanner/bssidscanner/run +++ b/pscheduler-tool-bssidscanner/bssidscanner/run @@ -9,98 +9,101 @@ # back to the test. Both system and api are able to be used here. # +import select +from os import getpid, makedirs, unlink, access, R_OK, system, listdir, path +from socket import socket, AF_UNIX, SOCK_DGRAM import datetime -import subprocess -import json -import sys -import time -import argparse -import time -from wifi import Cell #make sure that you have pip installed wifi - import pscheduler - -# from stdin -input = pscheduler.json_load(exit_on_error=True) - -# Take input from test spec -try: - interface = input['test']['spec']['interface'] - ssid = input['test']['spec']['ssid'] -except KeyError: - pscheduler.fail('Missing data in input') - -# convert the comma separated ssids to a list -ssid = list(ssid.split(',')) - -duration = input['test']['spec'].get('duration', 'PT5S') -duration = pscheduler.timedelta_as_seconds( pscheduler.iso8601_as_timedelta(duration) ) -timeout_iso = input['test']['spec'].get('timeout', 'PT10S') -timeout = pscheduler.timedelta_as_seconds( pscheduler.iso8601_as_timedelta(timeout_iso) ) +import os + +#temp file preserved between consecutive runs but not reboots +WPA_CONFIG_PATH = '/tmp/wpa_supplicant/wpa_supplicant.conf' +#initializes only when wpa_supplicant starts +WPA_CTRL_IFACE_BASE = '/var/run/wpa_supplicant' +interface = 'wlan0' +timeout = 3000 +ssid_set = set() + +# parse config +pscheduler_input = pscheduler.json_load(exit_on_error=True) +get_ssid = pscheduler_input['test']['spec'].get('ssid', None) +ssid_set = set(get_ssid.split(',')) if get_ssid else None +duration_iso = pscheduler_input['test']['spec'].get('duration', 'PT5S') +timeout_iso = pscheduler_input['test']['spec'].get('timeout', 'PT10S') +timeout = pscheduler.timedelta_as_seconds(pscheduler.iso8601_as_timedelta(timeout_iso)) +duration = pscheduler.timedelta_as_seconds(pscheduler.iso8601_as_timedelta(duration_iso)) start_time = datetime.datetime.now() succeeded = False error = '' diags = '' - -# Run the actual task here: -def get_all_bssids(interface): - """ - Scan the given interface for all bssids - Return a list of all bssids - """ - start_time = time.time() - cells = Cell.all(interface) # Specify interface to scan on - wifi_list = [] - for cell in cells: - bssid = {} - bssid['ssid'] = cell.ssid - bssid['signal'] = cell.signal - bssid['address'] = cell.address - bssid['frequency'] = pscheduler.si_as_number(cell.frequency[:-2]) - quality_num,quality_denom = cell.quality.split('/') - bssid['quality'] = float(quality_num) / float(quality_denom) - bssid['bitrates'] = sorted(map(lambda v : pscheduler.si_as_number(v[:-3]), cell.bitrates)) - bssid['encrypted'] = cell.encrypted - bssid['channel'] = cell.channel - bssid['mode'] = cell.mode - wifi_list.append(bssid) - - end_time = time.time() - elapsed_time = end_time - start_time - log_msg = "Scan finished in " + str(elapsed_time) - return wifi_list, elapsed_time - -""" -Scan on the given interface -Output a list of all bssids in json format with the given ssid -""" -all_bssids, elapsed_time = get_all_bssids(interface) ssid_list = [] - -# Check complete list for matching ssids -for bssid in all_bssids: - #if no ssids were given then append all the ssids - if not ssid: - ssid_list.append(bssid) - else: - #if ssid/ssids were given then only append those - if bssid['ssid'] in ssid: - ssid_list.append(bssid) - -succeeded = True - -# IMPORTANT NOTE: This code puts the process to sleep until the -# scheduled start time has arrived. It should be placed after all -# preparatory code has been executed and immediately before the tool -# is invoked (for plugins that run other programs) or any activity -# that does a measurement (for those that don't). - -try: - pscheduler.sleep_until(input['schedule']['start']) -except KeyError: - pscheduler.fail("Unable to find start time in input") - - +dir_path = path.dirname(WPA_CONFIG_PATH) + +#check if interface already exists +# interface_path = path.join(WPA_CTRL_IFACE_BASE,interface) +# os.system('killall wpa_supplicant') +# os.remove(interface_path) +if not access(f'{WPA_CTRL_IFACE_BASE}/{interface}', R_OK): + #create config file and start wpa_supplicant + if not path.exists(dir_path): + makedirs(dir_path) + with open(WPA_CONFIG_PATH, 'w') as f: + f.write('ctrl_interface='+WPA_CTRL_IFACE_BASE+'\r\n') + f.write('update_config=1\r\n') + os.system('wpa_supplicant -B -i '+interface+' -c '+WPA_CONFIG_PATH) + +# print('set up config file') +#setting up socket +sock = socket(AF_UNIX, SOCK_DGRAM) +sock.settimeout(3) +start = datetime.datetime.now() +# response will be written to this socket +recv_sock = "/tmp/wpa_ctrl_{}".format(os.getpid()) +sock.bind(recv_sock) +# print('set up and bind receive socket') + +ctrl_interface = f"{WPA_CTRL_IFACE_BASE}/{interface}" +# os.chmod(ctrl_interface, 0o777) +sock.connect(ctrl_interface) +# print('start attaching at', datetime.datetime.now() - start) +# attach to wpa_supplicant +sock.send(b'ATTACH') + +if sock.recv(3) != b'OK\n': + raise OSError(f"error attaching to {ctrl_interface}") + +# start scan +sock.send(bytes("SCAN", 'utf-8')) +# polling for scan results +poll = select.poll() +poll.register(sock, select.POLLIN) + +data = [] +# wait for scan to complete +while poll.poll(timeout): + result = sock.recv(4096) + if result.endswith(b'<3>CTRL-EVENT-SCAN-RESULTS '): + sock.send(bytes("SCAN_RESULTS", 'utf-8')) + break + +# gather scan results +while poll.poll(200): + result = sock.recv(8192) + if result: + data.append(result) + +blob = data[1].decode('utf-8') +result = [s.split('\t') for s in blob.split('\n')][1:-1] + +for bssid, freq, signal, flags, ssid in result: + if not ssid_set or ssid in ssid_set: + ssid_list.append({ + 'ssid': ssid, + 'bssid': bssid, + 'freq': int(freq), + 'signal': int(signal), + 'flags': flags + }) end_time = datetime.datetime.now() # Organize results into json data @@ -108,12 +111,14 @@ results = { 'succeeded': succeeded, 'result': { 'schema': 1, - 'time': pscheduler.timedelta_as_iso8601( end_time - start_time), + 'time': pscheduler.timedelta_as_iso8601(end_time - start_time), 'succeeded': succeeded, 'ssid_list': ssid_list }, 'error': error, - 'diags': diags } - -pscheduler.succeed_json(results) + 'diags': diags +} +# pscheduler.succeed_json(results) +# print(results) +# print('finished at', datetime.datetime.now() - start) diff --git a/pscheduler-tool-umichwpa/umichwpa/duration b/pscheduler-tool-umichwpa/umichwpa/duration index 0e4586b62c..8ecd05d9df 100644 --- a/pscheduler-tool-umichwpa/umichwpa/duration +++ b/pscheduler-tool-umichwpa/umichwpa/duration @@ -20,7 +20,6 @@ json = pscheduler.json_load(exit_on_error=True); timeout_iso = json.get("timeout", "PT10S") timeout = pscheduler.iso8601_as_timedelta(timeout_iso) + datetime.timedelta(seconds=5) - pscheduler.succeed_json({ "duration": pscheduler.timedelta_as_iso8601( timeout ) }) diff --git a/pscheduler-tool-umichwpa/umichwpa/run b/pscheduler-tool-umichwpa/umichwpa/run index 5e4addee4f..1498bb840a 100755 --- a/pscheduler-tool-umichwpa/umichwpa/run +++ b/pscheduler-tool-umichwpa/umichwpa/run @@ -19,8 +19,8 @@ import pscheduler import tempfile #error and diagnostic tracking -error = [] -diags = [] +error = '' +diags = '' authenticated = False need_root = False @@ -33,7 +33,7 @@ driver = '' ssid = '' bssid = '' key_managment = '' - +timeout = 4000 # from stdin input = pscheduler.json_load(exit_on_error=True) @@ -46,158 +46,140 @@ except KeyError: pscheduler.fail('Missing the interface in input') try: - username = input['test']['spec']['username'] + username = input['test']['spec']['_username'] except KeyError: - diags.append("Proceeding without a username") + diags += "Proceeding without a username" try: - password = input['test']['spec']['password'] + password = input['test']['spec']['_password'] except KeyError: - diags.append("Proceeding without a password") + diags += "Proceeding without a password" try: driver = input['test']['spec']['driver'] except KeyError: - diags.append("Proceeding without a driver") + diags += "Proceeding without a driver" try: ssid = input['test']['spec']['ssid'] except KeyError: - diags.append("Proceeding without a ssid") + diags += "Proceeding without a ssid" try: bssid = input['test']['spec']['bssid'] except KeyError: - diags.append("Proceeding without a bssid") + diags += "Proceeding without a bssid" try: - key_management = input['test']['spec']['key_management'] + key_management = input['test']['spec']['key-management'] except KeyError: - diags.append("Proceeding without key_management") - + diags += "Proceeding without key_management" try: driver = input['test']['spec']['driver'] except KeyError: - diags.append("proceeding with default driver") + diags += "proceeding with default driver" timeout_iso = input['test']['spec'].get('timeout', 'PT10S') timeout = pscheduler.timedelta_as_seconds( pscheduler.iso8601_as_timedelta(timeout_iso) ) succeeded = False -# create a temporary configuration file -temp = tempfile.TemporaryFile(mode = 'w+t') -path = temp.name -try: - temp.writelines(['ctrl_interface=DIR=/var/run/wpa_supplicant\n', 'update_config=1\n', 'network={\n']) - if ssid != '': - temp.write(' ssid="' + ssid + '"' + '\n') - if bssid != '': - temp.write(' bssid="' + bssid + '"' + '\n') - if password != '': - temp.write(' psk="' + password + '"' + '\n') - if key_management != '': - temp.write(' key_mgmt=' + key_management + '\n') - temp.write('}') - #temp.seek(0) - -#sleep until designated start time -try: - pscheduler.sleep_until(input['schedule']['start']) -except KeyError: - pscheduler.fail('Unable to find start time in input') - -# check if the EUID is not the root -if os.geteuid() != 0: - need_root = True - -#remove the interface file if it exists -interface_path = '/var/run/wpa_supplicant' + interface -if os.path.exists(interface_path): - need_root = True - diags.append('Need root privilage to delete prior interface file') - clear_interface = ['rm', interface_path] - if need_root: - clear_interface.insert(0, 'sudo') - # run the commands - status, stdout, stderr = pscheduler.run_program(clear_interface, timeout=timeout) - if status != 0: - succeeded = False - fail_json = { 'succeeded': succeeded, - 'error': 'failed to delete old interface file', - 'diags':'\n'.join(diags)} } - pscheduler.succeed_json(fail_json) - error.append("(failed to delete old interface file) Error returned: \n%s" % stderr.strip('\n')) - else: - succeeded = True - diags.append("Successfully deleted old interface file") - -# reset the need root flag as root might not be needed next time -need_root = False +WPA_CONFIG_PATH = '/tmp/wpa_supplicant/wpa_supplicant.conf' +dir_path = os.path.dirname(WPA_CONFIG_PATH) +WPA_CTRL_IFACE_BASE = '/var/run/wpa_supplicant' -#kill all previous wpa_supplicants -kill_wpa = ['killall', 'wpa_supplicant'] -if need_root: - diags.insert('Need root privelage to kill all wpa supplicant processes before starting a new one') - kill_wpa.insert(0, 'sudo') -status, stdout, stderr = pscheduler.run_program(kill_wpa, timeout=timeout) +wpa_status = ["sudo", "wpa_cli", "status"] +status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) +# print(status) + +if status: + # create config file and start wpa_supplicant + # print('create new interface') + if not os.path.exists(dir_path): + status, out, err = pscheduler.run_program(['sudo','mkdir',WPA_CONFIG_PATH]) + if status: + pscheduler.succeed_json( { + 'succeeded': False, + 'diags': '' + out, + 'error': 'failed to create dir for interface: ' + err, + 'result': None + }) + else: + diags += "created new interface dir\n" + + with open(WPA_CONFIG_PATH, 'w') as f: + f.write('ctrl_interface='+WPA_CTRL_IFACE_BASE+'\r\n') + f.write('update_config=1\r\n') + f.write('p2p_disabled=1\r\n') + status, out, err = pscheduler.run_program(['sudo','wpa_supplicant','-Dnl80211','-B','-i',interface,'-c',WPA_CONFIG_PATH]) + if status: + pscheduler.succeed_json( { + 'succeeded': False, + 'diags': '' + out, + 'error': 'failed to initialize interface: ' + err, + 'result': None + }) + else: + diags += out +# print('initalize interface') +temp = open(WPA_CONFIG_PATH,'w') +temp.writelines(['ctrl_interface=DIR=/var/run/wpa_supplicant\n', 'update_config=1\n', 'country=US\n', 'p2p_disabled=1\n', 'network={\n']) +if ssid != '': + temp.write('ssid="{}"\n'.format(ssid)) +temp.write('scan_ssid=1\n') +if bssid != '': + temp.write('bssid={}\n'.format(bssid)) +if key_management != '': + temp.write('key_mgmt={}\n'.format(key_management)) +if username != '': + temp.write('identity="{}"\n'.format(username)) +if password != '': + temp.write('password="{}"\n'.format(password)) +temp.write('eap=PEAP\n') +temp.write('phase1="peaplabel=0"\n') +temp.write('phase2="auth=MSCHAPV2"\n') +temp.write('}\n') +temp.close() -#run wpa to authenticate start_time = datetime.datetime.now() -wpa_auth = ['wpa_supplicant', '-i', interface, '-c', path, '-d', driver, '-B'] -if need_root: - wpa_auth.insert(0, 'sudo') +wpa_auth = ['sudo', 'wpa_cli', '-i', interface, 'reconfigure'] status, stdout, stderr = pscheduler.run_program(wpa_auth, timeout=timeout) - -if status != 0: - error.append('Error returned: \n%s' % stderr.strip('\n')) - succeeded = False - fail_json = { 'succeeded': succeeded, - 'error': 'failed to run wpa_supplicant', - 'diags':'\n'.join(diags)} } - - pscheduler.succeed_json(fail_json - -else: - diags.append(stdout) - -#use wpa_cli to check if it was intiizlized correctly -wpa_status = ["wpa_cli", "status"] -if need_root: - wpa_status.insert(0, 'sudo') - +wpa_status = ["sudo", "wpa_cli", "status"] status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) - if status != 0: - error.append('Error returned: \n%s' % stderr.strip('\n')) + error += 'Error returned: \n%s' % stderr.strip('\n') succeeded = False fail_json = { 'succeeded': succeeded, 'error': 'failed to run wpa_cli to validate the authentication', - 'diags':'\n'.join(diags)} } + 'diags': diags } succeeded = False else: - authenticated = True + diags += stdout succeeded = True +# print('reconfigure completed') + +res = stdout.split('\n') +while "wpa_state=COMPLETED" not in res: + status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) + # print(stdout) + res = stdout.split('\n') + time.sleep(0.3) #get the end time for wpa_supplicant to be initialized end_time = datetime.datetime.now() -# clean up the temporary file -temp.close() - # Organize results into json data results = { 'succeeded': succeeded, 'result': { 'schema': 1, 'time': pscheduler.timedelta_as_iso8601( end_time - start_time), - 'succeeded': succeeded - 'authenticated': authenticated + 'succeeded': succeeded, + 'final': res }, 'error': error, 'diags': diags } pscheduler.succeed_json(results) - From 91116e70d84b6d1a7ce95c2105b3660013c6a5de Mon Sep 17 00:00:00 2001 From: maxliu2001 Date: Fri, 9 Jun 2023 20:10:11 +0000 Subject: [PATCH 2/4] changed temp config file path --- pscheduler-tool-umichwpa/umichwpa/run | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pscheduler-tool-umichwpa/umichwpa/run b/pscheduler-tool-umichwpa/umichwpa/run index 1498bb840a..4f32759321 100755 --- a/pscheduler-tool-umichwpa/umichwpa/run +++ b/pscheduler-tool-umichwpa/umichwpa/run @@ -85,7 +85,7 @@ timeout_iso = input['test']['spec'].get('timeout', 'PT10S') timeout = pscheduler.timedelta_as_seconds( pscheduler.iso8601_as_timedelta(timeout_iso) ) succeeded = False -WPA_CONFIG_PATH = '/tmp/wpa_supplicant/wpa_supplicant.conf' +WPA_CONFIG_PATH = '/tmp/wpa_supplicant.conf' dir_path = os.path.dirname(WPA_CONFIG_PATH) WPA_CTRL_IFACE_BASE = '/var/run/wpa_supplicant' @@ -96,17 +96,17 @@ status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) if status: # create config file and start wpa_supplicant # print('create new interface') - if not os.path.exists(dir_path): - status, out, err = pscheduler.run_program(['sudo','mkdir',WPA_CONFIG_PATH]) - if status: - pscheduler.succeed_json( { - 'succeeded': False, - 'diags': '' + out, - 'error': 'failed to create dir for interface: ' + err, - 'result': None - }) - else: - diags += "created new interface dir\n" + # if not os.path.exists(dir_path): + # status, out, err = pscheduler.run_program(['sudo','mkdir',WPA_CONFIG_PATH]) + # if status: + # pscheduler.succeed_json( { + # 'succeeded': False, + # 'diags': '' + out, + # 'error': 'failed to create dir for interface: ' + err, + # 'result': None + # }) + # else: + # diags += "created new interface dir\n" with open(WPA_CONFIG_PATH, 'w') as f: f.write('ctrl_interface='+WPA_CTRL_IFACE_BASE+'\r\n') From 5d36bb9afcd3aa3d908230ed60a6b0bf7beb9777 Mon Sep 17 00:00:00 2001 From: maxliu2001 Date: Tue, 20 Jun 2023 15:01:44 +0000 Subject: [PATCH 3/4] added token option and cleaned up input processing --- pscheduler-test-dot1x/dot1x/cli-to-spec | 10 +-- pscheduler-test-dot1x/dot1x/validate.py | 4 +- pscheduler-tool-bssidscanner/run | 106 ++++++++++++++++++++++++ pscheduler-tool-umichwpa/umichwpa/run | 100 ++++++++++------------ 4 files changed, 158 insertions(+), 62 deletions(-) create mode 100644 pscheduler-tool-bssidscanner/run diff --git a/pscheduler-test-dot1x/dot1x/cli-to-spec b/pscheduler-test-dot1x/dot1x/cli-to-spec index 72232132fe..303ae4f22f 100755 --- a/pscheduler-test-dot1x/dot1x/cli-to-spec +++ b/pscheduler-test-dot1x/dot1x/cli-to-spec @@ -83,10 +83,10 @@ opt_parser.add_option("--password", action="store", type="string", dest="password") -opt_parser.add_option("--driver", - help="Wireless driver to use (defaults to system)", +opt_parser.add_option("--token", + help="File token(line identifier) that retrieves username/password", action="store", type="string", - dest="driver") + dest="token") opt_parser.add_option("--ssid", help="Service set identifier (SSID) if using wireless", @@ -141,8 +141,8 @@ if options.timeout is not None: if options.interface is not None: result['interface'] = options.interface -if options.driver is not None: - result['driver'] = options.driver +if options.token is not None: + result['token'] = options.token if options.username is not None: result['_username'] = options.username diff --git a/pscheduler-test-dot1x/dot1x/validate.py b/pscheduler-test-dot1x/dot1x/validate.py index e25b83024f..38416ff064 100644 --- a/pscheduler-test-dot1x/dot1x/validate.py +++ b/pscheduler-test-dot1x/dot1x/validate.py @@ -50,7 +50,7 @@ "host-node": { "$ref": "#/pScheduler/Host" }, "timeout": { "$ref": "#/pScheduler/Duration" }, "interface": { "$ref": "#/pScheduler/String" }, - "driver": { "$ref": "#/pScheduler/String" }, + "token": { "$ref": "#/pScheduler/String" }, "_username": { "$ref": "#/pScheduler/String" }, "_password": { "$ref": "#/pScheduler/String" }, "ssid": { "$ref": "#/pScheduler/String" }, @@ -61,6 +61,8 @@ # If listed here, these parameters MUST be in the test spec. "required": [ "interface", + "ssid", + "key-management" ], # Treat other properties as acceptable. This should # ALWAYS be false. diff --git a/pscheduler-tool-bssidscanner/run b/pscheduler-tool-bssidscanner/run new file mode 100644 index 0000000000..7fa5da4acc --- /dev/null +++ b/pscheduler-tool-bssidscanner/run @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +import select +from os import getpid, unlink, access, R_OK, listdir, path +from socket import socket, AF_UNIX, SOCK_DGRAM +import datetime +import pscheduler +import os + +#temp file preserved between consecutive runs but not reboots +WPA_CONFIG_PATH = '/tmp/wpa_supplicant/wpa_supplicant.conf' +#initializes only when wpa_supplicant starts +WPA_CTRL_IFACE_BASE = '/var/run/wpa_supplicant' +interface = 'wlan0' +timeout = 3000 +ssid_set = set() + +# parse config +pscheduler_input = pscheduler.json_load(exit_on_error=True) +get_ssid = pscheduler_input['test']['spec'].get('ssid', None) +ssid_set = set(get_ssid.split(',')) if get_ssid else set() +duration_iso = pscheduler_input['test']['spec'].get('duration', 'PT5S') +timeout_iso = pscheduler_input['test']['spec'].get('timeout', 'PT10S') +timeout = pscheduler.timedelta_as_seconds(pscheduler.iso8601_as_timedelta(timeout_iso)) +duration = pscheduler.timedelta_as_seconds(pscheduler.iso8601_as_timedelta(duration_iso)) +start_time = datetime.datetime.now() +succeeded = False +error = '' +diags = '' +ssid_list = [] + +#check if interface already exists +if not access(f'{WPA_CTRL_IFACE_BASE}/{interface}', R_OK): + #create config file and start wpa_supplicant + with open(WPA_CONFIG_PATH, 'w') as f: + f.write('ctrl_interface='+WPA_CTRL_IFACE_BASE+'\r\n') + f.write('update_config=1\r\n') + os.system('wpa_supplicant -B -i '+interface+' -c '+WPA_CONFIG_PATH) + +#setting up socket +sock = socket(AF_UNIX, SOCK_DGRAM) +sock.settimeout(3) +start = datetime.datetime.now() +# response will be written to this socket +recv_sock = f"/tmp/wpa_ctrl_{getpid()}" +sock.bind(recv_sock) + +ctrl_interface = f"{WPA_CTRL_IFACE_BASE}/{interface}" + +sock.connect(ctrl_interface) +print('start attaching at', datetime.datetime.now() - start) +# attach to wpa_supplicant +sock.send(b'ATTACH') + +if sock.recv(3) != b'OK\n': + raise OSError(f"error attaching to {ctrl_interface}") + +# start scan +sock.send(bytes("SCAN", 'utf-8')) +# polling for scan results +poll = select.poll() +poll.register(sock, select.POLLIN) + +data = [] +# wait for scan to complete +while poll.poll(timeout): + result = sock.recv(4096) + if result.endswith(b'<3>CTRL-EVENT-SCAN-RESULTS '): + sock.send(bytes("SCAN_RESULTS", 'utf-8')) + break + +# gather scan results +while poll.poll(200): + result = sock.recv(8192) + if result: + data.append(result) + +blob = data[1].decode('utf-8') +result = [s.split('\t') for s in blob.split('\n')][1:-1] + +for bssid, freq, signal, flags, ssid in result: + if not ssid_set or ssid in ssid_set: + ssid_list.append({ + 'ssid': ssid, + 'bssid': bssid, + 'freq': int(freq), + 'signal': int(signal), + 'flags': flags + }) +end_time = datetime.datetime.now() + +# Organize results into json data +results = { + 'succeeded': succeeded, + 'result': { + 'schema': 1, + 'time': pscheduler.timedelta_as_iso8601(end_time - start_time), + 'succeeded': succeeded, + 'ssid_list': ssid_list + }, + 'error': error, + 'diags': diags +} + +# pscheduler.succeed_json(results) +print(results) +print('finished at', datetime.datetime.now() - start) diff --git a/pscheduler-tool-umichwpa/umichwpa/run b/pscheduler-tool-umichwpa/umichwpa/run index 4f32759321..163e4f7870 100755 --- a/pscheduler-tool-umichwpa/umichwpa/run +++ b/pscheduler-tool-umichwpa/umichwpa/run @@ -18,13 +18,13 @@ import os import pscheduler import tempfile -#error and diagnostic tracking +# error and diagnostic tracking error = '' diags = '' authenticated = False need_root = False -#declare local variables +# declare local variables interface = '' path = '' username = '' @@ -38,12 +38,8 @@ timeout = 4000 # from stdin input = pscheduler.json_load(exit_on_error=True) -# Take input from test spec -try: - interface = input['test']['spec']['interface'] - -except KeyError: - pscheduler.fail('Missing the interface in input') +# take input from test spec +interface = input['test']['spec']['interface'] try: username = input['test']['spec']['_username'] @@ -55,61 +51,48 @@ try: except KeyError: diags += "Proceeding without a password" -try: - driver = input['test']['spec']['driver'] -except KeyError: - diags += "Proceeding without a driver" - -try: - ssid = input['test']['spec']['ssid'] -except KeyError: - diags += "Proceeding without a ssid" +ssid = input['test']['spec']['ssid'] try: bssid = input['test']['spec']['bssid'] except KeyError: diags += "Proceeding without a bssid" -try: - key_management = input['test']['spec']['key-management'] -except KeyError: - diags += "Proceeding without key_management" +key_management = input['test']['spec']['key-management'] +diags += "Proceeding without key_management" try: - driver = input['test']['spec']['driver'] + token = input['test']['spec']['token'] + with open('/etc/tokens', 'r') as f: + for line in f: + identifier, usrname, pwd = line.split(' ') + if identifier == token: + username = usrname + password = pwd except KeyError: - diags += "proceeding with default driver" + diags += "proceeding without token" +# validate the existance of username and password +if not username and not password: + pscheduler.succeed_json( { + 'succeeded': False, + 'diags': '', + 'error': ' username or/and password not supplied ', + 'result': None + }) timeout_iso = input['test']['spec'].get('timeout', 'PT10S') timeout = pscheduler.timedelta_as_seconds( pscheduler.iso8601_as_timedelta(timeout_iso) ) succeeded = False WPA_CONFIG_PATH = '/tmp/wpa_supplicant.conf' -dir_path = os.path.dirname(WPA_CONFIG_PATH) WPA_CTRL_IFACE_BASE = '/var/run/wpa_supplicant' +# use wpa_cli to check if the interface exists wpa_status = ["sudo", "wpa_cli", "status"] status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) -# print(status) - if status: - # create config file and start wpa_supplicant - # print('create new interface') - # if not os.path.exists(dir_path): - # status, out, err = pscheduler.run_program(['sudo','mkdir',WPA_CONFIG_PATH]) - # if status: - # pscheduler.succeed_json( { - # 'succeeded': False, - # 'diags': '' + out, - # 'error': 'failed to create dir for interface: ' + err, - # 'result': None - # }) - # else: - # diags += "created new interface dir\n" - with open(WPA_CONFIG_PATH, 'w') as f: - f.write('ctrl_interface='+WPA_CTRL_IFACE_BASE+'\r\n') f.write('update_config=1\r\n') f.write('p2p_disabled=1\r\n') status, out, err = pscheduler.run_program(['sudo','wpa_supplicant','-Dnl80211','-B','-i',interface,'-c',WPA_CONFIG_PATH]) @@ -122,29 +105,37 @@ if status: }) else: diags += out -# print('initalize interface') + +# write the config file for reconfiguring the interface temp = open(WPA_CONFIG_PATH,'w') temp.writelines(['ctrl_interface=DIR=/var/run/wpa_supplicant\n', 'update_config=1\n', 'country=US\n', 'p2p_disabled=1\n', 'network={\n']) -if ssid != '': - temp.write('ssid="{}"\n'.format(ssid)) +temp.write('ssid="{}"\n'.format(ssid)) temp.write('scan_ssid=1\n') if bssid != '': temp.write('bssid={}\n'.format(bssid)) -if key_management != '': - temp.write('key_mgmt={}\n'.format(key_management)) -if username != '': - temp.write('identity="{}"\n'.format(username)) -if password != '': - temp.write('password="{}"\n'.format(password)) +temp.write('key_mgmt={}\n'.format(key_management)) +temp.write('identity="{}"\n'.format(username)) +temp.write('password="{}"\n'.format(password)) temp.write('eap=PEAP\n') temp.write('phase1="peaplabel=0"\n') temp.write('phase2="auth=MSCHAPV2"\n') temp.write('}\n') temp.close() +# reconfigure the interface and establish connection start_time = datetime.datetime.now() wpa_auth = ['sudo', 'wpa_cli', '-i', interface, 'reconfigure'] status, stdout, stderr = pscheduler.run_program(wpa_auth, timeout=timeout) +if status != 0: + error += 'Error returned: \n%s' % stderr.strip('\n') + succeeded = False + fail_json = { 'succeeded': succeeded, + 'error': 'failed to reconfigure interface', + 'diags': diags } +else: + diags += stdout + succeeded = True + wpa_status = ["sudo", "wpa_cli", "status"] status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) if status != 0: @@ -153,24 +144,21 @@ if status != 0: fail_json = { 'succeeded': succeeded, 'error': 'failed to run wpa_cli to validate the authentication', 'diags': diags } - - succeeded = False else: diags += stdout succeeded = True -# print('reconfigure completed') +# iteratively checks the wpa state until completion res = stdout.split('\n') while "wpa_state=COMPLETED" not in res: status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout) - # print(stdout) res = stdout.split('\n') time.sleep(0.3) -#get the end time for wpa_supplicant to be initialized +# get the end time for wpa_supplicant to be initialized end_time = datetime.datetime.now() -# Organize results into json data +# organize results into json data results = { 'succeeded': succeeded, 'result': { From ddc127c7e51cddef29d6d84c2f0c37aa77ad0d5b Mon Sep 17 00:00:00 2001 From: maxliu2001 Date: Tue, 20 Jun 2023 18:29:02 +0000 Subject: [PATCH 4/4] added packaging rules --- .../rpm/pscheduler-tool-umichwpa.spec | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pscheduler-tool-umichwpa/umichwpa/unibuild-packaging/rpm/pscheduler-tool-umichwpa.spec b/pscheduler-tool-umichwpa/umichwpa/unibuild-packaging/rpm/pscheduler-tool-umichwpa.spec index 20c18c61e8..5c92e0c339 100644 --- a/pscheduler-tool-umichwpa/umichwpa/unibuild-packaging/rpm/pscheduler-tool-umichwpa.spec +++ b/pscheduler-tool-umichwpa/umichwpa/unibuild-packaging/rpm/pscheduler-tool-umichwpa.spec @@ -44,6 +44,25 @@ make \ DESTDIR=$RPM_BUILD_ROOT/%{dest} \ install +# Enable sudo for layer2 auth + +SUPP=$(command -v wpa_supplicant) +CLI=$(command -v wpa_cli) + +mkdir -p $RPM_BUILD_ROOT/%{_pscheduler_sudoersdir} +cat > $RPM_BUILD_ROOT/%{_pscheduler_sudoersdir}/%{name} <