From e62bdea0feb52c63d33f12888b281edd3e6c23b3 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 29 Feb 2024 09:41:32 -0500 Subject: [PATCH] Move Re-driving requests from c code to python Move redriving requests from c layer to python layer Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 42 ++----------------------- pyracf/common/irrsmo00.py | 17 +++++++++- tests/common/test_irrsmo00_interface.py | 39 +++++++++++++++++------ 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index f752798..5186924 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -48,7 +48,6 @@ static PyObject *call_irrsmo00(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; } - PyObject * full_result; char work_area[1024]; unsigned char req_handle[64] = {0}; running_userid_t running_userid_struct = {running_userid_length, {0}}; @@ -87,41 +86,6 @@ static PyObject *call_irrsmo00(PyObject *self, PyObject *args, PyObject *kwargs) &result_len, result_buffer); - // Use a PyList Structure to accumulate "bytes" objects of result_buffers - full_result = PyList_New(1); - PyList_SetItem(full_result, 0, Py_BuildValue("y#", result_buffer, result_len)); - - if ((saf_rc == 8) && (racf_rc == 4000) && (racf_rsn < 100000000)){ - free(result_buffer); - result_len = racf_rsn; - result_buffer = malloc(result_len); - memset(result_buffer, 0, result_len); - - // Call IRRSMO64 Again with the appropriate buffer size - IRRSMO64( - work_area, - alet, - &saf_rc, - alet, - &racf_rc, - alet, - &racf_rsn, - num_parms, - fn, - irrsmo00_options, - request_xml_length, - request_xml, - req_handle, - running_userid_struct, - acee, - &result_len, - result_buffer); - - PyList_Append(full_result, Py_BuildValue("y#", result_buffer, result_len)); - } - - free(result_buffer); - // https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue // // According to the Python 3 C API documentation: @@ -159,8 +123,8 @@ static PyObject *call_irrsmo00(PyObject *self, PyObject *args, PyObject *kwargs) // Py_BuildValue() will return a Tuple. return Py_BuildValue( - "{s:O,s:[B,B,B]}", - "resultBuffers", full_result, + "{s:y#,s:[B,B,B]}", + "resultBuffer", result_buffer, result_len, "returnCodes", saf_rc, racf_rc, racf_rsn); } @@ -172,7 +136,7 @@ static char call_irrsmo00_docs[] = " irrsmo00_options: uint,\n" " running_userid: bytes,\n" " running_userid_length: uint,\n" - ") -> Dict{ resultBuffers: List[bytes], returnCodes: List[int,int,int] }:\n" + ") -> Dict{ resultBuffer: bytes, returnCodes: List[int,int,int] }:\n" "# Returns an XML result string and return and reason " "codes from the IRRSMO00 RACF Callable Service.\n"; diff --git a/pyracf/common/irrsmo00.py b/pyracf/common/irrsmo00.py index b8c7f78..e1e04d0 100644 --- a/pyracf/common/irrsmo00.py +++ b/pyracf/common/irrsmo00.py @@ -67,10 +67,25 @@ def call_racf( running_userid=running_userid, running_userid_len=len(running_userid), ) + if ( + (result["returnCodes"][0] == 8) + and (result["returnCodes"][1] == 4000) + and (result["returnCodes"][2] < 100000000) + ): + first_result_buffer = result["resultBuffer"] + result = call_irrsmo00( + request_xml=request_xml, + request_xml_len=len(request_xml), + result_buffer_size=result["returnCodes"][2], + irrsmo00_options=irrsmo00_options, + running_userid=running_userid, + running_userid_len=len(running_userid), + ) + result["resultBuffer"] = first_result_buffer + result["resultBuffer"] # Preserve raw result XML just in case we need to create a dump. # If the decoded result XML cannot be parsed with the XML parser, # a dump may need to be taken to aid in problem determination. - self.__raw_result_xml = b"".join(result["resultBuffers"]) + self.__raw_result_xml = result["resultBuffer"] # Replace any null bytes in the result XML with spaces. result_xml = self.__null_byte_fix(self.__raw_result_xml) # 'irrsmo00.c' returns a raw unmodified bytes object containing a copy diff --git a/tests/common/test_irrsmo00_interface.py b/tests/common/test_irrsmo00_interface.py index bde7ed2..7a579e2 100644 --- a/tests/common/test_irrsmo00_interface.py +++ b/tests/common/test_irrsmo00_interface.py @@ -57,7 +57,7 @@ def test_irrsmo00_null_byte_fix( ]) # fmt: on call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [xml_containing_null_bytes], + "resultBuffer": xml_containing_null_bytes, "returnCodes": [0, 0, 0], } self.assertEqual( @@ -71,7 +71,7 @@ def test_irrsmo00_empty_result( ): # Simulate failure due to incomplete 'IRR.IRRSMO00.PRECHECK' setup call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [bytes([0 for i in range(256)])], + "resultBuffer": bytes([0 for i in range(256)]), "returnCodes": [8, 200, 16], } self.assertEqual(self.irrsmo00.call_racf(b""), [8, 200, 16]) @@ -82,20 +82,39 @@ def test_irrsmo00_result_buffer_full_failure( ): # Simulate scenario where result buffer is too small. call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml[:32]], - "returnCodes": [8, 4000, 32], + "resultBuffer": self.good_xml[:32], + "returnCodes": [8, 4000, 100000000], } self.assertEqual( self.irrsmo00.call_racf(b""), self.good_xml.decode("cp1047")[:32] ) + # def test_irrsmo00_result_buffer_full_redrive( + # self, + # call_irrsmo00_wrapper_mock: Mock, + # ): + # # Simulate scenario where result buffer is too small. + # call_irrsmo00_wrapper_mock.side_effect = [ + # { + # "resultBuffer": self.good_xml[:32], + # "returnCodes": [8, 4000, 32], + # }, + # { + # "resultBuffer": self.good_xml[32:], + # "returnCodes": [0, 0, 0], + # }, + # ] + # self.assertEqual( + # self.irrsmo00.call_racf(b""), self.good_xml.decode("cp1047") + # ) + def test_irrsmo00_result_buffer_full_success( self, call_irrsmo00_wrapper_mock: Mock, ): # Simulate scenario where result buffer is exactly the right size. call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml[: self.good_xml_null_terminator_index]], + "resultBuffer": self.good_xml[: self.good_xml_null_terminator_index], "returnCodes": [0, 0, 0], } self.assertEqual( @@ -105,7 +124,7 @@ def test_irrsmo00_result_buffer_full_success( def test_irrsmo00_normal_result(self, call_irrsmo00_wrapper_mock: Mock): call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml], + "resultBuffer": self.good_xml, "returnCodes": [0, 0, 0], } self.assertEqual( @@ -118,7 +137,7 @@ def test_irrsmo00_normal_result(self, call_irrsmo00_wrapper_mock: Mock): # ============================================================================ def test_irrsmo00_minimum_arguments(self, call_irrsmo00_wrapper_mock: Mock): call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml], + "resultBuffer": self.good_xml, "returnCodes": [0, 0, 0], } self.irrsmo00.call_racf(b"some bytes") @@ -133,7 +152,7 @@ def test_irrsmo00_minimum_arguments(self, call_irrsmo00_wrapper_mock: Mock): def test_irrsmo00_with_precheck_set_to_true(self, call_irrsmo00_wrapper_mock: Mock): call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml], + "resultBuffer": self.good_xml, "returnCodes": [0, 0, 0], } self.irrsmo00.call_racf(b"some bytes", precheck=True) @@ -148,7 +167,7 @@ def test_irrsmo00_with_precheck_set_to_true(self, call_irrsmo00_wrapper_mock: Mo def test_irrsmo00_with_run_as_userid_set(self, call_irrsmo00_wrapper_mock: Mock): call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml], + "resultBuffer": self.good_xml, "returnCodes": [0, 0, 0], } self.irrsmo00.call_racf(b"some bytes", run_as_userid="KRABS") @@ -165,7 +184,7 @@ def test_irrsmo00_with_custom_result_buffer_size( self, call_irrsmo00_wrapper_mock: Mock ): call_irrsmo00_wrapper_mock.return_value = { - "resultBuffers": [self.good_xml], + "resultBuffer": self.good_xml, "returnCodes": [0, 0, 0], } irrsmo00 = IRRSMO00(result_buffer_size=32768)