Skip to content

Instantly share code, notes, and snippets.

@kadler
Created July 28, 2021 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kadler/8595450fc0ae5fd61369a4ee7e880d2c to your computer and use it in GitHub Desktop.
Save kadler/8595450fc0ae5fd61369a4ee7e880d2c to your computer and use it in GitHub Desktop.
Calling QSYCHGPW via Python with Emoji
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