What was new in the MQ API?

I wanted to know what new features were available in different releases of MQ, but could not find the information documented.

I’ve taken the CMQC C header file from different releases on z/OS and shown the differences!

From MQ V8.0 to V9.0.1

CMQC

MQCNO_CURRENT_VERSION          5      
MQCNO_VERSION_6                6 
MQCNO_CURRENT_VERSION          6

MQCNO_CURRENT_LENGTH           188    
MQCNO_LENGTH_6                 208 
MQCNO_CURRENT_LENGTH           208 

MQAT_MCAST_PUBLISH             36 
MQAT_AMQP                      37 
MQAT_DEFAULT                   2 

MQOT_PROT_POLICY               1019 
MQOT_TT_CHANNEL                1020 
MQOT_AMQP_CHANNEL              1021 
MQOT_AUTH_REC                  1022 
MQ_AMQP_CLIENT_ID_LENGTH       256
MQRC_STORAGE_MEDIUM_FULL       2192
MQRC_ADMIN_TOPIC_STRING_ERROR  2598 
MQRC_AMQP_NOT_AVAILABLE        2599 
MQRC_CCDT_URL_ERROR            2600
MQADOPT_CHECK_CHANNEL_NAME     8  

MQCMDL_CURRENT_LEVEL           800                         
MQCMDL_LEVEL_801               801 
MQCMDL_LEVEL_802               802 
MQCMDL_LEVEL_900               900 
MQCMDL_LEVEL_901               901 
MQCMDL_LEVEL_902               902 
MQCMDL_LEVEL_903               903 
MQCMDL_LEVEL_904               904 
MQCMDL_LEVEL_905               905 
MQCMDL_CURRENT_LEVEL           905 

MQPL_APPLIANCE                 28
MQCAP_EXPIRED                  2 

 /* Media Image Scheduling */ 
MQMEDIMGSCHED_MANUAL           0 
MQMEDIMGSCHED_AUTO             1 
                                                                 
 /* Automatic Media Image Interval */ 
MQMEDIMGINTVL_OFF              0 
                                                                 
 /* Automatic Media Image Log Length */ 
MQMEDIMGLOGLN_OFF              0 
                                                                 
 /* Media Image Recoverability */ 
MQIMGRCOV_NO                   0 
MQIMGRCOV_YES                  1 
MQIMGRCOV_AS_Q_MGR             2

MQCA_AMQP_SSL_CIPHER_SUITES    2137 
MQCA_AMQP_VERSION              2136  
  
MQCA_LAST_USED                 2135     
MQCA_LAST_USED                 2137   

MQIA_ADVANCED_CAPABILITY       273 
MQIA_AMQP_CAPABILITY           265 

MQIA_AUTHENTICATION_METHOD     266
MQIA_KEY_REUSE_COUNT           267 

MQIA_LAST_USED                 264               
MQIA_LAST_USED                 273   

/* Key reuse count */ 
MQKEY_REUSE_DISABLED           0 
MQKEY_REUSE_UNLIMITED          (-1)  

struct tagMQCNO { 
  ...
  PMQCHAR    CCDTUrlPtr;           /* Address of CCDT URL string */ 
MQLONG     CCDTUrlOffset;        /* Offset of CCDT URL string */ 
MQLONG     CCDTUrlLength;        /* Length of CCDT URL */ 
MQBYTE8    Reserved;             /* Reserved */ 
  /* Ver:6 */  
}
...
MQCNO_DEFAULT ....                                                       
                                              

CMQCFC

MQCMD_INQUIRE_AMQP_CAPABILITY  216 
MQCMD_AMQP_DIAGNOSTICS         217

MQRCCF_CLWL_EXIT_NAME_ERROR    3374 
MQRCCF_SERVICE_NAME_ERROR      3375 
MQRCCF_REMOTE_CHL_TYPE_ERROR   3376 
MQRCCF_TOPIC_RESTRICTED        3377 
MQRCCF_CURRENT_LOG_EXTENT      3378 
MQRCCF_LOG_EXTENT_NOT_FOUND    3379 
MQRCCF_LOG_NOT_REDUCED         3380 
MQRCCF_LOG_EXTENT_ERROR        3381 
MQRCCF_ACCESS_BLOCKED          3382 

MQ_ENTITY_NAME_LENGTH          64             
MQ_ENTITY_NAME_LENGTH          1024  


MQIAMO_MONITOR_CLASS           839 
MQIAMO_MONITOR_TYPE            840 
MQIAMO_MONITOR_ELEMENT         841 
MQIAMO_MONITOR_DATATYPE        842 
MQIAMO_MONITOR_FLAGS           843 
MQIAMO64_QMGR_OP_DURATION      844 
MQIAMO64_MONITOR_INTERVAL      845 
MQIAMO_LAST_USED               845 

/* Defined values for MQIAMO_MONITOR_FLAGS */ 
MQIAMO_MONITOR_FLAGS_NONE      0 
MQIAMO_MONITOR_FLAGS_OBJNAME   1 
                                                       
/* Defined values for MQIAMO_MONITOR_DATATYPE */ 
MQIAMO_MONITOR_UNIT            1 
MQIAMO_MONITOR_DELTA           2 
MQIAMO_MONITOR_HUNDREDTHS      100 
MQIAMO_MONITOR_KB              1024 
MQIAMO_MONITOR_PERCENT         10000 
MQIAMO_MONITOR_MICROSEC        1000000 
MQIAMO_MONITOR_MB              1048576 
MQIAMO_MONITOR_GB              100000000 

MQIACF_AMQP_ATTRS              1401 
MQIACF_AMQP_DIAGNOSTICS_TYPE   1406 

MQIACF_SYSP_MAX_CONC_OFFLOADS  1412          
MQIACF_LAST_USED               1412          
MQIACF_AUTH_REC_TYPE           1412 
MQIACF_SYSP_MAX_CONC_OFFLOADS  1413 
MQIACF_SYSP_ZHYPERWRITE        1414 
MQIACF_Q_MGR_STATUS_LOG        1415 
MQIACF_ARCHIVE_LOG_SIZE        1416 
MQIACF_MEDIA_LOG_SIZE          1417 
MQIACF_RESTART_LOG_SIZE        1418 
MQIACF_REUSABLE_LOG_SIZE       1419 
MQIACF_LOG_IN_USE              1420 
MQIACF_LOG_UTILIZATION         1421 
MQIACF_LOG_REDUCTION           1422 
MQIACF_LAST_USED               1422 

MQIACH_LAST_USED               1643  
MQIACH_AMQP_KEEP_ALIVE         1644 
MQIACH_SECURITY_PROTOCOL       1645 
MQIACH_LAST_USED               1645

MQCAMO_LAST_USED               2712  
MQCAMO_MONITOR_CLASS           2713 
MQCAMO_MONITOR_TYPE            2714 
MQCAMO_MONITOR_DESC            2715 
MQCAMO_LAST_USED               2715 
                                             
MQCACF_LAST_USED               3206  
MQCACF_AMQP_CLIENT_ID          3207 
MQCACF_ARCHIVE_LOG_EXTENT_NAME 3208 
MQCACF_LAST_USED               3208 

MQCACH_LAST_USED               3570  
MQCACH_TOPIC_ROOT              3571 
MQCACH_LAST_USED               3571

MQGACF_LAST_USED               8014
MQGACF_MONITOR_CLASS           8015 
MQGACF_MONITOR_TYPE            8016 
MQGACF_MONITOR_ELEMENT         8017 
MQGACF_LAST_USED               8017 
  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
MQACT_REDUCE_LOG               10 
MQACT_ARCHIVE_LOG              11 
                                             

MQEVO_REST                     8 

MQRQ_FAILOVER_PERMITTED        30 
MQRQ_FAILOVER_NOT_PERMITTED    31 
MQRQ_STANDBY_ACTIVATED         32 

MQLDAP_AUTHORMD_SRCHGRPSN      3 

/* Authentication Method */ 
MQAUTHENTICATE_OS              0 
MQAUTHENTICATE_PAM             1 
                                                
/* Reduce Log Options */ 
MQLR_ONE                       1 
MQLR_AUTO                      (-1) 
MQLR_MAX                       (-2) 
                                             

From MQ 9.0.1 to MQ 9.1.1

CMQC

MQCNO_CURRENT_VERSION          6          
MQCNO_VERSION_7                7 
MQCNO_CURRENT_VERSION          7 
 
MQCNO_CURRENT_LENGTH           208            
MQCNO_LENGTH_7                 240 
MQCNO_CURRENT_LENGTH           240 

MQCNO_GENERATE_CONN_TAG        0x00200000

MQAN_NONE 
MQAN_NONE_ARRAY
MQRC_INCOMPLETE_TRANSACTION    2147  
MQRC_Q_MGR_RECONNECT_REQUESTED 2601
MQRC_SUB_JOIN_NOT_ALTERABLE    29440

/* Max queue file size values */ 
MQQFS_DEFAULT                  (-1) 

MQCMDL_CURRENT_LEVEL           905               
MQCMDL_LEVEL_910               910 
MQCMDL_LEVEL_911               911 
MQCMDL_LEVEL_912               912 
MQCMDL_LEVEL_913               913 
MQCMDL_LEVEL_914               914 
MQCMDL_LEVEL_915               915 
MQCMDL_CURRENT_LEVEL           915 

