├── .gitignore ├── AUTHORS ├── CHANGES ├── LICENSE ├── README.md ├── scripts └── yah3c ├── setup.py └── yah3c ├── __init__.py ├── __main__.py ├── eapauth.py ├── eappacket.py ├── usermgr.py └── yah3c.py /.gitignore: -------------------------------------------------------------------------------- 1 | ### /Users/maple/.gitignore-boilerplates/Python.gitignore 2 | 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Packages 9 | *.egg 10 | *.egg-info 11 | dist 12 | build 13 | eggs 14 | parts 15 | bin 16 | var 17 | sdist 18 | develop-eggs 19 | .installed.cfg 20 | lib 21 | lib64 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | 31 | #Translations 32 | *.mo 33 | 34 | #Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | 39 | 40 | ### /Users/maple/.gitignore-boilerplates/Global/OSX.gitignore 41 | 42 | .DS_Store 43 | Icon 44 | 45 | # Thumbnails 46 | ._* 47 | 48 | # Files that might appear on external disk 49 | .Spotlight-V100 50 | .Trashes 51 | 52 | 53 | ### /Users/maple/.gitignore-boilerplates/Global/Linux.gitignore 54 | 55 | .* 56 | !.gitignore 57 | *~ 58 | 59 | 60 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Author 2 | ------ 3 | 4 | Maple 5 | 6 | Contributors 7 | ------------ 8 | 9 | - qiao 10 | - houqp 11 | - tigersoldier 12 | - zlsun 13 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | YaH3C Changelog 2 | ============== 3 | 4 | Here is the full list of changes between each YaH3C release. 5 | 6 | Version 0.6 7 | ----------- 8 | 9 | Released on November 1st 2015 10 | 11 | * port to Python 3 12 | * remove colorama module 13 | 14 | Version 0.5 15 | ----------- 16 | 17 | Released on September 24th 2012 18 | 19 | * add command line argument support 20 | * add dhcp support 21 | * refactory usermgr module 22 | 23 | Version 0.4 24 | ----------- 25 | 26 | Released on September 20th 2012 27 | 28 | * remove plugin module 29 | 30 | Version 0.3 31 | ----------- 32 | 33 | Released on April 1th 2012 34 | 35 | * add eap-md5 support 36 | 37 | Version 0.2 38 | ----------- 39 | 40 | Released on December 29th 2011 41 | 42 | * complete refactory 43 | * plugins support 44 | 45 | Version 0.1 46 | ----------- 47 | 48 | Released on November 14th 2011 49 | 50 | * Initial commit 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2017 YaH3C Authors. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yah3c 2 | 3 | 本项目修改自 [YaH3C](http://github.com/humiaozuzu/YaH3C),需要使用 `Python 3` 运行. 4 | 5 | 修改是为了便于打包成 [Arch Linux](https://www.archlinux.org/) 的 [AUR](https://aur.archlinux.org/packages/yah3c/). 6 | 7 | ## 安装 8 | 9 | ### `ArchLinux` 用户: 10 | 11 | 推荐使用 `yaourt` 安装: 12 | 13 | ``` bash 14 | yaourt -S yah3c 15 | ``` 16 | 17 | 其他安装工具见 [AUR helpers - ArchWiki](https://wiki.archlinux.org/index.php/AUR_helpers). 18 | 你也可以 [手动安装](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages). 19 | 20 | ### 其他 Linux 用户 21 | 22 | ``` 23 | git clone https://github.com/zlsun/yah3c 24 | cd yah3c 25 | python3 setup.py install # 可能需要加上 sudo 26 | ``` 27 | 28 | ## 配置 29 | 30 | 用户的登陆信息按照如下的格式保存在文件`/etc/yah3c.conf`中: 31 | 32 | ``` ini 33 | [account] # 你的帐户 34 | password = 123456 # 密码 35 | ethernet_interface = eth0 # 使用的网卡,默认为eth0 36 | dhcp_command = dhcpcd # 验证成功后使用的dhcp命令(dhcpcd/dhclient),默认为空 37 | daemon = True # 验证成功后是否变成daemon进程,默认为是 38 | md5_challenge = xor # MD5-Challenge算法,xor或者md5,默认为xor 39 | ``` 40 | 41 | ## 使用 42 | 43 | ``` bash 44 | sudo yah3c -u account 45 | ``` 46 | 47 | ## Thanks 48 | 49 | * [humiaozuzu](https://github.com/humiaozuzu) - Original repo [YaH3C](https://github.com/humiaozuzu/YaH3C) 50 | * [qiao](https://github.com/qiao) - Write python installation script for YaH3C 51 | * [houqp](https://github.com/houqp) - Refered to houqp's [pyh3c](https://github.com/houqp/pyh3c) 52 | * [tigersoldier](https://github.com/tigersoldier) - Write EAP-Md5 for YaH3C 53 | 54 | ## License 55 | 56 | YaH3C的代码使用MIT License发布,此外,禁止使用YaH3C以及YaH3C的修改程序用于商业目的(比如交叉编译到路由进行销售等行为) 57 | -------------------------------------------------------------------------------- /scripts/yah3c: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from yah3c.yah3c import main 4 | main() 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from distutils.core import setup 5 | from setuptools import find_packages 6 | import yah3c.yah3c 7 | 8 | setup(name='yah3c', 9 | version=yah3c.yah3c.__version__, 10 | description='A program for h3c authentication in SYSU east campus.', 11 | author='maple', 12 | author_email='maplevalley8@gmail.com', 13 | url='https://github.com/humiaozuzu/YaH3C', 14 | download_url='https://github.com/humiaozuzu/YaH3C', 15 | license='MIT', 16 | packages=find_packages(), 17 | scripts=['scripts/yah3c'], 18 | ) 19 | -------------------------------------------------------------------------------- /yah3c/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zlsun/yah3c/c2ae839f27fea803de6d13e32e43f862ee2a85c7/yah3c/__init__.py -------------------------------------------------------------------------------- /yah3c/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | if __name__ == "__main__": 3 | from .yah3c import main 4 | main() 5 | 6 | -------------------------------------------------------------------------------- /yah3c/eapauth.py: -------------------------------------------------------------------------------- 1 | """ EAP authentication handler 2 | 3 | This module sents EAPOL begin/logoff packet 4 | and parses received EAP packet 5 | 6 | """ 7 | 8 | __all__ = ["EAPAuth"] 9 | 10 | import socket 11 | import os 12 | import sys 13 | import pwd 14 | import hashlib 15 | import subprocess 16 | 17 | # init() # required in Windows 18 | from .eappacket import * 19 | 20 | 21 | def display_prompt(msg_type, msg): 22 | if msg_type is 'in': 23 | prompt = '\x1b[92m' + '==> ' + '\x1b(B\x1b[m' 24 | elif msg_type is 'out': 25 | prompt = '\x1b[93m' + '==> ' + '\x1b(B\x1b[m' 26 | elif msg_type is 'error': 27 | prompt = '\x1b[31m' + '==> ' + '\x1b(B\x1b[m' 28 | 29 | prompt += '\x1b[1m' + msg + '\x1b(B\x1b[m' 30 | print(prompt) 31 | 32 | 33 | def display_packet(packet): 34 | # print ethernet_header infomation 35 | print('Ethernet Header Info: ') 36 | print('\tFrom: ' + repr(packet[0:6])) 37 | print('\tTo: ' + repr(packet[6:12])) 38 | print('\tType: ' + repr(packet[12:14])) 39 | print('\tData: ' + repr(packet[14:])) 40 | 41 | 42 | class EAPAuth: 43 | 44 | def __init__(self, login_info): 45 | # bind the h3c client to the EAP protocal 46 | self.client = socket.socket( 47 | socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETHERTYPE_PAE)) 48 | self.client.bind((login_info['ethernet_interface'], ETHERTYPE_PAE)) 49 | # get local ethernet card address 50 | self.mac_addr = self.client.getsockname()[4] 51 | self.ethernet_header = get_ethernet_header( 52 | self.mac_addr, PAE_GROUP_ADDR, ETHERTYPE_PAE) 53 | self.has_sent_logoff = False 54 | self.login_info = login_info 55 | self.version_info = b'\x06\x07PmJeSU5UNyV8Tk42cwZ7LLjgIxI=\x20\x20' 56 | 57 | def send_start(self): 58 | # sent eapol start packet 59 | eap_start_packet = self.ethernet_header + get_EAPOL(EAPOL_START) 60 | self.client.send(eap_start_packet) 61 | 62 | display_prompt('out', 'Sending EAPOL start') 63 | 64 | def send_logoff(self): 65 | # sent eapol logoff packet 66 | eap_logoff_packet = self.ethernet_header + get_EAPOL(EAPOL_LOGOFF) 67 | self.client.send(eap_logoff_packet) 68 | self.has_sent_logoff = True 69 | 70 | display_prompt('out', 'Sending EAPOL logoff') 71 | 72 | def send_response(self, packet_id, type, resp): 73 | eap_packet = self.ethernet_header + get_EAPOL(EAPOL_EAPPACKET, 74 | get_EAP(EAP_RESPONSE, packet_id, type, resp)) 75 | try: 76 | self.client.send(eap_packet) 77 | except socket.error as msg: 78 | print("Connection error!") 79 | exit(-1) 80 | 81 | def send_response_id(self, packet_id): 82 | username = self.login_info['username'].encode('latin') 83 | self.send_response(packet_id, EAP_TYPE_ID, 84 | self.version_info + username) 85 | 86 | def send_response_md5(self, packet_id, md5data): 87 | password = self.login_info['password'][0:16].encode('latin') 88 | username = self.login_info['username'].encode('latin') 89 | if self.login_info['md5_challenge'] == 'md5': 90 | data = bytes([packet_id]) + password + md5data 91 | digest = hashlib.md5(data).digest() 92 | else: 93 | data = password 94 | if len(data) < 16: 95 | data = data + b'\x00' * (16 - len(data)) 96 | digest = [] 97 | for i in range(0, 16): 98 | digest.append(data[i] ^ md5data[i]) 99 | digest = bytes(digest) 100 | resp = bytes([len(digest)]) + digest + username 101 | self.send_response(packet_id, EAP_TYPE_MD5, resp) 102 | 103 | def send_response_h3c(self, packet_id): 104 | password = self.login_info['password'][0:16].encode('latin') 105 | username = self.login_info['username'].encode('latin') 106 | resp = bytes([len(password)]) + password + username 107 | self.send_response(packet_id, EAP_TYPE_H3C, resp) 108 | 109 | def display_login_message(self, msg): 110 | """ 111 | display the messages received form the radius server, 112 | including the error meaasge after logging failed or 113 | other meaasge from networking centre 114 | """ 115 | try: 116 | print(msg.decode('gbk')) 117 | except UnicodeDecodeError: 118 | print(msg) 119 | 120 | def EAP_handler(self, eap_packet): 121 | vers, type, eapol_len = unpack("!BBH", eap_packet[:4]) 122 | if type != EAPOL_EAPPACKET: 123 | display_prompt('in', 'Got unknown EAPOL type %i' % type) 124 | 125 | # EAPOL_EAPPACKET type 126 | code, id, eap_len = unpack("!BBH", eap_packet[4:8]) 127 | if code == EAP_SUCCESS: 128 | display_prompt('in', 'Got EAP Success') 129 | 130 | if self.login_info['dhcp_command']: 131 | display_prompt('in', 'Obtaining IP Address:') 132 | subprocess.call([self.login_info['dhcp_command'], 133 | self.login_info['ethernet_interface']]) 134 | 135 | if self.login_info['daemon'] == 'True': 136 | daemonize('/dev/null', '/tmp/daemon.log', '/tmp/daemon.log') 137 | 138 | elif code == EAP_FAILURE: 139 | if (self.has_sent_logoff): 140 | display_prompt('in', 'Logoff Successfully!') 141 | 142 | # self.display_login_message(eap_packet[10:]) 143 | else: 144 | display_prompt('in', 'Got EAP Failure') 145 | 146 | # self.display_login_message(eap_packet[10:]) 147 | exit(-1) 148 | elif code == EAP_RESPONSE: 149 | display_prompt('in', 'Got Unknown EAP Response') 150 | elif code == EAP_REQUEST: 151 | reqtype = unpack("!B", eap_packet[8:9])[0] 152 | reqdata = eap_packet[9:4 + eap_len] 153 | if reqtype == EAP_TYPE_ID: 154 | display_prompt('in', 'Got EAP Request for identity') 155 | self.send_response_id(id) 156 | display_prompt( 157 | 'out', 'Sending EAP response with identity = [%s]' % self.login_info['username']) 158 | elif reqtype == EAP_TYPE_H3C: 159 | display_prompt('in', 'Got EAP Request for Allocation') 160 | self.send_response_h3c(id) 161 | display_prompt('out', 'Sending EAP response with password') 162 | elif reqtype == EAP_TYPE_MD5: 163 | data_len = unpack("!B", reqdata[0:1])[0] 164 | md5data = reqdata[1:1 + data_len] 165 | display_prompt('in', 'Got EAP Request for MD5-Challenge') 166 | self.send_response_md5(id, md5data) 167 | display_prompt('out', 'Sending EAP response with password') 168 | else: 169 | display_prompt('in', 'Got unknown Request type (%i)' % reqtype) 170 | elif code == 10 and id == 5: 171 | self.display_login_message(eap_packet[12:]) 172 | else: 173 | display_prompt('in', 'Got unknown EAP code (%i)' % code) 174 | 175 | def serve_forever(self): 176 | try: 177 | self.send_start() 178 | while True: 179 | eap_packet = self.client.recv(1600) 180 | 181 | # strip the ethernet_header and handle 182 | self.EAP_handler(eap_packet[14:]) 183 | except KeyboardInterrupt: 184 | print('Interrupted by user') 185 | self.send_logoff() 186 | except socket.error as msg: 187 | print("Connection error: %s" % msg) 188 | exit(-1) 189 | 190 | 191 | def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): 192 | '''This forks the current process into a daemon. The stdin, stdout, and 193 | stderr arguments are file names that will be opened and be used to replace 194 | the standard file descriptors in sys.stdin, sys.stdout, and sys.stderr. 195 | These arguments are optional and default to /dev/null. Note that stderr is 196 | opened unbuffered, so if it shares a file with stdout then interleaved 197 | output may not appear in the order that you expect. ''' 198 | 199 | # Do first fork. 200 | try: 201 | pid = os.fork() 202 | if pid > 0: 203 | sys.exit(0) # Exit first parent. 204 | except OSError as e: 205 | sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror)) 206 | sys.exit(1) 207 | 208 | # Decouple from parent environment. 209 | os.chdir("/") 210 | os.umask(0) 211 | os.setsid() 212 | 213 | # Do second fork. 214 | try: 215 | pid = os.fork() 216 | if pid > 0: 217 | sys.exit(0) # Exit second parent. 218 | except OSError as e: 219 | sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror)) 220 | sys.exit(1) 221 | 222 | # Now I am a daemon! 223 | 224 | # Redirect standard file descriptors. 225 | si = open(stdin, 'r') 226 | so = open(stdout, 'a+') 227 | se = open(stderr, 'ab+', 0) 228 | os.dup2(si.fileno(), sys.stdin.fileno()) 229 | os.dup2(so.fileno(), sys.stdout.fileno()) 230 | os.dup2(se.fileno(), sys.stderr.fileno()) 231 | -------------------------------------------------------------------------------- /yah3c/eappacket.py: -------------------------------------------------------------------------------- 1 | from struct import * 2 | 3 | # Constants 4 | # Reference: http://tools.ietf.org/html/rfc3748 5 | ETHERTYPE_PAE = 0x888e 6 | PAE_GROUP_ADDR = b"\x01\x80\xc2\x00\x00\x03" 7 | BROADCAST_ADDR = b"\xff\xff\xff\xff\xff\xff" 8 | 9 | EAPOL_VERSION = 1 10 | EAPOL_EAPPACKET = 0 11 | 12 | # packet info for EAPOL_EAPPACKET 13 | EAPOL_START = 1 14 | EAPOL_LOGOFF = 2 15 | EAPOL_KEY = 3 16 | EAPOL_ASF = 4 17 | 18 | EAP_REQUEST = 1 19 | EAP_RESPONSE = 2 20 | EAP_SUCCESS = 3 21 | EAP_FAILURE = 4 22 | 23 | # packet info followed by EAP_RESPONSE 24 | # 1 Identity 25 | # 2 Notification 26 | # 3 Nak (Response only) 27 | # 4 MD5-Challenge 28 | # 5 One Time Password (OTP) 29 | # 6 Generic Token Card (GTC) 30 | # 254 Expanded Types 31 | # 255 Experimental use 32 | EAP_TYPE_ID = 1 # identity 33 | EAP_TYPE_MD5 = 4 # md5 Challenge 34 | EAP_TYPE_H3C = 7 # H3C eap packet(used for SYSU east campus) 35 | 36 | # Packet builders 37 | 38 | 39 | def get_EAPOL(type, payload=b""): 40 | return pack("!BBH", EAPOL_VERSION, type, len(payload)) + payload 41 | 42 | 43 | def get_EAP(code, id, type=0, data=b""): 44 | if code in [EAP_SUCCESS, EAP_FAILURE]: 45 | return pack("!BBH", code, id, 4) 46 | else: 47 | return pack("!BBHB", code, id, 5 + len(data), type) + data 48 | 49 | 50 | def get_ethernet_header(src, dst, type): 51 | return dst + src + pack("!H", type) 52 | -------------------------------------------------------------------------------- /yah3c/usermgr.py: -------------------------------------------------------------------------------- 1 | """ User Management Module 2 | 3 | This module reads the 'users.conf' file and gets all users's info. 4 | """ 5 | 6 | __all__ = ["UserMgr"] 7 | 8 | import configparser 9 | 10 | class UserMgr: 11 | """User Manager 12 | The format of the user_info is: 13 | user_info = { 14 | "username": "maple", 15 | "password": "valley", 16 | "ethernet_interface": "eth0", 17 | "dhcp_command": "dhcpcd", 18 | "daemon": "True", 19 | "md5_challenge": "xor", 20 | # following has not implemented yet 21 | "carry_version_info": "True", 22 | "broadcast_logoff": "False", 23 | "packet_type": "unicast" 24 | } 25 | """ 26 | def __init__(self, path=None): 27 | if path is None: 28 | self.users_cfg_path = '/etc/yah3c.conf' 29 | else: 30 | self.users_cfg_path = path 31 | self.config = configparser.ConfigParser() 32 | self.config.read(self.users_cfg_path) 33 | 34 | def save_and_reload(self): 35 | fp = open(self.users_cfg_path, 'w') 36 | self.config.write(fp) 37 | fp.close() 38 | self.config.read(self.users_cfg_path) 39 | 40 | def get_user_number(self): 41 | return len(self.config.sections()) 42 | 43 | def get_all_users_info(self): 44 | users_info = [] 45 | for username in self.config.sections(): 46 | user_info = dict(self.config.items(username)) 47 | user_info['username'] = username 48 | users_info.append(user_info) 49 | 50 | return users_info 51 | 52 | def get_user_info(self, username): 53 | user_info = dict(self.config.items(username)) 54 | user_info['username'] = username 55 | return user_info 56 | 57 | def add_user(self, user_info): 58 | self.config.add_section(user_info['username']) 59 | self.update_user_info(user_info) 60 | 61 | def remove_user(self, username): 62 | self.config.remove_section(username) 63 | self.save_and_reload() 64 | 65 | def update_user_info(self, user_info): 66 | self.config.set(user_info['username'], 'password', 67 | user_info['password']) 68 | self.config.set(user_info['username'], 'ethernet_interface', 69 | user_info['ethernet_interface']) 70 | self.config.set(user_info['username'], 'dhcp_command', 71 | user_info['dhcp_command']) 72 | self.config.set(user_info['username'], 'daemon', 73 | user_info['daemon']) 74 | self.config.set(user_info['username'], 'md5_challenge', 75 | user_info['md5_challenge']) 76 | self.save_and_reload() 77 | -------------------------------------------------------------------------------- /yah3c/yah3c.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | """ Main program for YaH3C. 4 | 5 | """ 6 | 7 | __version__ = '0.6' 8 | 9 | import os, sys 10 | import configparser 11 | import getpass 12 | import argparse 13 | import logging 14 | 15 | from . import eapauth 16 | from . import usermgr 17 | 18 | 19 | def parse_arguments(): 20 | parser = argparse.ArgumentParser(description='Yet Another H3C Authentication Client', prog='yah3c') 21 | parser.add_argument('-u', '--username', 22 | help='Login in with this username') 23 | # parser.add_argument('-p', '--password', 24 | # help='Password') 25 | # parser.add_argument('-i', '--interface', default='eth0', 26 | # help='Etherent interface used. Set as eth0 by default.') 27 | # parser.add_argument('-d', '--daemon', action='store_true', 28 | # help='Fork to background after authentication.') 29 | # parser.add_argument('-D', '--dhcp', 30 | # help='DHCP cmd used to obtain ip after authentication.') 31 | parser.add_argument('-debug', action='store_true', 32 | help='Enable debugging mode') 33 | args = parser.parse_args() 34 | return args 35 | 36 | def prompt_user_info(): 37 | username = input('Input username: ') 38 | while True: 39 | password = getpass.getpass('Input password: ') 40 | password_again = getpass.getpass('Input again: ') 41 | if password == password_again: 42 | break 43 | else: 44 | print('Password do not match!') 45 | 46 | dev = input('Decice(eth0 by default): ') 47 | if not dev: 48 | dev = 'eth0' 49 | 50 | choice = input('Forked to background after authentication(Yes by default)\n: ') 51 | if choice == 'n' or choice == 'N': 52 | daemon = "False" 53 | else: 54 | daemon = "True" 55 | 56 | dhcp_cmd = input('Dhcp command(Press Enter to pass): ') 57 | if not dhcp_cmd: 58 | dhcp_cmd = '' 59 | 60 | md5_challenge = input("MD5-Challenge('xor' or 'md5', 'xor' by default): ") 61 | if not md5_challenge: 62 | md5_challenge = 'xor' 63 | 64 | return { 65 | 'username': username, 66 | 'password': password, 67 | 'ethernet_interface': dev, 68 | 'daemon': daemon, 69 | 'dhcp_command': dhcp_cmd, 70 | 'md5_challenge': md5_challenge 71 | } 72 | 73 | def enter_interactive_usermanager(): 74 | um = usermgr.UserMgr() 75 | 76 | if um.get_user_number() == 0: 77 | choice = input('No user conf file found, creat a new one?\n: ') 78 | if choice == 'y' or choice == 'Y': 79 | login_info = prompt_user_info() 80 | um.add_user(login_info) 81 | else: 82 | exit(-1) 83 | 84 | # user has been created or already have users 85 | while True: 86 | users_info = um.get_all_users_info() 87 | 88 | print('0 - add a new user') 89 | for i, user_info in enumerate(users_info): 90 | print('%d - %s(%s)' %(i + 1, user_info['username'], user_info['ethernet_interface'])) 91 | 92 | try: 93 | choice = int(input('Your choice: ')) 94 | except ValueError: 95 | print('Please input a valid number!') 96 | continue 97 | 98 | if choice == 0: 99 | try: 100 | user_info = prompt_user_info() 101 | um.add_user(user_info) 102 | except configparser.DuplicateSectionError: 103 | print('User already exist!') 104 | exit(-1) 105 | else: 106 | return users_info[choice - 1] 107 | 108 | def start_yah3c(login_info): 109 | yah3c = eapauth.EAPAuth(login_info) 110 | yah3c.serve_forever() 111 | 112 | def main(): 113 | args = parse_arguments() 114 | args = vars(args) 115 | 116 | # check for root privilege 117 | if not (os.getuid() == 0): 118 | print ('亲,要加sudo!') 119 | exit(-1) 120 | 121 | # check if debugging mode enabled 122 | if args['debug'] is True: 123 | logging.basicConfig(level=logging.DEBUG, 124 | format='%(asctime)s %(levelname)s: %(message)s', 125 | datefmt='%Y-%m-%d %H:%M:%S') 126 | logging.debug('Debugging mode enabled.') 127 | logging.debug(args) 128 | 129 | if args['username'] is None: 130 | # if no username specified then enter interactive mode 131 | login_info = enter_interactive_usermanager() 132 | else: 133 | # if there is username, then get it's info 134 | um = usermgr.UserMgr() 135 | login_info = um.get_user_info(args['username']) 136 | 137 | logging.debug(login_info) 138 | if 'md5_challenge' not in login_info: 139 | login_info['md5_challenge'] = 'xor' 140 | um.remove_user(login_info['username']) 141 | um.add_user(login_info) 142 | start_yah3c(login_info) 143 | 144 | if __name__ == "__main__": 145 | main() 146 | --------------------------------------------------------------------------------