Another in my catalogue of “everyone and their mother has done this if they needed to, but here’s a slight twist on it” articles.
To set the scene, a customer of mine decided they want their Power server in an enquiry state and so setup some new generic profiles with generic menus sans all their normal data entry options. Naturally on the first day someone disabled the account and locked out half the company, so the question became “can you stop that happening?”
After explaining that I didn’t want to go down the route of having no lockout on invalid password, I sold them on the idea of monitoring for a disable and automatically switching it back on.
For those not familiar with a watch at top level it’s a background monitor for a message that can trigger a response that has been available since V5R4. IBM have a nice support page that explains setting up a watch and even gives you a sample program to take away.
If you ask our good friend Dr Google you’ll find plenty of example watch programs to monitor for and re-enable profiles, however most of them are watching *SYSOPR which is fine assuming you don’t have the QSYSMSG queue setup.
If you want the full story of this queue I recommend the IBM Knowledge Center but in short if this queue exists certain messages, such as profile disables, go here instead of QSYSOPR. You have a very nice sample program to forward messages back to SYSOPR but that to me seems to defeat the purpose of the exercise. I also have a message monitor reporting on QSYSMSG but do I really want to amend this piece of software that I use for multiple customers to handle the edge case? There might be an argument that this is the “right” solution but it doesn’t feel it.
I therefore went for using *HSTLOG to pick up the message from QHST, my very basic code looks like:
PGM PARM(&OPTION &SESSION &ERROR &EVENT)
DCL VAR(&OPTION) TYPE(*CHAR) LEN(10)
DCL VAR(&SESSION) TYPE(*CHAR) LEN(10)
DCL VAR(&ERROR) TYPE(*CHAR) LEN(10) VALUE(‘ ‘)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&EVENT) TYPE(*CHAR) LEN(1024)
CHGVAR VAR(&USER) VALUE(%SUBSTRING(&EVENT 503 10))
IF COND(%SUBSTRING(&USER 1 3) *EQ ‘xxx’) THEN(DO)
CHGUSRPRF USRPRF(&USER) STATUS(*ENABLED)
SNDUSRMSG MSGID(USR0247) MSGF(ERRMSGF) MSGDTA(&USER) +
CHGVAR VAR(&ERROR) VALUE(‘ ‘)
Nice and simple my watch is on CPF1393 (User profile <profile> has been disabled) in the QHST log. It picks out the username with the CHGVAR command, I know that all the new generic profiles have a specific 3-character prefix so let’s test for that as well.
Just so I do have some traceability (and can mock the afflicted, probably not meant to admit that bit!) We’re also outputting a custom message to a message queue to flag a profile has been automatically re-enabled. For those who are curious my message is:
Automatically re-enabled profile &1 (&1 defined as character variable, message is severity 30 as my monitor picks up anything 30+)
Obviously, you could be doing a lot more with the error trapping/handling than I’ve included here. It’s also on my never-ending wishlist to integrate it into one of my other watch programs rather than doing it as standalone but for the purposes of the exercise it did what was needed.
As you might imagine from the intro the customer was destined for another platform beyond our humble IBMi but hopefully it’s a nice memento to keep.