MQIA_LAST_USED                 273          
MQIA_LAST_USED                 274   

MQIA_MAX_Q_FILE_SIZE           274  

struct tagMQCNO { 
  ...   
  MQCHAR28   ApplName;             /* Application name */ 
  MQBYTE4    Reserved2;            /* Reserved */ 
  /* Ver:7 */ 
};
MQCNO_DEFAULT.... 

CMQCFC

 MQCMD_AMQP_DIAGNOSTICS         217 
 MQCMD_INTER_Q_MGR_STATUS       218 
 MQCMD_INTER_Q_MGR_BALANCE      219 
 MQCMD_INQUIRE_APPL_STATUS      220 

 MQRCCF_PS_REQUIRED_MQUC        3383 
 MQRCCF_OBJECT_ALREADY_EXISTS   4001 

 MQRCCF_APPL_STATUS_NOT_FOUND   4097 
 MQCFT_STATUS                   27 

MQBACF_LAST_USED               7035   
MQBACF_REQUEST_ID              7036 
MQBACF_PROPERTIES_DATA         7037 
MQBACF_CONN_TAG                7038 
MQBACF_LAST_USED               7038 

MQIACF_LAST_USED               1422   
MQIACF_IGNORE_STATE            1423 
MQIACF_MOVABLE_APPL_COUNT      1424 
MQIACF_APPL_INFO_ATTRS         1425 
MQIACF_APPL_MOVABLE            1426 
MQIACF_REMOTE_QMGR_ACTIVE      1427 
MQIACF_APPL_INFO_TYPE          1428 
MQIACF_APPL_INFO_APPL          1429 
MQIACF_APPL_INFO_QMGR          1430 
MQIACF_APPL_INFO_LOCAL         1431 
MQIACF_APPL_IMMOVABLE_COUNT    1432 
MQIACF_BALANCED                1433 
MQIACF_BALSTATE                1434 
MQIACF_APPL_IMMOVABLE_REASON   1435 
MQIACF_DS_ENCRYPTED            1436 
MQIACF_CUR_Q_FILE_SIZE         1437 
MQIACF_CUR_MAX_FILE_SIZE       1438 
MQIACF_LAST_USED               1438 

MQIACH_LAST_USED               1645         
MQIACH_SPL_PROTECTION          1646 
MQIACH_LAST_USED               1646 

MQCACF_LAST_USED               3208         
MQCACF_APPL_IMMOVABLE_DATE     3209 
MQCACF_APPL_IMMOVABLE_TIME     3210 
MQCACF_LAST_USED               3210 

MQGACF_LAST_USED               8017         
MQGACF_APPL_STATUS             8018 
MQGACF_CHANGED_APPLS           8019 
MQGACF_ALL_APPLS               8020 
MQGACF_APPL_BALANCE            8021 
MQGACF_LAST_USED               8021 
                                            
MQIS_NO                        0 
MQIS_YES                       1 

/* Movable Options */ 
MQAPPL_IMMOVABLE               0 
MQAPPL_MOVABLE                 1 
                                    
/* Active Options */ 
MQACTIVE_NO                    0 
MQACTIVE_YES                   1 
                                    
/* Balance Options */ 
MQBALANCED_NO                  0 
MQBALANCED_YES                 1 
MQBALANCED_NOT_APPLICABLE      2 
MQBALANCED_UNKNOWN             3 
                                    
/* Balance State */ 
MQBALSTATE_NOT_APPLICABLE      0 
MQBALSTATE_LOW                 1 
MQBALSTATE_OK                  2 
MQBALSTATE_HIGH                3 
MQBALSTATE_UNKNOWN             4 

  /* Immovable Reasons */ 
MQIMMREASON_NONE               0 
MQIMMREASON_NOT_CLIENT         1 
MQIMMREASON_NOT_RECONNECTABLE  2 
MQIMMREASON_MOVING             3 
MQIMMREASON_APPLNAME_CHANGED   4 

From MQ 9.1.1 to MQ 9.2.2

CMQC

MQ_NHA_INSTANCE_NAME_LENGTH    48 

MQCMDL_CURRENT_LEVEL           915    
MQCMDL_LEVEL_920               920 
MQCMDL_LEVEL_921               921 
MQCMDL_LEVEL_922               922 
MQCMDL_CURRENT_LEVEL           922 

CMQCF

MQCACF_APPL_IMMOVABLE_TIME     3210 
MQCACF_LAST_USED               3210       
MQCACF_NHA_INSTANCE_NAME       3211 
MQCACF_LAST_USED               3211

MQRQ_STANDBY_ACTIVATED         32 
MQRQ_REPLICA_ACTIVATED         33 

From MQ 9.2.2. to 9.2.4

CMQC

MQBNO structure and  MQBNO_ constants

MQCNO_CURRENT_VERSION          7
MQCNO_VERSION_8                8 
MQCNO_CURRENT_VERSION          8

MQCNO_CURRENT_LENGTH           240    
MQCNO_LENGTH_8                 252 
MQCNO_CURRENT_LENGTH           252 

MQ_TEMPORARY_Q_PREFIX_LENGTH   32 
MQRC_BNO_ERROR                 2602 
MQRC_OUTBOUND_SNI_NOT_VALID    2603 

/* Streaming Queue Quality of Service Values */ 
MQST_BEST_EFFORT               0 
MQST_MUST_DUP                  1 

MQCMDL_CURRENT_LEVEL           922       
MQCMDL_LEVEL_923               923 
MQCMDL_LEVEL_924               924 
MQCMDL_CURRENT_LEVEL           924 

MQCA_LAST_USED                 2137
MQCA_LAST_USED                 2138 

MQIA_LAST_USED                 274      
MQIA_LAST_USED                 275 

MQIA_STREAM_QUEUE_QOS          275 

struct tagMQCNO { 
   ...     
   PMQBNO     BalanceParmsPtr;      /* Balance Parameter Pointer */ 
   MQLONG     BalanceParmsOffset;   /* Balance Parameter Offset */ 
   MQBYTE4    Reserved3;            /* Reserved */ 
   /* Ver:8 */ 
 };   

CMQCFC

MQRCCF_STREAMQ_DEST_NOT_SUPP   3384 
MQRCCF_STREAMQ_DEST_CONFLICT   3385 
MQRCCF_STREAMQ_NOT_SUPPORTED   3386 
MQRCCF_STREAMQ_CONFLICT        3387 
 
MQBACF_LAST_USED               7038    
MQBACF_MQBNO_STRUCT            7039 
MQBACF_LAST_USED               7039 
  
MQIACF_SYSP_SMF_STAT_TIME_MINS 1199 
MQIACF_SYSP_TRACE_CLASS        1200 
  
MQIACF_LAST_USED               1438
MQIACF_BALANCING_TYPE          1439 
MQIACF_BALANCING_OPTIONS       1440 
MQIACF_BALANCING_TIMEOUT       1441 
MQIACF_SYSP_SMF_STAT_TIME_SECS 1442 
MQIACF_SYSP_SMF_ACCT_TIME_MINS 1443 
MQIACF_SYSP_SMF_ACCT_TIME_SECS 1444 
MQIACF_LAST_USED               1444 

MQIACH_AUTH_INFO_TYPES         1622 

MQCACH_LAST_USED               3571      
MQCACH_TEMPORARY_MODEL_Q       3572 
MQCACH_TEMPORARY_Q_PREFIX      3573 
MQCACH_LAST_USED               3573 
                                         
MQIMMREASON_APPLNAME_CHANGED   4 
MQIMMREASON_IN_TRANSACTION     5 
MQIMMREASON_AWAITS_REPLY       6 

“I do not understand these get counts on z/OS”

I had a question from someone who was trying to use the MQ SMF statistics to understand their queue manager usage. This came from a post from Lynn Elkins who was talking about “Data ManagerGets”. I started writing a short answer… but the answer got longer, so I thought I would post on this topic.

The z/OS queue manager has different components, for example the logging component which manages recovery data, the buffer manager which manages pages in the buffer pool, the message manager which handles the API side of MQ requests, and the data manager which manages who messages are mapped to pages in a page set.

There is an SMF statistic QMSTGET which is the number of application MQGET requests, and QISTMGET, the number of requests to data manager to start getting a messages.

I’ll give some examples and explain why there could be a big difference in the numbers.

Shared queue

Simple MQGET of shared queue

An application issues an MQGET, there is a message on the queue but this is a shared queue, so data manager is not involved

QMSTGET is now +1, QISTMGET is unchanged

Local queue

Simple MQGET of local queue

An application issues an MQGET, there is a message on the queue the messsage is returned.

QMSTGET is now +1, QISTMGET is +1GET.

Get with wait when there was no message on the queue

The application issues an MQGET, so increment QMSTGET. The queue is empty, so do not change QISTMGET. Control is returned to the adapter and the application waits. A message arrives, the application is woken up, and reissues the MQGET. The message is returned.

Increment QMSTGET again, increment QISTMGET.
QMSTGET is now +2, QISTMGET is +1

The getting application polls the queue

Rather than use MQGET with wait, the application issues MQGET with no wait. There is a code

Loop forever:
MQGET; if message available then leave loop
else wait for 1 second
end

After 1 hour the statistics could be

QMSTGET is now + 3600, QISTMGET is unchanged.

