Created
July 28, 2021 15:54
-
-
Save kadler/8595450fc0ae5fd61369a4ee7e880d2c to your computer and use it in GitHub Desktop.
Calling QSYCHGPW via Python with Emoji
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from ctypes import c_char, c_int, c_uint, c_int16, c_uint16, \ | |
c_size_t, c_ulonglong, c_void_p, c_char_p, \ | |
addressof, sizeof, create_string_buffer, \ | |
CDLL, DEFAULT_MODE, POINTER, Structure | |
import unicodedata | |
RTLD_MEMBER = 0x00040000 | |
class ILEPointer(Structure): | |
"An ILE pointer type" | |
_pack_ = 16 | |
_fields_ = [ | |
("hi", c_ulonglong), | |
("lo", c_ulonglong) | |
] | |
def __str__(self): | |
return f"{self.hi:016x}{self.lo:016x}" | |
try: | |
_LIBC = CDLL("/QOpenSys/usr/lib/libc.a(shr_64.o)", | |
DEFAULT_MODE | RTLD_MEMBER) | |
_SETSPP = _LIBC._SETSPP | |
_SETSPP.argtypes = [POINTER(ILEPointer), c_void_p] | |
_ILELOADX = _LIBC._ILELOADX | |
_ILELOADX.argtypes = [c_char_p, c_uint] | |
_ILELOADX.restype = c_ulonglong | |
_ILESYMX = _LIBC._ILESYMX | |
_ILESYMX.argtypes = [POINTER(ILEPointer), c_ulonglong, c_char_p] | |
_ILECALLX = _LIBC._ILECALLX | |
_ILECALLX.argtypes = [ | |
POINTER(ILEPointer), | |
c_void_p, | |
POINTER(c_int16), | |
c_int16, | |
c_int | |
] | |
_RSLOBJ = _LIBC._RSLOBJ | |
_RSLOBJ.argtypes = [ | |
POINTER(ILEPointer), | |
c_char_p, | |
c_char_p | |
] | |
_RSLOBJ2 = _LIBC._RSLOBJ2 | |
_RSLOBJ2.argtypes = [ | |
POINTER(ILEPointer), | |
c_uint16, | |
c_char_p, | |
c_char_p | |
] | |
_PGMCALL = _LIBC._PGMCALL | |
_PGMCALL.argtypes = [ | |
POINTER(ILEPointer), | |
c_void_p, | |
c_uint, | |
] | |
_CVTSPP = _LIBC._CVTSPP | |
_CVTSPP.argtypes = [POINTER(ILEPointer)] | |
_CVTSPP.restype = c_void_p | |
_MEMCPY_WT2 = _LIBC._MEMCPY_WT2 | |
_MEMCPY_WT2.argtypes = [ | |
POINTER(ILEPointer), | |
POINTER(ILEPointer), | |
c_size_t, | |
] | |
except OSError: | |
# Either we couldn't load libc or we couldn't find the necessary syscalls | |
# exported from libc. Either way, this platform is unsupported so we raise | |
# an import error to prevent it from being used. | |
raise ImportError | |
ILELOAD_LIBOBJ = 0x00000001 | |
ILESYM_PROCEDURE = 1 | |
ILECALL_NOINTERRUPT = 0x00000004 | |
ILECALL_EXCP_NOSIGNAL = 0x00000020 | |
RSLOBJ_TS_PGM = 0x0201 | |
RSLOBJ_TS_SRVPGM = 0x0203 | |
PGMCALL_DIRECT_ARGS = 0x00000001 | |
PGMCALL_DROP_ADOPT = 0x00000002 | |
PGMCALL_NOINTERRUPT = 0x00000004 | |
PGMCALL_NOMAXARGS = 0x00000008 | |
PGMCALL_ASCII_STRINGS = 0x00000010 | |
PGMCALL_EXCP_NOSIGNAL = 0x00000020 | |
RESULT_VOID = 0 | |
RESULT_INT8 = -1 | |
RESULT_UINT8 = -2 | |
RESULT_INT16 = -3 | |
RESULT_UINT16 = -4 | |
RESULT_INT32 = -5 | |
RESULT_UINT32 = -6 | |
RESULT_INT64 = -7 | |
RESULT_UINT64 = -8 | |
RESULT_FLOAT64 = -10 | |
RESULT_FLOAT128 = -18 | |
ARG_END = 0 | |
ARG_MEMPTR = -11 | |
class MemPointer(ILEPointer): | |
"An ILE pointer type to be used with ARG_MEMPTR" | |
_pack_ = 16 | |
def __init__(self, addr=0): | |
super().__int__() | |
self.hi = 0 | |
self.lo = addr | |
@property | |
def addr(self): | |
return self.lo | |
@addr.setter | |
def addr(self, addr): | |
self.lo = addr | |
class ILEArglistBase(Structure): | |
"ILECALL argument list base member" | |
_pack_ = 16 | |
_fields_ = [ | |
('descriptor', ILEPointer), | |
('result', ILEPointer), | |
] | |
class Qus_ec_t(Structure): | |
"ERRC0100 error code format structure" | |
_fields_ = [ | |
('bytes_provided', c_int), | |
('bytes_available', c_int), | |
('exception_id', c_char * 7), | |
('reserved', c_char), | |
] | |
def __init__(self): | |
self.bytes_provided = sizeof(self) | |
def load_symbol(library, srvpgm, symbol): | |
obj = f"{library}/{srvpgm}" | |
actgrp = _ILELOADX(obj.encode(), ILELOAD_LIBOBJ) | |
if actgrp == 0xffffffffffffffff: | |
raise OSError(f"{obj} not found") | |
ptr = ILEPointer() | |
if _ILESYMX(ptr, actgrp, symbol.encode()) != ILESYM_PROCEDURE: | |
raise OSError(f"{symbol} procedure not found in {obj}") | |
return ptr | |
def change_password(user, old_pwd, new_pwd): | |
try: | |
ptr = change_password.ptr | |
except AttributeError: | |
ptr = ILEPointer() | |
if _RSLOBJ2(ptr, RSLOBJ_TS_PGM, b"QSYCHGPW", b"QSYS"): | |
raise OSError("Error resolving QSYCHGPW") | |
change_password.ptr = ptr | |
user_ebcdic = create_string_buffer(user.ljust(10).upper().encode('cp037')) | |
current_password = create_string_buffer(old_pwd.encode('utf-8')) | |
new_password = create_string_buffer(new_pwd.encode('utf-8')) | |
err_code = Qus_ec_t(); | |
current_len = c_int(len(current_password)) | |
new_len = c_int(len(new_password)) | |
current_ccsid = new_ccsid = c_int(1208) | |
print(current_len, new_len) | |
args = (c_void_p * 9)( | |
addressof(user_ebcdic), | |
addressof(current_password), | |
addressof(new_password), | |
addressof(err_code), | |
addressof(current_len), | |
addressof(current_ccsid), | |
addressof(new_len), | |
addressof(new_ccsid), | |
0 | |
) | |
if _PGMCALL(ptr, addressof(args), PGMCALL_EXCP_NOSIGNAL): | |
raise OSError("_PGMCALL") | |
if err_code.bytes_available: | |
print(err_code.exception_id.decode('cp037')) | |
return False | |
return True | |
user = 'kadlertest' | |
old_pwd = 'password' | |
new_pwd = 'test! 😀 test!' | |
change_password(user, old_pwd, new_pwd) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment