Repository: humiaozuzu/YaH3C
Branch: master
Commit: c0d873c6ca99
Files: 18
Total size: 36.3 KB
Directory structure:
gitextract_27jb11da/
├── .gitignore
├── AUTHORS
├── CHANGES
├── LICENSE
├── README.md
├── scripts/
│ └── yah3c
├── setup.py
└── yah3c/
├── __init__.py
├── colorama/
│ ├── __init__.py
│ ├── ansi.py
│ ├── ansitowin32.py
│ ├── initialise.py
│ ├── win32.py
│ └── winterm.py
├── eapauth.py
├── eappacket.py
├── usermgr.py
└── yah3c.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
### /Users/maple/.gitignore-boilerplates/Python.gitignore
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
nosetests.xml
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
.project
.pydevproject
### /Users/maple/.gitignore-boilerplates/Global/OSX.gitignore
.DS_Store
Icon
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
### /Users/maple/.gitignore-boilerplates/Global/Linux.gitignore
.*
!.gitignore
*~
================================================
FILE: AUTHORS
================================================
Author
------
Maple <MapleValley8gmail.com>
Contributors
------------
- qiao <xueqiaoxu@gmail.com>
- houqp <dave2008713@gmail.com>
- tigersoldier <tigersoldi@gmail.com>
================================================
FILE: CHANGES
================================================
YaH3C Changelog
==============
Here is the full list of changes between each YaH3C release.
Version 0.5
-----------
Released on September 24th 2012
* add command line argument support
* add dhcp support
* refactory usermgr module
Version 0.4
-----------
Released on September 20th 2012
* remove plugin module
Version 0.3
-----------
Released on April 1th 2012
* add eap-md5 support
Version 0.2
-----------
Released on December 29th 2011
* complete refactory
* plugins support
Version 0.1
-----------
Released on November 14th 2011
* Initial commit
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2010-2012 YaH3C Authors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
YaH3C
=====
YaH3C 是用于校园网认证的客户端,支持中山大学东校区。
感谢 [lpy](https://github.com/lpy) 为 OS X 提供的[版本](https://github.com/lpy/Yah3c)。
为什么不用iNode
---------------
* i开头完全是对Apple的侮辱嘛 = =
* 强制添加启动项
* gui和cli使用的udp交互,很多时候Linux/Mac下掉线完全是因为实现的效率太低
* 安装脚本居然是自删除的
* 默认强制记录日志文件,增加CPU负载,减少硬盘寿命,一段时间后就过GB了(是否有敏感信息不得而知了)
* Linux下仅仅支持Ubuntu 32位系统
* Mac下安装后居然要重启
* 使用的第三方库乱放和HomeBrew冲突
依赖
------------
* 主流Linux发行版,包括OpenWrt/DD-WRT
* Python2
安装
------------
首先,从github上下载,可以直接利用`git clone`,也可以下载压缩包自己解压然后安装。下面以git为例,如果没有则需要先安装:
```bash
# Ubuntu/Debian
sudo apt-get install git
# ArchLinux
sudo pacman -S git
```
然后,从项目中clone下来并安装
```bash
git clone git://github.com/humiaozuzu/YaH3C.git
cd YaH3C
sudo python setup.py install
```
**ArchLinux**默认安装的python是python3,你需要手动安装python2。
使用
----
完整的联网过程有2步,首先使用本客户端通过交换机的认证,然后获取ip。
### 认证
程序运行时必须要有root权限:
```bash
sudo yah3c
```
根据程序的提示输入账号密码就可以开始认证了,有些选项如果看不懂请直接按`Enter`。
### 获取ip
因为YaH3C仅仅是**认证**客户端,所以通过认证后你需要自己获取ip联网,不过为了方便还是添加了dhcp支持。
如果没有指定dhcp的命令,你可以在认证成功后使用自己喜欢的网络管理工具获取IP,如NetworkManager或Wicd。
YaH3C支持基本的命令行参数,执行`yah3c -h`可以看到支持的命令行参数
``` bash
$ yah3c -h
usage: yah3c [-h] [-u USERNAME] [-debug]
Yet Another H3C Authentication Client
optional arguments:
-h, --help show this help message and exit
-u USERNAME, --username USERNAME
Login in with this username
-debug Enable debugging mode
```
如执行`sudo yah3c -u Maple`可以自动认证`Maple`这个帐号
配置文件格式
---------
用户的登陆信息按照如下的格式保存在文件`/etc/yah3c.conf`中:
``` ini
[account] # 你的帐户
password = 123456 # 密码
ethernet_interface = eth0 # 使用的网卡,默认为eth0
dhcp_command = dhcpcd # 验证成功后使用的dhcp命令(dhcpcd/dhclient),默认为空
daemon = True # 验证成功后是否变成daemon进程,默认为是
```
ScreenShots
-----------
认证成功:

认证失败:

Todo
----
* ~~添加BSD BPF 支持,这样在OS X也可以使用了~~
* 完善收集调试信息的功能,方便用户提交认证信息
* 完善对H3C协议的支持
Thanks
------
* [qiao](https://github.com/qiao) - Write python installation script for YaH3C
* [houqp](https://github.com/houqp) - Refered to houqp's [pyh3c](https://github.com/houqp/pyh3c)
* [tigersoldier](https://github.com/tigersoldier) - Write EAP-Md5 for YaH3C
License
-------
YaH3C的代码使用MIT License发布,此外,禁止使用YaH3C以及YaH3C的修改程序用于商业目的(比如交叉编译到路由进行销售等行为)
================================================
FILE: scripts/yah3c
================================================
#!/usr/bin/env python
if __name__ == '__main__':
import yah3c.yah3c
yah3c.yah3c.main()
================================================
FILE: setup.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from distutils.core import setup
import yah3c.yah3c
setup(name='yah3c',
version=yah3c.yah3c.__version__,
description='A program for h3c authentication in SYSU east campus.',
author='maple',
author_email='maplevalley8@gmail.com',
url='https://github.com/humiaozuzu/YaH3C',
download_url='https://github.com/humiaozuzu/YaH3C',
license='MIT',
packages=['yah3c', 'yah3c/colorama'],
scripts=['scripts/yah3c'],
)
================================================
FILE: yah3c/__init__.py
================================================
================================================
FILE: yah3c/colorama/__init__.py
================================================
from .initialise import init, deinit, reinit
from .ansi import Fore, Back, Style
from .ansitowin32 import AnsiToWin32
VERSION = '0.2.4'
================================================
FILE: yah3c/colorama/ansi.py
================================================
'''
This module generates ANSI character codes to printing colors to terminals.
See: http://en.wikipedia.org/wiki/ANSI_escape_code
'''
CSI = '\033['
def code_to_chars(code):
return CSI + str(code) + 'm'
class AnsiCodes(object):
def __init__(self, codes):
for name in dir(codes):
if not name.startswith('_'):
value = getattr(codes, name)
setattr(self, name, code_to_chars(value))
class AnsiFore:
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
RESET = 39
class AnsiBack:
BLACK = 40
RED = 41
GREEN = 42
YELLOW = 43
BLUE = 44
MAGENTA = 45
CYAN = 46
WHITE = 47
RESET = 49
class AnsiStyle:
BRIGHT = 1
DIM = 2
NORMAL = 22
RESET_ALL = 0
Fore = AnsiCodes( AnsiFore )
Back = AnsiCodes( AnsiBack )
Style = AnsiCodes( AnsiStyle )
================================================
FILE: yah3c/colorama/ansitowin32.py
================================================
import re
import sys
from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style
from .winterm import WinTerm, WinColor, WinStyle
from .win32 import windll
if windll is not None:
winterm = WinTerm()
def is_a_tty(stream):
return hasattr(stream, 'isatty') and stream.isatty()
class StreamWrapper(object):
'''
Wraps a stream (such as stdout), acting as a transparent proxy for all
attribute access apart from method 'write()', which is delegated to our
Converter instance.
'''
def __init__(self, wrapped, converter):
# double-underscore everything to prevent clashes with names of
# attributes on the wrapped stream object.
self.__wrapped = wrapped
self.__convertor = converter
def __getattr__(self, name):
return getattr(self.__wrapped, name)
def write(self, text):
self.__convertor.write(text)
class AnsiToWin32(object):
'''
Implements a 'write()' method which, on Windows, will strip ANSI character
sequences from the text, and if outputting to a tty, will convert them into
win32 function calls.
'''
ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])')
def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
# The wrapped stream (normally sys.stdout or sys.stderr)
self.wrapped = wrapped
# should we reset colors to defaults after every .write()
self.autoreset = autoreset
# create the proxy wrapping our output stream
self.stream = StreamWrapper(wrapped, self)
on_windows = sys.platform.startswith('win')
# should we strip ANSI sequences from our output?
if strip is None:
strip = on_windows
self.strip = strip
# should we should convert ANSI sequences into win32 calls?
if convert is None:
convert = on_windows and is_a_tty(wrapped)
self.convert = convert
# dict of ansi codes to win32 functions and parameters
self.win32_calls = self.get_win32_calls()
# are we wrapping stderr?
self.on_stderr = self.wrapped is sys.stderr
def should_wrap(self):
'''
True if this class is actually needed. If false, then the output
stream will not be affected, nor will win32 calls be issued, so
wrapping stdout is not actually required. This will generally be
False on non-Windows platforms, unless optional functionality like
autoreset has been requested using kwargs to init()
'''
return self.convert or self.strip or self.autoreset
def get_win32_calls(self):
if self.convert and winterm:
return {
AnsiStyle.RESET_ALL: (winterm.reset_all, ),
AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT),
AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL),
AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL),
AnsiFore.BLACK: (winterm.fore, WinColor.BLACK),
AnsiFore.RED: (winterm.fore, WinColor.RED),
AnsiFore.GREEN: (winterm.fore, WinColor.GREEN),
AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW),
AnsiFore.BLUE: (winterm.fore, WinColor.BLUE),
AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA),
AnsiFore.CYAN: (winterm.fore, WinColor.CYAN),
AnsiFore.WHITE: (winterm.fore, WinColor.GREY),
AnsiFore.RESET: (winterm.fore, ),
AnsiBack.BLACK: (winterm.back, WinColor.BLACK),
AnsiBack.RED: (winterm.back, WinColor.RED),
AnsiBack.GREEN: (winterm.back, WinColor.GREEN),
AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW),
AnsiBack.BLUE: (winterm.back, WinColor.BLUE),
AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA),
AnsiBack.CYAN: (winterm.back, WinColor.CYAN),
AnsiBack.WHITE: (winterm.back, WinColor.GREY),
AnsiBack.RESET: (winterm.back, ),
}
def write(self, text):
if self.strip or self.convert:
self.write_and_convert(text)
else:
self.wrapped.write(text)
self.wrapped.flush()
if self.autoreset:
self.reset_all()
def reset_all(self):
if self.convert:
self.call_win32('m', (0,))
elif is_a_tty(self.wrapped):
self.wrapped.write(Style.RESET_ALL)
def write_and_convert(self, text):
'''
Write the given text to our wrapped stream, stripping any ANSI
sequences from the text, and optionally converting them into win32
calls.
'''
cursor = 0
for match in self.ANSI_RE.finditer(text):
start, end = match.span()
self.write_plain_text(text, cursor, start)
self.convert_ansi(*match.groups())
cursor = end
self.write_plain_text(text, cursor, len(text))
def write_plain_text(self, text, start, end):
if start < end:
self.wrapped.write(text[start:end])
self.wrapped.flush()
def convert_ansi(self, paramstring, command):
if self.convert:
params = self.extract_params(paramstring)
self.call_win32(command, params)
def extract_params(self, paramstring):
def split(paramstring):
for p in paramstring.split(';'):
if p != '':
yield int(p)
return tuple(split(paramstring))
def call_win32(self, command, params):
if params == []:
params = [0]
if command == 'm':
for param in params:
if param in self.win32_calls:
func_args = self.win32_calls[param]
func = func_args[0]
args = func_args[1:]
kwargs = dict(on_stderr=self.on_stderr)
func(*args, **kwargs)
elif command in ('H', 'f'): # set cursor position
func = winterm.set_cursor_position
func(params, on_stderr=self.on_stderr)
elif command in ('J'):
func = winterm.erase_data
func(params, on_stderr=self.on_stderr)
================================================
FILE: yah3c/colorama/initialise.py
================================================
import atexit
import sys
from .ansitowin32 import AnsiToWin32
orig_stdout = sys.stdout
orig_stderr = sys.stderr
wrapped_stdout = sys.stdout
wrapped_stderr = sys.stderr
atexit_done = False
def reset_all():
AnsiToWin32(orig_stdout).reset_all()
def init(autoreset=False, convert=None, strip=None, wrap=True):
if not wrap and any([autoreset, convert, strip]):
raise ValueError('wrap=False conflicts with any other arg=True')
global wrapped_stdout, wrapped_stderr
sys.stdout = wrapped_stdout = \
wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
sys.stderr = wrapped_stderr = \
wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
global atexit_done
if not atexit_done:
atexit.register(reset_all)
atexit_done = True
def deinit():
sys.stdout = orig_stdout
sys.stderr = orig_stderr
def reinit():
sys.stdout = wrapped_stdout
sys.stderr = wrapped_stdout
def wrap_stream(stream, convert, strip, autoreset, wrap):
if wrap:
wrapper = AnsiToWin32(stream,
convert=convert, strip=strip, autoreset=autoreset)
if wrapper.should_wrap():
stream = wrapper.stream
return stream
================================================
FILE: yah3c/colorama/win32.py
================================================
# from winbase.h
STDOUT = -11
STDERR = -12
try:
from ctypes import windll
except ImportError:
windll = None
SetConsoleTextAttribute = lambda *_: None
else:
from ctypes import (
byref, Structure, c_char, c_short, c_uint32, c_ushort
)
handles = {
STDOUT: windll.kernel32.GetStdHandle(STDOUT),
STDERR: windll.kernel32.GetStdHandle(STDERR),
}
SHORT = c_short
WORD = c_ushort
DWORD = c_uint32
TCHAR = c_char
class COORD(Structure):
"""struct in wincon.h"""
_fields_ = [
('X', SHORT),
('Y', SHORT),
]
class SMALL_RECT(Structure):
"""struct in wincon.h."""
_fields_ = [
("Left", SHORT),
("Top", SHORT),
("Right", SHORT),
("Bottom", SHORT),
]
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
"""struct in wincon.h."""
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", WORD),
("srWindow", SMALL_RECT),
("dwMaximumWindowSize", COORD),
]
def __str__(self):
return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
self.dwSize.Y, self.dwSize.X
, self.dwCursorPosition.Y, self.dwCursorPosition.X
, self.wAttributes
, self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
, self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
)
def GetConsoleScreenBufferInfo(stream_id=STDOUT):
handle = handles[stream_id]
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = windll.kernel32.GetConsoleScreenBufferInfo(
handle, byref(csbi))
return csbi
def SetConsoleTextAttribute(stream_id, attrs):
handle = handles[stream_id]
return windll.kernel32.SetConsoleTextAttribute(handle, attrs)
def SetConsoleCursorPosition(stream_id, position):
position = COORD(*position)
# If the position is out of range, do nothing.
if position.Y <= 0 or position.X <= 0:
return
# Adjust for Windows' SetConsoleCursorPosition:
# 1. being 0-based, while ANSI is 1-based.
# 2. expecting (x,y), while ANSI uses (y,x).
adjusted_position = COORD(position.Y - 1, position.X - 1)
# Adjust for viewport's scroll position
sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
adjusted_position.Y += sr.Top
adjusted_position.X += sr.Left
# Resume normal processing
handle = handles[stream_id]
return windll.kernel32.SetConsoleCursorPosition(handle, adjusted_position)
def FillConsoleOutputCharacter(stream_id, char, length, start):
handle = handles[stream_id]
char = TCHAR(char)
length = DWORD(length)
num_written = DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
success = windll.kernel32.FillConsoleOutputCharacterA(
handle, char, length, start, byref(num_written))
return num_written.value
def FillConsoleOutputAttribute(stream_id, attr, length, start):
''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
handle = handles[stream_id]
attribute = WORD(attr)
length = DWORD(length)
num_written = DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
return windll.kernel32.FillConsoleOutputAttribute(
handle, attribute, length, start, byref(num_written))
================================================
FILE: yah3c/colorama/winterm.py
================================================
from . import win32
# from wincon.h
class WinColor(object):
BLACK = 0
BLUE = 1
GREEN = 2
CYAN = 3
RED = 4
MAGENTA = 5
YELLOW = 6
GREY = 7
# from wincon.h
class WinStyle(object):
NORMAL = 0x00 # dim text, dim background
BRIGHT = 0x08 # bright text, dim background
class WinTerm(object):
def __init__(self):
self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes
self.set_attrs(self._default)
self._default_fore = self._fore
self._default_back = self._back
self._default_style = self._style
def get_attrs(self):
return self._fore + self._back * 16 + self._style
def set_attrs(self, value):
self._fore = value & 7
self._back = (value >> 4) & 7
self._style = value & WinStyle.BRIGHT
def reset_all(self, on_stderr=None):
self.set_attrs(self._default)
self.set_console(attrs=self._default)
def fore(self, fore=None, on_stderr=False):
if fore is None:
fore = self._default_fore
self._fore = fore
self.set_console(on_stderr=on_stderr)
def back(self, back=None, on_stderr=False):
if back is None:
back = self._default_back
self._back = back
self.set_console(on_stderr=on_stderr)
def style(self, style=None, on_stderr=False):
if style is None:
style = self._default_style
self._style = style
self.set_console(on_stderr=on_stderr)
def set_console(self, attrs=None, on_stderr=False):
if attrs is None:
attrs = self.get_attrs()
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
win32.SetConsoleTextAttribute(handle, attrs)
def set_cursor_position(self, position=None, on_stderr=False):
if position is None:
#I'm not currently tracking the position, so there is no default.
#position = self.get_position()
return
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
win32.SetConsoleCursorPosition(handle, position)
def erase_data(self, mode=0, on_stderr=False):
# 0 (or None) should clear from the cursor to the end of the screen.
# 1 should clear from the cursor to the beginning of the screen.
# 2 should clear the entire screen. (And maybe move cursor to (1,1)?)
#
# At the moment, I only support mode 2. From looking at the API, it
# should be possible to calculate a different number of bytes to clear,
# and to do so relative to the cursor position.
if mode[0] not in (2,):
return
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
# here's where we'll home the cursor
coord_screen = win32.COORD(0,0)
csbi = win32.GetConsoleScreenBufferInfo(handle)
# get the number of character cells in the current buffer
dw_con_size = csbi.dwSize.X * csbi.dwSize.Y
# fill the entire screen with blanks
win32.FillConsoleOutputCharacter(handle, ord(' '), dw_con_size, coord_screen)
# now set the buffer's attributes accordingly
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), dw_con_size, coord_screen );
# put the cursor at (0, 0)
win32.SetConsoleCursorPosition(handle, (coord_screen.X, coord_screen.Y))
================================================
FILE: yah3c/eapauth.py
================================================
""" EAP authentication handler
This module sents EAPOL begin/logoff packet
and parses received EAP packet
"""
__all__ = ["EAPAuth"]
import socket
import os, sys, pwd
from subprocess import call
from colorama import Fore, Style, init
# init() # required in Windows
from eappacket import *
def display_prompt(color, string):
prompt = color + Style.BRIGHT + '==> ' + Style.RESET_ALL
prompt += Style.BRIGHT + string + Style.RESET_ALL
print prompt
def display_packet(packet):
# print ethernet_header infomation
print 'Ethernet Header Info: '
print '\tFrom: ' + repr(packet[0:6])
print '\tTo: ' + repr(packet[6:12])
print '\tType: ' + repr(packet[12:14])
class EAPAuth:
def __init__(self, login_info):
# bind the h3c client to the EAP protocal
self.client = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETHERTYPE_PAE))
self.client.bind((login_info['ethernet_interface'], ETHERTYPE_PAE))
# get local ethernet card address
self.mac_addr = self.client.getsockname()[4]
self.ethernet_header = get_ethernet_header(self.mac_addr, PAE_GROUP_ADDR, ETHERTYPE_PAE)
self.has_sent_logoff = False
self.login_info = login_info
self.version_info = '\x06\x07bjQ7SE8BZ3MqHhs3clMregcDY3Y=\x20\x20'
def send_start(self):
# sent eapol start packet
eap_start_packet = self.ethernet_header + get_EAPOL(EAPOL_START)
self.client.send(eap_start_packet)
display_prompt(Fore.GREEN, 'Sending EAPOL start')
def send_logoff(self):
# sent eapol logoff packet
eap_logoff_packet = self.ethernet_header + get_EAPOL(EAPOL_LOGOFF)
self.client.send(eap_logoff_packet)
self.has_sent_logoff = True
display_prompt(Fore.GREEN, 'Sending EAPOL logoff')
def send_response_id(self, packet_id):
self.client.send(self.ethernet_header +
get_EAPOL(EAPOL_EAPPACKET,
get_EAP(EAP_RESPONSE,
packet_id,
EAP_TYPE_ID,
self.version_info + self.login_info['username'])))
def send_response_md5(self, packet_id, md5data):
md5 = self.login_info['password'][0:16]
if len(md5) < 16:
md5 = md5 + '\x00' * (16 - len (md5))
chap = []
for i in xrange(0, 16):
chap.append(chr(ord(md5[i]) ^ ord(md5data[i])))
resp = chr(len(chap)) + ''.join(chap) + self.login_info['username']
eap_packet = self.ethernet_header + get_EAPOL(EAPOL_EAPPACKET, get_EAP(EAP_RESPONSE, packet_id, EAP_TYPE_MD5, resp))
try:
self.client.send(eap_packet)
except socket.error, msg:
print "Connection error!"
exit(-1)
def send_response_h3c(self, packet_id):
resp = chr(len(self.login_info['password'])) + self.login_info['password'] + self.login_info['username']
eap_packet = self.ethernet_header + get_EAPOL(EAPOL_EAPPACKET, get_EAP(EAP_RESPONSE, packet_id, EAP_TYPE_H3C, resp))
try:
self.client.send(eap_packet)
except socket.error, msg:
print "Connection error!"
exit(-1)
def display_login_message(self, msg):
"""
display the messages received form the radius server,
including the error meaasge after logging failed or
other meaasge from networking centre
"""
try:
print msg.decode('gbk')
except UnicodeDecodeError:
print msg
def EAP_handler(self, eap_packet):
vers, type, eapol_len = unpack("!BBH",eap_packet[:4])
if type != EAPOL_EAPPACKET:
display_prompt(Fore.YELLOW, 'Got unknown EAPOL type %i' % type)
# EAPOL_EAPPACKET type
code, id, eap_len = unpack("!BBH", eap_packet[4:8])
if code == EAP_SUCCESS:
display_prompt(Fore.YELLOW, 'Got EAP Success')
if self.login_info['dhcp_command']:
display_prompt(Fore.YELLOW, 'Obtaining IP Address:')
call([self.login_info['dhcp_command'], self.login_info['ethernet_interface']])
if self.login_info['daemon'] == 'True':
daemonize('/dev/null','/tmp/daemon.log','/tmp/daemon.log')
elif code == EAP_FAILURE:
if (self.has_sent_logoff):
display_prompt(Fore.YELLOW, 'Logoff Successfully!')
#self.display_login_message(eap_packet[10:])
else:
display_prompt(Fore.YELLOW, 'Got EAP Failure')
#self.display_login_message(eap_packet[10:])
exit(-1)
elif code == EAP_RESPONSE:
display_prompt(Fore.YELLOW, 'Got Unknown EAP Response')
elif code == EAP_REQUEST:
reqtype = unpack("!B", eap_packet[8:9])[0]
reqdata = eap_packet[9:4 + eap_len]
if reqtype == EAP_TYPE_ID:
display_prompt(Fore.YELLOW, 'Got EAP Request for identity')
self.send_response_id(id)
display_prompt(Fore.GREEN, 'Sending EAP response with identity = [%s]' % self.login_info['username'])
elif reqtype == EAP_TYPE_H3C:
display_prompt(Fore.YELLOW, 'Got EAP Request for Allocation')
self.send_response_h3c(id)
display_prompt(Fore.GREEN, 'Sending EAP response with password')
elif reqtype == EAP_TYPE_MD5:
data_len = unpack("!B", reqdata[0:1])[0]
md5data = reqdata[1:1 + data_len]
display_prompt(Fore.YELLOW, 'Got EAP Request for MD5-Challenge')
self.send_response_md5(id, md5data)
display_prompt(Fore.GREEN, 'Sending EAP response with password')
else:
display_prompt(Fore.YELLOW, 'Got unknown Request type (%i)' % reqtype)
elif code==10 and id==5:
self.display_login_message(eap_packet[12:])
else:
display_prompt(Fore.YELLOW, 'Got unknown EAP code (%i)' % code)
def serve_forever(self):
try:
self.send_start()
while True:
eap_packet = self.client.recv(1600)
# strip the ethernet_header and handle
self.EAP_handler(eap_packet[14:])
except KeyboardInterrupt:
print Fore.RED + Style.BRIGHT + 'Interrupted by user' + Style.RESET_ALL
self.send_logoff()
except socket.error , msg:
print "Connection error: %s" %msg
exit(-1)
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
'''This forks the current process into a daemon. The stdin, stdout, and
stderr arguments are file names that will be opened and be used to replace
the standard file descriptors in sys.stdin, sys.stdout, and sys.stderr.
These arguments are optional and default to /dev/null. Note that stderr is
opened unbuffered, so if it shares a file with stdout then interleaved
output may not appear in the order that you expect. '''
# Do first fork.
try:
pid = os.fork()
if pid > 0:
sys.exit(0) # Exit first parent.
except OSError, e:
sys.stderr.write ("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )
sys.exit(1)
# Decouple from parent environment.
os.chdir("/")
os.umask(0)
os.setsid()
# Do second fork.
try:
pid = os.fork()
if pid > 0:
sys.exit(0) # Exit second parent.
except OSError, e:
sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
sys.exit(1)
# Now I am a daemon!
# Redirect standard file descriptors.
si = open(stdin, 'r')
so = open(stdout, 'a+')
se = open(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
================================================
FILE: yah3c/eappacket.py
================================================
from struct import *
## Constants
# Reference: http://tools.ietf.org/html/rfc3748
ETHERTYPE_PAE = 0x888e
PAE_GROUP_ADDR = "\x01\x80\xc2\x00\x00\x03"
BROADCAST_ADDR = "\xff\xff\xff\xff\xff\xff"
EAPOL_VERSION = 1
EAPOL_EAPPACKET = 0
# packet info for EAPOL_EAPPACKET
EAPOL_START = 1
EAPOL_LOGOFF = 2
EAPOL_KEY = 3
EAPOL_ASF = 4
EAP_REQUEST = 1
EAP_RESPONSE = 2
EAP_SUCCESS = 3
EAP_FAILURE = 4
# packet info followed by EAP_RESPONSE
# 1 Identity
# 2 Notification
# 3 Nak (Response only)
# 4 MD5-Challenge
# 5 One Time Password (OTP)
# 6 Generic Token Card (GTC)
# 254 Expanded Types
# 255 Experimental use
EAP_TYPE_ID = 1 # identity
EAP_TYPE_MD5 = 4 # md5 Challenge
EAP_TYPE_H3C = 7 # H3C eap packet(used for SYSU east campus)
### Packet builders
def get_EAPOL(type, payload=""):
return pack("!BBH", EAPOL_VERSION, type, len(payload))+payload
def get_EAP(code, id, type=0, data=""):
if code in [EAP_SUCCESS, EAP_FAILURE]:
return pack("!BBH", code, id, 4)
else:
return pack("!BBHB", code, id, 5+len(data), type)+data
def get_ethernet_header(src, dst, type):
return dst+src+pack("!H",type)
================================================
FILE: yah3c/usermgr.py
================================================
""" User Management Module
This module reads the 'users.conf' file and gets all users's info.
"""
__all__ = ["UserMgr"]
import ConfigParser
class UserMgr:
"""User Manager
The format of the user_info is:
user_info = {
"username": "maple",
"password": "valley",
"ethernet_interface": "eth0",
"dhcp_command": "dhcpcd",
"daemon": True,
# following has not implemented yet
"carry_version_info": True,
"broadcast_logoff": False
"packet_type": "unicast"
}
"""
def __init__(self, path=None):
if path is None:
self.users_cfg_path = '/etc/yah3c.conf'
else:
self.users_cfg_path = path
self.config = ConfigParser.ConfigParser()
self.config.read(self.users_cfg_path)
def save_and_reload(self):
fp = open(self.users_cfg_path, 'w')
self.config.write(fp)
fp.close()
self.config.read(self.users_cfg_path)
def get_user_number(self):
return len(self.config.sections())
def get_all_users_info(self):
users_info = []
for username in self.config.sections():
user_info = dict(self.config.items(username))
user_info['username'] = username
users_info.append(user_info)
return users_info
def get_user_info(self, username):
user_info = dict(self.config.items(username))
user_info['username'] = username
return user_info
def add_user(self, user_info):
self.config.add_section(user_info['username'])
self.update_user_info(user_info)
def remove_user(self, username):
self.config.remove_section(username)
self.save_and_reload()
def update_user_info(self, user_info):
self.config.set(user_info['username'], 'password',
user_info['password'])
self.config.set(user_info['username'], 'ethernet_interface',
user_info['ethernet_interface'])
self.config.set(user_info['username'], 'dhcp_command',
user_info['dhcp_command'])
self.config.set(user_info['username'], 'daemon',
user_info['daemon'])
self.save_and_reload()
================================================
FILE: yah3c/yah3c.py
================================================
#!/usr/bin/env python
# -*- coding:utf-8 -*-
""" Main program for YaH3C.
"""
__version__ = '0.5'
import os, sys
import ConfigParser
import getpass
import argparse
import logging
import eapauth
import usermgr
def parse_arguments():
parser = argparse.ArgumentParser(description='Yet Another H3C Authentication Client', prog='yah3c')
parser.add_argument('-u', '--username',
help='Login in with this username')
# parser.add_argument('-p', '--password',
# help='Password')
# parser.add_argument('-i', '--interface', default='eth0',
# help='Etherent interface used. Set as eth0 by default.')
# parser.add_argument('-d', '--daemon', action='store_true',
# help='Fork to background after authentication.')
# parser.add_argument('-D', '--dhcp',
# help='DHCP cmd used to obtain ip after authentication.')
parser.add_argument('-debug', action='store_true',
help='Enable debugging mode')
args = parser.parse_args()
return args
def prompt_user_info():
username = raw_input('Input username: ')
while True:
password = getpass.getpass('Input password: ')
password_again = getpass.getpass('Input again: ')
if password == password_again:
break
else:
print 'Password do not match!'
dev = raw_input('Decice(eth0 by default): ')
if not dev:
dev = 'eth0'
choice = raw_input('Forked to background after authentication(Yes by default)\n<Y/N>: ')
if choice == 'n' or choice == 'N':
daemon = False
else:
daemon = True
dhcp_cmd = raw_input('Dhcp command(Press Enter to pass): ')
if not dhcp_cmd:
dhcp_cmd = ''
return {
'username': username,
'password': password,
'ethernet_interface': dev,
'daemon': daemon,
'dhcp_command': dhcp_cmd
}
def enter_interactive_usermanager():
um = usermgr.UserMgr()
if um.get_user_number() == 0:
choice = raw_input('No user conf file found, creat a new one?\n<Y/N>: ')
if choice == 'y' or choice == 'Y':
login_info = prompt_user_info()
um.add_user(login_info)
else:
exit(-1)
# user has been created or already have users
users_info = um.get_all_users_info()
print '0 - add a new user'
for i, user_info in enumerate(users_info):
print '%d - %s(%s)' %(i + 1, user_info['username'], user_info['ethernet_interface'])
while True:
try:
choice = int(raw_input('Your choice: '))
except ValueError:
print 'Please input a valid number!'
else: break;
if choice == 0:
try:
user_info = prompt_user_info()
um.add_user(user_info)
except ConfigParser.DuplicateSectionError:
print 'User already exist!'
exit(-1)
else:
return users_info[choice - 1]
def start_yah3c(login_info):
yah3c = eapauth.EAPAuth(login_info)
yah3c.serve_forever()
def main():
args = parse_arguments()
args = vars(args)
# check for root privilege
if not (os.getuid() == 0):
print (u'亲,要加sudo!')
exit(-1)
# check if debugging mode enabled
if args['debug'] is True:
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
logging.debug('Debugging mode enabled.')
logging.debug(args)
# if no username specified then enter interactive mode
if args['username'] is None:
login_info = enter_interactive_usermanager()
logging.debug(login_info)
start_yah3c(login_info)
# if there is username, then get it's info
um = usermgr.UserMgr()
login_info = um.get_user_info(args['username'])
logging.debug(login_info)
start_yah3c(login_info)
if __name__ == "__main__":
main()
gitextract_27jb11da/
├── .gitignore
├── AUTHORS
├── CHANGES
├── LICENSE
├── README.md
├── scripts/
│ └── yah3c
├── setup.py
└── yah3c/
├── __init__.py
├── colorama/
│ ├── __init__.py
│ ├── ansi.py
│ ├── ansitowin32.py
│ ├── initialise.py
│ ├── win32.py
│ └── winterm.py
├── eapauth.py
├── eappacket.py
├── usermgr.py
└── yah3c.py
SYMBOL INDEX (79 symbols across 9 files)
FILE: yah3c/colorama/ansi.py
function code_to_chars (line 8) | def code_to_chars(code):
class AnsiCodes (line 11) | class AnsiCodes(object):
method __init__ (line 12) | def __init__(self, codes):
class AnsiFore (line 18) | class AnsiFore:
class AnsiBack (line 29) | class AnsiBack:
class AnsiStyle (line 40) | class AnsiStyle:
FILE: yah3c/colorama/ansitowin32.py
function is_a_tty (line 14) | def is_a_tty(stream):
class StreamWrapper (line 18) | class StreamWrapper(object):
method __init__ (line 24) | def __init__(self, wrapped, converter):
method __getattr__ (line 30) | def __getattr__(self, name):
method write (line 33) | def write(self, text):
class AnsiToWin32 (line 37) | class AnsiToWin32(object):
method __init__ (line 45) | def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
method should_wrap (line 74) | def should_wrap(self):
method get_win32_calls (line 85) | def get_win32_calls(self):
method write (line 113) | def write(self, text):
method reset_all (line 123) | def reset_all(self):
method write_and_convert (line 130) | def write_and_convert(self, text):
method write_plain_text (line 145) | def write_plain_text(self, text, start, end):
method convert_ansi (line 151) | def convert_ansi(self, paramstring, command):
method extract_params (line 157) | def extract_params(self, paramstring):
method call_win32 (line 165) | def call_win32(self, command, params):
FILE: yah3c/colorama/initialise.py
function reset_all (line 16) | def reset_all():
function init (line 20) | def init(autoreset=False, convert=None, strip=None, wrap=True):
function deinit (line 37) | def deinit():
function reinit (line 42) | def reinit():
function wrap_stream (line 47) | def wrap_stream(stream, convert, strip, autoreset, wrap):
FILE: yah3c/colorama/win32.py
class COORD (line 26) | class COORD(Structure):
class SMALL_RECT (line 33) | class SMALL_RECT(Structure):
class CONSOLE_SCREEN_BUFFER_INFO (line 42) | class CONSOLE_SCREEN_BUFFER_INFO(Structure):
method __str__ (line 51) | def __str__(self):
function GetConsoleScreenBufferInfo (line 60) | def GetConsoleScreenBufferInfo(stream_id=STDOUT):
function SetConsoleTextAttribute (line 68) | def SetConsoleTextAttribute(stream_id, attrs):
function SetConsoleCursorPosition (line 73) | def SetConsoleCursorPosition(stream_id, position):
function FillConsoleOutputCharacter (line 90) | def FillConsoleOutputCharacter(stream_id, char, length, start):
function FillConsoleOutputAttribute (line 100) | def FillConsoleOutputAttribute(stream_id, attr, length, start):
FILE: yah3c/colorama/winterm.py
class WinColor (line 6) | class WinColor(object):
class WinStyle (line 17) | class WinStyle(object):
class WinTerm (line 22) | class WinTerm(object):
method __init__ (line 24) | def __init__(self):
method get_attrs (line 31) | def get_attrs(self):
method set_attrs (line 34) | def set_attrs(self, value):
method reset_all (line 39) | def reset_all(self, on_stderr=None):
method fore (line 43) | def fore(self, fore=None, on_stderr=False):
method back (line 49) | def back(self, back=None, on_stderr=False):
method style (line 55) | def style(self, style=None, on_stderr=False):
method set_console (line 61) | def set_console(self, attrs=None, on_stderr=False):
method set_cursor_position (line 69) | def set_cursor_position(self, position=None, on_stderr=False):
method erase_data (line 79) | def erase_data(self, mode=0, on_stderr=False):
FILE: yah3c/eapauth.py
function display_prompt (line 18) | def display_prompt(color, string):
function display_packet (line 23) | def display_packet(packet):
class EAPAuth (line 30) | class EAPAuth:
method __init__ (line 31) | def __init__(self, login_info):
method send_start (line 42) | def send_start(self):
method send_logoff (line 49) | def send_logoff(self):
method send_response_id (line 57) | def send_response_id(self, packet_id):
method send_response_md5 (line 65) | def send_response_md5(self, packet_id, md5data):
method send_response_h3c (line 80) | def send_response_h3c(self, packet_id):
method display_login_message (line 89) | def display_login_message(self, msg):
method EAP_handler (line 100) | def EAP_handler(self, eap_packet):
method serve_forever (line 153) | def serve_forever(self):
function daemonize (line 168) | def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
FILE: yah3c/eappacket.py
function get_EAPOL (line 37) | def get_EAPOL(type, payload=""):
function get_EAP (line 40) | def get_EAP(code, id, type=0, data=""):
function get_ethernet_header (line 46) | def get_ethernet_header(src, dst, type):
FILE: yah3c/usermgr.py
class UserMgr (line 10) | class UserMgr:
method __init__ (line 25) | def __init__(self, path=None):
method save_and_reload (line 33) | def save_and_reload(self):
method get_user_number (line 39) | def get_user_number(self):
method get_all_users_info (line 42) | def get_all_users_info(self):
method get_user_info (line 51) | def get_user_info(self, username):
method add_user (line 56) | def add_user(self, user_info):
method remove_user (line 60) | def remove_user(self, username):
method update_user_info (line 64) | def update_user_info(self, user_info):
FILE: yah3c/yah3c.py
function parse_arguments (line 19) | def parse_arguments():
function prompt_user_info (line 36) | def prompt_user_info():
function enter_interactive_usermanager (line 67) | def enter_interactive_usermanager():
function start_yah3c (line 101) | def start_yah3c(login_info):
function main (line 105) | def main():
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (41K chars).
[
{
"path": ".gitignore",
"chars": 616,
"preview": "### /Users/maple/.gitignore-boilerplates/Python.gitignore\n\n*.py[cod]\n\n# C extensions\n*.so\n\n# Packages\n*.egg\n*.egg-info\nd"
},
{
"path": "AUTHORS",
"chars": 172,
"preview": "Author\n------\n\nMaple <MapleValley8gmail.com>\n\nContributors\n------------\n\n- qiao <xueqiaoxu@gmail.com>\n- houqp <dave20087"
},
{
"path": "CHANGES",
"chars": 565,
"preview": "YaH3C Changelog\n==============\n\nHere is the full list of changes between each YaH3C release.\n\nVersion 0.5\n-----------\n\nR"
},
{
"path": "LICENSE",
"chars": 1101,
"preview": "The MIT License\n\nCopyright (c) 2010-2012 YaH3C Authors. All rights reserved.\n\nPermission is hereby granted, free of char"
},
{
"path": "README.md",
"chars": 2389,
"preview": "YaH3C\n=====\n\nYaH3C 是用于校园网认证的客户端,支持中山大学东校区。\n\n感谢 [lpy](https://github.com/lpy) 为 OS X 提供的[版本](https://github.com/lpy/Yah3c"
},
{
"path": "scripts/yah3c",
"chars": 96,
"preview": "#!/usr/bin/env python\n\nif __name__ == '__main__':\n import yah3c.yah3c\n yah3c.yah3c.main()\n"
},
{
"path": "setup.py",
"chars": 514,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom distutils.core import setup\nimport yah3c.yah3c\n\nsetup(name='yah3c',\n"
},
{
"path": "yah3c/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "yah3c/colorama/__init__.py",
"chars": 138,
"preview": "from .initialise import init, deinit, reinit\nfrom .ansi import Fore, Back, Style\nfrom .ansitowin32 import AnsiToWin32\n\nV"
},
{
"path": "yah3c/colorama/ansi.py",
"chars": 1013,
"preview": "'''\r\nThis module generates ANSI character codes to printing colors to terminals.\r\nSee: http://en.wikipedia.org/wiki/ANSI"
},
{
"path": "yah3c/colorama/ansitowin32.py",
"chars": 6479,
"preview": "\r\nimport re\r\nimport sys\r\n\r\nfrom .ansi import AnsiFore, AnsiBack, AnsiStyle, Style\r\nfrom .winterm import WinTerm, WinColo"
},
{
"path": "yah3c/colorama/initialise.py",
"chars": 1277,
"preview": "import atexit\r\nimport sys\r\n\r\nfrom .ansitowin32 import AnsiToWin32\r\n\r\n\r\norig_stdout = sys.stdout\r\norig_stderr = sys.stder"
},
{
"path": "yah3c/colorama/win32.py",
"chars": 3779,
"preview": "\r\n# from winbase.h\r\nSTDOUT = -11\r\nSTDERR = -12\r\n\r\ntry:\r\n from ctypes import windll\r\nexcept ImportError:\r\n windll ="
},
{
"path": "yah3c/colorama/winterm.py",
"chars": 3581,
"preview": "\r\nfrom . import win32\r\n\r\n\r\n# from wincon.h\r\nclass WinColor(object):\r\n BLACK = 0\r\n BLUE = 1\r\n GREEN = 2\r\n"
},
{
"path": "yah3c/eapauth.py",
"chars": 8015,
"preview": "\"\"\" EAP authentication handler\n\nThis module sents EAPOL begin/logoff packet\nand parses received EAP packet \n\n\"\"\"\n\n__all_"
},
{
"path": "yah3c/eappacket.py",
"chars": 1212,
"preview": "from struct import *\n\n## Constants\n# Reference: http://tools.ietf.org/html/rfc3748\nETHERTYPE_PAE = 0x888e\nPAE_GROUP_ADDR"
},
{
"path": "yah3c/usermgr.py",
"chars": 2274,
"preview": "\"\"\" User Management Module\n\nThis module reads the 'users.conf' file and gets all users's info.\n\"\"\"\n\n__all__ = [\"UserMgr\""
},
{
"path": "yah3c/yah3c.py",
"chars": 3969,
"preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\n\"\"\" Main program for YaH3C.\n\n\"\"\"\n\n__version__ = '0.5'\n\nimport os, sys\nimpor"
}
]
About this extraction
This page contains the full source code of the humiaozuzu/YaH3C GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (36.3 KB), approximately 10.0k tokens, and a symbol index with 79 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.