Security on IBM i is well designed: it is the operating system itself that controls access to objects, not the application. The trouble is that many installations work around it, and for an understandable reason: a program did not work, somebody gave the user *ALLOBJ, it worked, and nobody ever went back.
Where to start: QSECURITY
DSPSYSVAL SYSVAL(QSECURITY)
The values you meet:
- 20 — anyone who signs on effectively has access to everything. Treat it as "no security".
- 30 — object authority is enforced. This is the reasonable minimum.
- 40 — as 30, plus integrity protection: programs cannot bypass system interfaces. This is the value IBM recommends and the one most healthy installations run on.
- 50 — 40 with additional checks, for environments with particularly strict requirements.
The move from 30 to 40 needs preparation: some old programs use techniques no longer allowed at level 40. The system tells you in advance, though — violations are recorded in the audit journal before you even raise the level, if auditing is on. You raise the level after watching that log for a few weeks, not before.
Who holds the keys to everything
This query answers the most important question:
SELECT AUTHORIZATION_NAME, STATUS, SPECIAL_AUTHORITIES
FROM QSYS2.USER_INFO
WHERE SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'
ORDER BY AUTHORIZATION_NAME;
The list that comes back is almost always longer than expected, and typically contains three groups: service accounts created years ago, users who were given *ALLOBJ to solve a momentary problem, and group profiles that propagate it to all their members.
*ALLOBJ is not the only special authority that matters: *SECADM allows managing user profiles, *JOBCTL allows acting on other people's jobs, *SPLCTL allows seeing every spooled file — including the payroll.
*PUBLIC: the setting that decides everything
Every object has a public authority, the one that applies to anyone without specific rights. The default comes from the library the object is created in, and on many installations it is *CHANGE: anybody can modify the data.
DSPOBJAUT OBJ(MYLIB/CUSTOMERS) OBJTYPE(*FILE)
The recommended model is the opposite: *PUBLIC *EXCLUDE on data, with access granted not to users directly but to programs.
Adopted authority: the key to the model
This is the mechanism that lets you take rights away from users without breaking the applications. A program compiled like this:
CRTBNDRPG PGM(MYLIB/UPDCUST)
USRPRF(*OWNER)
runs with the rights of the program's owner, not of whoever launches it. If the owner is a profile that can write to the customer file, the program can write even though the user, on their own, could not.
The result is the right one: the user can change the data only by going through the intended programs. If they try to open the same file with a download or a query, they have no rights. That is exactly the distinction *ALLOBJ erases.
Two cautions: the program itself has to be controlled, because whoever can change it can do anything the owner can do; and adopted authority does not automatically propagate to called programs unless you ask for it with USEADPAUT(*YES).
Authorization lists, to stay sane
Granting rights object by object becomes unmanageable as soon as you have a few dozen files. An authorization list is a container of permissions that objects are attached to:
CRTAUTL AUTL(PAYROLLDTA) TEXT('Access to personnel data')
GRTOBJAUT OBJ(MYLIB/PAY*) OBJTYPE(*FILE) AUTL(PAYROLLDTA)
From then on permissions are managed in one place, and adding a person does not require remembering every file involved.
A realistic route back
Taking *ALLOBJ away from everyone overnight stops the company. A route that works:
- Turn auditing on and let it gather data for a few weeks. You need to know who really accesses what, rather than guessing.
- Start with a single application, the least critical one. Set
*PUBLIC *EXCLUDEon its files andUSRPRF(*OWNER)on its programs. - Test with a real user who does not have
*ALLOBJ. This is where the unexpected access paths surface: reports, extractions, Excel macros reading the files directly. - Repeat, one application at a time.
- Remove
*ALLOBJonly at the end, and one user at a time.
Step 3 is what reveals the system's real architecture, which almost never matches the one people believe they have.
The check worth repeating every year
SELECT AUTHORIZATION_NAME, STATUS, PREVIOUS_SIGNON,
SPECIAL_AUTHORITIES
FROM QSYS2.USER_INFO
WHERE STATUS = '*ENABLED'
AND (PREVIOUS_SIGNON < CURRENT DATE - 6 MONTHS
OR PREVIOUS_SIGNON IS NULL)
ORDER BY PREVIOUS_SIGNON;
Enabled profiles that have not signed on for six months. They are almost always people who no longer work there, or service accounts for retired applications: the most convenient way in that exists, because nobody would notice them being used.
Which versions this works on
The security model — QSECURITY levels, object authority, *PUBLIC, authorization lists, adopted authority with USRPRF(*OWNER) — has been stable for a great many releases and behaves the same on 7.3, 7.4, 7.5 and 7.6. The commands EDTOBJAUT, GRTOBJAUT, RVKOBJAUT, CRTAUTL, DSPUSRPRF and CHGDLTPRF are all long-standing.
QSYS2.USER_INFO — the SQL view over user profiles is an IBM i Service, so its availability depends on the release and the database PTF level. It is also extended over time: the multi-factor authentication columns, for example, are recent additions. If a column mentioned here does not exist on your machine, it arrived later.
Before this view existed, the same listing was obtained like this:
DSPUSRPRF USRPRF(*ALL) TYPE(*BASIC)
OUTPUT(*OUTFILE) OUTFILE(QTEMP/PROFILES)
The resulting file is queried in SQL exactly like the view. It is the method that works on any release, and it stays useful today when you want a snapshot to archive.
Special authorities (*ALLOBJ, *SECADM, *JOBCTL, *SPLCTL) and the QAUDJRN audit journal with the QAUDCTL and QAUDLVL system values have been around a long time; the individual QAUDLVL values have been extended across releases.
Comments
No comments yet. Be the first to comment!
You need an account to comment. Log in · Sign up