IBM Support

IBM i Security Analysis: Determining a User's Effective Authority

How To


Summary

Determining a user's true access to IBM i objects can be challenging due to the many security mechanisms involved in authority evaluation. A user's effective authority may be derived from multiple sources, including private authorities, authorization lists, group profiles, adopted authority, and inherited permissions within the Integrated File System (IFS). Understanding the final authority that IBM i applies at runtime requires evaluating these sources in the same sequence used by the operating system.

This document presents a comprehensive, SQL-based methodology for determining a user's effective authority to both traditional library-based objects and Integrated File System (IFS) objects. It provides a step-by-step process for collecting, resolving, and consolidating authority information using IBM i Services and SQL queries, enabling administrators to accurately assess a user's access across two key IBM i object spaces:

Objects contained within a specified library
Objects located under a specified IFS directory path

The authority determination process follows the same evaluation order used by IBM i security at runtime, ensuring that the resulting authority calculations closely reflect actual system behavior. Throughout the document, each authority source is examined individually and then incorporated into the overall resolution process to produce an accurate representation of a user's effective permissions.

Upon completion, the process populates two output tables containing a complete authority inventory for the target user profile—one for library objects and one for IFS objects. These inventories can be used for security reviews, access validation, compliance audits, migration planning, troubleshooting authorization issues, and identifying excessive or unintended user privileges.

By leveraging SQL and IBM i Services, organizations can automate authority analysis, reduce reliance on manual security investigations, and gain a consistent, repeatable method for evaluating user access across the IBM i environment.

Environment

Operating System: IBM i
IBM i Version: 7.3 and above (V7R3M0+)

Steps

 

Authority Resolution Order

IBM i evaluates authority to an object in this precise sequence — the check stops at the first match:

Priority

Source

Description

1User *ALLOBJ special authorityIf the user profile has *ALLOBJ, access is granted unconditionally
2User private authorityA specific authority entry for the user on the object
3User authority via authorization listThe user has a private entry in the authorization list (*AUTL) securing the object
4Group *ALLOBJ special authorityAny group profile the user belongs to has *ALLOBJ
5Group private authority to the objectThe group profile has a private authority entry on the object
6Group authority via authorization listThe group profile has a private entry in the authorization list securing the object
7*PUBLIC authorityThe public authority of the object, or the *PUBLIC entry in the authorization list securing it

 

ℹ️ Important: 

  • Steps 4–6 check ALL group profiles assigned to the user (GROUP_PROFILE_NAME and SUPPLEMENTAL_GROUP_LIST in QSYS2.USER_INFO). If any group satisfies the check, the search stops.
  • Adopted authority is outside the scope of this document. The authority inventory generated by this process evaluates authorities that are directly associated with objects and user profiles, following IBM i runtime authority resolution rules. Authority obtained through program adoption is not evaluated because it is granted dynamically during program execution and depends on the specific program being called and its adoption attributes.

 

Prerequisites

  • The executing user must have *SECADM or *ALLOBJ special authority, OR specific *READ authority to QSYS2 catalog views and the objects being inventoried.
  • The SECAUDIT schema (library) must exist or be created in Step 1.
  • For IFS queries, QSYS2.IFS_OBJECT_STATISTICS and QSYS2.IFS_OBJECT_PRIVILEGES are used — these are available from V7R3M0.

 

Parameters

Before running any SQL below, replace these placeholder values with your actual targets:

Placeholder

Description

Example

'MYLIB'The library to inventory'PRODLIB'
'HUGO'The user profile to check authority for'JDOE'
'/home/mydir'The IFS directory path to inventory'/home/jdoe'

Step 1 — Create the Output Schema and Tables

Run this DDL once to create the schema and both output tables. If they already exist, the CREATE OR REPLACE clause will rebuild them.

 

⚠️ Important:

  • This SQL scripts must be executed using IBM Access Client Solutions (ACS) – Run SQL Scripts. Running the script from other SQL interfaces or tools may result in unexpected behavior, syntax errors, or incomplete execution. Before running the script, ensure you are connected to the correct IBM i system and that all required substitutions (such as library names and user profiles) have been made throughout the entire script.
 
SQL — DDL
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 1 - Create output schema and inventory tables
--  minvrm:      v7r3m0
-- ============================================================

-- Create the schema if it does not already exist
CREATE SCHEMA IF NOT EXISTS SECAUDIT;

-- --------------------------------------------------------
-- Output table for LIBRARY objects
-- --------------------------------------------------------
CREATE OR REPLACE TABLE SECAUDIT.LIB_AUTH_INVENTORY (
    INVENTORY_TS        TIMESTAMP       NOT NULL DEFAULT CURRENT_TIMESTAMP,
    TARGET_USER         VARCHAR(10)     NOT NULL,
    OBJECT_LIBRARY      VARCHAR(10)     NOT NULL,
    OBJECT_NAME         VARCHAR(10)     NOT NULL,
    OBJECT_TYPE         VARCHAR(10)     NOT NULL,
    OBJECT_OWNER        VARCHAR(10),
    AUTL_NAME           VARCHAR(10),    -- Authorization list securing the object
    AUTH_SOURCE         VARCHAR(50)     NOT NULL, -- Where authority came from
    AUTH_SOURCE_DETAIL  VARCHAR(100),   -- e.g. group name that provided access
    EFFECTIVE_AUTHORITY VARCHAR(50)     NOT NULL, -- e.g. *ALL, *CHANGE, *USE, *EXCLUDE
    OBJ_OPERATIONAL     CHAR(3),
    OBJ_MANAGEMENT      CHAR(3),
    OBJ_EXISTENCE       CHAR(3),
    OBJ_ALTER           CHAR(3),
    OBJ_REFERENCE       CHAR(3),
    DATA_READ           CHAR(3),
    DATA_ADD            CHAR(3),
    DATA_UPDATE         CHAR(3),
    DATA_DELETE         CHAR(3),
    DATA_EXECUTE        CHAR(3),
    CONSTRAINT LIB_AUTH_INV_PK
        PRIMARY KEY (TARGET_USER, OBJECT_LIBRARY, OBJECT_NAME, OBJECT_TYPE)
);

LABEL ON TABLE SECAUDIT.LIB_AUTH_INVENTORY
    IS 'Library Object Authority Inventory';

LABEL ON COLUMN SECAUDIT.LIB_AUTH_INVENTORY (
    INVENTORY_TS        IS 'Inventory Run Timestamp',
    TARGET_USER         IS 'User Profile Checked',
    OBJECT_LIBRARY      IS 'Object Library',
    OBJECT_NAME         IS 'Object Name',
    OBJECT_TYPE         IS 'Object Type',
    OBJECT_OWNER        IS 'Object Owner',
    AUTL_NAME           IS 'Authorization List',
    AUTH_SOURCE         IS 'Authority Source (Priority 1-7)',
    AUTH_SOURCE_DETAIL  IS 'Source Detail (e.g., Group Name)',
    EFFECTIVE_AUTHORITY IS 'Effective Authority Level'
);

