IBM Security Z Security

 View Only

 Check if a user exists with CARLA

Marco Egli's profile image
Marco Egli posted Wed April 30, 2025 04:53 AM

Hello

I'm seeking for input as I'm running out of possible ideas how to generate commands (most probably with CKR2PASS).

The objective is to generate (IDCAMS) delete commands for datasets found in CKFREEZE but users do not exist anymore.

For example I report all datasets matching pattern like OMVSUSER.**.ZFS from CKFREEZE. Then I extract the RACF-Userid and will do a check if the user is still present in the database or not, If the user is not present anymore the (IDCAMS) delete command should be generated to cleanup such orphaned files (automatically).

To get the list of users works with the define parameter using the following CARLA:
 newlist type=DSN nopage nodup retain required
  select  DSNAME=(OMVSUSER.*.ZFS)             
  define AUSER as word(dsname,2,'.')          
  sortlist,                                   
     AUSER                        
     
I have to check if the AUSER does exist or not. A possible approach was using the RACF search command but I have the feeling that there must be a more clever way to check if the 'AUSER' exists in the local database and if not generate the (IDCAMS) delete command like:
"DELETE " | DSNAME (but only if the AUSER is not found).

Currently I end up with few manual steps to work with the list from the RACF SEARCH command, filtering for message ICH31022I and feed back the list of users into a Carla that generates then the DELETE commands. This would work (manually) and I get the orphaned files deleted but you might have a more clever way to check with Carla if a user exists or not.

Another approach was to use the CKR2PASS option to use the AUSER as the KEY for a lookup but there is just nothing returned if the user does not exist. So working with the EMPTY= in the newlist only tells me that there was nothing found, but if the USERID/KEY can be returned again would be helpful. As the below Carla creates a partially expected list:
newlist type=DSN nopage nodup retain required DD=CKR2PASS
 select  DSNAME=(OMVSUSER.*.ZFS)                         
 define AUSER as word(dsname,2,'.')                      
 sortlist,                                                                                                       
 "newlist type=RACF nopage nodup retain required EMPTY='Undef User'" / ,
 "s s=base c=user key=" | AUSER                                      / ,
 "sortlist 'user ' | key(0) ' does exist'"                                 
 
Running this returns then a list as follows:
Undef User             
user USER1  does exist
user USER2  does exist
user USER3  does exist
Undef User  
user USER28  does exist
user USER44  does exist
user USER45  does exist
user USER67  does exist 

thanks and regards
marco

Jeroen Tiggelman's profile image
Jeroen Tiggelman

Instead of EMPTY='Undef User'

I think you could make it EMPTY='user " | AUSER(0) | " does not exist' 

or something like that.

Where everything between the double quotes[1] is generated literally for the next pass, '|' concatenates (so prevents intermediate blanks) and AUSER(0) would be the user you are looking for.

[1] Note I am only showing closing and reopening double quotes in this snippet.

Ronald van der Laan's profile image
Ronald van der Laan

Marco,

The following should do what you want:

newlist type=dsn f=ckrcmd                   
 define auser as word(dsn,2,'.')
 select dsn=OMVSUSER.**.ZFS not(auser:entype=2)      
 list 'DELETE' dsn                          

"auser:entype" is a lookup into the RACF database, where we obtain the entity type of the resource "auser".    1 = GROUP, 2 = USER, 4 = DATASET. 5 = GENERAL
By eliminating all the "auser" records that are not valid USERs, we can do your query in one run.

Marco Egli's profile image
Marco Egli

Hello Ronald and Jeroen

That was really helpful and super fast! I was already able to incorporate that into my program and it works as expected. I'll run few manual checks before triggering this automatically.

Your quick answer and providing working solution is much appreciated. Got it working with the entype, that was the smart solution I was looking for :-)!

thanks to both of you

kind reagrds
marco

Marco Egli's profile image
Marco Egli

Hi Ronald

You might be able to help with another addition to the selection of filesystems to delete.
Can this "select dsn=OMVSUSER.**.ZFS not(auser:entype=2)" be extended to generate as well the 'DELETE' for users not part of a specific group?

Would something like that work as well?
newlist type=dsn f=ckrcmd                   
 define auser as word(dsn,2,'.')
 select dsn=OMVSUSER.**.ZFS (not(auser:entype=2) or not(auser:CGGRPNM=GROUP1))      
 list 'DELETE' dsn 

Ronald van der Laan's profile image
Ronald van der Laan

Marco,

Unfortunately no, CGGRPNM is a repeat field in type=RACF, my trick only works for single value fields, like ENTYPE, OWNER, etc.
It would be nice if the lookup function would be able to change a single field into a repeat field, but this could quickly result in chaos, if you could do something like repeatfield:repeatfield:repeatfield, The source field can be a single or repeat field, but all the other fields should have one single value.

SAUL MAURICIO CHAGOLLA HERREJON's profile image
SAUL MAURICIO CHAGOLLA HERREJON

Very useful information.

Rob van Hoboken's profile image
Rob van Hoboken IBM Champion

If you want to check that a user is connected to a group, you can use the following two step process.

//* Write users connected to GROUP1 into &&USERS
//LISTGRP  EXEC C2RC
//USERS    DD DISP=(,PASS),DSN=&&USERS
//SYSIN    DD *
alloc type=racf active
newlist type=racf dd=USERS nopage
  select class=user cggrpnm=GROUP1
  sortlist profile(8)
//*
//LISTDSN  EXEC C2RC
//USERS    DD DISP=OLD,DSN=&&USERS
//SYSIN    DD *
deftype type=$users
alloc   type=$users dd=USERS
define  type=$users userid(8) as word(record,1)


newlist type=dsn f=ckrcmd                   
 define auser as word(dsn,2,'.')
 select dsn=OMVSUSER.**.ZFS not(auser:entype=2 and exists(auser:$users.userid.record))      
 list 'DELETE' dsn 
//*

Rob van Hoboken's profile image
Rob van Hoboken IBM Champion

I added an Idea for making the list of users connected to your GROUP1 accessible without using an external data set.  See if you like this approach and Vote for it if you do.
IBM Z Software Ideas portal

Marco Egli's profile image
Marco Egli

Hello Everyone

Thanks for all the valuable feedback and suggestions how to optimize my process, much appreciated! @Rob van Hoboken thank you for raising the idea, you have my vote on it.