Featured

When is activity trace enabled?

I found the documentation for activity trace was not clear as to the activity trace settings.

In mqat.ini you can provide information as to what applications (including channels) you want traced.

For example

applicationTrace:
ApplClass=USER
ApplName=progput
Trace=OFF

This file and trace value are checked when the application connects.  If you have TRACE=ON when the application connects, and you change it to TRACE=OFF, it will continue tracing.

If you have TRACE=OFF specified, and the application connects, changing it to TRACE=ON will not produce any records.

With

  • TRACE=ON, the application will be traced
  • TRACE=OFF the application will not be traced
  • TRACE= or omitted then the tracing depends on alter qmgr ACTVTRC(ON|OFF).   For a long running transaction using alter qmgr to turn it on, and then off, you will get trace records for the application from in the gap.

If you have

applicationTrace:
ApplClass=USER 
ApplName=prog* 
Trace=OFF

applicationTrace:
ApplClass=USER 
ApplName=progp*
Trace=ON

then program progput will have trace turned on because the definition is more specific.

You could have

applicationTrace:
ApplClass=USER 
ApplName=progzzz
Trace=OFF

applicationTrace:
ApplClass=USER 
ApplName=prog*
Trace=

to  be able to turn trace on for all programs beginning with prog, but not to trace progzzz.

 

Thanks to Morag of MQGEM  who got in contact with me, and said  long running tasks are notified of a change to the mqat.ini file, if the file has changed, and a queue manager attributed has been changed – even if it is changed to the same variable.

This and lots of other great info about activity trace (a whole presentation’s worth of information) is available here.

Understanding display authrec match(…) on midrange.

I found the documentation for the display authrec match(…) command hard to understand. There are ambiguous backward references (the profile … which profile?), too many ‘and’s, and I think some ‘or’s are missing. Below is how I interpret it.

  • Match exact: Select the record where the specified profile name specified is an exact match for a setmqauth record
  • Match profile: Display the setmqaut records which would be used to compute permissions, for the specified profile, and (specified userid or specified group).
  • Match membership:
    • For the specified userid do Match: profile() for the userid
    • For each group the specified userid is in, do Match: profile() for that group

I see the processing is in two stages

  1. Stage 1 extract the autrecs for the specified profile name
  2. Stage 2 filter the list using the specified userid or group.

Stage 1: extract the authrecs matching the specified profile name.

For match exact

Select the record where the specified profile name specified is an exact match for a setmqauth record. Profile(‘CP.**.99’) will match only ‘CP.**.99’.

For match profile and membership

If the specified profile has a generic then treat this as match(exact).

If the specified profile has no generics then extract all records which would apply when checking this profile.

For example for queue CP.AA.BB.99 might return

  • profile CP.AA.BB.99 (entity colinpaice) – this userid created the queue
  • profile CP.AA.BB.99 (entity mqm) – this entry is create when the queue is created
  • profile CP.**.99 (entity testuser) – this was done via setmqaut – not selected because less specific generic profile
  • profile CP.*.BB.99 (entity testuser) – this was done via setmqaut.

Stage 2. Filter the records depending on the specified userid or group.

Take the set of records from stage 1 and filter them. You can specify the principal (userid) or group. Note: If your qm.ini has SecurityPolicy=group then even if you have specified you setmqauth with a userid, it will use a group instead. This may mean that displaying a userid may give no results.

Match exact

Compare the specified entity and entity type with those in the the records. If they match display the record.

Match profile

Compare the specified entity, and entity type with those in the the records. If they match display the record.

Match membership

Compare the specified entity, and entity type with those in the the records. If they match display the record.

If the entity type in the record is group, and the specified userid is a member of the group then display it.

Examples

Match(profile) principal()

dis authrec profile(CP.AA.99) objtype(queue) match(profile)   principal('testuser')
AMQ8459I: Not found.    

There is no profile defined for the userid ‘testuser’

Match(profile) group()

dis authrec profile(CP.AA.99) objtype(queue) match(profile)   group('testuser')
   PROFILE(CP.*.99)                        ENTITY(testuser)  

There was a setmqauth -m -n “CP.*.99” -t queue -p testuser +get . Because of the qm.ini setting, and userid authorisations were converted to group authorisations. On some Unix systems, when a userid is created, it creates a group with the same name, and connects the userid to the group.

dis authrec profile(CP.AA.99) objtype(queue) match(profile)   group('test') 
AMQ8864I: Display authority record details.
    PROFILE(**) ENTITY(test) AUTHLIST(DSP,INQ) 

All members of group test, have Display and Inquire permissions on any queue.

Match(membership) principal()

dis authrec profile(CP.AA.99) objtype(queue) match(membership) principal('testuser')
AMQ8864I: Display authority record details.
   PROFILE(CP.*.99)                        ENTITY(testuser)
                         
AMQ8864I: Display authority record details.
   PROFILE(**)                             ENTITY(test)  

The display match(membership) combines all of the above. Any specific records, plus records for any group testuser is in.

Match(membership) group()

dis authrec profile(CP.AA.99) objtype(queue) match(membership) group('testuser')
AMQ8864I: Display authority record details.
   PROFILE(CP.*.99)                        ENTITY(testuser)

Because the group is specified, then this acts the same as match(profile) group(‘testuser’).

Match(profile) no group nor principal

dis authrec profile(CP.AA.99) objtype(queue) match(profile)   
AMQ8864I: Display authority record details.
   PROFILE(CP.AA.99)                       ENTITY(colinpaice)
 
AMQ8864I: Display authority record details.
   PROFILE(CP.AA.99)                       ENTITY(mqm)
 
AMQ8864I: Display authority record details.
   PROFILE(CP.*.99)                        ENTITY(testuser)
                
AMQ8864I: Display authority record details.
   PROFILE(CP.**.99)                       ENTITY(testuser)
                 
AMQ8864I: Display authority record details.
   PROFILE(**)                             ENTITY(test)

No userids or groups were specified, so all relevant autrecs for the profile CP.AA.99 are displayed.

Observation: There is a profile for PROFILE(CP.**.99) ENTITY(testuser) which does not show up when dis authrec profile(CP.AA.99) objtype(queue) match(membership) principal(‘testuser’) is used.

This is because with generic profiles, only the most specific generic profile is used, see Profile Priorities.

MQ Context on z/OS

Having struggled to get MQ Context working on mid range MQ, I thought I would try the same on z/OS.

If you want to allow applications to set Putdate, Putime, PutApplName etc. The application needs access to MQ Context. MQ MCA channels use this when putting a message from a remote queue manager, to keep the original values.

Which profiles are used?

You can disable context checking by defining a profile ‘qmgr.NO.CONTEXT.CHECKS’. If you want to enable context checking remove this profile if it exists.