-- --------------------------------------------------------
-- Output table for IFS objects
-- --------------------------------------------------------
CREATE OR REPLACE TABLE SECAUDIT.IFS_AUTH_INVENTORY (
    INVENTORY_TS        TIMESTAMP       NOT NULL DEFAULT CURRENT_TIMESTAMP,
    TARGET_USER         VARCHAR(10)     NOT NULL,
    IFS_PATH_NAME       VARCHAR(1024)   NOT NULL,
    OBJECT_TYPE         VARCHAR(20)     NOT NULL,
    OBJECT_OWNER        VARCHAR(10),
    AUTL_NAME           VARCHAR(10),    -- Authorization list securing the object
    AUTH_SOURCE         VARCHAR(50)     NOT NULL,
    AUTH_SOURCE_DETAIL  VARCHAR(100),
    EFFECTIVE_AUTHORITY VARCHAR(50)     NOT NULL,
    DATA_READ           CHAR(3),
    DATA_ADD            CHAR(3),
    DATA_UPDATE         CHAR(3),
    DATA_DELETE         CHAR(3),
    DATA_EXECUTE        CHAR(3),
    CONSTRAINT IFS_AUTH_INV_PK
        PRIMARY KEY (TARGET_USER, IFS_PATH_NAME)
);

LABEL ON TABLE SECAUDIT.IFS_AUTH_INVENTORY
    IS 'IFS Object Authority Inventory';

LABEL ON COLUMN SECAUDIT.IFS_AUTH_INVENTORY (
    INVENTORY_TS        IS 'Inventory Run Timestamp',
    TARGET_USER         IS 'User Profile Checked',
    IFS_PATH_NAME       IS 'Full IFS Path',
    OBJECT_TYPE         IS 'IFS Object Type',
    OBJECT_OWNER        IS 'Object Owner',
    AUTL_NAME           IS 'Authorization List',
    AUTH_SOURCE         IS 'Authority Source (Priority 1-7)',
    AUTH_SOURCE_DETAIL  IS 'Source Detail (e.g., Group Name)',
    EFFECTIVE_AUTHORITY IS 'Effective Authority Level'
);

 

NOTES: 

  • The SQL statements in this document assume that the SECAUDIT library exists on the system and is available to store the generated output tables. If the library does not already exist, create it before executing the SQL statements by running:  CRTLIB LIB(SECAUDIT)
     

ℹ️ Expected Result:

  •  Schema SECAUDIT and both empty tables are created.

 

Step 2 — Populate the Library Object Inventory

This query resolves authority for every object in 'MYLIB' for the user 'HUGO', applying the 7-priority cascade. Replace both placeholders before running.

 

⚠️ Before running::

  • Replace 'MYLIB' with your target library and 'HUGO' with your target user profile. 
  • Both the library 'MYLIB' and the target user profile 'HUGO' are referenced in multiple places within the SQL script. Please ensure that all occurrences are replaced before running it.
  • The DELETE at the top removes prior inventory rows to avoid primary key conflicts on re-run.
SQL — Step 2: Library Object Inventory
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 2 - Library object authority inventory
--               Resolves authority in IBM i priority order (1-7).
--               Replace 'MYLIB' and 'HUGO' before running.
--  minvrm:      v7r3m0
-- ============================================================

-- Remove any previous inventory rows for this user + library
DELETE FROM SECAUDIT.LIB_AUTH_INVENTORY
WHERE TARGET_USER    = 'HUGO'
  AND OBJECT_LIBRARY = 'MYLIB';

INSERT INTO SECAUDIT.LIB_AUTH_INVENTORY (
    INVENTORY_TS, TARGET_USER, OBJECT_LIBRARY, OBJECT_NAME, OBJECT_TYPE,
    OBJECT_OWNER, AUTL_NAME, AUTH_SOURCE, AUTH_SOURCE_DETAIL,
    EFFECTIVE_AUTHORITY, OBJ_OPERATIONAL, OBJ_MANAGEMENT, OBJ_EXISTENCE,
    OBJ_ALTER, OBJ_REFERENCE, DATA_READ, DATA_ADD, DATA_UPDATE, DATA_DELETE, DATA_EXECUTE
)
WITH

-- User profile attributes
user_attrs AS (
    SELECT AUTHORIZATION_NAME, SPECIAL_AUTHORITIES,
           GROUP_PROFILE_NAME, SUPPLEMENTAL_GROUP_LIST
    FROM QSYS2.USER_INFO
    WHERE AUTHORIZATION_NAME = 'HUGO'
),

-- Expand all group profiles into individual rows
user_groups AS (
    SELECT GROUP_PROFILE_NAME AS GROUP_NAME
    FROM user_attrs
    WHERE GROUP_PROFILE_NAME IS NOT NULL
      AND TRIM(GROUP_PROFILE_NAME) NOT IN ('', '*NONE')

    UNION ALL

    -- Supplemental groups - tokenize the space-delimited list with XMLTABLE
    SELECT TRIM(x.GROUP_TOKEN) AS GROUP_NAME
    FROM user_attrs,
         XMLTABLE(
             'for $t in tokenize($s, " ") return <g>{string($t)}</g>'
             PASSING SUPPLEMENTAL_GROUP_LIST AS "s"
             COLUMNS GROUP_TOKEN VARCHAR(10) PATH '.'
         ) AS x
    WHERE SUPPLEMENTAL_GROUP_LIST IS NOT NULL
      AND TRIM(SUPPLEMENTAL_GROUP_LIST) NOT IN ('', '*NONE')
      AND TRIM(x.GROUP_TOKEN) NOT IN ('', '*NONE')
),

-- All objects in the target library + detect *AUTL linkage
obj_list AS (
    SELECT os.OBJLIB, os.OBJNAME, os.OBJTYPE, os.OBJOWNER,
           NULLIF(TRIM(ap.AUTHORIZATION_LIST), '') AS AUTL_NAME
    FROM TABLE(QSYS2.OBJECT_STATISTICS('MYLIB', '*ALL')) AS os
    LEFT JOIN QSYS2.OBJECT_PRIVILEGES AS ap
        ON  ap.SYSTEM_OBJECT_SCHEMA = os.OBJLIB
        AND ap.OBJECT_NAME          = os.OBJNAME
        AND ap.OBJECT_TYPE          = os.OBJTYPE
        AND ap.USER_NAME            = '*PUBLIC'
        AND ap.OBJECT_AUTHORITY     = '*AUTL'
),

-- Priority 2: User private authority
user_priv AS (
    SELECT op.SYSTEM_OBJECT_SCHEMA AS OBJLIB, op.OBJECT_NAME AS OBJNAME,
           op.OBJECT_TYPE AS OBJTYPE, op.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           op.OBJECT_OPERATIONAL, op.OBJECT_MANAGEMENT, op.OBJECT_EXISTENCE,
           op.OBJECT_ALTER, op.OBJECT_REFERENCE,
           op.DATA_READ, op.DATA_ADD, op.DATA_UPDATE, op.DATA_DELETE, op.DATA_EXECUTE
    FROM QSYS2.OBJECT_PRIVILEGES AS op
    WHERE op.SYSTEM_OBJECT_SCHEMA = 'MYLIB'
      AND op.USER_NAME            = 'HUGO'
      AND op.OBJECT_TYPE         <> '*AUTL'
      AND op.USER_NAME           <> '*PUBLIC'
),