Multiple applications waiting on a queue

  • 100 applications issue MQGET with wait on a queue.
    • QMSTGET is now +100, and all applications are waiting in the adapter.
  • A message arrives one application wakes up and gets the message
    • QMSTMGET is now +101, QISTGET is now +1
  • The woken application reissues the MQGET
    • QMSTGET is now +102, QISTGET is now +1, and all applications are waiting in the adapter.

An application gets a message by message-id or correl-id

If the queue has not been indexed there is internal logic which searches along the queue for a message with matching message-id or correl-did. For example if there were 1000 messages on the queue, and the message was not found:

QMSTGET is now + 1, QISTMGET is now +1000.

An application gets a message by filter or message property

For example get the next message where the property color=”red”. This is like the previous case. The queue has to be searched looking for the specified property in the message header.

For example if there were 1000 messages on the queue, and the message was not found:

QMSTGET is now + 1, QISTMGET is now +1000.

Should you compare QMSTGET and QISTMGET?

If you gave me the two values, it would be very hard to draw any conclusions from it. Where it might be useful is comparing the difference over time. It delta or ratio changes, then it is likely that something has changed in your system, and could be a hint to go sniffing around.

Of course the delta or difference is likely to change with time of day, and day of week, so make sure you compare a similar time period.

Where’s my publish?

Like many things I do, it all started with an easy problem. I had an application which subscribed to a topic, it published on a topic string, then got the published message. Another application subscribed on the same topic string but did not get the message. I’ll leave clues for the experts to spot as I explain the progress I made.

The first complication was the subscribing and publishing application was in Python on z/OS (which runs in ASCII), and the other application was written in C using the default EBCDIC. I had to spend time working out how to convert from ASCII to EBCDIC. (When using CHARV you can specify a string and its code page and have MQ do it for you automatically – easy once you know which code page to use.) For other strings I had to convert manually using the A2E function from C run time.

There are some commands for displaying status of pub sub, it took a little while to understand them and give me the data I wanted.

For example

My application did a subscription with topic string “/currency/rate/EUR/GBP”.
The command gave

DIS TPSTATUS(‘/currency/rate/EUR/GBP’)
CSQM297I … CSQMDRTC NO TPSTATUS FOUND MATCHING REQUEST CRITERIA

Once I had opened the topic using the topic string, I got

CSQM201I … CSQMDRTC DIS TPSTATUS DETAILS
TPSTATUS(/currency/rate/EUR/GBP)
TYPE(TOPIC)
DEFPRESP(SYNC)
PUB(ENABLED)
SUB(ENABLED)
ADMIN()
RETAINED(NO)
PUBCOUNT(0)
SUBCOUNT(1)
PUBSCOPE(ALL)
SUBSCOPE(ALL)

I set up the subscription using Python

topic_string = ‘/currency/rate/EUR/GBP’
sub_desc = pymqi.SD() # create the basic subscription
sub_desc[‘Options’] = pymqi.CMQC.MQSO_CREATE + pymqi.CMQC.MQSO_RESUME +
pymqi.CMQC.MQSO_DURABLE + pymqi.CMQC.MQSO_MANAGED
sub_desc.set_vs(‘SubName’, “MYSUB” )
sub_desc.set_vs(‘ObjectString’, topic_string)

The code to get the subscribed message was

get_opts = pymqi.GMO(
MsgHandle=hMsg.msg_handle,
Options=pymqi.CMQC.MQGMO_NO_SYNCPOINT +
pymqi.CMQC.MQGMO_CONVERT +
pymqi.CMQC.MQGMO_PROPERTIES_IN_HANDLE +
pymqi.CMQC.MQGMO_FAIL_IF_QUIESCING +
pymqi.CMQC.MQGMO_WAIT)
get_opts[‘WaitInterval’] = 1000
data = sub.get(None, pymqi.md(), get_opts)
print(‘Received data: [%s]’ % data)

The code to publish to a topic was

msg = ‘1.3961’
topic = pymqi.Topic(qmgr, topic_string=topic_string)
topic.open(open_opts=pymqi.CMQC.MQOO_OUTPUT)
topic.close()

The Python program was subscribe, publish to topic, get the message.

When I ran the code, no messages were published. I tried changing the topic_string to ‘/currency/rate/EUR/USD’, that had no effect. Eventually I tracked down a code page problem in my code; I fixed that – but the program still did not publish a message.

The more knowledgable people reading this may have spotted one problem.

The first time the program ran, the subscription code created a SUB(MYSUB) with the given topic string (‘/currency/rate/EUR/USD’). When I changed the topic string to ‘/currency/rate/EUR/GBP’, and published a message, the subscription was using the original topic string with USD!, but publishing to GBP. Any changes to the SUBscription are ignored unless MQSO_ALTER is specified.

I deleted the SUB and reran my application. Displaying the subscription (MYSUB) gave

CSQM201I %CSQ9 CSQMDRTC DIS SUB DETAILS 934
SUB(MYSUB)
SUBID(C3E2D8D4C3E2D8F94040404040404040DAFEED99504CE540)
DURABLE(YES)
SUBTYPE(API)
TOPICSTR(/currency/rate/EUR/GBP)
SUBLEVEL(1)

I can display the topic string and see what is subscribed to it

dis tpstatus(‘/currency/rate/EUR/GBP’) type(sub)

This gave two subscriptions:

TPSTATUS(/currency/rate/EUR/GBP)
TYPE(SUB)
SUBID(C3E2D8D4C3E2D8F94040404040404040DAFE062AED26E2C0)
DURABLE(YES)
SUBTYPE(ADMIN)
SUBUSER(IBMUSER)

NUMMSGS(12)

and

TPSTATUS(/currency/rate/EUR/GBP)
TYPE(SUB)
SUBID(C3E2D8D4C3E2D8F94040404040404040DAFC73649B3C7200)
DURABLE(YES)
SUBTYPE(ADMIN)
SUBUSER(IBMUSER)

NUMMSGS(0)

So one subscription has seen 12 messages, the other subscription has seen 0 messages. This does not look like a wrong topic string, as they are resported as part of the display tpstatus.

I could not find a way of displaying all the information about a subscription in one command. I had to use DIS TPSTATUS.. TYPE(SUB), then use cut and paste to issue the DIS SUB SUBID(….). (It would be much easier for the poor end users if there was an ALL option to display all this data in one go.)

For example

SUB(COLIN)
SUBID(C3E2D8D4C3E2D8F94040404040404040DAFC73649B3C7200)
DURABLE(YES)
SUBTYPE(ADMIN)
DISTYPE(RESOLVED)
TOPICSTR(/currency/rate/EUR/GBP)
DEST(CP0000)

DESTQMGR()
DESTCORL(C3E2D8D4C3E2D8F94040404040404040DAFC73649B3C7200)
TOPICOBJ()
PUBACCT(00000000000000000000000000000000000000000000000000000000…)
USERDATA(CZZZ)
SUBUSER(IBMUSER)
SUBLEVEL(1)

So we can see from this subscription the topic string being subscribed on, and the queue name being used.

This subscription had no messages published to it; see the DISPLAY TPSTATUS TYPE(SUB) field NUMMSGS. Those of you with a PhD in PubSub may have spotted the problem; it is very well hidden. It is all to do with PubLevel and SubLevel. (The documentation is very confusing, it implies a subscription can have more than one sublevel).

I think of it as logic within publish which says for each subscription