You can display it using

RLIST MQADMIN CSQ9.NO.CONTEXT.CHECKS

You configure queue context using the profile qmrg.context.queue

for example

RLIST MQADMIN CSQ9.CONTEXT.CP0000 all
CLASS NAME
----- ----
MQADMIN CSQ9.CONTEXT.** (G)
...
LEVEL  OWNER      UNIVERSAL ACCESS  YOUR ACCESS  WARNING
-----  --------   ----------------  -----------  -------
 00    IBMUSER          NONE             ALTER    NO
...
USER ACCESS
---- ------
IBMUSER ALTER

This says that for the queue CP0000, display the profile CSQ9.CONTEXT.CP0000. It returned

  • MQADMIN CSQ9.CONTEXT.** this is the profile used
  • IBMUSER ALTER the only user authorised to this resource – with ALTER access it IBMUSER
  • The default access is NONE.

When a userid tried to open the queue – with set context options, the open got return code 2035 and a message on the console.

ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
CSQ9.CONTEXT.CP0000 CL(MQADMIN )
INSUFFICIENT ACCESS AUTHORITY
FROM CSQ9.CONTEXT.** (G)
ACCESS INTENT(CONTROL) ACCESS ALLOWED(NONE )

This shows the resource used CSQ9.CONTEXT.CP0000. The RACF profile used was CSQ9.CONTEXT.**. The userid had NONE access, and wanted CONTROL access.

You could define a more specific profile for example CSQ9.CONTEXT.CP*, and that would be used in preference to the CSQ9.CONTEXT.** profile.

The z/OS documentation Determining RACF protection says

Although multiple generic profiles can match a general resource name, only the most specific profile
actually protects it. For example, AB.CD, AB.CD.* and AB.**.CD all match the general resource name AB.CD, but AB.CD.* protects the resource.

With Midrange MQ on Unix, the permission is taken from all of the groups the userid is in- if one of the userid’s groups has get authority, the userid has get authority. With z/OS just one profile is used.

Changing a profile – don’t forget to refresh.

When changing a profile you need to remember to refresh the RACF in memory profiles, and tell MQ to pick up the changes.

I changed a profile

ralter MQADMIN CSQ9.CONTEXT.** UACC(CONTROL)

Refreshed the RACF in-memory profiles

setropts racflist(MQADMIN) refresh

And told MQ to refresh its profiles

%csq9 refresh security

How easy is it to display security information for MQ on z/OS?

I asked this question for midrange, and here are the answers for z/OS.

Key question are

Displaying security information

The RACF commands are

RLIST to display profile information, and who has access to the profile

SEARCH This allows you to search for profiles matching a parameter.

RLIST display profile information

An example command and output

RLIST MQADMIN CSQ9.CONTEXT.CP0000 all
CLASS NAME
----- ----
MQADMIN CSQ9.CONTEXT.** (G)
...
LEVEL  OWNER      UNIVERSAL ACCESS  YOUR ACCESS  WARNING
-----  --------   ----------------  -----------  -------
 00    IBMUSER          NONE             ALTER    NO
...
USER ACCESS
---- ------
IBMUSER ALTER

This says display the profile CSQ9.CONTEXT.CP0000. It returned

  • MQADMIN CSQ9.CONTEXT.** this is the profile used by RACF to determine the permissions
  • IBMUSER ALTER the only user authorised to this resource is IBMUSER, with ALTER access
  • The default access for any userid not covered is NONE.

SEARCH for a profile

An example command to list all MQQueue profiles for queue manager CSQ9.

SEARCH CLASS(MQQUEUE) FILTER(CSQ9.*)
CSQ9.AMSQ
CSQ9.NONE
CSQ9.ZZZZ
CSQ9.** (G)

Is a user authorised to use this queue?

Use RLIST to tell you the profile used for checking

  • Check the Universal Access
  • Check to see if the userid in the list
  • Check the groups in the list and see if the userid is a member of the group.

Which profile gave what access to the queue

Use the RLIST MQQUEUE qmgr.queueName.

Who is authorised to this queue

Use the rlist command as described above. You may have to write a script to post process the data, and replace the group name with the member of the group. I used the Rexx interface IRRXUTIL and wrote about 100 lines of code to do this. Please contact me if you are interested in this.

Can I audit the list of people and their access to queues beginning with CP?

Not easily.

The command

SEARCH CLASS(MQQUEUE) FILTER(CSQ9.CP*)

gives ICH31005I NO ENTRIES MEET SEARCH CRITERIA

The command

SEARCH CLASS(MQQUEUE) FILTER(CSQ9.A*)

Gives one queue (CSQ9.AMSQ). It does not list the default CSQ9.** for any other queues

You would have to issue the MQ command to get a list of queues, the parse the list, and pass the queue name to the RLIST command, and collect the set of userids and groups. Finally, change any groups to the list of members of the group.

I used the Rexx interface IRRXUTIL and wrote about 100 lines of code to do this. Please contact me if you are interested in this.

Thoughts on planning for security on midrange.

As I was working on some other blog posts relating to security profiles on midrange MQ, I thought about the best way to set up MQ security. Below are some things you need to consider, outside of the well documented topics.

Give people the authority they need to do their job – but no more

One of the rules of security is to give people the authority they need to do their job – but no more. People may need access to one set of resources (eg queues) but do not need access to other sets of resources (other queues). This means you need more than one security profile – one for each. Having one big security group covering both sets of resources is a no-no.

Use groups to give permissions rather than to userids

It is better to give groups permissions, than to give individual’s userid permissions. To add a new member to the team you add their userid to the group(s) – rather than to all the queues. To remove someone’s access – you delete them from the group(s). These changes are easy to do and easy to reverse. If you did it at the userid level, there could be many records you would needs to process.

If you want to give a userid permission to do something, then other people are likely to want the same permission. Give permission to one group, and all userids in that group will get the access.

Removing authority

If you want to remove someone’s authority to do something

  • “Just remove” them them from the mqm group.
  • Use dmpmqaut .. -p userid -e to see which groups have the permission. Either
    • “Just remove” the permission from the group. This means other people in the group will also lose permission
    • or “just remove” the userid from the group, which may mean the userid may lose access to other facilities.

“Just remove” could be a lot of work, as you want to remove access to one queue, but retain their access to other queues. You may need to set up other groups to cover this.

Review your setup

You may want to review your groups, permissions, and userids within groups for your MQ estate and develop a scheme where you have a queue, and groups to define the permissions to the queue. If you have queues PAY_IN…. and PAY_OUT… you will need two AUTHREC records, one for each.

Generic profiles