-- Priority 3: User private entry in the authorization list
user_autl_priv AS (
    SELECT ol.OBJLIB, ol.OBJNAME, ol.OBJTYPE,
           al.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           al.OBJECT_OPERATIONAL, al.OBJECT_MANAGEMENT, al.OBJECT_EXISTENCE,
           al.OBJECT_ALTER, al.OBJECT_REFERENCE,
           al.DATA_READ, al.DATA_ADD, al.DATA_UPDATE, al.DATA_DELETE, al.DATA_EXECUTE
    FROM obj_list AS ol
    JOIN QSYS2.OBJECT_PRIVILEGES AS al
        ON  al.SYSTEM_OBJECT_SCHEMA = 'QSYS'
        AND al.OBJECT_NAME          = ol.AUTL_NAME
        AND al.OBJECT_TYPE          = '*AUTL'
        AND al.USER_NAME            = 'HUGO'
    WHERE ol.AUTL_NAME IS NOT NULL
),

-- Priority 4: Any group profile that has *ALLOBJ
grp_allobj AS (
    SELECT ug.GROUP_NAME
    FROM user_groups AS ug
    JOIN QSYS2.USER_INFO AS gui
        ON gui.AUTHORIZATION_NAME = ug.GROUP_NAME
    WHERE gui.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'
    FETCH FIRST 1 ROW ONLY
),

-- Priority 5: Best group private authority on each object
grp_priv AS (
    SELECT op.SYSTEM_OBJECT_SCHEMA AS OBJLIB, op.OBJECT_NAME AS OBJNAME,
           op.OBJECT_TYPE AS OBJTYPE, op.USER_NAME AS GROUP_NAME,
           op.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           op.OBJECT_OPERATIONAL, op.OBJECT_MANAGEMENT, op.OBJECT_EXISTENCE,
           op.OBJECT_ALTER, op.OBJECT_REFERENCE,
           op.DATA_READ, op.DATA_ADD, op.DATA_UPDATE, op.DATA_DELETE, op.DATA_EXECUTE,
           ROW_NUMBER() OVER (
               PARTITION BY op.SYSTEM_OBJECT_SCHEMA, op.OBJECT_NAME, op.OBJECT_TYPE
               ORDER BY CASE op.OBJECT_AUTHORITY
                   WHEN '*ALL' THEN 1 WHEN '*CHANGE' THEN 2
                   WHEN '*USE' THEN 3 WHEN '*EXCLUDE' THEN 4 ELSE 5
               END
           ) AS RNK
    FROM QSYS2.OBJECT_PRIVILEGES AS op
    JOIN user_groups AS ug ON op.USER_NAME = ug.GROUP_NAME
    WHERE op.SYSTEM_OBJECT_SCHEMA = 'MYLIB'
      AND op.USER_NAME           <> '*PUBLIC'
),

-- Priority 6: Best group entry in the authorization list
grp_autl_priv AS (
    SELECT ol.OBJLIB, ol.OBJNAME, ol.OBJTYPE, al.USER_NAME AS GROUP_NAME,
           al.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           al.OBJECT_OPERATIONAL, al.OBJECT_MANAGEMENT, al.OBJECT_EXISTENCE,
           al.OBJECT_ALTER, al.OBJECT_REFERENCE,
           al.DATA_READ, al.DATA_ADD, al.DATA_UPDATE, al.DATA_DELETE, al.DATA_EXECUTE,
           ROW_NUMBER() OVER (
               PARTITION BY ol.OBJLIB, ol.OBJNAME, ol.OBJTYPE
               ORDER BY CASE al.OBJECT_AUTHORITY
                   WHEN '*ALL' THEN 1 WHEN '*CHANGE' THEN 2
                   WHEN '*USE' THEN 3 WHEN '*EXCLUDE' THEN 4 ELSE 5
               END
           ) AS RNK
    FROM obj_list AS ol
    JOIN QSYS2.OBJECT_PRIVILEGES AS al
        ON  al.SYSTEM_OBJECT_SCHEMA = 'QSYS'
        AND al.OBJECT_NAME          = ol.AUTL_NAME
        AND al.OBJECT_TYPE          = '*AUTL'
        AND al.USER_NAME           <> '*PUBLIC'
    JOIN user_groups AS ug ON al.USER_NAME = ug.GROUP_NAME
    WHERE ol.AUTL_NAME IS NOT NULL
),

-- Priority 7: *PUBLIC authority
pub_auth AS (
    -- Branch A: direct *PUBLIC (not secured by *AUTL)
    SELECT op.SYSTEM_OBJECT_SCHEMA AS OBJLIB, op.OBJECT_NAME AS OBJNAME,
           op.OBJECT_TYPE AS OBJTYPE, op.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           op.OBJECT_OPERATIONAL, op.OBJECT_MANAGEMENT, op.OBJECT_EXISTENCE,
           op.OBJECT_ALTER, op.OBJECT_REFERENCE,
           op.DATA_READ, op.DATA_ADD, op.DATA_UPDATE, op.DATA_DELETE, op.DATA_EXECUTE
    FROM QSYS2.OBJECT_PRIVILEGES AS op
    WHERE op.SYSTEM_OBJECT_SCHEMA = 'MYLIB'
      AND op.USER_NAME            = '*PUBLIC'
      AND op.OBJECT_AUTHORITY    <> '*AUTL'

    UNION ALL

    -- Branch B: object secured by *AUTL - get *PUBLIC from inside the auth list
    SELECT ol.OBJLIB, ol.OBJNAME, ol.OBJTYPE,
           al.OBJECT_AUTHORITY, al.OBJECT_OPERATIONAL, al.OBJECT_MANAGEMENT,
           al.OBJECT_EXISTENCE, al.OBJECT_ALTER, al.OBJECT_REFERENCE,
           al.DATA_READ, al.DATA_ADD, al.DATA_UPDATE, al.DATA_DELETE, al.DATA_EXECUTE
    FROM obj_list AS ol
    JOIN QSYS2.OBJECT_PRIVILEGES AS al
        ON  al.SYSTEM_OBJECT_SCHEMA = 'QSYS'
        AND al.OBJECT_NAME          = ol.AUTL_NAME
        AND al.OBJECT_TYPE          = '*AUTL'
        AND al.USER_NAME            = '*PUBLIC'
    WHERE ol.AUTL_NAME IS NOT NULL
),

