Using PyArg_ParseTupleAndKeywords to parse data in Python external functions.

I was failing to use PyArg_ParseTupleAndKeywords succcessfully in an external Python function. It took about a day to get it to work. Below are some of the lessons learned in using this facility.


When Python calls an external function (written in C) you can pass parameters, and keywords. For example a function taking one positional parameter, and keywords a,b,c,d could be used:

rc = zconsole.put( 12345 , d = 7, b = 10 )

rc = zconsole.put( 12345 , b=10, d= 7)


  • 12345 is a positional parameter,
  • keyword d is set to the value 7
  • keyword b is set to the value 10
  • the keyword values a and c are not set, and the values are unchanged.

My C program had

static PyObject *console_put(PyObject *self, PyObject *args, PyObject *keywds ) {

int a = 0;
int b = 0;
int c = 0;
int d = 0;
int pos0 = 0;
int pos1 = 0;
static char *kwlist[] = {“pos0″,”pos1,”,”a”,”b”,”c”,”d”,NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds, “i|i$iiii”, kwlist,
&pos0 ,
&pos1 ,
&a , // i
&b , // i
&c , // i
&d )) // i
return NULL;

The kwlist array contains the keywords, so it includes a,b,c,d. It must also include labels for the positional parameters (I was missing this for the first day!). pos0 is for the first positional parameter. There is also an optional second position parameter pos1. The list ends with a NULL.

The PyArg_ParseTupleAndKeywords function takes

  • args passed into your function
  • keywds passed into your function
  • the format string “i|i$iiii”. This says
    • i – a required positional integer
    • | – following parameters are optional
    • i -an optional positional integer
    • $ – the following are keywords
    • iiii – 4 integers corresponding to the keywords in {“pos0″,”pos1,”,“a”,”b”,”c”,”d”,NULL};

The message

SystemError: more argument specifiers than keyword list entries (remaining format:’i’)

means the number of elements in the format string does not match the number of elements in the keywords array. I got the above error when I removed “pos0″,”pos1” from the list.

Processing strings

With well defined values like integers have a known length. Strings can have different sizes.

In the format you define s#,

  • s – return a pointer to the string
  • # – give the length of the string.

Py_ssize_t lMsg;
char * p;

static char kwlist[] = {“pos0″,”pos1″,”a”,”b”,”c”,”d”,NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds, “i|i$s#iii”, kwlist,
&pos0 ,
&pos1 ,
&p , // s this variable is a string
&lMsg , // this is the size of the string the ‘#’ above
&b , // i this variable is int
&c , // i this variable is an int
&d )) // i
{ return NULL; }

The code

rc = zconsole.put( 12345 , a = “abcde”, b = 10 )



Setting up the function to use keywords

You need to set a flag to say that keywords are being used. For example