If you have multiple generic profiles which apply to a queue, only the most specific profile will be used. Profile AA.BB.*.DD would be used in preference to AA.*.CC.DD

If a generic profile exists with the same name, but different groups, then all applicable instances of the most specific profile will be used. Profile AA.BB.*.DD group test, and profile AA.BB.*.DD group test2, would both be used if the userid is in both groups.

Separation of responsibilities

You may not want people who can administer queues, from processing messages on queues. Userids in the mqm group, or in the default group of the userid that created the queue, have all permissions for the queue. You may want to have a tool for deploying administrative changes, and use MQAdmin groups to control who can administer the object.

It took me a while to partially understand setmqaut and dspmqaut – and your security may be a mess.

On Linux, I was looking into MQ context security , where you can prevent a user from putting a fake information into the MQMD, and to my surprise it kept on working! It took me a while to work out what was going on.

Some of the things I learned include

  • If a userid is in the mqm group, it overrides any setmqaut statements. You may want to have a group called MQADMIN, and have your administrators in that group rather than the mqm group; so they can create or alter queues , but not put messages to sensitive queues.
  • Your overall access permission depends on the settings for the policy for the userid and any groups it is in. If one of your groups has permission, you have permission. If no group has permission, your userid gets no permission.
  • If you add or remove userids from groups, you have to use the runmqsc command refresh security to pick up the changes.
  • If you are using a userid in the mqm group to test your application – you may be testing with a different set of permissions to your target user.
  • It is better to define security profiles using groups rather than userids. If someone joins the team, you just put them in the group. If security is done using userids, you have to replicate all of the definitions of an existing user. Similarly if someone leaves the team.
  • The difference between group and principal (userid) is fuzzy. You define authority on a userid – but it appears as a group. Thanks to Joshm who pointed out that on Unix the qm.ini SecurityPolicy=user|group|UserExternal|default controls whether security is done with userids or groups. I need to explore this, but it explains some of my confusion
  • Some of the commands, for example dmpmqaut do not work as documented, but you can work round it.
  • setmqauth and dspmqauth parameters are read asis – with display authrec mixed case fields need to be surrounded with single quotes.
  • If you remove permission, then check, as you may get permission from more than one group.

Controlling the ability to change the context of a message.

This facility allows an application to specify the MQMD fields PutApplType, PutApplName, PutDate and. ApplOriginData, rather than have them filled in by the queue manager. An MCA channel would do this when putting a message, to keep the original information. See origin context.

The key security parmeter is “setall” which allows these fields to be set.

Being a good tester, I displayed the permissions before changing them.

dspmqaut -m QMA -n CP0000 -t queue -p colinpaice

This says display the attributes for Queue CP0000 for user colinpaice.

I also defined authorities for another userid

setmqaut -m QMA -n CP0000 -t queue -p testuser +allmqi

I could not see how to use dspmqaut to display the authorities for all users of a queue, however you can use the runqmqsc DIS AUTHREC command, dmpmqaut and dmpmqcfg -m … -x authrec to dump out the permissions for users of an object.

The documentation is a little unclear – it talks about entity without actually saying what an entity was. I assumed the entity was the queue name, it actually means userid or group – but this is not strictly true.

runmqsc dis authrec displayed

dis authrec profile(CP0000)
     3 : dis authrec profile(CP0000)

AMQ8864I: Display authority record details.
   PROFILE(CP0000)                         ENTITY(mqm)
   ENTTYPE(GROUP)                          OBJTYPE(QUEUE) 
   AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,
   PASSALL,PASSID,SET,SETALL,SETID)

AMQ8864I: Display authority record details.
   PROFILE(CP0000)                         ENTITY(testuser)
   ENTTYPE(GROUP)                          OBJTYPE(QUEUE)
   AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

AMQ8864I: Display authority record details.
   PROFILE(**)                             ENTITY(test)
   ENTTYPE(GROUP)                          OBJTYPE(TOPIC)
   AUTHLIST(DSP)
...                        

This needs a bit of explaining.

Display information about a group’s access to a profile

AMQ8864I: Display authority record details.
   PROFILE(CP0000)                         ENTITY(mqm)
   ENTTYPE(GROUP)                          OBJTYPE(QUEUE)
   AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID) 

For Object type of Queue, there is a profile for object CP0000. The profile applies to group mqm. It has lots of access. That was pretty self explanatory.

Display information about a userid’s access to a profile

AMQ8864I: Display authority record details.
   PROFILE(CP0000)                         ENTITY(testuser)
   ENTTYPE(GROUP)                          OBJTYPE(QUEUE)
   AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

This is just like the first section, except I had defined it for principal (userid) testuser – not a group.

Using DIS AUTHREC gave