-- Authority resolution - 7-priority CASE chain
resolved AS (
    SELECT 'HUGO' AS TARGET_USER,
        ol.OBJLIB, ol.OBJNAME, ol.OBJTYPE, ol.OBJOWNER, ol.AUTL_NAME,
        CASE
            WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%'
                THEN 'Priority 1 - User *ALLOBJ special authority'
            WHEN up.OBJNAME  IS NOT NULL THEN 'Priority 2 - User private authority'
            WHEN uap.OBJNAME IS NOT NULL THEN 'Priority 3 - User authority via authorization list'
            WHEN (SELECT COUNT(*) FROM grp_allobj) > 0
                THEN 'Priority 4 - Group *ALLOBJ special authority'
            WHEN gp.OBJNAME  IS NOT NULL THEN 'Priority 5 - Group private authority'
            WHEN gap.OBJNAME IS NOT NULL THEN 'Priority 6 - Group authority via authorization list'
            ELSE 'Priority 7 - *PUBLIC authority'
        END AS AUTH_SOURCE,
        CASE
            WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%'
                THEN 'User profile: HUGO'
            WHEN up.OBJNAME  IS NOT NULL THEN 'User profile: HUGO'
            WHEN uap.OBJNAME IS NOT NULL THEN 'Authorization list: ' || COALESCE(ol.AUTL_NAME, '')
            WHEN (SELECT COUNT(*) FROM grp_allobj) > 0
                THEN 'Group profile: ' || (SELECT GROUP_NAME FROM grp_allobj)
            WHEN gp.OBJNAME  IS NOT NULL THEN 'Group profile: ' || gp.GROUP_NAME
            WHEN gap.OBJNAME IS NOT NULL THEN 'Group profile: ' || gap.GROUP_NAME
                || ' via authorization list: ' || COALESCE(ol.AUTL_NAME, '')
            ELSE '*PUBLIC'
        END AS AUTH_SOURCE_DETAIL,
        CASE
            WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%'
                THEN '*ALL (via *ALLOBJ)'
            WHEN up.OBJNAME  IS NOT NULL THEN up.EFFECTIVE_AUTHORITY
            WHEN uap.OBJNAME IS NOT NULL THEN uap.EFFECTIVE_AUTHORITY
            WHEN (SELECT COUNT(*) FROM grp_allobj) > 0 THEN '*ALL (via *ALLOBJ)'
            WHEN gp.OBJNAME  IS NOT NULL THEN gp.EFFECTIVE_AUTHORITY
            WHEN gap.OBJNAME IS NOT NULL THEN gap.EFFECTIVE_AUTHORITY
            ELSE COALESCE(pa.EFFECTIVE_AUTHORITY, '*EXCLUDE (no *PUBLIC entry)')
        END AS EFFECTIVE_AUTHORITY,
        CASE WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN up.OBJNAME  IS NOT NULL THEN up.OBJ_OPERATIONAL
             WHEN uap.OBJNAME IS NOT NULL THEN uap.OBJ_OPERATIONAL
             WHEN (SELECT COUNT(*) FROM grp_allobj) > 0 THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.OBJ_OPERATIONAL
             WHEN gap.OBJNAME IS NOT NULL THEN gap.OBJ_OPERATIONAL
             ELSE pa.OBJ_OPERATIONAL END AS OBJ_OPERATIONAL,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.OBJ_MANAGEMENT
             WHEN uap.OBJNAME IS NOT NULL THEN uap.OBJ_MANAGEMENT
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.OBJ_MANAGEMENT
             WHEN gap.OBJNAME IS NOT NULL THEN gap.OBJ_MANAGEMENT
             ELSE pa.OBJ_MANAGEMENT END AS OBJ_MANAGEMENT,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.OBJ_EXISTENCE
             WHEN uap.OBJNAME IS NOT NULL THEN uap.OBJ_EXISTENCE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.OBJ_EXISTENCE
             WHEN gap.OBJNAME IS NOT NULL THEN gap.OBJ_EXISTENCE
             ELSE pa.OBJ_EXISTENCE END AS OBJ_EXISTENCE,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.OBJ_ALTER
             WHEN uap.OBJNAME IS NOT NULL THEN uap.OBJ_ALTER
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.OBJ_ALTER
             WHEN gap.OBJNAME IS NOT NULL THEN gap.OBJ_ALTER
             ELSE pa.OBJ_ALTER END AS OBJ_ALTER,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.OBJ_REFERENCE
             WHEN uap.OBJNAME IS NOT NULL THEN uap.OBJ_REFERENCE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.OBJ_REFERENCE
             WHEN gap.OBJNAME IS NOT NULL THEN gap.OBJ_REFERENCE
             ELSE pa.OBJ_REFERENCE END AS OBJ_REFERENCE,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.DATA_READ
             WHEN uap.OBJNAME IS NOT NULL THEN uap.DATA_READ
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.DATA_READ
             WHEN gap.OBJNAME IS NOT NULL THEN gap.DATA_READ
             ELSE pa.DATA_READ END AS DATA_READ,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.DATA_ADD
             WHEN uap.OBJNAME IS NOT NULL THEN uap.DATA_ADD
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.DATA_ADD
             WHEN gap.OBJNAME IS NOT NULL THEN gap.DATA_ADD
             ELSE pa.DATA_ADD END AS DATA_ADD,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.DATA_UPDATE
             WHEN uap.OBJNAME IS NOT NULL THEN uap.DATA_UPDATE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.DATA_UPDATE
             WHEN gap.OBJNAME IS NOT NULL THEN gap.DATA_UPDATE
             ELSE pa.DATA_UPDATE END AS DATA_UPDATE,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.DATA_DELETE
             WHEN uap.OBJNAME IS NOT NULL THEN uap.DATA_DELETE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.DATA_DELETE
             WHEN gap.OBJNAME IS NOT NULL THEN gap.DATA_DELETE
             ELSE pa.DATA_DELETE END AS DATA_DELETE,
        CASE WHEN up.OBJNAME  IS NOT NULL THEN up.DATA_EXECUTE
             WHEN uap.OBJNAME IS NOT NULL THEN uap.DATA_EXECUTE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.OBJNAME  IS NOT NULL THEN gp.DATA_EXECUTE
             WHEN gap.OBJNAME IS NOT NULL THEN gap.DATA_EXECUTE
             ELSE pa.DATA_EXECUTE END AS DATA_EXECUTE
    FROM obj_list AS ol
    LEFT JOIN user_priv      AS up  ON up.OBJLIB  = ol.OBJLIB AND up.OBJNAME  = ol.OBJNAME AND up.OBJTYPE  = ol.OBJTYPE
    LEFT JOIN user_autl_priv AS uap ON uap.OBJLIB = ol.OBJLIB AND uap.OBJNAME = ol.OBJNAME AND uap.OBJTYPE = ol.OBJTYPE
    LEFT JOIN (SELECT * FROM grp_priv      WHERE RNK = 1) AS gp  ON gp.OBJLIB  = ol.OBJLIB AND gp.OBJNAME  = ol.OBJNAME AND gp.OBJTYPE  = ol.OBJTYPE
    LEFT JOIN (SELECT * FROM grp_autl_priv WHERE RNK = 1) AS gap ON gap.OBJLIB = ol.OBJLIB AND gap.OBJNAME = ol.OBJNAME AND gap.OBJTYPE = ol.OBJTYPE
    LEFT JOIN pub_auth        AS pa  ON pa.OBJLIB  = ol.OBJLIB AND pa.OBJNAME  = ol.OBJNAME AND pa.OBJTYPE  = ol.OBJTYPE
)
SELECT CURRENT_TIMESTAMP, TARGET_USER, OBJLIB, OBJNAME, OBJTYPE, OBJOWNER, AUTL_NAME,
       AUTH_SOURCE, AUTH_SOURCE_DETAIL, EFFECTIVE_AUTHORITY,
       OBJ_OPERATIONAL, OBJ_MANAGEMENT, OBJ_EXISTENCE, OBJ_ALTER, OBJ_REFERENCE,
       DATA_READ, DATA_ADD, DATA_UPDATE, DATA_DELETE, DATA_EXECUTE
