IRRSEQ00 also known as R_ADMIN can be used by an application to issue RACF commands, or extract information from RACF. It is used by the Python interface to RACF pysear.
Using this was not difficult – but has it challenges (including a designed storage leak!).
I also had a side visit into That’s strange – the compile worked.
Challenges
The documentation explains how to search through the profiles.
The notes say
When using extract-next to return all general resource profiles for a given class, all the discrete profiles are returned, followed by the generic profiles. An output flag indicates if the returned profile is generic. A flag can be specified in the parameter list to request only the generic profiles in a given class. If only the discrete profiles are desired, check the output flag indicating whether the returned profile is generic. If it is, ignore the entry and terminate your extract-next processing.
- To search for all of the profiles, specify a single blank as the name, and use the extract_next value.
- There are discrete and generic profiles. If you specify flag bit 0x20000000 For extract-next requests: return the next alphabetic generic profile. This will not retrieve discrete profiles. If you do not specify this bit, you get all profiles.
This is where it gets hard.
- The output is returned in a buffer allocated by IRRSEQ00. This is the same format as the control block used to specify parameters. After a successful request, it will contain the profile, and may return all of the segments (such as a userid’s TSO segment depending on the option specified).
- Extract the information you are interested in.
- Use this data as input to the irrseq00 call. I set used pParms = buffer;
- After the next IRRSEQ00 request FREE THE STORAGE pointed to by pParms.
- Use the data returned to you in the new buffer.
- Loop
The problems with this are
The documentation says
The output storage is obtained in the subpool specified by the caller in the Out_message_subpool parameter. It is the responsibility of the caller to free this storage.
I do not know how to issued a FREEMAIN/STORAGE request from a C program! Because you cannot free the z/OS storage from C, you effectively get a storage leak!
I expect the developers did not think of this problem. Other RACF calls get the back in the same control block, and you get a return code if the control block is too small.
I solved this by having some assembler code in my C program see Putting assembler code inside a C program.
My program
Declare constants
#pragma linkage(IRRSEQ00 ,OS)
// Include standard libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
int main( int argc, char *argv??(??))
{
// this structure taken from pysear is the parameter block
typedef struct {
char eyecatcher[4]; // 'PXTR'
uint32_t result_buffer_length; // result buffer length
uint8_t subpool; // subpool of result buffer
uint8_t version; // parameter list version
uint8_t reserved_1[2]; // reserved
char class_name[8]; // class name - upper case, blank pad
uint32_t profile_name_length; // length of profile name
char reserved_2[2]; // reserved
char volume[6]; // volume (for data set extract)
char reserved_3[4]; // reserved
uint32_t flags; // see flag constants below
uint32_t segment_count; // number of segments
char reserved_4[16]; // reserved
// start of extracted data
char data[1];
} generic_extract_parms_results_t;
// Note: This structure is used for both input & output.
Set up the irrseq00 parameters
I want to find all profiles for class ACCTNUM. You specify a starting profile of one blank, and use the get next request.
char work_area[1024];
int rc;
long SAF_RC,RACF_RC,RACF_RS;
long ALET = 0;
char Function_code = 0x20; // Extract next general resource profile
// RACF is ignored for problem state
char RACF_userid[9];
char * ACEE_ptr = 0;
RACF_userid[0]=0; // set length to 0
char Out_message_subpool = 1;
char * Out_message_string; // returned by program
generic_extract_parms_results_t parms;
memset(&parms,0,sizeof(parms));
memcpy(&parms.eyecatcher,"PXTR",4);
parms.version = 0;
memcpy(&parms.class_name,"ACCTNUM ",8);
parms.profile_name_length = 1;
parms.data[0] =' ';
char *pParms = (char *) & parms;
Function_code = 0x20; // get next resource
int i;
generic_extract_parms_results_t * pGEP;
Loop round getting the data
I knew there were only 3 discrete profiles and one generic (with a “*” in it) .
For extract-next requests, SAF_RC = 4, RACFRC = 4 and RACFRS = 4, means. there are no more profiles that the caller is authorised to extract.
for (i=0;i < 6;i++)
{
parms.flags = 0x04000000; // get next + base only
rc=IRRSEQ00(
&work_area,
&ALET , &SAF_RC,
&ALET , &RACF_RC,
&ALET , &RACF_RS,
&Function_code,
pParms,
&RACF_userid,
&ACEE_ptr,
&Out_message_subpool,
&Out_message_string
);
pParms = Out_message_string;
pGEP = (generic_extract_parms_results_t *) pParms;
if (RACF_RC == 0 )
{
printf("return code SAF %d RACF %d RS %d %2.2x %8.8x %*.*s \n",
SAF_RC,RACF_RC,RACF_RS, Function_code, pGEP-> flags,
pGEP->profile_name_length,
pGEP-> profile_name_length, pGEP->data);
}
else
{
printf("return code SAF %d RACF %d RS %d \n",
SAF_RC,RACF_RC,RACF_RS );
break;
}
}
return 8;
}
The results were
return code SAF 0 RACF 0 RS 0 20 00000000 ACCT#
return code SAF 0 RACF 0 RS 0 20 00000000 IZUACCT
return code SAF 0 RACF 0 RS 0 20 10000000 TESTGEN*
return code SAF 4 RACF 4 RS 4
For TESTGEN* the flag is 0x10 which is On output: indicates that the profile returned by RACF is generic. When using extract-next to cycle through profiles, the caller should not alter this bit. For the others this bit is off, meaning the profiles are discrete.