For many applications, the first line of security is the menu system. A user is given an initial menu, and is only allowed to execute programs called from that menu, or menus referenced by the initial menu. The question is, then, what programs are reachable from a given initial menu?
Provided are:
The program is called from the command line with the following parameters:
The prune program parameter controls whether all occurences of a program are printed, or only the one with the shortest path.
As an example, consider the folowing menus
------------------------- | Menu A | | | |1. Menu AA 12. PGM01 | |2. Menu AB | |3. Menu AC | | | | | ------------------------- ------------------------- ------------------------- ------------------------- | Menu AA | | Menu AB | | Menu AC | | | | | | | |1. Menu AAA 12. PGM01 | |1. Menu ABA 12. PGM02 | | 11. PGM01 | |2. Menu AAB 13. PGM02 | |2. Menu ABB 13. PGM03 | | 12. PGM02 | | | | | | 13. PGM03 | | | | | | 14. PGM04 | | | | | | | ------------------------- ------------------------- ------------------------- ------------------------- ------------------------- | Menu AAA | | Menu AAB | | | | | | 12. PGM01 | | 12. PGM06 | | 13. PGM02 | | 13. PGM07 | | 14. PGM05 | | 14. PGM08 | | | | | | | | | ------------------------- ------------------------- ------------------------- ------------------------- | Menu ABA | | Menu ABB | | | | | | 12. PGM07 | | 12. PGM09 | | 13. PGM08 | | 13. PGM10 | | 14. PGM09 | | 14. PGM11 | | | | | | | | | ------------------------- -------------------------Now, the way these menus are represented in the database is:
AAMENU AAOPTION AAOBJECT AAOBJECTYP ------ -------- -------- ---------- A 1 AA M A 2 AB M A 3 AC M A 12 PGM01 P AA 1 AAA M AA 2 AAB M AA 12 PGM01 P AA 13 PGM02 P AAA 12 PGM01 P AAA 13 PGM02 P AAA 14 PGM05 P AAB 12 PGM06 P AAB 13 PGM07 P AAB 14 PGM08 P AB 1 ABA M AB 2 ABB M AB 12 PGM02 P AB 13 PGM03 P ABA 12 PGM07 P ABA 13 PGM08 P ABA 14 PGM09 P ABB 12 PGM09 P ABB 13 PGM10 P ABB 14 PGM11 P AC 12 PGM01 P AC 13 PGM02 P AC 14 PGM03 P AC 15 PGM04 P
To run the program in unpruned (plum) mode:
call cp1220r (A '0')
giving the following result:
PGM01/12 AA/ 1 A PGM01/12 AAA/ 1 AA/ 1 A PGM01/12 AC/ 3 A PGM01/12 A PGM02/12 AB/ 2 A PGM02/13 AA/ 1 A PGM02/13 AAA/ 1 AA/ 1 A PGM02/13 AC/ 3 A PGM03/13 AB/ 2 A PGM03/14 AC/ 3 A PGM04/15 AC/ 3 A PGM05/14 AAA/ 1 AA/ 1 A PGM06/12 AAB/ 2 AA/ 1 A PGM07/12 ABA/ 1 AB/ 2 A PGM07/13 AAB/ 2 AA/ 1 A PGM08/13 ABA/ 1 AB/ 2 A PGM08/14 AAB/ 2 AA/ 1 A PGM09/12 ABB/ 2 AB/ 2 A PGM09/14 ABA/ 1 AB/ 2 A PGM10/13 ABB/ 2 AB/ 2 A PGM11/14 ABB/ 2 AB/ 2 A
Pretty ugly. This was orginally written as part of an application to programmatically maintain the JDEdwards Function Key Security file (F9612). Not only were all program calls from menus documented, but also program calls from other programs (via function keys and selection exits). Once we determined which programs were reachable from the initial menu, we went into each program and turned off each function key/selection option which referenced a program which was *not* reachable from the initial menu. Pretty reports were not part of the product, but this is beta free-ware, so feel free to write your own.
This is also probably more information than we need. More useful is the listing produced in prune mode, which shows only the shortest path to each program.
To run the program in prune mode:
call cp1220r (A '1')
giving the following result
PGM01/12 A PGM02/13 AA/ 1 A PGM03/13 AB/ 2 A PGM04/15 AC/ 3 A PGM05/14 AAA/ 1 AA/ 1 A PGM06/12 AAB/ 2 AA/ 1 A PGM07/13 AAB/ 2 AA/ 1 A PGM08/14 AAB/ 2 AA/ 1 A PGM09/14 ABA/ 1 AB/ 2 A PGM10/13 ABB/ 2 AB/ 2 A PGM11/14 ABB/ 2 AB/ 2 A
The following links take you to the source code, written in beautiful /free ILE/RPG. The source is distributed under a creative commons license.
Why, with dynamic data structures. I create a linked list in the heap, and store the pointers to my heap storage in a user space. The following is an example of how we determine whether a given menu already exists in the linked list (transitive references to menus lead to infinite loops)
The data structure looks like ...
* * used for records in heap storage * d recordDS ds Based(ds@) d parent@ * d option 3a d object 10a d pathLen 10i 0 d pathVar 1a *
... and pruneMnu() utilizes the data structure thusly:
ppruneMnu b d pi 1n d testMenu 10a d pmDS ds LikeDS(recordDS) Based(pm@) /free pm@ = ds@; DoW (pmDS.parent@ <> *NULL And pmDS.object <> testMenu); pm@ = pmDS.parent@; EndDo; Return (pmDS.object = testMenu); /end-free ppruneMnu e
No storage is allocated for pmDS; it is used to examine the heap. ds@ contains a pointer to the current heap entry, and we are 'running' up the linked list to see if there are any transitive menu references. Clear as mud. If anybody actually reads this stuff, please send me an email - I have received absolutely *no* feedback as regards the site, yet the logs show people are visiting.