IBM Security Z Security

Expand all | Collapse all

Programatic Maintenance of Group Connections

  • 1.  Programatic Maintenance of Group Connections

    Posted Thu September 10, 2020 03:29 PM
    I am trying to programmatically maintain the connections to a large number of groups based on data in the user id's CSDATA segment.  On the user id's CSDATA segment I have 2 fields called $ROLEKEY and $AU.    Depending on the values in those fields I want to CONNECT or REMOVE the user from the group.

    For example:
    If the user is in $ROLEKEY=DSTI and $AU=045982 then they should be connected to group RADM0001
    If the user is in $ROLEKEY=DICR and $AU=163908 then they should be connected to group RADM0002

    I have probably 100 combinations of the above to maintain.

    If figure its a 2 pass query, but with so many combinations to maintain, I could not figure out an efficient method to set it up.



    ------------------------------
    Linnea Sullivan
    ------------------------------


  • 2.  RE: Programatic Maintenance of Group Connections

    Posted Fri September 11, 2020 03:15 AM
    Edited by Rob van Hoboken Fri September 11, 2020 05:00 AM

    Hi Linnea
    This is how you list the users that have a specific rolekey in a department.  Simply select their CSDATA segments using a comparison on both fields in a single SELECT, this applies both tests as a AND condition:
    newlist type=racf name=role0001
      select class=user segment=csdata $ROLEKEY=DSTI $AU=045982
      sortlist profile(8,"User ID") :name custom_data
    The :NAME field finds the corresponding BASE segment, picks up the name, CUSTOM_DATA formats all the CSKEY/CSDATA/CSFLAG values as an illustration.

    Finding all users that are NOT connected to a group is also easy.  You simply select the BASE segment for all user IDs and exclude the ones that have the required CONNECT already:
    newlist type=racf name=conn0001
      select class=user segment=base
      exclude cggrpnm=RADM0001
      sortlist profile(8,"User ID") name connects

    You can also convert the EXCLUDE into a NOT( ) clause like so:
    newlist type=racf name=conn0001
      select class=user segment=base not(cggrpnm=RADM0001)
      sortlist profile(8,"User ID") name connects


    But these reports find thousands of user IDs.  We must combine the two NEWLIST, so the 2nd NEWLIST only works on profiles that have been selected by the 1st.  CARLa offers the PROFLIST keyword to link the results of two NEWLIST:

    newlist type=racf name=role0001 outlim=0
      select class=user segment=csdata $ROLEKEY=DSTI $AU=045982
      sortlist profile(8,"User ID") :name custom_data
    newlist type=racf name=conn0001 proflist=role0001
      select class=user segment=base
      exclude cggrpnm=RADM0001
      sortlist profile(8,"User ID") name connects


    OUTLIM=0 suppresses output of the 1st NEWLIST, so the results are only used internally for PROFLIST processing.  PROFLIST=ROLE0001 in the 2nd NEWLIST restricts the selection to profiles that were selected in the NEWLIST referenced, even when that NEWLIST works on different segments.
    Internally the two NEWLISTs work concurrently, each selecting profiles (segments really) that match the SELECT command.  The 2nd NEWLIST selects thousands and thousands of USERs, so you want to make the SELECT commands as precise as possible.  After the whole database has been read, the results of the 2 NEWLISTs are combined, only profiles (by key) that were selected in both are processed for output.

    Now, you probably want to generate RACF commands for the user IDs that are not yet connected to the right group, so this is how:

    newlist type=racf name=role0001 outlim=0
      select class=user segment=csdata $ROLEKEY=DSTI $AU=045982
      sortlist profile(8,"User ID") :name custom_data
    newlist type=racf name=conn0001 proflist=role0001 nopage dd=ckrcmd
      select class=user segment=base
      exclude cggrpnm=RADM0001
      sortlist "CONNECT" profile(8) "GROUP(RADM0001)"


    You might also want to remove CONNECTs to this group, if the user does not have the right ROLEKEY and AU.  This is where you can use NOTPROFLIST:

    newlist type=racf name=role0001 outlim=0
      select class=user segment=csdata $ROLEKEY=DSTI $AU=045982
      sortlist profile(8,"User ID") :name custom_data
    newlist type=racf name=rem0001 notproflist=role0001 nopage dd=ckrcmd
      select class=user segment=basecggrpnm=RADM0001
      sortlist "REMOVE" profile(8) "GROUP(RADM0001)"


    By the way, some years ago I wrote a  CARLa script to  implement role based administration for RACF groups, using CSDATA fields.  The whole process, including documentation and source code, can be found in the zSecure Wiki.  Or better, navigate to the Wiki section of the Knowledge Center and find the Chapter about RBAC concepts.


    ------------------------------
    Rob van Hoboken
    ------------------------------


  • 3.  RE: Programatic Maintenance of Group Connections

    Posted Fri September 11, 2020 06:03 AM
    Edited by Rob van Hoboken Fri September 11, 2020 06:04 AM

    Some more information about CSDATA segment fields. 

    Starting with z/OS 2.4, Custom Fields are also supported on DATASET and General Resource profiles.  Before that, they were used only on USER and GROUP.

    The RACF native fields are:
    CSCNT - the number of fields defined in the segment
    CSKEY - the name of the field
    CSTYPE - the type (CHAR,FLAG, HEX, NUM)
    CSVALUE  - the value stored

    CARLa adds a combined field CUSTOM_DATA that includes CSKEY and CSVALUE,  and can be used in SELECT, DEFINE SUBSELECT and SORTLIST/DISPLAY commands.  Listing all profiles with any CDATA fields (the segment selection is added for completeness):

    newlist type=racf
      select segment=csdata cscnt>0
      sortlist class key custom_data

    The field names from  CSKEY can also be used as normal CARLa fields, as long as you only use CSDATA segments.  This would find users with a $AU field:

    newlist type=racf
      select segment=csdata exists($AU)
      sortlist class key custom_data

    Listing only the $AU field:

    newlist type=racf
      select segment=csdata exists($AU)
      sortlist class key $AU

    Selecting only $AU values starting with 1234:

    newlist type=racf
      select segment=csdata $AU=1234*
      sortlist class key $AU

    Using a profile list from the RA panels, you enter SE (segments) in front of a profile and select the CSDATA segment.  Or you type a / in front of the Show segments checkbox of the profile search panel.

    Currently it is impossible to add a Custom Field value directly into a report from another segment type or newlist type.  This can be achieved for USER and GROUP profiles using an external (DEFTYPE) file containing the profile key and the CSVALUE values of one CSKEY, and using DEFTYPE lookup:

    //STEP1 EXEC C2RC
    //$AU DD DISP=(,PASS),DSN=&&AU
    //SYSIN DD *
    alloc type=racf active
    newlist type=racf nopage dd=$AU
      select class=(user,group) segment=csdata cskey=$au
      sortlist profile(8) $au
    //STEP2 EXEC C2RC
    //$AU DD DISP=OLD,DSN=&&AU
    //SYSIN DD *
    alloc type=racf active
    deftype type=$au
    alloc type=$au dd=$au
    define type=$au profile(8) as substr(record,1,8)
    define type=$au $au(0) as substr(record,10)
    newlist type=racf
      select class=dataset exists(userid:$au.profile.$au)
      sortlist profile acl acl:$au.profile.$au

    Be aware of the limitation of lookup, select, repeated fields and compound fields.

    ------------------------------
    Rob van Hoboken
    ------------------------------


  • 4.  RE: Programatic Maintenance of Group Connections

    Posted Fri September 11, 2020 07:13 AM
    You stated that you might have 100 role administration groups, now if you added the $ROLEKEY and $AU for each group as Custom Fields in the CSDATA segment of the group, you could use these as a table, and use the table to generate your CARLa dynamically:

    //STEP1 EXEC C2RC
    //CKR2PASS DD DISP=(,PASS),DSN=&&CKR2PASS
    //SYSIN DD *
    alloc type=racf active
    newlist type=racf nopage dd=ckr2pass
      define group(8) as profile
      define var(4) as substr(profile,5,4) /* unique suffix */
      select class=group segment=csdata cskey=$rolekey cskey=$au
      sortlist,
       'newlist type=racf name=role' | var 'outlim=0',
     / ' select class=user segment=csdata',
         '$ROLEKEY=' | $rolekey(0) '$AU=' | $au(0),
     / ' sortlist profile(8,"User ID")',
     / 'newlist type=racf nopage dd=ckrcmd',
         'name=conn' | var 'proflist=role' | var,
     / ' select class=user segment=base',
     / ' exclude cggrpnm=' | group,
     / ' sortlist "CONNECT" profile(8) "GROUP(' | group | ')"',
     / 'newlist type=racf nopage dd=ckrcmd',
         'name=rem' | var 'notproflist=role' | var,
     / ' select class=user segment=base cggrpnm=' | group,
     / ' sortlist "REMOVE" profile(8) "GROUP(' | group | ')"'
    //STEP2 EXEC C2RC
    //CKR2PASS DD DISP=OLD,DSN=&&CKR2PASS
    //CKRCMD DD SYSOUT=*
    //SYSIN DD *
    alloc type=racf active
    alloc type=ckrcmd dd=ckrcmd
    include dd=ckr2pass
    //


    Step1 finds all groups that have a $ROLEKEY and a $AU field, for each group found it generates the required 3 NEWLISTs. 
    It needs a unique NAME= for each NEWLIST, so we extract the sequence number (or any other field you might imagine) into a defined field VAR.
    Next we use the apostrophe to build CARLa commands, within these commands we use the quote for literals needed in the 2nd step.

    ------------------------------
    Rob van Hoboken
    ------------------------------