FROM resolved
ORDER BY OBJLIB, OBJNAME, OBJTYPE;

 

ℹ️ Expected Result:

  •  SECAUDIT.LIB_AUTH_INVENTORY is populated with one row per object in the library, each showing the resolved authority and its source.

 

Sample Output — Library Inventory

TARGET_USEROBJECT_LIBRARYOBJECT_NAMEOBJECT_TYPEEFFECTIVE_AUTHORITYAUTH_SOURCE
HUGOV6CASTILA*QRYDFN*EXCLUDEPriority 7 - *PUBLIC authority
HUGOV6CASTILADPAUT*PGM*CHANGEPriority 2 - User private authority
HUGOV6CASTILADPAUT1*PGM*CHANGEPriority 7 - *PUBLIC authority
HUGOV6CASTILADPAUT2*PGM*USEPriority 2 - User private authority
HUGOV6CASTILASP_INFO*FILE*CHANGEPriority 3 - User authority via authorization list

Step 3 — Populate the IFS Object Inventory

This query resolves authority for every object under an IFS directory for the user 'HUGO'. 

⚠️ Before running::

  • Replace '/home/mydir' and 'HUGO' before running. 
  • Both the directory '/home/mydir' and the target user profile 'HUGO' are referenced in multiple places within the SQL script. Please ensure that all occurrences are replaced before running it.

SQL — Step 3: IFS Object Inventory

-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 3 - IFS object authority inventory
--               Resolves authority in IBM i priority order (1-7).
--               Replace '/home/mydir' and 'HUGO' before running.
--  minvrm:      v7r3m0
-- ============================================================

-- Remove any previous inventory rows for this user + path before re-inserting
DELETE FROM SECAUDIT.IFS_AUTH_INVENTORY
WHERE TARGET_USER    = 'HUGO'
  AND IFS_PATH_NAME LIKE '/home/mydir%';

INSERT INTO SECAUDIT.IFS_AUTH_INVENTORY (
    INVENTORY_TS, TARGET_USER, IFS_PATH_NAME, OBJECT_TYPE, OBJECT_OWNER,
    AUTL_NAME, AUTH_SOURCE, AUTH_SOURCE_DETAIL, EFFECTIVE_AUTHORITY,
    DATA_READ, DATA_ADD, DATA_UPDATE, DATA_DELETE, DATA_EXECUTE
)
WITH

-- User profile attributes
ifs_user_attrs AS (
    SELECT AUTHORIZATION_NAME, SPECIAL_AUTHORITIES,
           GROUP_PROFILE_NAME, SUPPLEMENTAL_GROUP_LIST
    FROM QSYS2.USER_INFO
    WHERE AUTHORIZATION_NAME = 'HUGO'
),

-- All group profiles for the user
ifs_user_groups AS (
    SELECT GROUP_PROFILE_NAME AS GROUP_NAME
    FROM ifs_user_attrs
    WHERE GROUP_PROFILE_NAME IS NOT NULL
      AND TRIM(GROUP_PROFILE_NAME) NOT IN ('', '*NONE')

    UNION ALL

    SELECT TRIM(x.GROUP_TOKEN) AS GROUP_NAME
    FROM ifs_user_attrs,
         XMLTABLE(
             'for $t in tokenize($s, " ") return <g>{string($t)}</g>'
             PASSING SUPPLEMENTAL_GROUP_LIST AS "s"
             COLUMNS GROUP_TOKEN VARCHAR(10) PATH '.'
         ) AS x
    WHERE SUPPLEMENTAL_GROUP_LIST IS NOT NULL
      AND TRIM(SUPPLEMENTAL_GROUP_LIST) NOT IN ('', '*NONE')
      AND TRIM(x.GROUP_TOKEN) NOT IN ('', '*NONE')
),

-- All IFS objects under the target directory (recursive)
ifs_obj_list AS (
    SELECT PATH_NAME, OBJECT_TYPE, OBJECT_OWNER,
           AUTHORIZATION_LIST AS AUTL_NAME
    FROM TABLE(QSYS2.IFS_OBJECT_STATISTICS(
                    START_PATH_NAME     => '/home/mydir',
                    SUBTREE_DIRECTORIES => 'YES'))
),

-- Priority 2: User private authority on each IFS object
ifs_user_priv AS (
    SELECT ip.PATH_NAME, ip.AUTHORIZATION_NAME,
           ip.DATA_AUTHORITY AS EFFECTIVE_AUTHORITY,
           ip.DATA_READ, ip.DATA_ADD, ip.DATA_UPDATE, ip.DATA_DELETE, ip.DATA_EXECUTE
    FROM TABLE(QSYS2.IFS_OBJECT_PRIVILEGES(
                    PATH_NAME => '/home/mydir')) AS ip
    WHERE ip.AUTHORIZATION_NAME = 'HUGO'
      AND ip.AUTHORIZATION_NAME <> '*PUBLIC'
),

-- Priority 3: User private entry in the authorization list on IFS object
ifs_user_autl_priv AS (
    SELECT ol.PATH_NAME,
           al.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           al.DATA_READ, al.DATA_ADD, al.DATA_UPDATE, al.DATA_DELETE, al.DATA_EXECUTE
    FROM ifs_obj_list AS ol
    JOIN QSYS2.OBJECT_PRIVILEGES AS al
        ON  al.SYSTEM_OBJECT_SCHEMA = 'QSYS'
        AND al.OBJECT_NAME          = ol.AUTL_NAME
        AND al.OBJECT_TYPE          = '*AUTL'
        AND al.USER_NAME            = 'HUGO'
    WHERE ol.AUTL_NAME IS NOT NULL
),

-- Priority 4: Any group that has *ALLOBJ
ifs_grp_allobj AS (
    SELECT ug.GROUP_NAME
    FROM ifs_user_groups AS ug
    JOIN QSYS2.USER_INFO AS gui
        ON gui.AUTHORIZATION_NAME = ug.GROUP_NAME
    WHERE gui.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'
    FETCH FIRST 1 ROW ONLY
),

-- Priority 5: Best group private authority on each IFS object
ifs_grp_priv AS (
    SELECT ip.PATH_NAME, ip.AUTHORIZATION_NAME AS GROUP_NAME,
           ip.DATA_AUTHORITY AS EFFECTIVE_AUTHORITY,
           ip.DATA_READ, ip.DATA_ADD, ip.DATA_UPDATE, ip.DATA_DELETE, ip.DATA_EXECUTE,
           ROW_NUMBER() OVER (
               PARTITION BY ip.PATH_NAME
               ORDER BY CASE ip.DATA_AUTHORITY
                   WHEN '*ALL' THEN 1 WHEN '*CHANGE' THEN 2
                   WHEN '*USE' THEN 3 WHEN '*EXCLUDE' THEN 4 ELSE 5
               END
           ) AS RNK
    FROM TABLE(QSYS2.IFS_OBJECT_PRIVILEGES(
                    PATH_NAME => '/home/mydir')) AS ip
    JOIN ifs_user_groups AS ug ON ip.AUTHORIZATION_NAME = ug.GROUP_NAME
    WHERE ip.AUTHORIZATION_NAME <> '*PUBLIC'
),

