API Corner: Using the User Profile Exit Programs
July 20, 2005 Shannon O'Donnell
The code for this article is available for download.
One task that is common to every iSeries, regardless of the business it resides in, is the creation, deletion, changing and restoring of OS/400 user profiles. On some systems, only the Security Officer has the ability to create or make changes to a user profile. On other systems, there are a number of trusted individuals who have been given the authority to change or create a user profile. On almost every system, each user is given, at the very least, the authority to change their own user profile password.
With all this adding, changing, and deleting going on, it would be a really good idea if you had more information about who is doing what to your system’s user profiles. In this article, I will show you how you can use the iSeries’ System Exit Points to keep track of your profiles.
As with most of the system commands, IBM has given us a way to add our own functionality to the activity through the use of the system registration facility. If you’re not familiar with it, the system registration facility is the iSeries version of the Windows registry. At certain pre-defined points within OS/400, IBM has granted you the ability to add your own processes to certain commands and other system level functions.
For example, using the system registration facility you can cause OS/400 to execute code that you have written so that when someone attempts to log on to your system using Telnet, you can decide to allow it, deny it, or simply log the attempt. Or you might want to log all FTP commands to a database for later analysis. There are dozens and dozens of such pre-defined Exit Points available to you within the system registration facility. We are going to take advantage of five of those exit points in this article to log all user profile creation, deletion, change and restore activity.
For this article, we are going to concentrate on the following exit points:
Exit Point |
Description | Format |
QIBM_QSY_CHG_PROFILE | Change User Profile |
CHGP0100 |
QIBM_QSY_CRT_PROFILE | Create User Profile |
CRTP0100 |
QIBM_QSY_RST_PROFILE | Restore User Profile |
RSTP0100 |
QIBM_QSY_DLT_PROFILE | Delete User Profile (Before Delete) |
DLTP0100 |
QIBM_QSY_DLT_PROFILE | Delete User Profile (After Delete) |
DLTP0200 |
Figure 1: The User Profile Exit Points
The really nice thing about these particular exit points is that they all share the same common input data structure. Therefore, instead of having to write a separate program for each exit point, we can use the same program, and simply attach it to the five exit points shown here. Anything that makes your life easier has got to be a good thing, right?
When someone adds a new user profile, changes an existing user profile, deletes a user profile or restores a user profile, the exit point attached to that system-level function will call the exit program that you define for it. In our example, we are going to create an RPG IV program that does nothing more strenuous than send someone a message describing the activity that just occurred for a given user profile. You can of course build upon this example and have your program perform a lot more useful functions when any profile activity occurs.
We will call our sample program PROFEXITR1 and compile it in library QGPL. That will make it easy for the system to find it when it needs it.
Most, if not all exit points have an input data structure. That is, data is passed from the exit point to your program so that you can do something with it. In the Telnet exit program mentioned above, you can receive such information as the IP address the Telnet command originated from, the user profile attempting to log in, and even the name of the device the user is trying to attach to with the Telnet command. Almost all exit points have some basic information that you will need in order to allow your program to intelligently evaluate the requested function. In some cases, with some exit points such as the Telnet exit point, you can even let your program tell OS/400 whether or not to allow the function to continue. In other words, you can cause your iSeries to behave in pretty much any way you desire.
For this article, all of the exit points shown in Figure 1 share a common input data structure. This data structure is shown here:
DProfData DS D* D PextPgm 1 20 D* Exitpgm name D PextFmt 21 28 D* Exitpgm fmt D PusrPrf 29 38 D* User profile
In this example, I have named the data structure ProfData (profile data). The data structure has three subfields named PextPgm, PextFmt and PusrPrf. When this program is called by the system registration facility, it will pass to it the values that will be stored in these variables. PextPGM will contain the name of the exit point that called this program. PExtFmt will contain the exit point format name and PusrPrf will contain the name of the user profile that the activity was performed upon. As you can see from this code fragment, your program can then do “something” and return control back to the exit point.
D Apost C Const('''') C *Entry Plist C Parm PROFDATA * * Determine which exit point the call to this program came from C Select C When PextFmt = 'CHGP0100' C Eval Usage = 'changed' When PextFmt = 'CRTP0100' C Eval Usage = 'created' C When PextFmt = 'DLTP0100' C Eval Usage = 'deleted' C When PextFmt = 'DLTP0200' C Eval Usage = 'deleted' C When PextFmt = 'RSTP0200' C Eval Usage = 'restored' C Endsl * * Send someone a message about this user profile's activity C Eval CmdString = 'SNDMSG MSG(' + Apost + C 'User Profile ' + C %Trim(Pusrprf) + ' was ' + C %Trim(Usage) + '. ' + Apost + ') ' + C 'TOUSR(SHANNON)' C Callp(e) Cmds(CmdString:200)
In this example, I am sending a simple message to my own user profile telling me what activity occurred on the user profile that triggered the exit point in the first place. When the message arrives on my message queue, the SENDER ID will be the user profile of the person who executed the Change, Add, Delete or Restore user profile command. Compile the source code you downloaded with this article and attach it to the exit points shown above by using the command WRKREGINF (Work with Registration Information) from an iSeries command line.
One really useful feature that you might want to incorporate here, instead of or in addition to the SNDMSG command, is to have your exit program call the program I wrote about in the IBM article Prevent Access To System Request Menu so that for every user profile created, you can have OS/400 disable your user’s access to the System Request and/or Attention Key menus. You could also log all profile activity to a database and perform any number of other functions. One note of caution, if you are going to have your exit program open or work with any OS/400 databases, make sure you add the library the database lives in to this program’s runtime library list, as part of your inline code. Do this before you attempt to open it because your exit program is called at the system level and OS/400 may not know where the database lives unless you tell it first. If you are using this exit program to monitor when user profiles are deleted, you can even be as granular as doing something prior to the profile deletion (Exit Format DLTP0100) and then again after the profile deletion has completed (Exit Format DLTP0200).
Use the user profile exit point program described here as another tool in your security arsenal. At some point in the future, you may need to know who was messing around with your user profiles!