If SubLevel <= PubLevel then publish the message
else skip the publish
  • The subscription from the python code had SubLevel = 0. (This was latent bug – it should have been set to 1!
  • The SubLevel from my DEFINE SUB command was the default 1.
  • The PubLevel from the Python code was 0 – this was the problem.

So the publish to my manual DEFINE SUB was skipped, and the publish to the Python code worked because PubLevel = 0 matched SubLevel = 0

The message is being published – but it is not still not there.

When I restarted my queue manager and ran the test, the Python application got no message found, which was a surprise to me. When I reran it, with debug code enabled – the get worked, and carried on working all day. Next day the same problem occurred. Very strange – is the debug code affecting the messages ?

I then remembered the default syncpoint behaviour (one of those face palm moments). On midrange the default is to put out out sync-point, so the messages are immediately available. On z/OS the default is to put within sync-point. The messages are only visible after a commit, or the implicit commit at MQDISC. On z/OS the messages were in syncpoint, and there was no commit. When I ran my program the second time, it got the message from the first run, and so on!

I put the commit in – and it all worked.

Check list of what to check

Check you are subscribing to the correct topic string.

Plan carefully how you define your topic(strings).

If you want to have an application define a subscription, consider some defensive programming.

  • MQSO_CREATE will create a subscription based on the specified data. If it already exists report an error.
  • MQSO_CREATE + MQSO_RESUME will create a subscription based on the specified data. If it already exists it will not report an error. A second usage will not change the subscription.
  • MQSO_CREATE + MQSO_ALTER will create a subscription based on the specified data. A second usage will update the subscription. This could be considered dangerous if you have multiple applications running concurrently changing the topic string or other parameters.
  • MQSO_RESUME does not create a subscription, not updates it. it uses the information in the subscription object.

It would be safer for an Administrator to define the MQSUB, and the applications to refer to it. Do not allow application users to be able to define a subscription. They should use the pre-defined MQSUB and add the topic string to give more granular data. For example I could use a null object and have a topic string of /TOP/SECRET/DATA/SPIESIN/ENGLAND. If you haven’t set up security properly then I could access the data.

Check the PubLevel and the SubLevel.

If you are not using this functionality set PubLevel to 9 and SubLevel to 1 ( the defaults).

You can DISPLAY SUB(….) SUBLEVEL to see the specified value.

The PubLevel is specified in the MQPMO.PubLevel. There is no display command for this.

Check the sync-point options.

You should always, always, always specify MQPMO_NO_SYNCPOINT, or MQPMO_SYNCPOINT and the commit. Do not let it default in case someone ports your code to or from z/OS. You can waste days hunting down this problem.

What do you mean, I can’t set the maximum queue depth?

Ive been involved with MQ for the whole of its life (I worked on the very first release), and I’ve just discovered something which is really basic!

I was testing out some code, and wanted to set the max depth of the queue to a low value for the duration of a test.

I thought this was easy; just use MQSET, specify parameter MQIA_MAX_Q_DEPTH, and the value I wanted (9).

When it reported

Reason 2067: FAILED: MQRC_SELECTOR_ERROR

I added in extra code to printout the values and yes, this was the value returned. If this was a bug I was sure it would have been spotted many years ago. I checked the documentation (remember, if all else fails, read the documentation). Look, I can set get inhibit, put inhibit etc ahh – max depth was not listed.

So when you get Reason 2067: FAILED: MQRC_SELECTOR_ERROR please check the documentation.

Colin’s list of MQ messages

This blog post is my annotations to MQ messages, containing descriptions of what I did to get an MQ message, and what I did to fix the problem. It is meant for web search programs, rather than humans.

I will extend it as I experience problems.

AMQ7026E: A principal or group name was invalid.

I could display an auth entry

dspmqaut -m qml -t qmgr -g “cn=dynamic, o=Your Company”


Entity cn=dynamic, o=Your Company has the following authorizations for object qml:
connect

but not delete it

setmqaut -m qml -t qmgr -g “cn=dynamic,o=Your Company” -connect

AMQ7026E: A principal or group name was invalid.

I had set this up using LDAP, but MQ was not able to find the record in LDAP. This is because I had changed the configuration. There was an LDAP search

(&(objectClass=groupOfNames)(OU=cn=dynamic, o=Your Company))

It could not be found because there was no LDAP entry with objectClass=groupOfNames with an entry (OU=cn=dynamic, o=Your Company)

I had changed

DEFINE AUTHINFO(MYLDAP) +
AUTHTYPE(IDPWLDAP) +
GRPFIELD(sn)

to

GRPFIELD(ou)

So when MQ came to delete it, it looked for

(&(objectClass=groupOfNames)(OU=cn=dynamic, o=Your Company))

instead of

(&(objectClass=groupOfNames)(SN=cn=dynamic, o=Your Company))

and could not delete it.

I changed the LDAP group to add the OU, and the SETMQAUT command worked.

AMQ5532E: Error authorizing entity in LDAP

EXPLANATION:
The LDAP authorization service has failed in the ldap_first_entry call while
trying to find user or group ‘NULL’. Returned count is 0. Additional context is
‘cn=mqadmin,ou=groups,o=your Company’.

Colin’s comments

I had defined a dynamic group, by specifying the group name as part of the LDAP user entry.

When I changed the authinfo object yo have nestgrp(yes), I got the above message because there was no record for cn=mqadmin,ou=groups,o=your Company’.

Define the record with the appropriate object class as defined by the MQ AUTHINFO attribute CLASSGRP. (CLASSGRP(‘groupOfNames’) in my case).

AMQ5530E: Error from LDAP authentication and authorization service

EXPLANATION:
The LDAP authentication and authorization service has failed. The
‘ldap_ssl_environment_init’ call returned error 113 : ‘SSL initialization call
failed’. The context string is ‘keyfile=”/var/mqm/qmgrs/qml/ssl/key.kdb”
SSL/TLS rc=408 (ERROR BAD KEYFILE PASSWORD)’. Additional code is 0.

Colin’s comments.

I had changed the keyring using alter qmgr CERTLABL(ECRSA1024) SSLKEYR(‘/home/colinpaice/mq/zzserver’)

AMQ5530E: Error from LDAP authentication and authorization service

EXPLANATION:
The LDAP authentication and authorization service has failed. The
‘ldap_simple_bind’ call returned error 49 : ‘Invalid credentials’. The context
string is ‘10.1.1.2:389 ‘. Additional code is 0.

Colin’s comments

An anonymous logon to LDAP was attempted (LDAPUSER and LDAPPWD omitted) and the LDAP server had allowAnonymousBinds off.

Specify userid and password.

API: 2460 (099C) (RC2460): MQRC_HMSG_ERROR during get

I had this during an MQGET when the GMO was not using Version:4.

This would apply to PMO not using Version:3.

Reason 2464: FAILED: MQRC_IMPO_ERROR

MQIMPO impo = {MQIMPO_DEFAULT};

I got this return code because I had a C program on z/OS and compiled it using the ASCII option. This meant the IMPO eye catcher was ASCII 0x494D504F)  instead of EBCDIC 0xC9D4D7D6.

MQIMPO impo = {MQIMPO_DEFAULT};

// if we are in ascii mode we need to convert eyecatcher from ASCII to
// EBCDIC
__a2e_l(impo.StrucId,sizeof(impo.StrucId));

This also applies to

2482: FAILED: MQRC_PD_ERROR

2440 (0988) (RC2440): MQRC_SUB_NAME_ERROR

I got this because my data was in EBCDIC, but I had specified the code page as 437 ( ASCII).

AMQ9669E The PKCS #11 token could not be found

AMQ9669E The PKCS #11 token could not be found. Severity 30 : Error Explanation The PKCS #11 driver failed to find the token specified to MQ in the PKCS #11 token label field of the GSK_PKCS11 SSL CryptoHardware parameter. The channel is <insert_3>; in some cases its name cannot be determined and so is shown as ‘????’. The channel did not start. Response Ensure that the PKCS #11 token exists with the label specified. Restart the channel.

I got this when I had the following in my mqclient.ini

SSL:

SSLCryptoHardware=GSK_PKCS11=/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so\;UserPIN (mytoken)\;12345678\;SYMMETRIC_CIPHER_ON\;