-- Priority 6: Best group authority via authorization list on IFS object
ifs_grp_autl_priv AS (
    SELECT ol.PATH_NAME, al.USER_NAME AS GROUP_NAME,
           al.OBJECT_AUTHORITY AS EFFECTIVE_AUTHORITY,
           al.DATA_READ, al.DATA_ADD, al.DATA_UPDATE, al.DATA_DELETE, al.DATA_EXECUTE,
           ROW_NUMBER() OVER (
               PARTITION BY ol.PATH_NAME
               ORDER BY CASE al.OBJECT_AUTHORITY
                   WHEN '*ALL' THEN 1 WHEN '*CHANGE' THEN 2
                   WHEN '*USE' THEN 3 WHEN '*EXCLUDE' THEN 4 ELSE 5
               END
           ) AS RNK
    FROM ifs_obj_list AS ol
    JOIN QSYS2.OBJECT_PRIVILEGES AS al
        ON  al.SYSTEM_OBJECT_SCHEMA = 'QSYS'
        AND al.OBJECT_NAME          = ol.AUTL_NAME
        AND al.OBJECT_TYPE          = '*AUTL'
        AND al.USER_NAME           <> '*PUBLIC'
    JOIN ifs_user_groups AS ug ON al.USER_NAME = ug.GROUP_NAME
    WHERE ol.AUTL_NAME IS NOT NULL
),

-- Priority 7: *PUBLIC authority on IFS objects
ifs_pub_auth AS (
    -- Branch A: object NOT secured by auth list
    SELECT ip.PATH_NAME, ip.DATA_AUTHORITY AS EFFECTIVE_AUTHORITY,
           ip.DATA_READ, ip.DATA_ADD, ip.DATA_UPDATE, ip.DATA_DELETE, ip.DATA_EXECUTE
    FROM TABLE(QSYS2.IFS_OBJECT_PRIVILEGES(
                    PATH_NAME => '/home/mydir')) AS ip
    JOIN ifs_obj_list AS ol ON ol.PATH_NAME = ip.PATH_NAME AND ol.AUTL_NAME IS NULL
    WHERE ip.AUTHORIZATION_NAME = '*PUBLIC'
      AND ip.DATA_AUTHORITY     <> '*AUTL'

    UNION ALL

    -- Branch B: object IS secured by auth list - get *PUBLIC from inside the list
    SELECT ol.PATH_NAME, al.OBJECT_AUTHORITY,
           al.DATA_READ, al.DATA_ADD, al.DATA_UPDATE, al.DATA_DELETE, al.DATA_EXECUTE
    FROM ifs_obj_list AS ol
    JOIN QSYS2.OBJECT_PRIVILEGES AS al
        ON  al.SYSTEM_OBJECT_SCHEMA = 'QSYS'
        AND al.OBJECT_NAME          = ol.AUTL_NAME
        AND al.OBJECT_TYPE          = '*AUTL'
        AND al.USER_NAME            = '*PUBLIC'
    WHERE ol.AUTL_NAME IS NOT NULL
),

-- Authority resolution - 7-priority CASE chain
ifs_resolved AS (
    SELECT 'HUGO' AS TARGET_USER,
        ol.PATH_NAME, ol.OBJECT_TYPE, ol.OBJECT_OWNER, ol.AUTL_NAME,
        CASE
            WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%'
                THEN 'Priority 1 - User *ALLOBJ special authority'
            WHEN up.PATH_NAME  IS NOT NULL THEN 'Priority 2 - User private authority'
            WHEN uap.PATH_NAME IS NOT NULL THEN 'Priority 3 - User authority via authorization list'
            WHEN (SELECT COUNT(*) FROM ifs_grp_allobj) > 0
                THEN 'Priority 4 - Group *ALLOBJ special authority'
            WHEN gp.PATH_NAME  IS NOT NULL THEN 'Priority 5 - Group private authority'
            WHEN gap.PATH_NAME IS NOT NULL THEN 'Priority 6 - Group authority via authorization list'
            ELSE 'Priority 7 - *PUBLIC authority'
        END AS AUTH_SOURCE,
        CASE
            WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%'
                THEN 'User profile: HUGO'
            WHEN up.PATH_NAME  IS NOT NULL THEN 'User profile: HUGO'
            WHEN uap.PATH_NAME IS NOT NULL THEN 'Authorization list: ' || COALESCE(ol.AUTL_NAME, '')
            WHEN (SELECT COUNT(*) FROM ifs_grp_allobj) > 0
                THEN 'Group profile: ' || (SELECT GROUP_NAME FROM ifs_grp_allobj)
            WHEN gp.PATH_NAME  IS NOT NULL THEN 'Group profile: ' || gp.GROUP_NAME
            WHEN gap.PATH_NAME IS NOT NULL THEN 'Group profile: ' || gap.GROUP_NAME
                || ' via authorization list: ' || COALESCE(ol.AUTL_NAME, '')
            ELSE '*PUBLIC'
        END AS AUTH_SOURCE_DETAIL,
        CASE
            WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%'
                THEN '*ALL (via *ALLOBJ)'
            WHEN up.PATH_NAME  IS NOT NULL THEN up.EFFECTIVE_AUTHORITY
            WHEN uap.PATH_NAME IS NOT NULL THEN uap.EFFECTIVE_AUTHORITY
            WHEN (SELECT COUNT(*) FROM ifs_grp_allobj) > 0 THEN '*ALL (via *ALLOBJ)'
            WHEN gp.PATH_NAME  IS NOT NULL THEN gp.EFFECTIVE_AUTHORITY
            WHEN gap.PATH_NAME IS NOT NULL THEN gap.EFFECTIVE_AUTHORITY
            ELSE COALESCE(pa.EFFECTIVE_AUTHORITY, '*EXCLUDE (no *PUBLIC entry)')
        END AS EFFECTIVE_AUTHORITY,
        CASE WHEN up.PATH_NAME  IS NOT NULL THEN up.DATA_READ
             WHEN uap.PATH_NAME IS NOT NULL THEN uap.DATA_READ
             WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.PATH_NAME  IS NOT NULL THEN gp.DATA_READ
             WHEN gap.PATH_NAME IS NOT NULL THEN gap.DATA_READ
             ELSE pa.DATA_READ END AS DATA_READ,
        CASE WHEN up.PATH_NAME  IS NOT NULL THEN up.DATA_ADD
             WHEN uap.PATH_NAME IS NOT NULL THEN uap.DATA_ADD
             WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.PATH_NAME  IS NOT NULL THEN gp.DATA_ADD
             WHEN gap.PATH_NAME IS NOT NULL THEN gap.DATA_ADD
             ELSE pa.DATA_ADD END AS DATA_ADD,
        CASE WHEN up.PATH_NAME  IS NOT NULL THEN up.DATA_UPDATE
             WHEN uap.PATH_NAME IS NOT NULL THEN uap.DATA_UPDATE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.PATH_NAME  IS NOT NULL THEN gp.DATA_UPDATE
             WHEN gap.PATH_NAME IS NOT NULL THEN gap.DATA_UPDATE
             ELSE pa.DATA_UPDATE END AS DATA_UPDATE,
        CASE WHEN up.PATH_NAME  IS NOT NULL THEN up.DATA_DELETE
             WHEN uap.PATH_NAME IS NOT NULL THEN uap.DATA_DELETE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.PATH_NAME  IS NOT NULL THEN gp.DATA_DELETE
             WHEN gap.PATH_NAME IS NOT NULL THEN gap.DATA_DELETE
             ELSE pa.DATA_DELETE END AS DATA_DELETE,
        CASE WHEN up.PATH_NAME  IS NOT NULL THEN up.DATA_EXECUTE
             WHEN uap.PATH_NAME IS NOT NULL THEN uap.DATA_EXECUTE
             WHEN (SELECT SPECIAL_AUTHORITIES FROM ifs_user_attrs) LIKE '%*ALLOBJ%' THEN 'YES'
             WHEN gp.PATH_NAME  IS NOT NULL THEN gp.DATA_EXECUTE
             WHEN gap.PATH_NAME IS NOT NULL THEN gap.DATA_EXECUTE
             ELSE pa.DATA_EXECUTE END AS DATA_EXECUTE
    FROM ifs_obj_list AS ol
    LEFT JOIN ifs_user_priv      AS up  ON up.PATH_NAME  = ol.PATH_NAME
    LEFT JOIN ifs_user_autl_priv AS uap ON uap.PATH_NAME = ol.PATH_NAME
    LEFT JOIN (SELECT * FROM ifs_grp_priv      WHERE RNK = 1) AS gp  ON gp.PATH_NAME  = ol.PATH_NAME
    LEFT JOIN (SELECT * FROM ifs_grp_autl_priv WHERE RNK = 1) AS gap ON gap.PATH_NAME = ol.PATH_NAME
    LEFT JOIN ifs_pub_auth        AS pa  ON pa.PATH_NAME  = ol.PATH_NAME
)
SELECT CURRENT_TIMESTAMP, TARGET_USER, PATH_NAME, OBJECT_TYPE, OBJECT_OWNER,
       AUTL_NAME, AUTH_SOURCE, AUTH_SOURCE_DETAIL, EFFECTIVE_AUTHORITY,
       DATA_READ, DATA_ADD, DATA_UPDATE, DATA_DELETE, DATA_EXECUTE
