IBM Security Z Security

Security for Z

Join this online user group to communicate across Z Security product users and IBM experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.

 View Only
Expand all | Collapse all

CARLA to create list of > READ dataset permissions for select users

  • 1.  CARLA to create list of > READ dataset permissions for select users

    Posted 24 days ago

    Hi team,

    I'm trying to create a list of dataset profile permits where users matching a specific logon ID format have greater than READ access either directly or via a group. This is my current code, it nearly works but only returns profiles where matching IDs have direct permits. I can't seem to figure out a way to get it to show permits to the selected users that occur via groups as well. Can you offer any suggestions?

    NEWLIST type=racf retain
    DEFINE #stripacl(explode) subselect acl(access=(alter,update,control),
      user=(,
          D%1*,,
          D%2*,,
          D%3*,,
          D%4*,,
          D%5*,,
          D%6*,,
          D%7*,,
          D%8*,,
          D%9*,,
          D%0*,,
          L%1*,,
          L%2*,,
          L%3*,,
          L%4*,,
          L%5*,,
          L%6*,,
          L%7*,,
          L%8*,,
          L%9*,,
          L%0*,
         ))
    SELECT c=dataset segment=base,
      acl(access=(alter,update,control),
      id=(,
          D%1*,,
          D%2*,,
          D%3*,,
          D%4*,,
          D%5*,,
          D%6*,,
          D%7*,,
          D%8*,,
          D%9*,,
          D%0*,,
          L%1*,,
          L%2*,,
          L%3*,,
          L%4*,,
          L%5*,,
          L%6*,,
          L%7*,,
          L%8*,,
          L%9*,,
          L%0*,
          ))
    SORTLIST  class key #stripacl



    ------------------------------
    Nathan Shrive
    ------------------------------


  • 2.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago

    Hey Nathan.

    The thing about NEWLIST TYPE=RACF, it selects profiles (only) on the fields that are available in the profile.  That is due to the place where the SELECT command is processed, (almost) directly in the profile reading engine.  It sees profiles in the physical order of profiles in the database.  So when SELECT sees a DATASET profile, it does not know if the USERID field in the profile refers to a user ID or to a group name.  And worse, if the USERID field contains a group name, it has no clue about the user IDs connected to the group.

    Consequently, the values you can use in the SELECT USERID=xxx command must be exactly the values that are specified in the profile.  The ACL( ) compound field is, essentially, syntax sugar to make it easier to specify a combination of the value you expect in the USERID field and in the ACCESS field for a single ACL entry.  It does not support functions like EXPLODE and RESOLVE.  This is reflected by the field name ID in SELECT ACL(ID=(D%1*,D%2*,D%3*)) that you used.  This variant of ACL() does not know USER= or GROUP=.

    For many reports I reach out to NEWLIST TYPE=RACF_ACCESS, it makes the ID and ACCESS field easier to specify, and it is processed after all the profiles have been read, so lookup from the ID field is possible in the SELECT command, which it is not (really) in NEWLIST TYPE=RACF.  However, NEWLIST TYPE=RACF_ACCESS does not support EXPLODE and RESOLVE either.  If only there was an Idea that you could vote for...

    Nope, you are stuck with the old fashioned two-pass CARLa.  Pass 1 should collect all groups that have one of your suspect users connected, and write these groups into a flat file.  Pass 2 should check the values in USERID, and compare these either to the list of patterns, or to the names in the flat file.

    Or your pass 1 could write one file with BOTH the group names containing the suspect users AND the suspect user ids too.  This is what the batch job would look like.

    // EXEC C2RC
    //CKR2PASS DD DISP=(,PASS),DSN=&&IDS
    //SYSIN    DD *
    newlist type=racf nopage dd=ckr2pass
      select class=group userid=(,
          D%1*,,
          D%2*,,
          D%3*,,
          D%4*,,
          D%5*,,
          D%6*,,
          D%7*,,
          D%8*,,
          D%9*,,
          D%0*,,
          L%1*,,
          L%2*,,
          L%3*,,
          L%4*,,
          L%5*,,
          L%6*,,
          L%7*,,
          L%8*,,
          L%9*,,
          L%0*,
          )
      sortlist profile(8)
    newlist type=racf nopage dd=ckr2pass
      define masklist as profile
      select class=user seg=base masklist=(,
          D%1*,,
          D%2*,,
          D%3*,,
          D%4*,,
          D%5*,,
          D%6*,,
          D%7*,,
          D%8*,,
          D%9*,,
          D%0*,,
          L%1*,,
          L%2*,,
          L%3*,,
          L%4*,,
          L%5*,,
          L%6*,,
          L%7*,,
          L%8*,,
          L%9*,,
          L%0*,
          )
      sortlist profile(8)
    // EXEC C2RC
    //IDLIST    DD DISP=OLD,DSN=&&IDS
    //SYSIN    DD *
    alloc type=racf active
    deftype type=$ids
    alloc type=$ids dd=IDLIST
    define type=$ids id(8) as substr(record,1,8)

    NEWLIST type=racf retain
    DEFINE #stripacl(explode) subselect acl(access=(alter,update,control) user:$ids.id.record<>' ')
    SELECT class=dataset acl(access=(alter,update,control) id:$ids.id.record<>' ')
    sortlist profile #stripacl
    //

    Typed from memory, while logged off, not tested.



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



  • 3.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago

    Hi Rob, thanks very much for your detailed response! Unfortunately, when I ran the code I got this:

    PARM:  I DD=CKRSPROF
     
     
    Include CKRSPROF subsys EA1917.EA1917GP.JOB01024.D0000103.?
         1 |PRINT DD=CKREPORT
         2 |IMBED MEMBER=CKRXDEF1 NOLIST
    End of  CKRSPROF (include level 1)
     
    Input:  SYSIN    subsys EA1917.EA1917GP.JOB01024.D0000104.?
     
         1 |
         2 |alloc type=racf active
         3 |deftype type=$ids
         4 |alloc type=$ids dd=IDLIST
         5 |define type=$ids id(8) as substr(record,1,8)
         6 |NEWLIST type=racf retain
         7 |DEFINE #stripacl(explode) subselect acl(access=(alter,update,control),
         8 |user:$ids.id.record<>' ')
         9 |SELECT class=dataset acl(access=(alter,update,control),
        10 | id:$ids.id.record<>' ')
    CKR1159 12 Lookup not allowed in subselect clause in SELECT statement - before word "$ids.id.record<>" at SYSIN line 10
        11 |sortlist profile #stripacl
        12 |



    ------------------------------
    Nathan Shrive
    ------------------------------



  • 4.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago

    While I'm at it, I have another complicated query, looking to return a list of user ID connections to groups that grant > READ access to datasets and have a revoke date on the connection. The following 2 pass code appeared to nearly work, but I ended up with some entries in the report that don't have in scope group connections. I think this was because the subselect and select statements do not match but I couldn't figure out what it needs to be.

    //CKRCARLA EXEC PGM=CKRCARLA,REGION=64M,PARM='I DD=CKRSPROF'
    //STEPLIB  DD DISP=SHR,DSN=SYS1.CONSUL.SCKRLOAD
    //CKRCARLA DD DISP=SHR,DSN=SYS1.CONSUL.SCKRCARL
    //SYSPRINT DD SYSOUT=*
    //CKREPORT DD DISP=(MOD,CATLG),DSN=*.DELFILES.REPORT,
    //            DCB=(RECFM=VB,LRECL=1200),SPACE=(TRK,(30,30),RLSE)
    //CKRCMD   DD SYSOUT=*
    //CKR2PASS DD DISP=(,PASS),DSN=&&IDS
    //CKRCMD03 DD SYSOUT=*
    //CKRSPROF DD DATA,DLM='\/'
    PRINT DD=CKREPORT
    IMBED MEMBER=CKRXDEF1 NOLIST
    \/
    //SYSIN    DD DATA,DLM='\/'
    NEWLIST  TYPE=RACF_ACCESS NODUP NOPAGE dd=ckr2pass
    SELECT CLASS=DATASET ACCESS>READ MISSING(ID:DFLTGRP)
    EXCLUDE ID=(EXC02999)
    SORTLIST,
    ID
     
    \/  <- End of SYSIN delimiter
    //CKRCARLA EXEC PGM=CKRCARLA,REGION=64M,PARM='I DD=CKRSPROF'
    //STEPLIB  DD DISP=SHR,DSN=SYS1.CONSUL.SCKRLOAD
    //CKRCARLA DD DISP=SHR,DSN=SYS1.CONSUL.SCKRCARL
    //IDLIST    DD DISP=OLD,DSN=&&IDS
    //SYSPRINT DD SYSOUT=*
    //CKREPORT DD DISP=(MOD,CATLG),DSN=*.DELFILES.REPORT,
    //            DCB=(RECFM=VB,LRECL=1200),SPACE=(TRK,(30,30),RLSE)
    //CKRCMD   DD SYSOUT=*
    //CKR2PASS DD SYSOUT=*
    //CKRCMD03 DD SYSOUT=*
    //CKRSPROF DD DATA,DLM='\/'
    PRINT DD=CKREPORT
    IMBED MEMBER=CKRXDEF1 NOLIST
    \/
    //SYSIN    DD DATA,DLM='\/'
     
    alloc type=racf active
    deftype type=$ids
    alloc type=$ids dd=IDLIST
    define type=$ids id(8) as substr(record,1,8)
     
    NEWLIST  HEADER=CSVT RETAIN,
     TT="RACF GROUP CONNECTINS"
    DEF #STRIPCON subselect CONNECTS(GRPREVOKEDT<>NEVER ,
    group:$ids.id.record<>' ')
    SELECT S=BASE C=USER cgrevkdt<>NEVER AND cggrpnm:$ids.id.record<>' '
    SORTLIST,
    :RUN.SYSTEM("LPAR"),
    KEY,
    #STRIPCON



    ------------------------------
    Nathan Shrive
    ------------------------------



  • 5.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago
    Edited by Rob van Hoboken 23 days ago

    RACF_ACCESS adds the QUALOWN access level, in case a group matches the HLQ of the data set, and this level is more powerful than READ, so all HLQ groups will be included in your IDLIST file.  I should have mentioned, I guess, my standard EXCLUDE for RACF_ACCESS contains parts of:

    EXCLUDE ID=(-*)    /* do not show UACC as an access list entry */
    EXCLUDE ACCESS=QUALOWN /* HLQ groups that aren't included in ACL */

    Also, I've come to enjoy the smaller amount of JCL in my jobs by using C2RC instead of the whole explicit JCL bit.  But this gives me junk at the top of SYSPRINT, so I now use

    // JCLLIB ORDER=(prefix.CKRPARM,prefix.SCKRPROC) 
    // EXEC C2RC,PARM.C2RC='PRINT DD=CKREPORT; I M=C2RXDEF1 NOLIST'

    It is pretty amazing and scary to see the JCL generated by the SUB command in zSecure ISPF cluttering up everyone's JCL libraries.  I thought up the whole skeleton based submit with CKRSPROF dd etc more than 33 years ago as a quick way to answer customer demands to submit jobs containing CARLa code without having to write JCL.  The earliest change log entry in CKRESUB dates from 1993, which means the base code must have existed earlier, just don't remember if it was 1990, 1991.  Just goes to show that quick-fix solutions can have an unexpected lifespan.

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



  • 6.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago

    Awkward.  There is no real reason why a DEFTYPE lookup should be denied, except complexity in the (assembler) code and lack of time.  Anyway.  You can change the SELECT command to

    SELECT class=dataset access=(alter,update,control) userid:$ids.id.record>' '

    though this does not check on the combination of suspect user IDs and excessive access within each ACL entry.  As a result, profiles will be selected where a suspect user ID only has READ, though those lines will be suppressed in output by the output SUBSELECT.



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



  • 7.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago

    Thanks Rob,

    Unfortunately when I updated the select statement to this:

    SELECT class=dataset access=(alter,update,control),
     userid:$ids.id.record<>' '

    I got this message:

    CKR1036 12 Field "ACCESS" is only supported for SUBSELECT clauses at SYSIN line 9



    ------------------------------
    Nathan Shrive
    ------------------------------



  • 8.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 23 days ago

    Yes, I'm logged on to TSO now and can check the syntax.  The standard field for ACCESS levels in DATASET profiles is USERACS, together in a repeated list with USERID, so the select should have been 

    SELECT class=dataset useracs=(alter,update,control),
     userid:$ids.id.record<>' '

    The ACL( ) compound field was designed to make the syntax easier, so SELECT ACL(ID=xxx) instead of USERID (which also selects groups), and SELECT ACL(ACCESS>READ) instead of USERACS>READ.



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



  • 9.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 22 days ago

    The syntax of the limitedACLsubselectclause was taken from the normal syntax from DEFINE ... SUBSELECT ACL(), with the restriction that USER and GROUP cannot be used, because this information is not known at the type the selection is processed. That syntax was based on the sub-fields of this combined field on output.

    The ACL (CARLa) field combines information from both the unconditional and conditional access control lists. 

    For the DATASET class, the unconditional access control list consists of the repeated (RACF database template) fields USERID, USERACS, and ACSCNT.
    The conditional access control list consists of the repeated fields PROGRAM, USER2ACS, PROGACS, PACSCNT, and ACL2VAR.

    Regards,
    Jeroen



    ------------------------------
    Jeroen Tiggelman
    IBM - Software Development Manager IBM zSecure
    Delft
    ------------------------------



  • 10.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 22 days ago

    Thanks. It ran, but unfortunately I'm still getting some undesired results where dataset profiles are appearing in the report that have no matching ID entries. I think the issue is those dataset profiles have an ACL entry that matches the criteria useracs=(alter,update,control), and a different ACL entry that matches userid:$ids.id.record<>' ' so the profile meets the selection criteria. 

    In the training material we got from Tom a year or so ago it has this line:

    'Alternatively, for SELECT ACL, you can use ACL(ID=<id> ACCESS=<access>) to enforce that the ID and ACCESS tested belong to the same ACL entry'</access></id>

    So I assume that means if you don't use the subselect syntax it looks across multiple ACL entries? I think thats also the same problem I am having with the other revoke group connections query.



    ------------------------------
    Nathan Shrive
    ------------------------------



  • 11.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 22 days ago

    You are right, Nathan.  As I wrote before

    You can change the SELECT command to

    SELECT class=dataset access=(alter,update,control) userid:$ids.id.record>' '

    though this does not check on the combination of suspect user IDs and excessive access within each ACL entry.  As a result, profiles will be selected where a suspect user ID only has READ, though those lines will be suppressed in output by the output SUBSELECT.

    A SELECT command like below selects users where any of the connect groups has a revoke date, and where any of the groups are in the $IDS list.  It does not test if these tests apply to the same connect group entry.

    SELECT S=BASE C=USER cgrevkdt<>NEVER AND cggrpnm:$ids.id.record<>' '

    If you want to overcome the issues with repeat groups, SUBSELECT and the SELECT ACL( ) limitations (that Jeroen mentioned as limitedACLsubselectclause), look at RACF_ACCESS.   This converts a list of (standard) permits into individual objects (lines), and same with the list of CONNECTS.  Furthermore, it supports lookup of attributes (object and implicit lookup) in SELECT.  Your SELECT command would translate to

    newlist type=racf_access
      SELECT CLASS=GROUP :cgrevkdt<>NEVER profile:$ids.id.record<>' '

    In this select, the GROUP is selected, the user ID is available as ID.  ACCESS contains the connect authority.  The connect attributes are available as implicit lookup, user's attribute can be used with ID lookup, like id:special.



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



  • 12.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 22 days ago

    Hi Nathan,

    Yes, the point of the ACL() construction is that the whole clause is evaluated against each entry in the repeat group, while if you select on the individual repeated fields each field is scanned separately for the occurrence of one of the specified values, and the "found" or "not found" results are then ANDed (as just putting clauses behind each other is an implicit AND).

    @Rob: "limitedACLsubselectclause" is how we have always documented this since I built the function back in 2001: https://www.ibm.com/docs/en/szs/3.1.0?topic=SS2RWS_3.1.0/carla_lang/carla_cmnd_lang_select_srch_prof_name.htm#carla_cmnd_lang_select_srch_prof_name__selacl

    Regards,



    ------------------------------
    Jeroen Tiggelman
    IBM - Software Development Manager IBM zSecure
    Delft
    ------------------------------



  • 13.  RE: CARLA to create list of > READ dataset permissions for select users

    Posted 5 days ago

    Thanks Jeroen and Rob.

    I was a bit slow on the up take but I think I finally understand what you meant. I need to pick SUBSELECT or RACF_ACCESS not try to do them both.

    I was able to get both my queries working, the only sacrifice I had to make was not resolving to the user in the Personal User with > Update access report which wasn't really necessary anyway. 

    Personal User with > Update access report

    Pass 1:

    newlist type=racf_access nopage dd=ckr2pass
      select class=group id=(,
          D%1*,,
          D%2*,,
          D%3*,,
          D%4*,,
          D%5*,,
          D%6*,,
          D%7*,,
          D%8*,,
          D%9*,,
          D%0*,,
          L%1*,,
          L%2*,,
          L%3*,,
          L%4*,,
          L%5*,,
          L%6*,,
          L%7*,,
          L%8*,,
          L%9*,,
          L%0*,
          ),
          missing(:cgrevkdt)
      sortlist profile(8)
    newlist type=racf nopage dd=ckr2pass
      define masklist as profile
      select class=user seg=base masklist=(,
          D%1*,,
          D%2*,,
          D%3*,,
          D%4*,,
          D%5*,,
          D%6*,,
          D%7*,,
          D%8*,,
          D%9*,,
          D%0*,,
          L%1*,,
          L%2*,,
          L%3*,,
          L%4*,,
          L%5*,,
          L%6*,,
          L%7*,,
          L%8*,,
          L%9*,,
          L%0*,
          )
      sortlist profile(8)

    Pass 2:

    alloc type=racf active
    deftype type=$ids
    alloc type=$ids dd=IDLIST
    define type=$ids id(8) as substr(record,1,8)
    define type=RACF_ACCESS  hlq as word(profile,1,".")
    NEWLIST type=racf_access retain pl=0 header=csvt
    SELECT class=dataset access=(alter,update,control),
     id:$ids.id.record<>' ' missing(hlq:dfltgrp)
    EXCLUDE profile=(,
          %%S0*.**,
          )
    sortlist profile id access id:name

    Connect Groups Granting Update Access in an invalid way

    Pass 1:

    NEWLIST  TYPE=RACF_ACCESS NODUP NOPAGE dd=ckr2pass
    SELECT CLASS=DATASET ACCESS>READ MISSING(ID:DFLTGRP)
    EXCLUDE ACCESS=QUALOWN
    SORTLIST,
    ID

    Pass 2:

    alloc type=racf active
    deftype type=$ids
    alloc type=$ids dd=IDLIST
    define type=$ids id(8) as substr(record,1,8)
     
    NEWLIST TYPE=RACF_ACCESS  HEADER=CSVT RETAIN,
     TT="RACF GROUP CONNECTINS"
    SELECT CLASS=GROUP (:cgrevkdt<>NEVER profile:$ids.id.record<>' ',
     :cgrevkdt>=TODAY) OR ID=(TMP*,TEMP*) profile:$ids.id.record<>' ' ,
    :cgrevkdt>TODAY+2
     EXCLUDE ID=(Z%%SA%,Z%%SB%) or PROFILE(EXC0*,SER0*)
    SORTLIST,
    :RUN.SYSTEM("LPAR"),
    PROFILE ID :cgrevkdt



    ------------------------------
    Nathan Shrive
    ------------------------------