static struct PyMethodDef console_methods[] = {
{“put”, (PyCFunction)console_put,METH_KEYWORDS | METH_VARARGS, console_put_doc},
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */

I want to pass a variable number of data items

You can configure PyArg_ParseTupleAndKeywords with a list containing optional fields, but how do you pass multiple fields in?

You can say parse the data, and return a field as a python object.

PyObject *rv = NULL;

if (!PyArg_ParseTupleAndKeywords(args, keywds, “O|….”, kwlist,
&rv ,

rc = PyTuple_Check(rv );
if (rc == 1 ) // it is a tuple
size = PyTuple_Size(rv );
printf(“Tuple size %d\n”,size);

The “O” code says return the object, rather than the string.

You can now do your own checks on the code for example get the type of the object.

  • rc = PyList_Check(t );
  • rc = PyLong_Check( t)
  • rc = PyBytes_Check(t );
  • rc = PyByteArray_Check(t);
  • rc = PyBool_Check(t);
  • rc = PyFloat_Check(t);
  • rc = PyFunction_Check(t) ;
  • rc = PySet_Check(t );
  • rc = PyTuple_Check(t );
  • rc = PyDict_Check(t );
  • rc = PyUnicode_Check(t);
  • rc = PyComplex_Check(t);

There is no “getType” function as such see here.

Once you know it’s type you can use Pyxxx_Size to get the size, or number of elements in the object.

If the data is a tuple of 3 bits of data

rc = zconsole.put((“a123456789″,”b123″,”c44” ) )

PyTuple_Check(rv) will return 1, and you can get the number of elements using PyTuple_Size which returns 3.

You can use PyArg_ParseTuple to dig into the objects you have retrieved, for example, for the object rv obtained above:

if (!PyArg_ParseTuple(rv, “s#|s#”,
&p1 , // message text
&lMsg1 , //i
&p2 , // message text
return NULL;
printf(“p1 %.s\n”,lMsg1,lMsg1,p1);
printf(“p2 %.s\n”,lMsg2,lMsg2,p2);

Parsing a fixed size tuple

You can use ‘(…)’ within the format string to process data in a tuple, so you do not need to dig into the object

if (!PyArg_ParseTupleAndKeywords(args, keywds, “(s#s#)|$iiiii”, kwlist,
&p1 , // string1
&lMsg1 , //i
&p2 , // string2
&lMsg2, //i

Getting the type of an object

There is no “getType” function as such.

You can use

int type;
type = PyType_GetFlags(Py_TYPE(rv ));
printf(“TYPE = %8.8x\n”,type);

The values of type are listed here. A constant is defined as


which is 0x04000000. I found it easier to use the pyTuple_Check() function than decode the fields.

How do I assemble a program in Unix System Services using the c complier?

My preferred way of assembling some code is to use JCL. The next best way is to use the “as – Use the HLASM assembler to produce object files“. (For example “as -a -d xxxx.o xxxx.s 1>a”) Unfortunately I needed to use the”C” compiler xlc, because I wanted to compile a file for a Python External command.

The basic syntax is

xlc “-Wa,LIST” zonsole.s 1>a 2>b


  • -Wa specifies these are options for the assembler source
  • LIST says generate a listing. By default it does not generate a listing, only the error file.
  • zonsole.s is my assembler source program
  • 1>a says put the listing into file a
  • 2>b says put the error file into file b

At the top of the listing file is

No Overriding ASMAOPT Parameters
No Process Statements

** ASMA425N Option conflict in invocation parameters. LIST overrides an earlier setting.

The options in the -Wa are described here

Should all red flags be green?

This question came out of a discussion on an MQ forum, where the question was if MQ does one time delivery, how come he got the same message twice?

Different sorts of MQ gets.

There are a variety of patterns for getting a message.

  • Destructive get out of sync-point. One application can get the message. It is removed from the system. As part of the MQGET logic there is a commit of the get so once it has gone it has gone. This is usually used for non persistent message. Persistent messages are usually processed within sync-point, but there are valid cases when the get of a persistent out of sync-point is valid.
  • Destructive get within sync-point. One application can get the message. The queue manger holds a lock on the message which makes it invisible to other applications. When the commit is issued (either explicitly or implicitly) , the message is deleted. If the application rolls back (either implicitly of explicitly) the message becomes visible on the queue again, and the lock released.
  • Browse. One or more applications can get the message when using the get-with-browse option. Sync-point does not come into the picture, because there are no changes to the message.
  • One problem with get-with-browse is you can have many application instances browsing the queue, and they may do the same work on a message, wasting resources. To help with this, there is cooperative browse. This is effectively browse and hide. This allows a queue monitor application to browse the message, and start a transaction saying process “this” message. A second instance of the queue monitor will not see the message. If the message has not been got within a specified time interval the “hide” is removed, and so the message becomes visible. See Avoiding repeated delivery of browsed messages.

The customer’s question was, that as the get was destructive, how come the message was processed twice – could this be a bug in MQ?

The careful reader may have spotted why a message can be got twice.

Why the message was processed “twice”.

Consider an application which does the following

MQGET destructive, in sync-point

Write “processed message id …. ” to the log
Update DB2 record

You might the see following in the log

processed message id x’aabbccdd01′.
processed message id .x’aabbccdd02′.
processed message id x’eeffccdd17′. .

Expanding the transaction to give more details

MQGET destructive, in sync-point
Write “processed message id …. ” to the log
Update DB2 record

If DB2 update worked then commit
else backout

If there was a DB2 problem, you could get the following on the log:

processed message id x’aabbccdd01′.
processed message id x’aabbccdd01′.
processed message id x’eeffccdd17′. .

You then say “Ah Ha – MQ delivered the message twice”. Which is true, but you should be saying “Ah Ha – MQ delivered the message but the application didn’t want it. The second time MQ delivered it, the application processed it”. Perhaps change the MQ phrase to “MQ does one time successful delivery“.

Why is this blog post called Should all red flags be green?

A proper programmer (compared to a coder), will treat a non successful transaction as a red flag, and take an action because it is an abnormal situation. For example write a message to an error log

  1. Transaction ABCD rolled back because “DB2 deadlock on ACCOUNTS table”
  2. Transaction ABCD rolled back because “MQ PUT to REPLYQUEUE failed – queue full”
  3. Transaction ABCD rolled back because “CICS is shutting down”

The Architects and systems programmers can look at these messages and take action.

For example with DB2, investigate the lock held duration. Can you reduce the time the lock is held, perhaps by rearranging with within a unit of work, for example “MQGET, MQPUT reply, DB2 update, commit” instead of “MQGET, DB2 update, MQPUT of reply, commit.

For MQ queue full, make the maximum queue depth bigger, or find out why the queue wasn’t being drained.

CICS shutting down.You may always get some reasons to rollback.

Once you have put an action plan in place to reduce the number of red flags, you can mark the action item complete, change its status from red to green and keep the project managers happy (who love green closed action items).

Note: This may be a never ending task!

After thought

In the online discussion, Morag pointed out that perhaps the same message was put twice. Which would show the same symptoms. This could have been due to a put out of syncpoint, and the transaction rolled back.

Using z/OSMF Network Configuration assistant for TCPIP, to define AT-TLS configuration

I initially found it hard to set up the AT-TLS configuration for MQ. The easiest way was to use the sample configurations provided by MQ. See here for an overview. I used Scenario 5 – Between an IBM MQ for z/OS queue manager and a client application running on IBM MQ for Multiplatforms.

Using the MQ samples, this took about 10 minutes once I had PAGENT and SYSLOGD set up.

I thought I would try to use the TCP provided facilities. There is a lot of documentation, but it is not easy to find what you need. It has been written as an IBM developer, rather than from an end user or task based perspective.

I then thought I would try to use the “way of the future” and the z/OS configuration tool z/OSMF. You use a browser to connect to z/OSMF and do your work through the browser interface. The z/OSMF interface has configuration tools, and workflow tools which guide you step by step through configuration.

I’ve blogged Using z/OSMF workflows for TCPIP. Using the workflow was not very successful.

The Network Configuration Assistance is used to configure the PAGENT, and I used it to define a AT-TLS configuration. Initially this was a struggle as there was no documentation to tell me how to do it. Once I had been through the configuration a couple of times, I found the correct path through the configuration progress and it is relatively painless.

My mission.

My mission was to configure AT-TLS and to provide two ports for use with MQ.

I wanted to do this using two people (me with two userids) and do the typical steps when changing systems, such as saving configurations before changing them, and deploying them, when I had a “change window”.

Using the Network configuration assistant (CA)

AT-TLS concepts

You need to be aware of the AT-TLS concepts when defining the configuration. From an administrator’s perspective:

  • What ports you want to protect? This is known by the CA as Traffic Descriptors. You can specify
    • An IP port
    • A range of IP ports
  • What IP addresses you want to protect.
    • The IP address. A TCP/IP stack can support different IP addresses. You can use a specific IP address. You can select on all IPV4, or all IPV6, or all addresses.
    • The name of a group of IP addresses. z/OSMF CA calls these Address Groups.
  • How do you want to protect the session. For example what levels of TLS, and what cipher specs do you want to use. This is known by the CA as Security levels.
  • The mapping of ports to protecting the session. z/OSMF calls this Requirement Maps.
  • You configure at the TCPIP stack level.
  • z/OSMF has groups of z/OS instances, with one or more z/OS instances, and you can have multiple TCPIP stacks in a z/OS instance.

Backing store

The configuration assistant(CA), stores configuration in a backing store. You can use tools to copy the current store. I found a copy of the file in /global/zosmf/data/app/CAV2R4/backingStore/save Data. I should be able to use standard backup procedures to keep a copy of the file. The resulting configuration is created in a file which is used by PAGENT.

You can copy a backing store within the CA, and so go back to the original one if you need to.

Before you start.

You should collect the information that you will be used to configure PAGENT. For example

  • Which systems and IP stacks will be used.
  • Which keyrings and certificates will be used?
  • For each port you want to protect.
  • What rules do you want, for example which cipher specs.

I found the terms used when creating the rules manually – did not map to the CA concepts, but once you understood the difference in terminology it was ok.

How to define the resources

If you define the configuration bottom up. You define all of the rules, then when you get to configure the TCPIP stack, the rules and other components should all be there, you just have to select them.

If you define the configuration top down, you define the TCPIP stack, then the rules for the stack. You have to define the TCPIP stack, then the rules, then go back and reconfigure the TCPIP stack to add the rules.

I think bottom up configuration is better while you gain experience of the tool. Once you are familiar with the tool then the top down approach will work ok, and may be how you update the configuration.

Getting started

  • Double click on the Network Configuration Assistant icon.
  • You get a page Welcome to V2R4 Configuration Assistant for z/OS Communications Server. On this page you can specify the name of the backing store. The pull down lists the existing backing stores. If you do not have a backing store create one. You can use “tools”button to copy the backing store.
  • The “getting started” gives you information on how to use the panels. I found it a little confusing at times. It displays the help in a separate window. In the Table of Contents, it has “AT/TLS – getting started”. I didn’t find the help or tutorials much use.
  • On the Welcome page, press Proceed.
    • I sometimes get “The backing store is locked by your id.” I got this after I had shutdown down z/OSMF without logging off.
    • You can use “Tools” to manage your backing store, and configuration.
    • “Select a TCP/IP technology to configure” : AT-TLS
    • The layout of the panels, make me think you create the definitions from top to bottom, and so the tabs are defined left to right. I think it is easier to define resources then create the group/image/stack.

Define the rules for which ports to be protected

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Traffic Descriptors tab.

  • Actions -> New…
  • Name COLINTD
  • Actions-> New…
  • Under the Details tab, specify the port or port range and any other information
  • Under the KeyRing tab, specify the keyring and the Certificate label or let it default to the TCPIP stack level keyring.
  • Under the Advanced tab, I let everything default.
  • Click OK
  • You can define a second port within this Traffic Descriptor
  • Click OK

You can press Save to save the current definitions.

Define which IP addresses you want to protect (optional)

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Address Groups tab.

By default it has

  • All_IPv4_Addresses
  • All_IPv6_Addresses
  • All_IP_Addresses

A TCPIP stack can host different IP addresses, one for each connector coming in. If you want to limit rules to particular stack owned IP addresses, create a definition.

  • Actions-> New
  • Name: COLINAG
  • IP Address:
  • IP Address:
  • OK

You can press Save to save the current definitions.

How do you want to protect the session.

For example what levels of TLS, and what cipher specs do you want to use.

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Security Levels tab.

  • Actions: -> New…
  • Name: COLINSL
  • Select levels of TLS you want to use
  • Next, then select cipher specs. I used “Use 2019 suggested values”
  • Next – I took the default (“Do not generate FIPS 140 support“)
  • Click on Advanced settings.
    • If you want to use client authentication click the “Use client authentication” box
    • OK
  • Finish

Your definition should be in the list.

You can press Save to save the current definitions.

Mapping of ports to Session protection

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Requirement Maps tab.

  • Actions: -> New…
  • Name: COLINMAP .
  • In the mappings table,
    • use the Traffic Descriptor pull down and select the Traffic Descriptor you created above. For example COLINTD.
    • Under Security Level pull down select the security definition you created above. For example COLINSL.
  • OK

If I changed an existing definition, I had a pop-up

Modify Requirement Map.
The requirement map you are changing may be referenced in at least one connectivity rule.

Prior to making this change you may want to see which connectivity rules are referencing this requirement map. Click OK to show where used. Click Proceed to proceed with the Modify; otherwise, click Cancel.

Click OK to show where it is used.

Click Proceed

You can press Save to save the current definitions.

Create the group, z/OS instance and TCPIP Stack

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Systems tab.

  • Action: -> Add z/OS group…
  • Name: COLINGR
  • Click OK
  • Action: -> Add z/OS system image…
  • Name: COLMVSA
  • Press OK
  • I get a pop-up Proceed to the next step? Connectivity rules are configured for each TCP/IP stack. To continue with configuration you need to add a TCP/IP stack to the new z/OS system image. Do you want to add a TCP/IP stack now? Click on Proceed.
  • This gets to the Add TCP/IP stack
  • Name:TCPIP
  • OK
  • I get a pop-up. Proceed to the next Step? o continue with the configuration you should add connectivity rules to the TCP/IP stack. Do you want to be directed to the TCP/IP stack rules panel? Proceed.
    • If you cancel you can use the Actions -> rules to define the rules.
  • I get a pop-up Proceed to the Next Step? Do you want to start a wizard to create a connectivity rule? Click Proceed.
  • This gets to the Data End points where you associate the IP addresses to the stack instance.
  • Name: COLINRN
  • Select from the address group pull-down, or let it default.
  • Press Next
  • This gets to the Requirement Mapping to Stack association.
    • You can select from the existing requirements map see Mapping of ports to Session protection above, or create a new mapping.
    • You can create a new map, for example Name: COLINMP
      • Select from the Traffic Descriptor pull down
      • Select from the Security level pull down.
  • Press Next
  • You can specify advanced settings, such as Tracing, Tuning, Environment, Effective times, Handshake
  • Finish
  • Close

You can press Save to save the current definitions.

Join the bits up

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Systems tab.

  • Select a group instance
  • Actions: Install All files for this group
  • This will list the configuration files.
  • On the Configured File Name,
    • right click on the file name value, and ->Show Configuration File. This will show you the configuration as it might be deployed.
    • right click on the file name value and -> Install … . Specify the a file name and click GO.
    • Close
  • You can use
    • Actions: Install to create the configuration file
    • Actions: Show configuration file to see the generated configuration

You can now use the configuration file as input to PAGENT.

You can press Save to save the current definitions.

Extending the configuration to add a new rule

It took a while to work out how to do this, but it is really easy.

In the page Network Configuration Assistant (Home) -> AT-TLS page, click on the Traffic Descriptors tab.

  • Create a new Traffic descriptor as above
  • Get back to Network Configuration Assistant (Home) -> AT-TLS page, and click on the Systems tab.
  • Select a TCPIP instance, and click Actions: -> Rules..
  • Actions: -> New
  • Connectivity rule name: rule2
  • Press Next
  • You can select from the existing requirements map see Mapping of ports to Session protection above, or create a new mapping. If you have just created a new rule, then you may not have defined a mapping, and create it “inline”.

Then install it.

Use the configuration

You need to change the PAGENT JCL to use the created configuration file. You may want to copy it to a backup, as the next time you reconfigure it can overwrite the file. Or just create a new file perhaps with a date in the filename.

If you have problems with a newly reconfigured file you need a copy of the previous, working, definitions.

Display the configuration

On many items, you can use right click -> Show where used. This will then display the group, image, stack, connectivity rules and data end points where the item is used.

Should I use this just to get started, or every time.

When I created my definitions by hand, I could put definitions in to a “Common” section, and have multiple TCPIP stacks in one configuration file. I could have small files with bits of configuration in them.

If you use the CA, “common” definitions are copied into the configuration file, and you have one configuration file per TCPIP stack instance, so you do not need to have a common section etc.

As a configuration tool, now I know how to use it, I might continue to use it – but it is slightly more complex than this.

I want to enable trace for one definition. To do so means I have to…

  • Change the configuration to set the trace. This can be difficult if someone else is in the middle of changing the configuration.
  • Deploy the whole configuration. You may pick up incomplete changes which have been made, but not deployed.
  • If a second TCPIP stack is using the configuration, this may get trace enabled if the configuration file is recreated.

Overall (my views may change tomorrow), I would use the CA to create my configuration. Then not use it again – or use it again to generate definitions which I can copy into my master configuration files. I would restructure the configuration so create small files with specific content.

Using z/OSMF workflows for TCPIP.

I found it hard to set up the AT-TLS configuration for MQ. The easiest way was to use the sample configurations provided by MQ. See here for an overview. I used Scenario 5 – Between an IBM MQ for z/OS queue manager and a client application running on IBM MQ for Multiplatforms.

This took about 10 minutes once I had PAGENT and SYSLOGD set up.

I thought I would try to use the TCP provided facilities. There is a lot of documentation, but it is not easy to find what you need. It has been written as an IBM developer, rather than from an end user perspective.

I then thought I would try to use the “way of the future” and the z/OS configuration tool z/OSMF. You use a browser to connect to z/OSMF and do your work through the browser interface. The z/OSMF interface has configuration tools, and workflow tools which guide you step by step through configuration.

I found using the workflow tools was harder than using the TCPIP documentation and TCPIP samples, and I would not recommend its use.

Ive blogged Using z/OSMF Network Configuration assistant for TCPIP, to define AT-TLS configuration. Which worked.

The workflow stuff makes the easy bit “easier”, but does not help with the hard stuff. An improvement would be to skip the workflow, and have one page of instructions saying copy samples into Proclib, and Unix; run a RACF job. We could do with a workflow to help configure syslogd, which I had a struggle to get working in a non trivial situation. For example having error messages for PAGENT go to one file, and have the TLS trace go into another file.

My mission.

My mission was to configure AT-TLS and to provide two ports for use with MQ.

I wanted to do this using two people (me with two userids) and do the typical steps when changing systems, such as saving configurations before changing them, and deploying them, when I had a “change window”.

Initial steps

z/OSMF provides facilities like ISPF, Workload management configuration, system status etc. I used Workflow.

It was hard to know where to start. I assumed (wrongly) that there would be a workflow to define the AT-TLS definitions.

It seems you use Workflow to define the PAGENT and syslogd JCL, and not for configuring the PAGENT or syslogd.

Instructions to use Workflow to configure TCPIP JCL procedures

  • Double click the workflow icon.
  • From the actions pull down, select Create workflow…
  • You need to select Workflow definition file: I could not find what I had to specify. There was no prompting. The “?” basically said “put a value here”. The help key just gave me a panel with information about using creating a workflow.
  • I found an IBM support document which says
    • Workflows for Policy-based Networking
    • ezb_pagent_setup_wizard.xml – This workflow provides the steps for setting up the Policy Agent (Pagent). Pagent is required for all of the policy-based networking technologies: IPSec, AT-TLS, IDS, PBR, and QoS. Pagent uses syslogd for logging.
    • ezb_syslogd_setup_wizard.xml – This workflow provides the steps for setting up syslogd.
    • ezb_tcpip_profile_sample_wizard.xml – This workflow provides a sample TCP/IP profile which contains common statements required to enable AT-TLS and IP Security, and additionally includes port reservation statements for running daemons.
  • I had to use the fully qualified filename /usr/lpp/zosmf/workflow/plugins/izuca/ezb_syslogd_setup_wizard.xml
  • This came up with an error in the workflow name because the default name has ‘z/OS… ‘ and ‘/’ is not a valid character. I removed the ‘/’.
  • At the bottom of the page you can Assign all steps to owner user id. I did not do this, and had to assign steps below
  • You get a list of steps that need to be done.
  • Assign the work to a userid
    • Select all of the steps, and use Actions-> Assignment and ownership -> Add assignees.
    • This displays the assigned roles. I used Actions -> add to add my SAF userid. I pressed OK and returned to the list of steps – all now assigned to me.
  • I selected the first step “define the “RACF userid for Syslogd”, Actions -> Accept .
  • Click on the task, and it gives you a window with tabs. The important tab is Perform. If this is greyed out, you have not accepted the task!
    • Fill in the details and click Next, Next etc. You can edit the contents.
    • You can save it – but you need to give a data set. It suggested SYS1(SYSLOGD). I had to change it (every time) to COLIN.ATTLS(…)
    • Next – gives you the save panel. You have to specify the dataset where you want to save it. The default was wrong for me.
    • Once saved you have to submit it manually, check the output, and edit the file if needed.
  • Back at the workflow details, it had step 1 complete (even though you may not have submitted it)
  • I accepted step 2 and started working on it.
    • It asks for Dataset HLQ – but I could not change it.
    • I stepped through the definitions – and had to type in my dataset again (why can’t it remember what I specified last time).
    • This step just creates a job with some RACF definitions in it.
  • I ran step 3 -again just creating a JCL member of definitions
  • Step 4 “Sample Syslogd Configuration Setup“. This just copies in a sample configuration.
    • “Save” did not do anything
  • Step 5 “Sample started procedure for Syslogd” creates a sample Procedure.
  • On the workflows page, it shows the workflow is 100% complete.

Having been through all of this, the create JCL did not run, one line in error was

// VARS=”,
// PARMS=”
// ‘/&PARMS.’)

  • &PROG had not been specified – you gave to go and find what you need to specified (SYSLOGD)
  • There is a blank after the &PROG., so the REGION=0K,TIME=NOLIMIT, is ignored
  • The location of the configuration (in &VARs) is not specified.

Create the PAGENT JCL

I followed the same process to create the PAGENT file.

I used file /usr/lpp/zosmf/workflow/plugins/izuca/ezb_pagent_setup_wizard.xml.

When this JCL ran, it produced messages

06/16 08:00:20 SYSERR :000: …plfm_config_medium_open: cannot open ‘/etc/pagent.conf’, errno EDC5129I No such file or directory.

You have to know to copy the configuration file from the PDS to /etc/pagent.conf.

Comments on using the workflows

This seems a lot of work to produce code which does not work. The process feels unloved. I am surprised that the problems I found have not been fixed – they are Unit Test level bugs.

I think it is far simpler to follow the documentation, for example to create the procedure. The documentation says

Update the cataloged procedure, syslogd, by copying the sample in SEZAINST(SYSLOGD) to your system or recognized PROCLIB. Specify syslogd parameters and change the data set names to suit your local configurtion See the syslog daemon section of SEZAINST(EZARACF) for SAF considerations for started procedures

The instructions could be on one side of paper, and would be quicker than using the workflow.

Debugging AT-TLS session problems

I deliberately misconfigured AT-TLS to see how easy it would be to identify and resolve the problems from an AT-TLS perspective. It turned out worse than I expected. There is little information on the z/OS to help you.

I configured TTLSEnvironmentAction {trace 255 } (see the bottom of this blog) and refreshed the PAGENT. I had configured SYSLOGD so records for *.TCPIP.*.* went to /var/log/TCPIP.

I reran my MQ client application and got

  • from MQ on Linux, in file /var/mqm/errors/AMQERR01.LOG return code 2393 (MQRC_SSL_INITIALIZATION_ERROR).
  • On Linux there was a file /var/mqm/trace/AMQ.SSL.TRC – which only IBM can format!
  • From TCPIP on z/OS EZD1287I TTLS Error RC: 402 Initial Handshake LOCAL: REMOTE: JOBNAME: CSQ9CHIN RULE: REMOTE-TO-CSQ1 USERID: START1 GRPID: 0000001B ENVID: 0000000B CONNID: 0000006E This give
    • the address of my client,
    • the name of the chinit
    • which AT-TLS rule was used

The message EZD1287I TTLS Error RC: 402 Initial Handshake pointed me to Cryptographic Services System Secure Sockets Layer Programming – No SSL cipher specifications. The first reason was

The client and server cipher specifications do not contain at least one value in common. Client and server cipher specifications might be limited depending on which System SSL FMIDs are installed. See Cipher suite definitions for more information. Server cipher specifications are dependent on the type of algorithms that are used by the server certificate (RSA, DSA, ECDSA, or Diffie-Hellman), which might limit the options available during cipher negotiation.

MQ Trace

I took an MQ trace and formatted it. I used grep to find which file had “Cipher” in it.

Within this file I searched for Start of GSKit TLS Handshake Transcript.

This had information sent to the server as part of the handshake, and further down it had the reason code. You can see from the example that the fields and their values have been displayed (so cipher spec 003c is displayed as tls_rsa_with_aes_128_cbc_sha256)

Start of GSKit TLS Handshake Transcript (1119 bytes)
   Length: 28
   3E 5B 45 66 EE A3 C1 9F FB 81 0C 2F 38 19 DF 95     >[Ef......./8...
   5A 1B 54 CC B8 CB B6 C9 87 39 5E 88                 Z.T......9^.
 Length: 00
 Length: 04
 00 FF 00 3C                                         ...<
 Length: 01
 00                                                  .
 Length: 74
 00 0D 00 18 00 16 06 01 05 01 04 01 03 01 02 01     ................
 06 03 05 03 04 03 03 03 02 03 02 02 00 00 00 2A     ...............*
 00 28 00 00 25 73 79 73 74 65 6D 32 65 2D 64 65     .(..%system2e-de
 66 32 65 2D 73 76 72 63 6F 6E 6E 2E 63 68 6C 2E     f2e-svrconn.chl.
 6D 71 2E 69 62 6D 2E 63 6F 6D             
  Extension Count: 2
  signature_algorithms 13
  server_name 0
End of GSKit TLS Handshake Transcript
{  rriEvent
 RetCode = 20009665, rc1 = 420, rc2 = 0, Comment1='SYSTEM.DEF.SVRCONN', 
 Comment2='gsk_secure_soc_init', Comment3=''

With this trace, I am able to see what was sent to z/OS.

The AT-TLS Trace

The trace ( configured in syslogd to be in /var/log/TCPIP) had a one line entry with (I’ve reformatted it to make it easier to read).

Map CONNID: 0000006B 
TYPE: InBound 
STATUS: Enabled 

and data

RC: 0 Connection Init
RC: 0 Call GSK_SECURE_SOCKET_OPEN - 00000052FD6228F0
RC: 0 Set GSK_FD(300) - 000000000000006B
RC: 0 Set GSK_USER_DATA(200) - 000000007EC32430
RECV CIPHER 160303007B 

and one loooong record with

SEND CIPHER 15030300020228 

From the AT-TLS trace of the data received from the client, it is the data as received, and has not been split down into useful fields.

I could not find any documentation on how to format this string. It is not easy to create a program to format this (and get it right), for example converting cipher spec 003c to TLS_RSA_WITH_AES_128_CBC_SHA256. However I have a REXX exec which works in ISPF and decodes the data into fields, but not the contents of the fields – so the cipher spec is reported as 003c

I had some success taking this data, and creating a file which Wireshark could process. See Wireshark – using external data: Bodging a hex dump file. This was not always successful, as it looks like the data is truncated, and can have non hex data in the hex stream.

Note, the System SSL server started task, GSKSRVR, can capture System SSL trace. The output is like

Job TCPIP     Process 0101001D  Thread 00000001  read_v3_client_hello            
Received CLIENT-HELLO message                                                  

with no detailed information

Tracing just one session

If you have a busy system you could get trace data for many sessions. You may want to set up a TLS rule, so you use a “debug port”, or you specify the remote host IP address, and port, using information from the error message

EZD1287I TTLS Error RC: 402 Initial Handshake LOCAL: REMOTE:

And dont forget…

And do not forget to reset the TTLSEnvironmentAction entry to reset the trace, and to refresh the PAGENT.

Wireshark – using external data

Export the trace in hex format

  • Capture your trace.
  • Select the line(s) of interest
  • File -> Export Packet Dissections -> As Plain Text
  • On the next screen
    • Select the directory and file name
    • Select the Export as “Plain text” – it adds .txt to the file name you chose above, if required.
    • Select the packet range
    • Packet format: Bytes (and only bytes)
    • Save

If you select Packet Format : Bytes you get output like

0000  00 d8 61 e9 31 2a 8c 16 45 36 f4 8a 08 00 45 10   ..a.1*..E6....E.
0010  00 78 39 c5 40 00 40 06 ec a4 0a 01 00 02 0a 01   .x9.@.@.........
0020  00 03 bc 3e 00 16 0d 5b 33 ab 44 ae 0b 8f 80 18   ...>...[3.D.....

If you select Packet Format: Details

You get

No.     Time           Source                Destination           Dst port port   Protocol Length Info
      1 0.000000000                  22       48190  SSH      134    Client: Encrypted packet (len=68)

Frame 1: 134 bytes on wire (1072 bits), 134 bytes captured (1072 bits) on interface enp0s31f6, id 0
Ethernet II, Src: LCFCHeFe_36:f4:8a (8c:16:45:36:f4:8a), Dst: Micro-St_e9:31:2a (00:d8:61:e9:31:2a)
Internet Protocol Version 4, Src:, Dst:
Transmission Control Protocol, Src Port: 48190, Dst Port: 22, Seq: 1, Ack: 1, Len: 68
SSH Protocol

If you specify If you select Packet Format: Details + Bytes you get both sets of output in the file.

If you try to import this files back into Wire Shark, it should work, as it will ignore lines which do not begin with a hexadecimal offset.

Import a hex dump file

Using the “bytes” file created above

  • File -> Import from Hex Dump
  • File /u/colin/aaa.txt
  • Offsets: Hexadecimal
  • Encapsulation type: Ethernet

The data is displayed as if it was real time capture.

The Wireshark documentation on importing data is here.

Information in the imported file.

Various bits of information are not in the hex dump file, and WireShark creates (fakes) them. For example

  • The packet number is the data record number of the data in the file.
  • The time between packets is an incrementing microsecond counter, 0.000000, 0.000001, 0.000002 etc
  • The packet length is taken from the length of the data record.
  • The “arrival time” is the time the data was read from the file.
  • The encapsulation type is taken from the import page.
  • However information such as source, destination, port, destination port are taken from the data.

Bodging a hex dump file

I had a AT-TLS trace from PAGENT which was a string of raw hex data, with no interpretation of the TLS data. AT-TLS does not provide any way of formatting this data.

I was partially successful in using WireShark to process this data, and decode the TLS fields.

The first part of the data is the IP and TCP header info, followed by the TLS data.

I obtained a hex dump of a TLS handshake and took the first x42 bytes.

0000  8c 16 45 36 f4 8a 00 d8 61 e9 31 2a 08 00 45 00 
0010  xx xx 01 3d 00 00 3f 06 5c ef 0a 01 01 02 0a 01 
0020  00 02 05 86 b8 dc 34 b1 03 17 57 c4 a5 0c 80 18
0030  0f fc 1d bf 00 00 01 01 08 0a 9d cf 5c b7 db 69 
0040  e9 0d 

I then wrote an ISPF editor rexx program to take the TLS trace and convert into the similar format, such as

0042   16 03 03 08 8E 02 00 00 4D 03 03 62 A8 75 18 C9
0052   5D 61 E1 1B 71 40 6A 6B 95 A8 F9 E5 E8 3A 83 AB
07E2   F0 61 98 51 92 4B 2E 0A 29

Then changed the xx xx to the length of the data – 12. So xx xx becomes (x7ea – 12) = x07dd.

The data could sometimes be imported.

If anyone is interested I can send them the ISPF rexx exec.

The trace from PAGENT is some times incomplete or wrong. I had long records with

0A29C..TRC at the end, which is clearly not hex data.

Hints on bodging.

It took me several hours to get the first successful import of TLS data. Some of the problems I had were

  • The offsets were wrong. I sometimes had the wrong offset, or the same offset more than once
  • The xx xx needs to be correct.
  • In the PAGENT trace file I had data like 160303007B which is of length 10 – but only length 5 hex characters. The length would be 00 47 ( 00 42 + 5)

Netstat, TTLS and AT-TLS

Once a session has been established using AT-TLS to do end to end TLS encryption, you can use netstat to display information about the session, and what configuration is being used. It feels slightly incomplete, in that some of the data I expected is not available.

What sessions are using a Port? – and display TTLSPolicy information

tso netstat all (port 1414

You can use other filter statements, using port 1414 was easy to specify.

This displays the high level TTLS information, see the blue text below

EZZ2350I MVS TCP/IP NETSTAT CS V2R4       TCPIP Name: TCPIP           16:40:39
EZZ2550I Client Name: CSQ9CHIN                 Client Id: 000000BB
EZZ2551I Local Socket:          Foreign Socket: 
EZZ2577I   BytesIn:            0000002248        BytesOut:           0000002076
EZZ2574I   SegmentsIn:         0000000020        SegmentsOut:        0000000014
EZZ2536I   StartDate:          05/31/2022        StartTime:          16:31:54
EZZ2552I   Last Touched:       16:36:57          State:              Establsh
EZZ2553I   RcvNxt:             0626077759        SndNxt:             3598815082
EZZ2554I   ClientRcvNxt:       0626076574        ClientSndNxt:       3598812426
EZZ2555I   InitRcvSeqNum:      0626074325        InitSndSeqNum:      3598810349
EZZ2556I   CongestionWindow:   0000018720        SlowStartThreshold: 0000065535
EZZ2557I   IncomingWindowNum:  0626208746        OutgoingWindowNum:  3598877418
EZZ2558I   SndWl1:             0626077759        SndWl2:             3598815082
EZZ2559I   SndWnd:             0000062336        MaxSndWnd:          0000064256
EZZ2560I   SndUna:             3598815082        rtt_seq:            3598814997
EZZ2561I   MaximumSegmentSize: 0000001440        DSField:            00
EZZ2563I   Round-trip information:
EZZ2564I     Smooth trip time: 7.000             SmoothTripVariance: 19.000
EZZ2565I   ReXmt:              0000000000        ReXmtCount:         0000000000
EZZ2572I   DupACKs:            0000000000        RcvWnd:             0000130987
EZZ2566I   SockOpt:            88                TcpTimer:           00
EZZ2567I   TcpSig:             04                TcpSel:             40
EZZ2568I   TcpDet:             E4                TcpPol:             00
EZZ2593I   TcpPrf:             89                TcpPrf2:            20
EZZ2593I   TcpPrf3:            00
EZZ2593I   DelayAck:           Yes
EZZ2537I   QOSPolicy:          No
EZZ2545I   TTLSPolicy:         Yes
EZZ2546I     TTLSRule:         REMOTE-TO-CSQ1
EZZ2547I     TTLSGrpAction:    CSQ1-GROUP-ACTION
EZZ2542I   RoutingPolicy:      No
EZZ2570I   ReceiveBufferSize:  0000065536        SendBufferSize:     0000065536
EZZ2538I   ReceiveDataQueued:  0000000000
EZZ2539I   SendDataQueued:     0000000000
EZZ2611I   SendStalled:        No
EZZ2609I   Ancillary Input Queue: N/A

From the clientid (connection id) display any TTLS information

From the netstat allconn (port 1414 command, you get each session, and its clientid (see above for clientid 000000BB).

From the tso netstat allconn (port 1414 command, you get one line per session with the connection ID and remote IP address and port.

EZZ2350I MVS TCP/IP NETSTAT CS V2R4       TCPIP Name: TCPIP           16:55:18
EZZ2585I User Id  Conn     Local Socket           Foreign Socket         State
EZZ2586I -------  ----     ------------           --------------         -----
EZZ2587I CSQ9CHIN 000000BB        Establsh
EZZ2587I CSQ9CHIN 00000022             Listen

Issue the command to display the TTLS information details about connection.

tso netstat ttls conn 000000BB detail

ConnID: 000000bb
  JobName:      CSQ9CHIN
  SecLevel:     TLS Version 1.2
  Cipher:       003C TLS_RSA_WITH_AES_128_CBC_SHA256
  KeyShare:     N/A
  CertUserID:   N/A
  MapType:      Primary
  FIPS140:      Off
  SessionID:    01010018 0A010002 CFEE0000 00000000
                00000000 00000000 62970B05 00000001
  SIDReuseReq:  Off
  Priority:       1
  LocalAddr:      All
  LocalPort:      1414
  RemoteAddr:     All
  RemotePort:     All
  JobName:        CSQ9CHIN
  Direction:      Inbound
    GroupID:                    00000007
    TTLSEnabled:                On
    CtraceClearText:            Off
    Trace:                      2
    SyslogFacility:             Daemon
    SecondaryMap:               Off
    FIPS140:                    Off
    HandshakeRole:              Server
    SuiteBProfile:              Off
    MiddleBoxCompatMode:        Off
    Keyring:                    START1/MQRING
    V3CipherSuites:             003C TLS_RSA_WITH_AES_128_CBC_SHA256
    Trace:                      255
    SSLV2:                      Off
    SSLV3:                      Off
    TLSV1:                      Off
    TLSV1.1:                    Off
    TLSV1.2:                    On
    TLSV1.3:                    On
    ResetCipherTimer:           0
    ApplicationControlled:      Off
    HandshakeTimeout:           10
    CertificateLabel:           ZZZZ
    SecondaryMap:               Off
    TruncatedHMAC:              Off
    ClientMaxSSLFragment:       Off
    ServerMaxSSLFragment:       Off
    ClientHandshakeSNI:         Off
    ServerHandshakeSNI:         Off
    ClientECurves:              0021 secp224r1
                                0023 secp256r1
                                0024 secp384r1
                                0025 secp521r1
                                0019 secp192r1
                                0029 X25519
    ClientKeyShareGroups:       0023 secp256r1
    ServerKeyShareGroups:       0023 secp256r1
                                0024 secp384r1
                                0025 secp521r1
                                0029 X25519
                                0030 X448
    SignaturePairs:             0601 TLS_SIGALG_SHA512_WITH_RSA
                                0603 TLS_SIGALG_SHA512_WITH_ECDSA
                                0501 TLS_SIGALG_SHA384_WITH_RSA
                                0503 TLS_SIGALG_SHA384_WITH_ECDSA
                                0401 TLS_SIGALG_SHA256_WITH_RSA
                                0403 TLS_SIGALG_SHA256_WITH_ECDSA
                                0402 TLS_SIGALG_SHA256_WITH_DSA
                                0301 TLS_SIGALG_SHA224_WITH_RSA
                                0303 TLS_SIGALG_SHA224_WITH_ECDSA
                                0302 TLS_SIGALG_SHA224_WITH_DSA
                                0201 TLS_SIGALG_SHA1_WITH_RSA
                                0203 TLS_SIGALG_SHA1_WITH_ECDSA
                                0202 TLS_SIGALG_SHA1_WITH_DSA
                                0806 TLS_SIGALG_SHA512_WITH_RSASSA_PSS
                                0805 TLS_SIGALG_SHA384_WITH_RSASSA_PSS
                                0804 TLS_SIGALG_SHA256_WITH_RSASSA_PSS
    ClientAuthType:             Required
    CertValidationMode:         Any
    Renegotiation:              Default
    RenegotiationIndicator:     Optional
    RenegotiationCertCheck:     Off
    3DesKeyCheck:               Off
    ClientEDHGroupSize:         Legacy
    ServerEDHGroupSize:         Legacy
    PeerMinCertVersion:         Any
    PeerMinDHKeySize:           1024
    PeerMinDsaKeySize:          1024
    PeerMinECCKeySize:          192
    PeerMinRsaKeySize:          1024
    ServerScsv:                 Off
    GSK_V3_SESSION_TIMEOUT:     86400
    GSK_V3_SIDCACHE_SIZE:       512
    HttpCdpEnable:              Off
    HttpCdpProxyServerPort:     80
    HttpCdpResponseTimeout:     15
    HttpCdpMaxResponseSize:     204800
    HttpCdpCacheSize:           32
    HttpCdpCacheEntryMaxsize:   0
    OcspAiaEnable:              Off
    OcspProxyServerPort:        80
    OcspRetrieveViaGet:         Off
    OcspUrlPriority:            On
    OcspRequestSigalg:          0401 TLS_SIGALG_SHA256_WITH_RSA
    OcspClientCacheSize:        256
    OcspCliCacheEntryMaxsize:   0
    OcspNonceGenEnable:         Off
    OcspNonceCheckEnable:       Off
    OcspNonceSize:              8
    OcspResponseTimeout:        15
    OcspMaxResponseSize:        20480
    OcspServerStapling:         Off

Which AT-TLS groups are being used?

I didn’t find this information very useful. It isn’t clear what a group is. The doc says

Use the TTLSGroupAction statement to specify parameters for a Language Environment process required to support secure connections. The TTLSGroupAction statement indicates whether a selected connection should use AT-TLS security.

tso netstat ttls group
tso netstat ttls

TTLSGrpAction                             Group ID           Conns
----------------------------------------  -----------------  -----
CSQ1-GROUP-ACTION                         0000003F               1
GrpActOff                                 00000040               0
GrpActOn                                  00000041               0
GA1                                       00000042               0

tso netstat ttls group detail

  GroupID:         0000003F
  Tasks:           4                    GroupConns:      1
  WorkQElements:   0                    SyslogQElements: 0
    Env: CSQ1-INBOUND-ENVIRONMENT-ACTION           EnvConns: 1
TTLSGrpAction:   GrpActOff
  GroupID:         00000040
  Tasks:           4                    GroupConns:      0
  WorkQElements:   0                    SyslogQElements: 0
TTLSGrpAction:   GrpActOn
  GroupID:         00000041
  Tasks:           4                    GroupConns:      0
  WorkQElements:   0                    SyslogQElements: 0
TTLSGrpAction:   GA1
  GroupID:         00000042
  Tasks:           4                    GroupConns:      0
  WorkQElements:   0                    SyslogQElements: 0