FROM ifs_resolved
ORDER BY PATH_NAME;

 

ℹ️ Expected Result:

  •  SECAUDIT.IFS_AUTH_INVENTORY is populated with one row per IFS object under the target directory, each showing the resolved authority and source.

 

Sample Output — IFS Inventory

TARGET_USERIFS_PATH_NAMEOBJECT_TYPEEFFECTIVE_AUTHORITYAUTH_SOURCE
HUGO/home/v6castil*DIR*CHANGEPriority 3 - User authority via authorization list
HUGO/home/v6castil/.sh_history*STMF*EXCLUDEPriority 7 - *PUBLIC authority
HUGO/home/v6castil/AJSWeb.jar*STMF*CHANGEPriority 3 - User authority via authorization list
HUGO/home/v6castil/aut.txt*STMF*CHANGEPriority 3 - User authority via authorization list
HUGO/home/v6castil/aut2.txt*STMF*EXCLUDEPriority 7 - *PUBLIC authority

 

Step 4 — Review the Results

4a — Library Object Authority Summary (by source)

A high-level count of how many objects each authority source controls, grouped by library.

SQL — Step 4a: Library Summary
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 4a - Library authority summary by source
--  minvrm:      v7r3m0
-- ============================================================

SELECT
    TARGET_USER,
    OBJECT_LIBRARY,
    AUTH_SOURCE,
    COUNT(*)              AS OBJECT_COUNT,
    LISTAGG(DISTINCT EFFECTIVE_AUTHORITY, ', ')
        WITHIN GROUP (ORDER BY EFFECTIVE_AUTHORITY) AS AUTHORITY_LEVELS
FROM SECAUDIT.LIB_AUTH_INVENTORY
GROUP BY
    TARGET_USER,
    OBJECT_LIBRARY,
    AUTH_SOURCE
ORDER BY
    TARGET_USER,
    OBJECT_LIBRARY,
    AUTH_SOURCE;

 

4b — Library Object Authority Detail

Full detail of every object in the library inventory including all authority bits.

SQL — Step 4b: Library Detail
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 4b - Full library authority detail
--  minvrm:      v7r3m0
-- ============================================================

SELECT
    TARGET_USER,
    OBJECT_LIBRARY,
    OBJECT_NAME,
    OBJECT_TYPE,
    OBJECT_OWNER,
    AUTL_NAME,
    AUTH_SOURCE,
    AUTH_SOURCE_DETAIL,
    EFFECTIVE_AUTHORITY,
    DATA_READ,
    DATA_ADD,
    DATA_UPDATE,
    DATA_DELETE,
    DATA_EXECUTE,
    OBJ_OPERATIONAL,
    OBJ_MANAGEMENT,
    OBJ_EXISTENCE,
    OBJ_ALTER,
    OBJ_REFERENCE
FROM SECAUDIT.LIB_AUTH_INVENTORY
ORDER BY
    TARGET_USER,
    OBJECT_LIBRARY,
    OBJECT_TYPE,
    OBJECT_NAME;

 

4c — IFS Object Authority Summary (by source)

A high-level count of how many IFS objects each authority source controls.

SQL — Step 4c: IFS Summary
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 4c - IFS authority summary by source
--  minvrm:      v7r3m0
-- ============================================================

SELECT
    TARGET_USER,
    AUTH_SOURCE,
    COUNT(*)              AS OBJECT_COUNT,
    LISTAGG(DISTINCT EFFECTIVE_AUTHORITY, ', ')
        WITHIN GROUP (ORDER BY EFFECTIVE_AUTHORITY) AS AUTHORITY_LEVELS
FROM SECAUDIT.IFS_AUTH_INVENTORY
GROUP BY
    TARGET_USER,
    AUTH_SOURCE
ORDER BY
    TARGET_USER,
    AUTH_SOURCE;

 

4d — IFS Object Authority Detail

Full detail of every IFS object in the inventory.

SQL — Step 4d: IFS Detail
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 4d - Full IFS authority detail
--  minvrm:      v7r3m0
-- ============================================================

SELECT
    TARGET_USER,
    IFS_PATH_NAME,
    OBJECT_TYPE,
    OBJECT_OWNER,
    AUTL_NAME,
    AUTH_SOURCE,
    AUTH_SOURCE_DETAIL,
    EFFECTIVE_AUTHORITY,
    DATA_READ,
    DATA_ADD,
    DATA_UPDATE,
    DATA_DELETE,
    DATA_EXECUTE
FROM SECAUDIT.IFS_AUTH_INVENTORY
ORDER BY
    TARGET_USER,
    IFS_PATH_NAME;

 