dis authrec profile(CP0000) objtype(queue) group('testuser')
AMQ8864I: Display authority record details.
PROFILE(CP0000) ENTITY(testuser)
ENTTYPE(GROUP) OBJTYPE(QUEUE)
AUTHLIST(BROWSE,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

dis authrec profile(CP0000) objtype(queue) principal('testuser')
4 : dis authrec profile(CP0000) objtype(queue) principal('testuser')
AMQ8459I: Not found.

However if I display information about the userid, it displays

uid=1002(testuser) gid=1004(testuser) groups=1004(testuser),1005(test)

so there is a group for the userid as well as the userid itself.

All in all – I found this a little confusing.

Other profiles.

AMQ8864I: Display authority record details.
   PROFILE(**)                             ENTITY(test)
   ENTTYPE(GROUP)                          OBJTYPE(TOPIC)
   AUTHLIST(DSP)

There is a generic profile ** for object type topic. If there was a topic CP0000 then userid/group test would have DSP access.

Displaying what you want

You can limit the object type displayed

dis authrec profile(CP0000) objtype(queue)

this just displayed the queue records for profile CP0000 (and so did not display the topic record above), so you can be selective.

You can use

dis authrec profile(CP0000) objtype(queue) group(‘testuser’)

or principal(‘userid’) to display records for just a group or userid.

However

dis authrec profile(‘CP*’) objtype(Queue)

gives

AMQ8459I: Not found.

Because there is no profile with name CP*. It does not display all profiles beginning with CP.

Using setmqaut

I wanted to test out context security, and did not want my application to be able to set certain fields in the MQMD.

If the userid had permissions, put and setall, my application was able to set the application name.

I turned off the permission with

setmqaut -m QMA -n CP0000 -p testuser -t queue -setall

and got rc=2035 MQRC_NOT_AUTHORIZED as expected.

Note: The userid also needs the “global level” switch

setmqaut -m QMA –t qmgr -p testuser +setall

enabled at the queue manager level. The application needs both +setall permissions to be able to set these context fields in the MQMD at put time.

This is not the end of the story…

With my normal administrator userid colinpaice, I used

setmqaut -m QMA -n CP0000 -t queue -p colinpaice -setall

to remove the setall permission; and this had no effect! I was still able to set the certain fields in the MQMD.

Hidden away in the documentation is a line

If a principal is a member of more than one user group, the principal effectively has the combined authorities of all those user groups

After I issued the setmqauth command, the dspmqauth command

dspmqaut -m QMA -n CP0000 -t queue -p colinpaice

gave

get
put
setall

which shows the userid still has setall access.

From the dis authrec command, it gave

2 : dis authrec profile(CP0000) objtype(QUEUE) 
AMQ8864I: Display authority record details.
PROFILE(CP0000) ENTITY(mqm)
ENTTYPE(GROUP) OBJTYPE(QUEUE)
AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

so the group mqm has SETALL access to the queue.

It gets more confusing. I used the command

setmqaut -m QMA -n CP0000 -t queue -p colinpaice -setall

to turn off setall permissions

dspmquth with -p colinpaice showed setall

dspmquth with -g colinpaice did not have setall!

This has me stumped for a few hours!

Being in the mqm group trumps the setmqaut definitions.

If a userid is in the mqm group, then it looks like there are no other checks. An implications of this is if your development team are in the mqm group, and they checking “error paths”, the MQ call will work, when it would fail for non group mqm users.

I used

sudo gpasswd –d colinpaice mqm

to remove my userid from the group. I had to use the runmqsc command refresh security command to get the queue manager to pick up the change.

Once I had done this then the setmqaut commands with +setall and -setall worked as expected. I used

sudo gpasswd –add colinpaice mqm

and the runmqsc refresh security command, for the setmqaut commands to be ignored.

The command

dspmqaut -m QMA -n CP0000 -t queue -p colinpaice

was accurate, in that when the userid was in the group, the command shows what access the userid has.

When the userid was not in the group, I remove access

setmqaut -m QMA -n CP0000 -t queue -p colinpaice -remove

the display command gave

Entity colinpaice has the following authorizations for object CP0000:
crt

When the userid was in group mqm the dspmqaut command gave

dspmqaut -m QMA -n CP0000 -t queue -p colinpaice
Entity colinpaice has the following authorizations for object CP0000:
get
browse
put
inq
set
crt
dlt
chg
dsp
passid
passall
setid
setall
clr

How easy is it to display security information on midrange.

If you thought it was easy, I would disagree with you.

While investigating a security problem (why my code worked, when it should have got a not authorised return code) I struggled to answer questions like

There are links to my solutions for some of the problems.

What commands are there?

There are four MQ commands providing similar functions

Definition of terms

Profile name

This can be the name of a queue, or a string which is used for comparisons and can include single * or double **. For example

  • PAYROLL for a particular queue,
  • PAYROLL.*.INPUT, which would apply to objects PAYROLL.A.INPUT, PAYROLL.B.INPUT, but not PAYROLL.A.B.INPUT, nor PAYROLL.INPUT.
  • PAYROLL.**.INPUT which would apply to PAYROLL.A.INPUT, PAYROLL.B.INPUT, PAYROLL.A.B.INPUT, but not PAYROLL.INPUT.
  • ** used as a fall back if there are no other definitions.

Example profiles

  • setmqaut -m QMA -n PAYROLL -t queue -g testuser +put
  • setmqaut -m QMA -n ‘PAYROLL.*.INPUT’ -t queue -g testuser +put
  • setmqaut -m QMA -n ‘PAYROLL.**.INPUT’ -t queue -g testuser +put
  • setmqaut -m QMA -n ‘**’ -t queue -g MQAdmin +chg +dlt

On Unix you need the single quotes around any profile which includes *, to prevent the shell replacing it with a list of file names.

You need to be careful about quoting strings with mixed case data. dspmqaut and setmqaut do not need quoting. For runmqsc display|set authrec the mixed case fields need quoting.

A profile is created

  • by the setmqaut command,
  • the runmqsc set authrec command,
  • when the object is created. In which case, the queue manager creates an entry for the mqm group, and for the principal group of the user that created the object. Userid ibmsys1 created a queue, and there were entries for group mqm, and group zpdt. These definitions have full access. (The userid that created a queue can put and get messages from the queue – and you cannot separate administration of the queue, and usage of the queue.)

Userid and group

Unix has the concept of User Private Groups (UPG). A userid can have a group with the same name as the userid, which makes the security just a touch more confusing.

You can use the id command to list which groups a userid is in

id ibmsys1
uid=1001(ibmsys1) gid=1006(zpdt) groups=1006(zpdt),27(sudo),1007(MQAdmin)

Userid ibmsys1 with numeric id 1001 is a member of 3 groups: zpdt, sudo and MQAdmin.

You can specify the authority to be given to a userid – but it looks like the userid is not used, but the default group is used! See Explicit giving a userid access – does not give the userid access. This could just be a Linux feature.

Displaying information.

dspmqaut -m QMA -n ‘PAYROLL.**.INPUT’ -t queue -g testuser

This lists the information for the group testuser and the profile PAYROLL.**.INPUT’. It reports “put” access.

What access does the group ibmsys1 have?

dspmqaut -m QMA -n ‘PAYROLL’ -t queue -g ibmsys1

Entity ibmsys1 has the following authorizations for object PAYROLL:

 

 

Shows the group has no access defined.

What access does the userid (principal) ibmsys1 have?

dspmqaut -m QMA -n ‘PAYROLL’ -t queue -p ibmsys1

Entity ibmsys1 has the following authorizations for object PAYROLL:
dlt
chg

This is because userid ibmsys1 has MQAdmin as one of its group.

Adding -e option to the dmpmqaut command (Display all profiles used to calculate the cumulative authority that the entity has to the object specified in -n Profile) shows which profiles will be used.

dmpmqaut -m QMA -n ‘PAYROLL’ -t queue -p ibmsys1 -e
profile: **
object type: queue
entity: MQAdmin
entity type: group
authority: dlt chg

We can see that the profile used to determine the access permissions came from the “**” profile statement for group(entity) MQAdmin.

Explicit giving a userid access – does not give the userid access.

On my Linux Ubuntu machine, using the following command to explicitly give a userid access; gives it to the userid’s principal group.

setmqaut -m QMA -n PAYROLL -t queue -p ibmsys1 +put

dmpmqaut -m QMA -n PAYROLL -t queue -p ibmsys1 -e
profile: PAYROLL
object type: queue
entity: zpdt
entity type: group
authority: put

profile: **
object type: queue
entity: MQAdmin
entity type: group
authority: dlt chg

This shows the group zpdt got the access – not the userid.

For this userid we can see that there was a specific profile “PAYROLL” for the zpdt group giving put permission, and the generic profile for the MQAdmin group giving inquire and display permissions.

The display authrec command

If you use dis authrec profile(PAYROLL) it will display all possible profiles including the profiles for queues, process etc. Ensure all mixed case values are surrounded by single quotes.

dis authrec profile(PAYROLL) objtype(queue)

gave

AMQ8864I: Display authority record details.
  PROFILE(PAYROLL) ENTITY(colinpaice)
  ENTTYPE(GROUP) OBJTYPE(QUEUE)
  AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

AMQ8864I: Display authority record details.
  PROFILE(PAYROLL) ENTITY(mqm)
  ENTTYPE(GROUP) OBJTYPE(QUEUE)
  AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

AMQ8864I: Display authority record details.
  PROFILE(PAYROLL) ENTITY(testuser)
  ENTTYPE(GROUP) OBJTYPE(QUEUE)
 AUTHLIST(PUT)

AMQ8864I: Display authority record details.
  PROFILE(**) ENTITY(test) ENTTYPE(GROUP) OBJTYPE(QUEUE) AUTHLIST(DSP,INQ) 

AMQ8864I: Display authority   record details. 
  PROFILE(**) ENTITY(MQAdmin)
  ENTTYPE(GROUP) OBJTYPE(QUEUE)
  AUTHLIST(CHG,DLT)

but

dis authrec profile(PAYROLL) objtype(queue) group(MQAdmin)

gives not found however, using single quotes,

dis authrec profile(PAYROLL) objtype(queue) group(‘MQAdmin’)

gives

AMQ8864I: Display authority record details.
  PROFILE(**) ENTITY(MQAdmin)
  ENTTYPE(GROUP) OBJTYPE(QUEUE)
  AUTHLIST(CHG,DLT)

List all objects

You can use

runmqsc dis authrec type(queue)

to display all queue records with (up to three lines per entry) see above for an example.

You can use the dmpmqaut -l option Dump only the profile name and type. Use this option to generate a terse list of all defined profile names and types.

dmpmqaut -m QMA -l -t queue

Which gives output like

profile: PAYROLL, object type: queue
profile: PAYROLL.*.INPUT, object type: queue
profile: PAYROLL.**.INPUT, object type: queue

Unfortunately this is output to stderr, so you cannot immediately pipe this into grep or other commands.

You can use

dmpmqaut -m QMA -l -t queue 3>&1- 1>&2 2>&3|grep PAYROLL

The dmpmqaut command says you can use generics and wild cards in the name described Using OAM generic profiles on AIX®, Linux®, and Windows systems. I could not get this to work, for example using PAYROLL.**

The runmqsc DIS AUTHREC command says profile can have The name of the object or generic profile for which to display the authority records.

I think the documentation means “the string used in the profile definition, not a generic search argument.”


For example I wanted to use a qualifier ‘*’, but the command

dmpmqaut -m QMA -n ‘CP.*’

gives

No matching authority records.

runmqsc dis entauth – display the authorizations an entity has to a specified object

This very useful command was pointed out to me by Morag. It has been in MQ since MQ 7.5.

It allows you to ask what permissions a userid or group has to a specific resource. For example

A typical display

dis entauth principal(‘testuser’) objtype(queue) objname(CP0000)
AMQ8866I: Display entity authority details.
OBJNAME(CP0000) ENTITY(testuser)
ENTTYPE(PRINCIPAL) OBJTYPE(QUEUE)
AUTHLIST(BROWSE,CRT,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID)

Queue does not exist

dis entauth principal(‘testuser’) objtype(queue) objname(CP000ZZZZZZ)
AMQ8147E: IBM MQ object CP000ZZZZZZ not found.

Silly me – I missed the quotes off from around the userid


dis entauth principal(testuser) objtype(queue) objname(CP0000)
3 : dis entauth principal(testuser) objtype(queue) objname(CP0000)
AMQ8871E: Entity, principal or group not known.

Dump mq configuration

You can use the dmpmqcfg command to dump out the authrec records.

dmpmqcfg -m QMA -x authrec -o 1line

gives output like (where there is one line for each SET… statement).

SET AUTHREC PROFILE(‘CP.*.00’) GROUP(‘colinpaice’) OBJTYPE(QUEUE) AUTHADD(GET,PUT)
SET AUTHREC PROFILE(‘PAYROLL.**.INPUT’) GROUP(‘testuser’) OBJTYPE(QUEUE) AUTHADD(PUT)
SET AUTHREC PROFILE(‘@class’) GROUP(‘colinpaice’) OBJTYPE(QUEUE) AUTHADD(CRT)

The -o 1line option creates one line of output for each record. You can use platform tools to process the data, for example use grep to filter lines, and parse the parts between ‘ ‘. See an example python script at the bottom.

The documentation says -n [*|ObjectName] Filter the definitions produced by object or profile name, the object/profile name can contain a single asterisk. But it didnt work for me.

My basic queries

Is this user authorised to use this queue?

You can use

dspmqaut -m QMA -n PAYROLL.A -t queue -p ibmsys1

If the queue does not exist you will get AMQ7085E: Object PAYROLL.A, type queue not found.

Or you can use the runmqsc command

dis entauth principal(‘testuser’) objtype(queue) objname(CP0000)

What security profiles are involved with this user and that queue.

Or which profiles gave a user access to the queue?

Display the userids id and groups. If userid is in group mqm, it will get all access regardless of the setmqaut settings.

Display all the profiles involved with a userid -e … or group -g …

dmpmqaut -m QMA -n PAYROLL.A -t queue -e

Display all the permission a user has with a userid -p … or group -g …

dspmqaut -m QMA -n ‘CP.ZZ.00’ -t queue -p testuser
Entity testuser has the following authorizations for object CP.ZZ.00:
inq
crt
dsp

Display the profiles which determine the permissions for a user

dmpmqaut -m QMA -n ‘CP.ZZ.00’ -t queue -e -p testuser
profile: **
object type: queue
entity: test
entity type: group
authority: inq dsp

profile: @class
object type: queue
entity: test
entity type: group
authority: crt

The inq and dsp permissions came from the “**” profile for the test group.

Who is authorised to this queue?

This is a tricky one. I could find two hard ways of

dmpmqaut -m QMA -n ‘CP.ZZ.00’ -t queue 2> file

dmpmqcfg -m QMA -x authrec -o 1line > file

Then post-processing the output to extract group name and permissions, then merging the records.

For example to see the members of a group.

getent group |grep mqm

gives
mqm:x:1003:colinpaice,ibmsys1

I want to audit the access to the queues beginning with CP.

Another tricky one.

  • dmpmqcfg -m QMA -n ‘CP*’ -t queue -o 1line -x object > queuelist
  • This gives a list of all queues starting with CP. Process this list to select each queue in turn
  • dmpmqaut -m QMA -n $queuename -t queue -e > accesslist
  • This accesslist file has the profile name, the group and the permissions.
  • Take each group name, and extract the members of the group.
  • For each member of the list use
  • dspmqaut -m QMA -n $queue -t queue -p $userid
  • Take this list extract the permissions, and produce a pretty report.

If there is a better way I would love to hear it.

A partial solution is to take the output of

dmpmqaut -m QMA -l -t queue 2>list

dmpmqcfg -m QMA -x authrec -o 1line > file

Then use tools like grep to extract the records of interest, then use other tools to issue dmpmqaut -m QMA -n ‘….’ -t queue, capture the output and process it.

But this means you have to interpret generic profiles like ‘CP.**.INPUT’ yourself.

Sample code for post processing dmpmqcfg output

Below is a small Python program that takes the output from dmpmqcfg and processes it to replace groups with users in the groups, and gives one line per userid,permission,profile, source_group

#
# Copyright (c) 2020 Stromness Software Solutions.
# 
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
# 
# * Contributors:
# *   Colin Paice - Initial Contribution
# 
from sys import stdin
import grp

for line in stdin:
  sline= line.strip()
  s = sline.split(' ')
  if s[0] != "SET":
     continue
  p = s[2][9:-2] # get the profile
  g = s[3][7:-2] # get the group 
  try:
    ginfo = grp.getgrnam(g)
    ids = ginfo.gr_mem 
    if len(ids) == 0:  # group can be empty
       ids = [g]  
  except KeyError:
    ids = [g] # group not found - must be userid
  t = s[4][8:-1] #type

  a = s[5][8:-1]  # get the authorities
  aa = a.split(",")
# Output userid authority profile type group_it_came_from
  for aaa in aa:
    for i in ids:
       print(i,aaa,p,t.g) 

Invoke it as

cat data | python3 ~/python/sec.py |sort -k1,3|uniq |grep -v mqm 

grep -v mqm removes all accesses due to group mqm membership

Example output

colinpaice SET SYSTEM.SELECTION.VALIDATION.QUEUE QUEUE 
colinpaice SET TEMP QUEUE colinpaice
colinpaice SET XQMB QUEUE colinpaice
colinpaice SUB SYSTEM.ADMIN.TOPIC TOPIC colinpaice
testuser PUT COLIN_* QUEUE test
testuser PUT CP0000 QUEUE testuser

Using jConsole and with z/OS Liberty web server

I wanted to get some monitoring information out from z/OSMF using jConsole on my Ubuntu machine. Eventually this worked, but I had a few problems on the way. The same technique can be used for base Liberty, MQWeb, z/OSMF and ZOWE all of which are based on Liberty.

Configuring z/OSMF

I changed the z/OSMF configuration to include

<featureManager> 
  <feature>restConnector-2.0</feature> 
</featureManager> 

and restarted the server.

In the stdout (or message log) will be something like

CWWKX0103I: The JMX REST connector is running and is available at the following service
URL: service:jmx:rest://sss.com:10443/IBMJMXConnectorREST

You need the URL. The message above gave service:jmx:rest://sss.com:10443/IBMJMXConnectorREST, but I needed to use service:jmx:rest://10.1.1.2:10443/IBMJMXConnectorREST .

The port number came from the httpEndpoint with id=”defaultHttpEndpoint” . I have another httpEndpoint with port 24993, and this also worked with jConsole.

Set up jConsole

I set up a script for jConsole

k1='-J-Djavax.net.ssl.keyStore=/home/colinpaice/ssl/ssl2/adcdc.p12'
k2='-J-Djavax.net.ssl.keyStorePassword=password'
k3='-J-Djavax.net.ssl.keyStoreType=pkcs12'
t1='-J-Djavax.net.ssl.trustStore=/home/colinpaice/ssl/ssl2/zca.jks'
t2='-J-Djavax.net.ssl.trustStorePassword=password'
t3='-J-Djavax.net.ssl.trustStoreType=jks'
d='-J-Djavax.net.debug=ssl:handshake'
d=' '
de='-debug'
de=' '
s='service:jmx:rest://10.1.1.2:10443/IBMJMXConnectorREST'
jconsole $de $s $k1 $k2 $k3 $t1 $t2 $t3 $d

Where

  • the -J .. parameters are passed through to java,
  • the -Djava… are the standard set of parameters to define the key stores on the Linux

Running this script gave a pop up window with

Secure connection failed. Retry insecurely?

The connection to service:jmxLret://10.1.1.2:10443/IBMJMXConnectorREST could not be made using SSL.

Would you like to try without SSL?

This was because of the exception

java.io.IOException: jmx.remote.credentials not provided.

I could not see how to pass userid and password to jConsole.

I then used Cntrl+N to create a new connection and entered Username: and Password: which jConsole requires. After a short delay of a few seconds jConsole responded with a graphs of Heap Memory Usage, and Threads in use. You can then select from the Measurement Beans.

The TLS setup

In the keystore I had a certificate which I had used to talk to a Liberty instance before.

This was signed, and the CA certificate had been imported into the key trust keyring on z/OS, for that HttpEndPoint.

The server responded with a server certificate (“CN=SERVER,O=SSS,C=GB”) which had been signed on z/OS. The signing certificate had been exported from z/OS and downloaded to Linux

I created a jks key trust store using this certificate, using the command

keytool -importcert -file temp4ca.pem -keystore zca.jks -storetype jks -storepass password

and used this trust store to validate the server certificate sent down from z/OS.

This worked with jConsole.

I created a pkcs12 keystore using keytool

keytool -importcert -file temp4ca.pem -keystore zca2.p12 -storetype pkcs12 -storepass password

Which also worked.

Problems using a .p12 trust store

I used

runmqakm -keydb -create -db zca.p12 -type pkcs12 -pw password
runmqakm -cert -add -file temp4ca.pem -db zca.p12 -type pkcs12 -pw password -label tempca
runmqakm -cert -details -db zca.p12 -type pkcs12 -pw password -label tempca

to create a pkcs12 keystore and import the z/OS CA certificate. The -details option displayed it.

When I tried to use it, jConsole produced the message (after the Cntl+N)

Secure connection failed. Retry insecurely?

The connection to service:jmxLret://10.1.1.2:10443/IBMJMXConnectorREST could not be made using SSL.

Would you like to try without SSL?

I used Ctrl-N as before, and got the same message.

Using

d=’-J-Djavax.net.debug=ssl:handshake’

and rerunning the script, produced a TLS trace. At the bottom was

VMPanel.connect, handling exception: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

%% Invalidated:…
VMPanel.connect, SEND TLSv1.2 ALERT: fatal, description = internal_error

Using a trace at the server, gave the unhelpful , SEND TLSv1.2 ALERT:

Using openssl also failed. Create the .p12 keystore

openssl pkcs12 -export -out zca.p12 -in temp4ca.pem -name zCA -nokeys

and rerun the jconsole script, and it failed the same way.

Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

It looks like runmqakm and openssl do not create a valid trust store with an imported certificate.

Additional diagnostics

When the trust store created by keytool was used; at the top of the TLS trace output was

System property jdk.tls.client.cipherSuites is set to ‘null’

Ignoring disabled cipher suite: SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
trustStore is: /home/colinpaice/ssl/ssl2/zca.p12
trustStore type is : pkcs12

trustStore provider is :
init truststore
adding as trusted cert:
Subject: CN=TEMP4Certification Authority, OU=TEST, O=TEMP
Issuer: CN=TEMP4Certification Authority, OU=TEST, O=TEMP
Algorithm: RSA; Serial number: 0x0
Valid from Tue Jul 14 00:00:00 BST 2020 until Fri Jul 02 23:59:59 BST 2021

keyStore is : /home/colinpaice/ssl/ssl2/adcdc.p12
keyStore type is : pkcs12
keyStore provider is :
init keystore
init keymanager of type SunX509

When the runmqakm or openssl was used, the green entries were missing.

When I used runmqakm to create the pkcs12 keystore

runmqakm -cert -details -db zca.p12 -type p12 -pw password -label tempca

listed the certificate successfully.

When I used keytool to list the contents

keytool -list -keystore zca.p12 -storetype pkcs12 -storepass password
Keystore type: PKCS12
Keystore provider: SunJSSE

Your keystore contains 0 entries

When I created the key store with keytool, both runmqakm and keytool displayed the certificate.

The problem looks like Java is only able to process the imported CA certificates when keytool was used to create the trust store.

When the burglar alarm goes off – would you just mute it?

I’m sure you’ve all been told to ignore links like

You have wun $1,000,000 click hear to download a dodgy application to steal your money” or

We have been unable to deliver a parcel to you. Click here to rearrange delivery and pay the excess money” but how about
Your connection is not private, Net::err_cert_invalid – click here to accept it

Collect 10 points if you did not fall for any of these.

I would like to talk about the last one, about your connection is not private; because I saw a web site recommending “click here to accept”.

You get messages like this if there are problems with the certificate. Common problems are

  • Your browser does not recognise the certificate, because it has not been signed by any CA in your browser’s trust store. This looks like someone is sending you an invalid certificate. It may be your enterprise security team need to update all browsers with the missing certificate, but they should have spotted this problem not you.
  • The certificate sent from the server has “valid host addresses are…. 10.1.1.2, my sys.com” and this has been sent from a different site. This could be because bad guys have intercepted your request and played “Man in the middle” between you and the server.
  • Less common, is where the certificate has parameters which your browser cannot handle. For example very old cipher specs, and your browser only supports TLS 1.2 or above.
  • It could be caused by a server using a self signed certificate. It may be acceptable to use this in a test environment, but it is not secure – as anyone could have created it. If it is signed, then you can check the digital signature.

All of these should set off the intruder alarm.

If you get a message like this – do not click on the accept button. This is just like muting the burglar alarm, and ignoring the warning – bad guys could steal your personal details – and you would not know.

Many web servers are configured with a bad certificate, for example they may specify an alternate name of 127.0.0.1, but not “localhost”. It is much easier (though wrong) to tell people to accept the certificate, than to fix the certificate.

Do not trust it

The blog post went on to say that you can download the certificate which has been sent to you and install it in your key store. I felt like screaming “NO!” and attacking the screen with a hammer!

Imaging, twenty years ago, you were a bank manager, and a man comes in, and says “I am a policeman, and we are doing a survey about your bank’s safe and where you keep the money. I would like my colleague “fingers” to go down inspect it. He has to work anonymously, which is why he is wearing a mask, and gloves, and he is wearing a black and white striped shirt. I’ll come back tomorrow”. You let “fingers” go down to the safe on his own, and say goodbye to the nice policeman. An hour later you find your safe is empty and there is no sign of the two men.

Your first mistake was to accept the policeman was a policeman. You should have checked his credentials before doing anything else. If he was fake, then any identification papers would be fake. You need to talk to your contacts in the local police station, and check if your visitor is valid or bogus (while he is sitting in your office).

Only in rare situations, such as a test environment, would you extract the certificate from what was sent to you, and install it in your key store. If you install it, then later, another request can come in from the bad guys, and be validated by the CA you just installed.

If you need a CA, you go through the proper corporate process. For example as part of the overnight maintenance on your machine, or download it securely from a known site. Emailing may not be good enough if your machine has been hacked.

So, in summary, today’s lesson is

  1. Do not “accept” bad certificates when using web site. Fix the the server.
  2. Get any additional certificates through an approved process – do not accept what the server is giving you.

In the words of the Police Constable in Dixon of Dock Green. “Evening all – mind how you go”.

Connect to Liberty, the clever way, to give different qualities of service.

While I was investigating two TCP/IP stacks I discovered you can set up Liberty Web Server to support different classes of service depending on TCP Host name, and port number.

You can configure <httpEndpoint…> with a host and port number, and point to other set up parameters and so configure

  • the host name
  • the httpsPort number
  • the maximum number of active connections for this definition
  • which keyring to use as the trust store
  • which keyring to use as the key store
  • which certificate the server should use in the key store
  • which TLS protocols for example TLS 1.2 or 1.3
  • what logging you want done: date,time, userid, url, response time
  • which file you want the access logging information to be written to
  • which sites can/cannot use this, the addressExcludeList and addressIncludeList.

How do you set up another http address and port ? It is really easy – just define another set of definitions!

Why would you want to do this?

You may want to restrict people’s access to the server. For example external people are told to access the server using a specified port, and you can specify which cipher specification should be used, and what trust store is used to validate a client authentication request.

You may want want to restrict the number of connections into a port, and have a port for administrators so they can always logon.

How do I do this?

You need to define another httpEndpoint. This in turn points to

I set up a file called colin.xml and included it in the server.xml file.

<server> 
 <httpEndpoint id="colinstHttpEndpoint" 
   host="10.1.1.2" 
   accessLoggingRef="colinaccessLogging" 
   sslOptionsRef="colinSSLRefOptions"
   httpsPort="29443"> 

   <tcpOption   
     addressIncludeList="10.1.*.*" 
     maxOpenConnections="3" /> 
 </httpEndpoint> 
 
 <sslOptions 
   id="colinSSLRefOptions" 
   sslRef="colinSSLOptions" 
 /> 

 <httpAccessLogging id="colinaccessLogging" enabled="true"/> 

 <ssl clientAuthentication="true" 
   clientAuthenticationSupported="true" 
   id="colinSSLOptions" 
   keyStoreRef="racfKeyStore" 
   trustStoreRef="racfTrustStore"                                                                             
   serverKeyAlias="ZZZZ" 
   sslProtocol="TLSv1.2" /> 
                                                                                
 <keyStore filebased="false" id="racfKeyStore" 
   location="safkeyring://START1/KEY" 
   password="password" readOnly="true" type="JCERACFKS"/> 
                                                                                                   
 <keyStore filebased="false" id="racfTrustStore" 
   location="safkeyring://START1/TRUST" 
   password="password" readOnly="true" type="JCERACFKS"/> 

</server> 

Where do the security violations go for MQ on z/OS?

This question came in from a customer who was reviewing the subsystem security on z/OS. For example CICS reports its own violations.

MQ security violations are reported by the security manager, RACF, and are displayed on the job log.

MQ delegates the security checks to RACF, so auditing is mostly done by RACF. The only exception is the RESLEVEL profile, which MQ writes its own audit records to RACF.

See a section in the IBM documentation.

For example, userid COLIN is not authorised to issue MQ commands, so there are messages on the job log.

%CSQ9 START CHINIT
ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
CSQ9.START.CHINIT CL(MQCMDS )
INSUFFICIENT ACCESS AUTHORITY
FROM CSQ9.** (G)
ACCESS INTENT(CONTROL) ACCESS ALLOWED(NONE )

%CSQ9 DEF QL(AAAA)
ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
CSQ9.DEFINE.QLOCAL CL(MQCMDS )
INSUFFICIENT ACCESS AUTHORITY
FROM CSQ9.** (G)
ACCESS INTENT(ALTER ) ACCESS ALLOWED(NONE )

Trying to use a queue

ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
CSQ9.ZZZZ CL(MQQUEUE )
INSUFFICIENT ACCESS AUTHORITY
ACCESS INTENT(UPDATE ) ACCESS ALLOWED(NONE )

The queue had been define with AUDITING FAILURES(READ)

Another queue had been defined with NOTIFY(COLIN). This means that whenever there was a violation, userid COLIN got a message sent to its TSO session.

RACF reports violations and audit information to SMF. You can use standard RACF facilities, such as RACF report writer, to process the SMF data.

Using RACF report writer

This RACFRW command is documented in the Z/OS Security Server RACF Auditors Guide. (Note this is deprecated, but the replacement seems to leave it to the user to do all the summarising etc.)

//SMFDUMP EXEC PGM=IFASMFDP,REGION=0M
//SYSPRINT DD SYSOUT=A
//ADUPRINT DD SYSOUT=A
//OUTDD DD DISP=(MOD,CATLG),DSN=IBMUSER.SMF,
// SPACE=(CYL,(5,5)),
// DCB=(BLKSIZE=13000,RECFM=VB)
//SMFDATA DD DISP=SHR,DSN=SYS1.S0W1.MAN1
//SMFDATB DD DISP=SHR,DSN=SYS1.S0W1.MAN2
//SMFOUT DD DISP=(NEW,PASS,DELETE),SPACE=(CYL,(10,1)),
// DSN=&&SMFOUT
//SYSIN DD *
  INDD(SMFDATA,OPTIONS(DUMP))
  INDD(SMFDATB,OPTIONS(DUMP))
  OUTDD(SMFOUT,TYPE(020,030,080,081,083))
  DATE(2020221,2022221)
  START(0000)
  ABEND(NORETRY)
  USER2(IRRADU00) 
  USER3(IRRADU86) 
/* 
//S1  EXEC PGM=IKJEFT01,REGION=0M 
//SYSPRINT DD SYSOUT=* 
//SORTWK01 DD  DISP=(NEW,PASS,DELETE),SPACE=(CYL,(10,1)), 
//             DSN=&&SORT1 
//SYSTSPRT DD SYSOUT=* 
//RSMFIN  DD DISP=(SHR,DELETE),DSN=*.SMFDUMP.SMFOUT 
//SYSTSIN DD * 
  RACFRW TITLE('RACF REPORTS') GENSUM 
  SELECT VIOLATIONS 
  SUMMARY RESOURCE BY(USER) 
  END 
/* 

The report gave


USER/                                               -------- I N T E N T S--------           
    *JOB                  SUCCESS WARNING VIOLATION ALTER CONTROL UPDATE READ TOTAL 

MQCMDS =+CSQ9.REFRESH.SECURITY                                                                                    
    COLIN      COLIN PAICE      0       0         1     1       0      0    0     1 

MQQUEUE=CSQ9.ZZZZ 
    ADCDC      ADCDC            0       0         1     0       0      1    0     1 
    COLIN      COLIN PAICE      0       0         6     0       0      6    0     6

From this we can see userid COLIN (with owner’s name COLIN PAICE) had 6 violations trying to get UPDATE access to the queue(MQQUEUE) ZZZZ in queue manager CSQ9.

The userid COLIN also tried to use the REFRESH SECURITY command. The + in +CSQ9, means that a generic profile was used. There was one violation, needing ALTER access.

Auditing successes

When the queue had AUDITING ALL(READ) it wrote a record for all accesses to the queue – success or failure.

using

//SYSTSIN DD *
RACFRW TITLE('RACF REPORTS') GENSUM
SUMMARY RESOURCE BY(USER)
END
/*

and no Select statement, it reported all records. I had an application which opened a queue for output, put a message to it, opened the queue for input, got the message. The output of RACFRW had

USER/                                               -------- I N T E N T S--------           
    *JOB            SUCCESS WARNING VIOLATION ALTER CONTROL UPDATE READ TOTAL                                                                     
MQADMIN = 
    COLIN   COLIN PAICE    8     0         0     0       0      0    0      8
MQQUEUE = CSQ9.ZZZZ 
    COLIN   COLIN PAICE   14     0         1     0       0     15    0     15
    IBMUSER                2     0         0     2       0      0    0      2

For every open/close of the ZZZZ queue, there were two opens for update, and and open of the MQADMIN class – with no object.

With AUDITING FAILURES(READ), so only failures of READ access or above are logged, the output was

USER/                                               -------- I N T E N T S--------           
    *JOB            SUCCESS WARNING VIOLATION ALTER CONTROL UPDATE READ TOTAL                                                                     
MQADMIN = 
    COLIN   COLIN PAICE    2     0         0     0       0      0    0      2

With an entry once for each job.