I commented out the SSLCryptoHardware… (I used #SSLCryptoHardware…) and it worked.

Z/OS messages

CSQY010E %CSQ9 CSQYASCP LOAD MODULE CSQYARIB IS NOT AT THE CORRECT
RELEASE LEVEL

If you get CSQYARIB then this can be caused by running Beta code past its validity date.

CSQX630E %CSQ9 CSQXRESP Channel ???? requires SSL

The chinit needs some SSL tasks and a keyring

%csq9 ALTER QMGR SSLTASKS(5) SSLKEYR(MQRING)

Restart the CHINIT.

Return codes

3015 (0BC7) (RC3015): MQRCCF_CFST_PARM_ID_ERR

IBM Documentation: Explanation. Parameter identifier is not valid. The MQCFST Parameter field value was not valid.

Colin’s comment. I passed a value which was valid, but the context was not valid. For example I issued a PCF command to start SMDSCONN. On the console the command gave

CSQM174E M801 CSQMSSMD ‘SMDSCONN’ KEYWORD IS NOT ALLOWED WITH CFLEVEL(4) – THIS KEYWORD REQUIRES CFLEVEL(5)

3229 (0C9D) (RC3220) MQRCCF_PARM_VALUE_ERROR

I got this trying to use MQCMD_INQUIRE_Q.

I had used qtype=MQOT_LOCAL_Q = 1004 when I should have used MQQT_LOCAL = 1

The PCF return message told me the incorrect parameter and value

2019 (07E3) (RC2019): MQRC_HOBJ_ERROR

I got the MQRC_HOBJ_ERROR when using MQSUB to subscribe to a topic. This is described here.

Colin’s comment

I got this because the queue I was using was not consistent with the subscription definition. For example

  • The subscription was using a managed subscription and I was using a queue
  • The queue name I specified in the queue handle did not match the queue name in the subscription

You can use the DISPLAY SUB(..) DEST DESTCLAS

A managed subscription will have a DEST(SYSTEM.MANAGED.DURABLE…) and DESTCLAS(MANAGED).

When using a queue you will have DEST(COLINSUBQ) DISTYPE(RESOLVED)


LDAP error messages and codes

This blog post is a repository for the LDAP error codes I experienced, and the actions I took to resolve the problems.

LDAP return codes

Messages include return codes like “3”, but the LDAP programming book has terms like “LDAP_PARAM_ERROR”.

These are defined in

/usr/include/ldap*.h,

SSL initialization failures reason codes.

https://www.ibm.com/docs/en/zos/2.5.0?topic=utilities-ssltls-information-ldap-client#idg18488__failrc

GLD1342E Unwilling to open file or directory ‘/var/ldap/schema’:

File or directory UID 0, UID of program 990023, GID of file or directory 1, GIDs of program (990018).

Colin’s comments

The LDAP started task expects to be the file owner of the /var/ldap/* files. On ADCD they were OMVSKERN:OMVSGRP. I used

chown -R gldsrv:gldgrp /var/ldap/*

to change the file owner.

Object class violation: additional info: R001026 No structural object class specified for ‘cn=ibmuser, o=Your Company’.

Colin’s comments

I had an ldif file with

dn: cn=mq, o=Your Company
changetype: add
objectclass: top
#objectclass: person
#objectclass: organizationalPerson
objectclass: ibm-nativeAuthentication
cn: mq
telephoneNumber: 1234567
telephoneNumber: 12345672
sn: Administrator

And no proper object class. When I uncommented person or organizationalPerson it worked.

R001030 Entry contains attribute ‘ibm-nativeid’ which is not allowed for object class

I was trying to add ‘ibm-nativeid’ to an entry. This attributed belongs to object class ibm-nativeAuthentication. The object has to have this object class, for example, add the lines in the bold font.

dn: cn=colin, o=Your Company
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: ibm-nativeAuthentication
cn: LDAP Administrator
sn: Administrator
ibm-nativeId: COLIN

Credentials are not valid: R004062 Credentials are not valid

By accident I overwrote my administration userid definition.

Colin’s comments

Edit GLD.CNFOUT(DSCONFIG) ( or what every config file you are using)

Comment out the adminDN, and add in the cn=admin and its password.

From

adminDN “cn=ibmuser, o=Your Company”
# adminDN “cn=Admin”
# adminPW secret

to

# adminDN “cn=ibmuser, o=Your Company”
adminDN “cn=Admin”
adminPW secret

  • Stop and restart LDAP.
  • Fix the userid
  • Change the admin definitions back
  • restart LDAP.

R003070 Access denied because user does not have ‘write’ permission for all modified attributes

I used a command like ldapmodify -a -h 127.0.0.1 -p 389 -D “cn=adcda, o=Your Company” -w adcdapw1 -f mqacl.* to change some definitions, but the userid cn=adcda,o=Your Company did not have the correct permissions.

You can enable the LDAP acl trace using f gldsrv,debug 128, and reset it using f gldsrv,debug 0

To change/add/delete an ACL the id needs restricted:rscw

For example

dn: o=Your Company
changetype: modify
replace: aclEntry
aclEntry : access-id:cn=ibmuser, o=Your Company:
object:ad:normal:grant:rscw:sensitive:rscw:critical:rscw
aclEntry : access-id:cn=adcda, o=Your Company:
object:ad:normal:rscw:sensitive:rscw:critical:rscw:restricted:rscw

Insufficient access: R003057 Access denied because user does not have ‘add’ permission for the parent entry

Trying to add an entry.

The userid is not authorised to add an entry. It needs an acl with object:ad ( a for add, d for delete)

dn: o=Your Company
changetype: modify
replace: aclEntry
aclEntry : access-id:cn=ibmuser, o=Your Company:
object:ad:normal:rscw:sensitive:rscw:critical:rscw
aclEntry : access-id:cn=adcda, o=Your Company:
object:ad:normal:rscw

GLD1116E Unable to initialize an SSL connection with …: 515 – Key share list is not valid.

My GSK_CLIENT_TLS_KEY_SHARES GSK_SERVER_TLS_KEY_SHARES environment variables had an invalid value. They had 0021 which is not supported in TLS 1.3.

Look in the gsktrace

GLD1063E Unable to initialize the SSL environment: 416 – Permission denied.

GLD1160E Unable to initialize the LDAP client SSL support: Error 113, Reason -17.

ICH408I USER(GLDSRV ) GROUP(GLDGRP ) IRR.DIGTCERT.LISTRING CL(FACILITY) INSUFFICIENT ACCESS AUTHORITY ACCESS INTENT(READ ) ACCESS ALLOWED(NONE )

In the LDAP config file I had sslKeyRingFile START1.MQRING. The userid GLDSRV did not have read access to the list ring facitity IRR.DIGTCERT.LISTRING CL(FACILITY)

permit IRR.DIGTCERT.LISTRING CL(FACILITY) id(GLDSRV)
SETROPTS RACLIST(FACILITY) REFRESH

GLD1160E Unable to initialize the LDAP client SSL support: Error 113, Reason 705

I had GSK_OCSP_CLIENT_CACHE_SIZE=10000, when I set it to 100, it worked.

GLD1160E Unable to initialize the LDAP client SSL support: Error 113, Reason 2.
GLD1063E Unable to initialize the SSL environment: 202 – Error detected while opening the certificate database.

  • reason code 2: Keyring open error
  • SSL return code 202: Keyring open error

Actions

  • Check value specified
  • Check access
    • rdefine rdatalib START1.MQRING.LST UACC(NONE)
    • SETROPTS RACLIST(RDATALIB) REFRESH
    • permit START1.MQRING.LST class(RDATALIB) ACCESS(READ) id(GLDSRV)

Check the keyring exists ( list the contents of it)

RACDCERT LISTRING(name) ID(COLIN)

Get out a gsk trace .

  • Add GSK_TRACE=0xff to the env file.
  • By default the output goes to gskssl.*.trc
  • Format it using gsktrace gskssl.*.trc gsktrace.out
  • oedit gsktrace.out search for ERROR. I had ERROR gsk_open_keyring(): IRRSDL00 GetData failed: SAF 8, RC 8, Reason 84.
  • These are documented here. 8 8 84 means keyring not found.

GLD1160E Unable to initialize the LDAP client SSL support: Error 113, Reason -99.

Reason -99 is GSK_ERROR_UNKNOWN_ERROR!

I got this when trying to use OCSP with LDAP. I had

GSK_OCSP_RESPONSE_SIGALG_PAIRS=0601050305010804

If I remove the 0804 ( or 0806 or 0805) then startup got past this message.

GLD1116E Unable to initialize an SSL connection 8 – Certificate validation error.

Colin’s comments

I got this many times for many different reasons.

I had Certificate Revocation List processing enabled.

In the GSK trace I had

ERROR check_crl_issuer_extensions(): crlSign bit is not set in KeyUsage
ERROR check_revoked(): Unable to verify CRL issuer extensions: Error 0x03353026

03353026 Incorrect key usage.

Explanation: The key usage certificate extension does not permit the requested key operation.

My CA was not defined properly I needed

keyUsage = keyCertSign, digitalSignature,cRLSign

GLD1116E Unable to initialize an SSL connection openssl SSL alert number 42

Colin’s comments

The certificate sent from the client was missing the authorityKeyIdentifier extension, because the CA certificate is missing.

In the -config xxx.cnf and the specified -extensions … or the default extensions

subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always

You need to change the CA, regenerate the end user certificate, and redistribute the CA.

533 – Remote partner indicates unsupported certificate.

GLD1116E Unable to initialize an SSL connection 402 – No SSL cipher

Colin’s comments 1

I could see from the gsktrace on zOS there was a message ERROR read_client_hello_cipher_select(): No intersection with client cipher suites.

This means the list of available cipher specs on the server did not include the one sent from the client.

Colin’s comments 2

The server’s certificate was not compatible with the list in GSK_V3_CIPHER_SPECS_EXPANDED. For example the list had only EC certificates, but the server was RSA.

Colin’s comments 3

I had a server certificate defined as

SIZE(521) NISTECC …

In the trace I had

EXIT gsk_get_ec_parameters_info(): <— Exit status 0x00000000 (0) EC curve type 34, key size 521
ERROR send_v3_alert(): Sent SSL V3 alert 40 to 10.1.0.2[38736]

INFO edit_ciphers(): Server certificate ec curve 0034 not in supported ecurve tls extension. EC cipher suites disabled

When I changed the size to 256 it worked, and used (C02C,C02B,C024,C023)

From here 0034 is TLS_DH_anon_WITH_AES_128_CBC_SHA

GLD1116E Unable to initialize an SSL connection with 10.1.0.2: 412 –
SSL protocol or certificate type is not supported.

Colin’s comments

The server had been configured for only GSK_PROTOCOL_TLSV1_3=on.

The GSKTRACE output has Client does not support TLS V1.3. No protocol version match found.

GLD1116E Unable to initialize an SSL connection with … 434 – Certificate key is not compatible with cipher suite.

Colin’s comments

The server’s certificate is not consistent with the certificate sent from the client.

For example the server is using an RSA certificate, but the client is sending and EC certificate.

For example server is an RSA certificate. From the list GSK_V3_CIPHER_SPECS_EXPANDED = C024C006C007C008c024c023c025130313011302009E

it chooses 009E. 009E is TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 =

128-bit AES in Galois Counter Mode encryption with 128-bit AEAD authentication and ephemeral Diffie-Hellman key exchange signed with an RSA certificate.

When my elliptic certificate from the client comes in,

Signature Algorithm: SHA256withRSA, Key: Sun EC public key, 521 bits, parameters: secp521r1 NIST P-521

This is incompatible.

When the server certificate is an Elliptic certificate, then certificate C024 is used. C024 is

TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 256-bit AES encryption with SHA-384 message authentication and ephemeral ECDH key exchange signed with an ECDSA certificate.

This works for both of them.

GLD1116E Unable to initialize an SSL connection 440 – Incorrect key usage.

Colin’s comments.

The server’s certificate was defined with KEYUSAGE(CERTSIGN,KEYAGREE)

When I added HANDSHAKE, recreated the certificate, and restarted the LDAP server it worked. KEYUSAGE(HANDSHAKE,CERTSIGN,KEYAGREE).

Certsign says this is a used as a CA.

GLD1116E Unable to initialize an SSL connection with 127.0.0.1: 533 – Remote partner indicates unsupported certificate.

Colin’s comments.

I got this when the GSK_TLS_SIG_ALG_PAIRS=”0403″ did match up with the server’s version.

In the gsktrace for the server I got TLS 1.3 alert 43 received from

In the client’s gsktrace it had

Certificate key algorithm 13, Signature algorithm 25
INFO read_tls13_certificate(): Using client’s signature algorithm list to check server certificate chain
ERROR read_tls13_certificate(): Signature algorithm 25 in server certificate not in client signature algorithms list
ERROR send_tls13_alert(): Sent TLS 1.3 alert 43 to …

in gskcms.h

  • x509_alg_ecPublicKey = 13,
  • x509_alg_sha256WithRsaEncryption = 25,

GLD1116E Unable to initialize an SSL connection with 127.0.0.1: 467 – Signature algorithm not in signature algorithm pairs list.

See previous for 553. The GSK_TLS_SIG_ALG_PAIRS from the client does not mach the server certitificate’s signature.

RACDCERT LIST(LABEL(‘SERVEREC’ )) id(start1)

gives

Signing Algorithm: sha256RSA

This table says 0401 SHA-256 with RSA, so this value is needed in the GSK_TLS_SIG_ALG_PAIRS.

GLD1116E Unable to initialize an SSL connection with …: 516 – No key share groups in common with parter

The configuration was

  • server GSK_SERVER_TLS_KEY_SHARES=0030
  • client GSK_CLIENT_TLS_KEY_SHARES=0024

Specify values with a common value.

TLS 1.3 supports 00300029002500240023

TLS 1.2 supports 00250024002300210019

So you could specify =002300240025

LDAPSEARCH client on Linux

ldap_search_ext: Bad search filter (-7)

with -b “o=Your Company” “&(objectClass=*)”

remove the &()s

-b “o=Your Company” “objectClass=*”

worked

ldap_sasl_interactive_bind_s: Unknown authentication method (-6)
additional info: SASL(-4): no mechanism available:

No certificate was sent from the client to the host.

ldap_sasl_interactive_bind_s: Can’t contact LDAP server (-1)
additional info: A TLS fatal alert has been received.

Colin’s comments 1

The list of certificate types the client sent up ( first part of the handshake) did not match any of the list of supported certificates in GSK_V3_CIPHER_SPECS_EXPANDED=009E002FC027c02dc023c025130313011302

I used Wireshark to display network traffic, and the the list of supported certificate types sent in the client hello.

z/OS gsktrace shows

Initial SSL V3 4-character cipher specs:
009E002FC027C02DC023C025130313011302
SSL V3 cipher C02D skipped due to key algorithm
SSL V3 cipher C023 skipped due to key algorithm
SSL V3 cipher C025 skipped due to key algorithm
SSL V3 cipher 1303 skipped for TLS V1.2 sessions
SSL V3 cipher 1301 skipped for TLS V1.2 sessions
SSL V3 cipher 1302 skipped for TLS V1.2 sessions
SSL V3 cipher specs: 009E002FC027
Using TLSV1.2 protocol
Using V3 cipher specification 009E

  • 009E is TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
  • 002F is TLS_RSA_WITH_AES_128_CBC_SHA
  • C027 is TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

and the z/OS default key had

Signing Algorithm: sha256RSA
Key Usage: HANDSHAKE, DATAENCRYPT, DOCSIGN
Key Type: RSA
Key Size: 4096

Colins’s comments 2

In the gsktrace I had

ERROR check_ocsp_signer_extensions(): extended keyUsage does not allow OCSP Signing

This is because the certificate used in the ocsp server, did not have

Extended Key Usage: critical, OCSP Signing

Resign the certicate and check the attribute has been set by

openssl x509 -in ocspcert.pem -text -nooutless

ldap_sasl_interactive_bind_s: Can’t contact LDAP server (-1)
additional info: An unknown public key algorithm was encountered.

Colin’s comments

As part of the “certificate verify”, the Signature Algorithm passed to the server, was not in the GSK_TLS_SIG_ALG_PAIRS list in the z/OS LDAP environment file.

Check all relevant are specified

GSK_TLS_SIG_ALG_PAIRS=060105010401030108060805080405030403

ldap_sasl_interactive_bind_s: Can’t contact LDAP server (-1)
additional info: (unknown error code)

I got this when using OCSP for certificate validation. OCSP sent down a flow from the server, and the ldapserver code was not expecting it, so ends.

Action: set

GSK_SERVER_OCSP_STAPLING=OFF

ldap_sasl_interactive_bind_s: Invalid credentials (49)


additional info: R004062 Credentials are not valid (srv_ssl_get_client_info:928)

Colin’s comments 1.

The TLS handshake was accepted, but the mapping of the DN to a userid did not return a userid.

Turn on LDAP trace using f GLDSRV,debug LDAPBE gave

LDAPBE srv_process_bind_request()374: do_bind msgID=1, connID=4, flags=0x22, controls=0x0, DN=”, authType=3, bindType=1, version=3
LDAPBE srv_process_bind_request()939: do_return_bind msgID=1, connID=4, bindDN=”, safUserID=”, dnList=0x0, grpList=0x0, rc=49: R004062 Credentials are not valid (srv_ssl_get_client_info:928)

ERROR srv_process_bind_request()957: Request failed OP code=0 bind=CN=secp521r,O=cpwebuser,C=GB

Map the certificate to a userid – note the ‘.’ in the SDNFILTER name.

//S1 EXEC PGM=IKJEFT01,REGION=0M
//STEPLIB DD DISP=SHR,DSN=SYS1.MIGLIB
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
*RACDCERT LISTMAP ID(ADCDE)
*RACDCERT DELMAP(LABEL('LINUXECEC' )) ID(ADCDE)
*SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH
RACDCERT MAP ID(ADCDE ) -
   SDNFILTER('CN=secp521r.O=cpwebuser.C=GB') -
   WITHLABEL('LINUXECEC)
RACDCERT LISTMAP ID(ADCDE)
SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH
/*

Once you have defined the mapping, you do not need to restart LDAP, it is picked up on the next usage.

Colin’s comments 2.

The mapping of certificate to userid exists, but the userid is revoked, or otherwise not available.

ERROR srv_ssl_get_client_info() 902: safRc=8 racfRc=8 racfRsn=40

This is from R_usermap (IRRSIM00): Map application user

  • racfrsn 28 – Certificate is not valid.
  • racfrsn 40 – The Distinguished Name length is not valid, or the Distinguished Name string is all blanks (x’20’), all nulls (x’00’), or a combination of blanks and nulls.
  • racfrsn 48 – There is no distributed identity filter mapping the supplied distributed identity to a RACF user ID, or The IDIDMAP RACF general resource class is not active or not RACLISTed.

ldap_ssl_client_init failed! rc == 113, failureReasonCode == 2

This is not listed in table 7 of the LDAP client programming

I turned on trace using ldapsearch .. -d all …

and got

ERROR ldap_ssl_client_init()710: Unable to initialize SSL environment: Error 202
TRACE ldap_ssl_client_init()744: <= Status 113, Reason 2

Error code 202 is in the table = Keyring open error.

ldap_connect()409: Unable to initialize SSL connection to 127.0.0.1[1389]: Error 116, Reason -99

Colin’s comments

This was due to a mismatch in the GSK_TLS_SIG_ALG_PAIRS statement.

ldap_connect()409: Unable to initialize SSL connection to 127.0.0.1[1389]: Error 116, Reason -13

Colin’s comments

This was due to a mismatch in the supported versions of TLS.

ldap_connect()409: Unable to initialize SSL connection to 127.0.0.1[1389]: Error 116, Reason 438

ldap_ssl_socket_initUnable to initialize SSL connection: Error 456.

Colin’s comments

On the system log I had

ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
CSFOWH CL(CSFSERV )
INSUFFICIENT ACCESS AUTHORITY
ACCESS INTENT(READ ) ACCESS ALLOWED(NONE )

I used the following to get access, and it worked.

permit CSFOWH class(CSFSERV) ACCESS(read) id(COLIN)
SETROPTS RACLIST(CSFSERV) REFRESH

What they don’t tell you about using a REST interface.

After I stumbled on a change to my Python program which gave 10 times the throughput to a Web Server, I realised that I knew only a little about using REST. It is the difference between the knowledge to get a Proof Of Concept working, and the knowledge to run properly in production; it is the difference between one request a minute to 100 requests a second.

This blog post compares REST and traditional client server and suggests ways of using REST in production. The same arguments also apply to long running classical client server applications.

A REST request is a stateless, self contained request which you send to the back-end server, and get one response back. It is also known as a one shot request. Traditional client server applications can send several requests to the back-end as part of a unit of work.

In the table below I compare an extreme REST transaction, and an extreme traditional Client Server

AttributeRESTClient Server
ConnectionCreate a new connection for every request.Connect once, stay connected all day, reuse the session, disconnect at end of day.
Workload BalancingThe request can select from any available server, and so on average, requests will be spread across all connections. If a new server is added, then it will get used.The application connects to a server and stays connected. If the session ends and restarts, it may select a different server.
If a new server is added, it may not be used.
AuthenticationEach request needs authentication. If the userid is invalidated, the request will fail. Note that servers cache userid information, so it may take minutes before the request is
re-authenticated.
Authentication is done as part of the connection. If the userid is invalidated during the day, the application will carry on working until it restarts.
IdentificationBoth userid+password, and client certificate can be used to give the userid.Both userid+password, and client certificate can be used to give the userid. If you want to change which identity is used, you should disconnect and reconnect.
CostIt is very expensive to create a new connection. It is even more expensive when using TLS, because of the generation of the secret key. As a result it is very very expensive to use REST requests.The expensive create connection is done once, at start of day. Successive request do not have this overhead, so are much cheaper
Renew TLS session keyBecause there is only one transfer per connection you do not need to renew the encryption key.Using the same session key for a whole day is weak, as it makes it easier to break it. Renewing the session key after an amount of data has been processed, or after a time period is good practice.
RequestSome requests are suitable for packaging in one request, for example where just one server is involved.This can support more complex requests, for example DB2 on system A, and MQ on system B.
Number of connectionsThe connection is active only when it is used.The connection is active even though it has not been used for a long time. This can waste resources, and prevent other connections from being made to the server.
StatisticsYou get an SMF record for every request. Creating an SMF record costs CPU.You get one SMF record for collection of work, so reducing the overall costs. The worst case is one SMF record for the whole day.

What are good practices for using REST (and Client Server) in production?

Do not have a new connection for every request. Create a session which can be reused for perhaps 50 requests or ten minutes, depending on workload. This has the advantages :

  • You reduce the costs of creating the new connection for every request, by reusing the session.
  • You get workload balancing. With the connection ending and being recreated periodically, you will get the connections spread across all available connections. You should randomise the time a connection is active for, so you do not get a lot of time-out activity occurring at the same time
  • You get the re-authentication regularly.
  • The TLS key is renewed periodically.
  • You avoid the long running connections doing nothing.
  • For a REST request you may get fewer SMF records, for a Client-Server you get more SMF requests, and so more granular data.

How can I do this?

With Java you can open a connection, and have the client control how long it is open for.

With Python and the requests package, you can use

s = requests.Session()
res = s.get(geturl,headers=my_header,verify=v,cookies=jar,cert=cpcert)

res = s.get(geturl,headers=my_header,verify=v,cookies=jar,cert=cpcert)
etc

With Curl you can reuse the session.

Do I need to worry if my throughput is low?

No, If you are likely to have only one request to a server, and so cannot benefit from having multiple requests per connection you might just as well stay with a “one shot” and not use any of the tuning suggestions.

One Minute MVS performance – TCP/IP

Question: In your car how do you tell if your car has a problem? Answer: You look at the dashboard and see if there is a red light showing. You may not know how to fix it – but you know that you need to get help to fix it.

The aim of this series of blog posts is to show you what to look for in z/OS performance and if you have a problem.

I will cover

What is a TCP/IP performance problem?

People complain about a TCP/IP performance problem when “it” seems slow. This could be caused by a variety of problems

  • Data between two ends is being discarded. This can occur on an unreliable, or overloaded component, whose default action is to throw away data, knowing it will be resent.
  • The time taken to get from one end to the other and back (“a ping”) is slow. This can be caused by slow or overloaded components.
  • There is a lot of data to send, for example a movie, or a web page with lots of javascript or graphics.
  • Or all of the above.

There is a quote “Never under estimate the bandwith with of a lorry full of tapes”. It might take 10 hours, but a truck 6 ft wide by 20 ft long could hold 300,000 1TB tapes and deliver 8 TBytes/second (with a round trip time of 20 hours). Which is more than the internet can provide!

You need to know

  • Are packets being thrown away? You see this from the number of packets which were resent.
  • What is the round trip time? (You could use ping – but you may not be able to)
  • Is data being sent efficiently – in big blocks?

TCP/IP concepts

With TCP/IP there is a connection between a sender and a receiver. The sender sends numbered packets of data to the receiver. The receiver sends an acknowledgement that a packet has been received.

The following is a representation of the flow

  • The sender sends packet 1
  • The sender sends packet 2
  • The sender sends packet 3
  • The receiver receives packet 1 and sends an acknowledgement for packet 1
  • The sender sends packet 4
  • The receiver receives packet 2 and sends an acknowledgement for packet 2
  • The sender waits until the acknowledgement of packet 1 has been received
  • The sender sends packet 5 and waits till the acknowledgement of packet2 has been received
  • etc

This way it is self limiting. It means the sender cannot send more than the receiver can handle.

If a packet goes missing, eventually the sender gets a time out, and resends it.

There are two parts to “performance”.

  1. FTP like: How much data can be sent per second. This is of interest to FTP and MQ, where there is mainly a one way transmission of lots of data. The round trip time is not so critical if you can have a lot of data in transit.
  2. Transactional: Send some data and wait for the remote end to respond, for example a web browser. The amount of data may be measured in KB, but the round trip time is important.

The term “window” is often used in TCP/IP.

The term “send window” on the sender side represents the total number of packets yet to be acknowledged by the receiver. With a bigger window, there is more data in the pipe line, and the throughput goes up. With a window of 1, one packet is sent and the sender waits for the acknowledgement before sending the next. With this, if there is a high latency, the overall throughput will be low.

More details

One of the factors that affects performance is the receive buffer size. If this was set to 4KB, it means that an application can read up to 4 KB of data at a time. This receive buffer size is sent to the sender, and basically says “send chunks up to this size – as that is all the receiver can take” – this sets the send-buffer-size.

The term Dynamic Right Sizing(DRS) allows the TCP receive buffer size to expand if the network conditions are favourable.

The term Outbound Right Sizing(ORS) allows the TCP send buffer size to expand if the network conditions are favourable.

Another term used is congestion window. If too much data is sent, or the network is unreliable, packets will get lost or thrown away. The congestion window is a measure of how much data can be in-flight. If packets get lost, the congestion window is made smaller. If packets are not lost, then it will try to increase the congestion window. This is a very rough indication of the quality of the network.

FTP like performance

There are several factors which can improve the throughput down a connection

  • Make packets bigger. In the early days of TCP/IP a typical packet was 256 bytes. These days a typical default packet size can be 64KB or more.
    • One of the Smarts in the protocol is called dynamic right sizing, where TCP will send increasing larger packets until the receiver says “big enough”. The packet size can change with load.
  • How much data to send before waiting for the acknowledgement. For a reliable connection, where data is never lost, it is efficient to send a lot of data before waiting. This is called a large send window.
  • If the connection is unreliable, it may be more efficient to have only a small send window, before waiting for the acknowledgement.

Transactional work

  • Having big buffers may not improve throughput, for example with a web page, the data may all fit into 2KB. In this case having a buffer size of 16KB or 64 KB may make no difference to throughput or performance.
  • Typically if one packet contains all the data, then this will be acknowledge as soon as it arrives.
  • Some web pages with a lot of javascript or images, may require big buffers, and many packets.

How to see what is going on

You can use the well known “ping” command to send data to the remote end, and get the response. This gives a measure of the network time.

I found most of the data for looking at performance, is available from the netstat command. I found it useful to capture the output of the command in a file or data set.

What connections are connected to this server?

I use the netstat command in TSO , because my fingers are more used to it, and the command options are more memorable than the omvs command ( for example with omvs netstat, do I need the -a or -A option)

netstat conn (port 1414
netstat conn report hlq colin ( port 1414
netstat conn report dsn ‘colin.output’ ( port 1414

These all gave the same output. The report hlq colin creates a data set colin.netstat.conn. The data set name is from the hlq, ‘netstat’, and the subcommand. You can specify a data set name using the ‘dsn’ option.

For omvs you can use

netstat -c -p TCPIP -P 1414 > filename

That lists all of the connections for port 1414.

The command gave me

MVS TCP/IP NETSTAT CS V2R4       TCPIP Name: TCPIP           09:18:34    
User Id  Conn     Local Socket           Foreign Socket         State    
-------  ----     ------------           --------------         -----    
CSQ9CHIN 00000023 10.1.1.2..1414         10.1.0.2..60538        Establsh 
CSQ9CHIN 00000022 0.0.0.0..1414          0.0.0.0..0             Listen   

There is one connection established from 10.1.0.2 port 60538 to the server with the port listening on 1414.

The commands below give a lot of information about the connection

netstat all report hlq colin (ipport 10.1.0.2+60538
netstat -A -p TCPIP -B 10.1.0.2+60538 > all.port1

Output from the netstat command

The fields are described at the bottom of this page.

Both commands gave me the same output.

There is a lot of data. I’ve broken it into sections with comments after the interesting fields.

  MVS TCP/IP NETSTAT CS V2R4       TCPIP Name: TCPIP           09:23:29 
  Client Name: CSQ9CHIN                 Client Id: 00000023 
  Local Socket: 10.1.1.2..1414          Foreign Socket: 10.1.0.2..60538 
  BytesIn:            0000002988        BytesOut:           0000002912 
  SegmentsIn:         0000000019        SegmentsOut:        0000000011   
  
  • 09:23:29 is the time when request was made. If you repeat the command you can get the interval between commands, and so calculate rates.
  • You get the client (job) name CSQ9CHIN.
  • The listener socket for the job (local socket) 10.1.1.2 with port 1414.
  • The foreign socket – the remote end of the connection. IP address 10.1.0.2 port 60538.
  • You can get the data rate If you repeat the command, calculate the deltas BytesIn and BytesOut, and divide by the time between measurement.
  StartDate:          06/16/2021        StartTime:          10:00:21 
  Last Touched:       10:20:37          State:              Establsh 
  RcvNxt:             2019327903        SndNxt:             0864946572 
  ClientRcvNxt:       2019327903        ClientSndNxt:       0864946572 
  InitRcvSeqNum:      2019324914        InitSndSeqNum:      0864943659 
  CongestionWindow:  0000018720        SlowStartThreshold: 0000065535 
  

Look at the congestion window. Big is good. Small may indicate small amounts of data being sent or it may indicate network problems, either slow connections or packets are being dropped.

  IncomingWindowNum:  2019458463        OutgoingWindowNum:  0865008524 
  SndWl1:             2019327903        SndWl2:             0864946572 
  SndWnd:             0000061952        MaxSndWnd:          0000064256 
  

Check the send window. A small (1KB) send window can indicate poor configuration at the remote client, or only small amounts of data are being sent.

  SndUna:             0864946572        rtt_seq:            0864946064 
  MaximumSegmentSize: 0000001440        DSField:            00 
  Round-trip information:
    Smooth trip time: 6.000              SmoothTripVariance: 12.000 
  

Monitor the smooth route trip time (in milliseconds) this the local end to the remote end, and back. The variance gives a measure of the spread of response times. These are not strictly averages.

If you had a million requests taking 1 millisecond, and then had a long request taking 1000 milliseconds. The “Average” response time would change by a very small amount (to 1.09 milliseconds). The smoothed (or weighted average) may be something like – (99 * previous average + current value) /100. In this case the “average” goes up to 10.9 milliseconds, which is noticeable different.

  ReXmt:              0000000000        ReXmtCount:         0000000000 

The re transmits should be zero – or not changing. If this number increases it means the network has lost packets.

  DupACKs:            0000000000        RcvWnd:             0000130560  

The receive window is usually set to 2 * receive buffer.

   SockOpt:            88                TcpTimer:           00   

Check SockOpt. Check bit 0x08. If set this indicates “delayed acknowledgement disabled”. See Nagle algorithm. This value being set is good.

If this is not set, then sender can delay sending data for up to about 200 ms, and so combine data from different applications into the same packet for the same destination. This reduces network traffic as there are fewer packets, but it delays the data being sent.

  TcpSig:             04                TcpSel:             40 
  TcpDet:             E4                TcpPol:             00 
  TcpPrf:            81                TcpPrf2:            20 
  TcpPrf3:            00

For FTP type applications check the TCP Performance Flag TcpPrf. This says if Dynamic Right sizing (using bigger buffers) is enabled. The flag bits are x80 – enabled, x40 Active, x20 Active but disabled. X80 |X40 is good.

The TCP performance flag2 TcpPrf2. This is for outbound right sizing (ORS). A non zero value is good.

  DelayAck:           Yes 
  QOSPolicy:          No 
  TTLSPolicy:         No 
  RoutingPolicy:      No 
  ReceiveBufferSize:  0000065536        SendBufferSize:     0000065536  

These buffer sizes should be large with 64KB or larger, if so the system can dynamically increase them.

They can be configured at the TCP/IP level, or by the application. If they are 64KB or higher then TCP Dynamic Right Sizing can be used (adjust the buffers to match the load).

  ReceiveDataQueued:  0000000000 
  SendDataQueued:     0000000000  

These should always be zero.

  • Received data queued means the application is slow to retrieve the data
  • Send data queued – the application has issued a send – but TCP/IP cannot process it.
  SendStalled:        No 
  Ancillary Input Queue: N/A  

Send stalled should always be no.

What do you need to check?

  • SendStalled, ReceiveDataQueued,SendDataQueued should all be 0. They usually are 0. They would be non zero if there was a problem right now. If the problem gets better, these values would be 0.
  • Check ReXmt = The total number of times a packet has been retransmitted for this connection. This count is historical for the life of the connection.
    • If this is zero then there have been no re transmits, and so no packets lost.
    • If this is non zero, then it could be a historical problem. Wait and reissue the netstat command. If the ReXmt value has changed, this indicates packets are being lost.
  • Check the round trip time (and variance). Is the value what you expected? If there is traffic flowing on the connection, display the value multiple times, and see if there is significant variation.
  • Check ReceiveBufferSize and SendBufferSize. Values of 64KB or larger are good. Small is not good.
  • Check congestion window.

It is good to have some data for a normal day, and a problem day. For example if the packets are often lost, then this may not be the problem. If the SendBufferSize is only 8KB today and was 64KB last week – this would a good place to start looking. So capture and save NETSTAT reports for typical sessions.

What about connections into z/OS

Windows has a netstat command.

On Linux Netstat has been superseded with ss for example

ss –info dst 10.1.1.2
ss –info dst 10.1.1.2:1414
ss –info src 101.0.2

This is ss dash dash info …

gives similar information for connections going to 10.1.1.2, or the address and port 10.1.1.2:1414

Example netstat output from a slow FTP in connection

Client Name: IBMUSER                  Client Id: 000006FE 
Local Socket: 10.1.1.2..1109          Foreign Socket: 10.1.0.2..35508 
  BytesIn:            0220191104        BytesOut:           0000000000
  SegmentsIn:         0000152946        SegmentsOut:        0000083051
  StartDate:          06/28/2021        StartTime:          13:47:56 
  Last Touched:       14:24:28          State:              Establsh 
  RcvNxt:             3569682809        SndNxt:             2105824963
  ClientRcvNxt:       3569577977        ClientSndNxt:       2105824963
  InitRcvSeqNum:      3349491704        InitSndSeqNum:      2105824962
  CongestionWindow:   0000005760        SlowStartThreshold: 0000065535
  IncomingWindowNum:  3569946679        OutgoingWindowNum:  2105889219
  SndWl1:             3569681369        SndWl2:             2105824963
  SndWnd:             0000064256        MaxSndWnd:          0000064256
  SndUna:             2105824963        rtt_seq:            2105824962
  MaximumSegmentSize: 0000001440        DSField:            00 
  Round-trip information: 
    Smooth trip time: 3.000             SmoothTripVariance: 2.000 
  ReXmt:              0000000000        ReXmtCount:         0000000000
  DupACKs:            0000000000        RcvWnd:             0000263870 
  SockOpt:            A0                TcpTimer:           00 
  TcpSig:             04                TcpSel:             40 
  TcpDet:             E0                TcpPol:             00 
  TcpPrf:             E0                TcpPrf2:            28 
  TcpPrf3:            00 
  DelayAck:           Yes 
  QOSPolicy:          No 
  TTLSPolicy:         No 
  RoutingPolicy:      No 
  ReceiveBufferSize:  0000184351        SendBufferSize:     0000184320 
  ReceiveDataQueued:  0000104832 
    OldQDate:         06/28/2021        OldQTime:           14:24:27 
  SendDataQueued:     0000000000 
  SendStalled:        No 
  Ancillary Input Queue: N/A 
  Application Data:   EZAFTP0S D IBMUSER   C      FSSH 

Comments

  • Congestion window low
  • Smooth trip time: 3.00 good
  • ReXmt: 0 good
  • Receive buffr 184351- good
  • Receive buffer queued 104832 – BAD

How to move a queue from one page set to another page set on z/OS?

I was asked this excellent question, and a quick search in the documentation showed there is a section in the documentation How to balance loads on page sets. Great – this worked a treat – for user queues, but there are a few additional things you need to consider. You also need to be careful when moving system queues.

Moving application queues.

Once you have moved the queues, you should backup the definitions so if you have to recreate the queue manager, you have a copy of the correct definitions you can use.

You need to update your central repository with the new storage class, and the updated definition for the queues and storage class. This is for when you deploy a new queue manager, it picks up the correct definitions.

Moving system queues.

This is the same as for application queues, but you have to do more.


Many people use the CSQINP1 and CSQINP2 data sets provided by the queue manager so they are executed at startup. This is what happens if you use the default QMGR JCL. If you move the SYSTEM.* queues you will need to make a copy of the datasets, make changes to the data sets, so the objects have the correct storage class, and then change the queue manager job to point to the new data sets. Alternatively create a file with the DEFINE QL.. objects you have changed, and have this member first in the list. This file would be executed first. If the objects do not exist, they would be created.

Note: If definitions have DEFINE … REPLACE the definition will override any existing definition.

SYSTEM.COMMAND.INPUT queue

You will not be able to move SYSTEM.COMMAND.INPUT using commands in CSQUTIL, as the command processor reads from this queue. You need to

+cpf alter ql(SYSTEM.COMMAND.INPUT) get(disabled) put(disabled)

This will stop the command processor.

Use commands from the operator console to move it to the new page set

Once you have moved the queue use

+cpf start cmdserv

to restart the command server.

If you want to use SYSTEM.* objects used by the CHINIT you will need to stop the CHINIT for the duration of the moves.

Other system queues

You should also review any model queues, for example SYSTEM.CLUSTER.TRANSMIT.MODEL.QUEUE, and SYSTEM.COMMAND.REPLY.MODEL, so any future queues are created on the correct page set.

Someone pointed out that they were not able to move SYSTEM.PENDING.DATA.QUEUE because a system thread had it open. The altered the queue to get(disabled), the system thread closed the queue, and so they were able to move it.

When to do this?

You may want to schedule an outage while moving queues around, especially SYSTEM.* queues. The moves should be very quick (unless you have deep queues). The other tasks may take longer to do.

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