4e — Objects where the user has *EXCLUDE or no authority

A focused query highlighting where the user is denied access — useful for confirming the inventory captured *EXCLUDE entries correctly.

ℹ️ 

  •  This UNION query covers both library objects and IFS objects in a single result set, making it easy to review all denied access in one pass.
SQL — Step 4e: Denied / Excluded Objects
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 4e - Denied/excluded objects (both spaces)
--  minvrm:      v7r3m0
-- ============================================================

SELECT 'LIBRARY'    AS OBJECT_SPACE,
       TARGET_USER,
       OBJECT_LIBRARY AS LOCATION,
       OBJECT_NAME,
       OBJECT_TYPE,
       EFFECTIVE_AUTHORITY,
       AUTH_SOURCE,
       AUTH_SOURCE_DETAIL
FROM SECAUDIT.LIB_AUTH_INVENTORY
WHERE EFFECTIVE_AUTHORITY LIKE '%*EXCLUDE%'
   OR EFFECTIVE_AUTHORITY LIKE '%no *PUBLIC%'

UNION ALL

SELECT 'IFS',
       TARGET_USER,
       LEFT(IFS_PATH_NAME, 80),
       IFS_PATH_NAME,
       OBJECT_TYPE,
       EFFECTIVE_AUTHORITY,
       AUTH_SOURCE,
       AUTH_SOURCE_DETAIL
FROM SECAUDIT.IFS_AUTH_INVENTORY
WHERE EFFECTIVE_AUTHORITY LIKE '%*EXCLUDE%'
   OR EFFECTIVE_AUTHORITY LIKE '%no *PUBLIC%'

ORDER BY OBJECT_SPACE, TARGET_USER, LOCATION;

 

Step 5 — Optional: Clean Up Before Re-running

If you need to re-run the inventory for the same user (e.g., after authority changes), delete the existing rows first to avoid primary key constraint violations:

SQL — Step 5: Clean Up
-- ============================================================
--  category:    IBM i Services - Security
--  description: Step 5 - Remove prior inventory rows before re-run
--  minvrm:      v7r3m0
-- ============================================================

DELETE FROM SECAUDIT.LIB_AUTH_INVENTORY
WHERE TARGET_USER = 'HUGO';

DELETE FROM SECAUDIT.IFS_AUTH_INVENTORY
WHERE TARGET_USER = 'HUGO';

 

Key IBM i Services Used

ServiceTypeDescription
QSYS2.OBJECT_STATISTICS()Table FunctionEnumerates all objects in a library with ownership and AUTL info
QSYS2.OBJECT_PRIVILEGESViewObject-level authority entries (private + *PUBLIC) for library objects and authorization lists
QSYS2.IFS_OBJECT_STATISTICS()Table FunctionEnumerates IFS objects under a directory path
QSYS2.IFS_OBJECT_PRIVILEGESViewIFS object-level authority entries
QSYS2.USER_INFOViewUser profile attributes including SPECIAL_AUTHORITIES, GROUP_PROFILE_NAME, SUPPLEMENTAL_GROUP_LIST
XMLTABLE / tokenize()XQuerySplits the supplemental group list string into individual rows — PTF-level independent, works on all V7R3+

 

Authority Source Values in the Output Tables

The AUTH_SOURCE column in both output tables will contain one of these exact values:

AUTH_SOURCE value

Meaning

Priority 1 - User *ALLOBJ special authorityUser profile has *ALLOBJ; all objects are fully accessible
Priority 2 - User private authorityExplicit private authority entry granted directly to the user
Priority 3 - User authority via authorization listUser has a private entry in the *AUTL securing this object
Priority 4 - Group *ALLOBJ special authorityA group the user belongs to has *ALLOBJ
Priority 5 - Group private authorityA group the user belongs to has a private authority entry on the object
Priority 6 - Group authority via authorization listA group the user belongs to has a private entry in the *AUTL securing this object
Priority 7 - *PUBLIC authorityNo specific authority found; effective authority comes from *PUBLIC

 

Execution Order Summary

Run the steps in this order against your IBM i system using IBM Access Client Solutions (ACS) Run SQL Scripts:

  1. Run Step 1 — Create SECAUDIT schema and both output tables (DDL, run once)
  2. Run Step 2 — Library object inventory INSERT (replace MYLIB / HUGO)
  3. Run Step 3 — IFS object inventory INSERT (replace /home/mydir / HUGO)
  4. Run Step 4 — Review results (queries 4a–4e as needed)
  5. Run Step 5 — Optional cleanup before re-run

 

Notes and Limitations

  • Supplemental groups are stored in QSYS2.USER_INFO.SUPPLEMENTAL_GROUP_LIST as a space-delimited string. XMLTABLE with the XQuery tokenize() function splits the list into individual rows — this approach is PTF-level independent and works on all V7R3+ systems. If your list uses a comma delimiter instead of a space, change the " " in tokenize($s, " ") to ",".
  • Authorization list detection: QSYS2.OBJECT_STATISTICS does not expose the authorization list name directly. The obj_list CTE identifies the *AUTL by LEFT JOINing QSYS2.OBJECT_PRIVILEGES for the row where USER_NAME = '*PUBLIC' and OBJECT_AUTHORITY = '*AUTL' — when such a row exists, AUTHORIZATION_LIST holds the authorization list name securing the object.
  • Group authority tie-breaking (Priorities 5 & 6): When multiple group profiles have authority, the ROW_NUMBER() window function selects the most permissive group authority (*ALL > *CHANGE > *USE > *EXCLUDE). This mirrors IBM i runtime behavior, which grants access if any group provides sufficient authority.
  • IFS SUBTREE_DIRECTORIES => 'YES': This setting causes IFS_OBJECT_STATISTICS to recurse into subdirectories. Set to 'NO' if you want a flat (single-level) scan only.
  • Performance: For large libraries or deep IFS trees, consider adding WITH UR to SELECT portions inside the CTEs where read-isolation is acceptable. Filtering by object type (e.g., *FILE, *PGM) can significantly reduce runtime.
  • Re-running: Always run Step 5 (DELETE) before Step 2/3 to avoid primary key constraint violations.
  • The SQL scripts must be executed using IBM Access Client Solutions (ACS) – Run SQL Scripts. Running the script from other SQL interfaces or tools may result in unexpected behavior, syntax errors, or incomplete execution. Before running the script, ensure you are connected to the correct IBM i system and that all required substitutions (such as library names and user profiles) have been made throughout the entire script.

References

Document maintained by the IBM i Security Practice. Always validate SQL in a development partition before executing against production.
Made with IBM Bob

Document Location

Worldwide

[{"Type":"MASTER","Line of Business":{"code":"LOB68","label":"Power HW"},"Business Unit":{"code":"BU070","label":"IBM Infrastructure"},"Product":{"code":"SWG60","label":"IBM i"},"ARM Category":[{"code":"a8m0z0000000CHyAAM","label":"Security"}],"ARM Case Number":"","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"and future releases;7.3.0;7.4.0;7.5.0;7.6.0"}]

Document Information

Modified date:
13 July 2026

UID

ibm17279605