IBM Support

Listing All Server Authentication Entries on a System

Troubleshooting


Problem

The DSPSVRAUTE command shows the server authentication entry for only one user. This document lists two options to display all server authentication entries on the system.

Resolving The Problem

The DSPSVRAUTE command displays server authentication entries for only one user at a time.

Sometimes an administrator may wish to review DDM security for all users on the system. For example, an administrator may wish to know which users on SERVERA have stored credentials for DDM access to SERVERB. Having only the DSPSVRAUTE command to list one user at a time can be tedious.

New in V7R1 and V7R2 (as of April 2015) is view: QSYS2.DRDA_AUTHENTICATION_ENTRY_INFO .
Ensure the job issuing SELECT statements against DRDA_AUTHENTICATION_ENTRY_INFO has a valid CCSID set. CCSID 65535 will result in unreadable characters.

See the following URL for complete details regarding DRDA_AUTHENTICATION_ENTRY_INFO:
http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzajq/rzajqviewdrdaauthinfo.htm?lang=en-us

An alternate option for older systems is to use the following source code to create a program to list all the server authorization entries on the system. The results are listed in a QPRINT spooled file.

The system value QRETSVRSEC is listed at the top of the spooled file. This system value determines whether to retain server security data when executing the ADDSVRAUTE command. A value of 0 indicates no security data will be retained.

If your password is not stored and the target system requires a password, an authorization failure on attempt to connect is issued resulting in message CPF9190.

When the program is called interactively, the screen shows the progress of how many hundreds of users have been processed. There is an optional parameter to provide a server name. The parameter is not case-sensitive.

Following are some examples of calling the program using the optional Server parameter:

CALL LISTAUTE QDDMSERVER
CALL LISTAUTE myserver

Caution: This code is not supported by IBM. It is provided AS IS. The code is written in C.


/******************************************************************************/
/* LICENSE AND DISCLAIMER:                                                    */
/*                                                                            */
/* This material contains IBM copyrighted sample programming source code for  */
/* your consideration. This sample code has not been thoroughly tested under  */
/* all conditions. IBM, therefore, cannot guarantee or imply reliability,     */
/* serviceability, or function.  IBM provides no program services for this    */
/* material. This material is provided "AS IS" WITHOUT WARRANTY OF ANY KIND,  */
/* EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED      */
/* WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SOME  */
/* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE     */
/* ABOVE EXCLUSIONS MAY NOT APPLY TO YOU. IN NO EVENT WILL IBM BE LIABLE TO   */
/* ANY PARTY FOR ANY DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES */
/* FOR ANY USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST       */
/* PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON YOUR     */
/* INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN IF EXPRESSLY ADVISED OF THE */
/* POSSIBILITY OF SUCH DAMAGES.                                               */
/*                                                                            */
/* COPYRIGHT                                                                  */
/* ---------                                                                  */
/* (C) Copyright IBM CORP. 2006, 2006                                         */
/* All rights reserved.                                                       */
/* US Government Users Restricted Rights -                                    */
/* Use, duplication or disclosure restricted                                  */
/* by GSA ADP Schedule Contract with IBM Corp.                                */
/* Licensed Material - Property of IBM                                        */
/******************************************************************************/
/* ListFunct                                                                  */
/* Author:  Shane Smith (shanes1@us.ibm.com)                                  */
/* Version: 1.0                                                               */
/* This program is designed to call the server authentication entry APIs to   */
/* generate a report of all user profiles and their associated entries.       */
/*                                                                            */
/* APIs Used:                                                                 */
/*    QsyRetrieveServerEntries                                                */
/*    QGYOLAUS                                                                */
/*    QWCRSVAL                                                                */
/******************************************************************************/
#include <QSYSINC/H/QWCRSVAL>   /* Retrieve system value API                  */
#include <QSYSINC/H/QGYOLAUS>   /* Open list of authorized users API          */
#include <QSYSINC/H/QSYSVRFN>   /* Server Authentication Entry APIs           */
#include <QSYSINC/H/QUSEC>      /* Standard error code structures             */
#include <QSYSINC/H/STDIO>      /* fprintf()                                  */
#include <QSYSINC/H/STRING>     /* memset()                                   */
#include <QSYSINC/H/CTYPE>      /* toupper()                                  */

/******************************************************************************/
/* Miscellaneous definitions                                                  */
/******************************************************************************/
#define UID_LEN      10
#define SVR_LEN      200
#define BUFFER_SIZE  512000
#define SMALL_BUFFER 1024
#define RCVR_FORMAT  "SVRE0100"
#define USER_FORMAT  "AUTU0100"
#define SVR_NAME     "*FIRST"
#define SVR_OPT      '1'
#define LINE_FOOTER  "------------"
#define LINE_SYSVAL  "SYSTEM VALUE QRETSVRSEC:    "
#define LINE_UID     "USER PROFILE:               "
#define LINE_SVR     " |---> SERVER/RDB NAME:     "
#define LINE_SID     "     |---> USER FOR SERVER: "
#define LINE_SID2    " |   |---> USER FOR SERVER: "
#define LINE_PWD     "     |---> PASSWORD STORED: "
#define LINE_PWD2    " |   |---> PASSWORD STORED: "
#define LINE_DIV     " |"
#define PWD_YES      '1'
#define PWD_NO       '0'
#define SYS_VAL_0    "Do not retain the security-related information"
#define SYS_VAL_1    "Retain the security-related information"

/******************************************************************************/
/* Static variables                                                           */
/******************************************************************************/
static char* cmd_ = "OVRPRTF FILE(QPRINT) TOFILE(*FILE) USRDTA('SVRENTRIES')";
static char* server_;
static int   serverlen_ = 0;
static FILE* qprint_ = 0;

/******************************************************************************/
/* Function Prototypes                                                        */
/******************************************************************************/
void closeSpoolFile();
int  compareServerName(char* server);
void openSpoolFile();
void processAllUsers();
int  processReceiver(char* rcvr, char* user, int current, int last);
void processUser(char* user);
void retrieveSystemValue();

/******************************************************************************/
/* Main method.                                                               */
/* Launches the program, looks up each user profile, and checks for           */
/* authorization entries for each user.                                       */
/* Usage:                                                                     */
/*    CALL LISTAUTE                                                           */
/*     -> List all users that have authorization entries defined.             */
/*    CALL LISTAUTE PARM('server')                                            */
/*     -> List all users that have an authorization entry for the given server*/
/******************************************************************************/
void main(int argc, char *argv[]) {
   openSpoolFile();                  /* Attempt to open the QPRINT spool     */
   if(qprint_ == 0) {                /* If pointer still null, bail out      */
       printf("Unable to open spool file.  Exiting...");
       return;
   }
   if(argc >= 2) {
       server_ = argv[1];
       serverlen_ = strlen(server_);
   }

   retrieveSystemValue();
   processAllUsers();
   closeSpoolFile();
}

/******************************************************************************/
/* closeSpoolFile                                                             */
/* Close the spool file out.                                                  */
/******************************************************************************/
void closeSpoolFile() {
   fclose(qprint_);
}

/******************************************************************************/
/* compareServerName                                                          */
/* Checks to see if the server name passed in is a match (case-insensitive)   */
/* to the name provided on program call.                                      */
/* @param char* Pointer to server name to compare.                            */
/* @return int Value of 1 if a match, else 0.                                 */
/******************************************************************************/
int compareServerName(char* server) {
   int len, i;
   len = serverlen_;
   if(strlen(server)!=serverlen_) return 0; /* Length mismatch, not a match  */
   for(i=0; i<serverlen_; i++)
       if(toupper((int)(*(server+i)))!=toupper((int)(*(server_+i))))
           return 0;                        /* Any mismatch, not a match.    */
   return 1;                                /* Made it this far, must match. */
}

/******************************************************************************/
/* openSpoolFile                                                              */
/* Open spool file for writing.  Also overrides QPRINT so that user data      */
/* shows Ap Admin.                                                            */
/******************************************************************************/
void openSpoolFile() {
   system(cmd_);
   qprint_ = fopen("QGPL/QPRINT", "w");
}

/******************************************************************************/
/* processAllUsers                                                            */
/* This method will obtain a list of all the users on the system.  The buffer */
/* size means that max processed would be about 42K users.  For each user in  */
/* the list the processUser method will be called.                            */
/******************************************************************************/
void processAllUsers() {
   char rcvr[BUFFER_SIZE];           /* Receiver variable for user profiles  */
   char uid[UID_LEN+1];              /* Used to store the UID for processUser*/
   int  size;                        /* Size of receiver variable            */
   int  numToReturn;                 /* Number of users to return            */
   int  avail;                       /* Number of users returned             */
   int  i, j, offset;                /* Used in loops.                       */
   Qgy_List_Info_T info;             /* Output list information              */
   Qus_EC_t errio;                   /* Error structure                      */

   memset(uid, '\0', sizeof(uid));   /* Want a null terminated string.       */
   size = sizeof(rcvr);              /* Save off size, API requires pointer  */
   numToReturn = -1;                 /* All users, synchronously             */
   errio.Bytes_Provided = sizeof(errio);    /* Set up the error structure    */

   QGYOLAUS((void*)rcvr,             /* Call the API to get a list of users  */
            &size,                   /* Pointer to size of the receiver      */
            &info,                   /* List information pointer             */
            &numToReturn,            /* Number of users to return            */
            USER_FORMAT,             /* Format of user records               */
            "*ALL      ",            /* Want all user profiles returned      */
            "*NONE     ",            /* Don't want to filter by group profile*/
            (void*)&errio);          /* Pointer to error structure           */

   avail = *((int*)(((char*)&info)+4)); /* Cast ouptut to char*, pointer math*/
                                        /* ,then dereference                 */

   /**************************************************************************/
   /* FORMAT OF RECEIVER VARIABLE (REPEATS FOR EACH USER)                    */
   /* OFFSET  SIZE    DESCRIPTION                                            */
   /* ------  ------  ------------------------------------------------------ */
   /*      0      10  Profile Name                                           */
   /*     10       1  User or group indicator.                               */
   /*     11       1  Group members indicator.                               */
   /**************************************************************************/
   offset = 0;                       /* Initialize offset into the receiver  */
   for(i=0; i<avail; i++) {          /* Loop through available user profiles */
       if(i%100==0) printf("Processed %d users...\n", i);
       for(j=0; j<UID_LEN; j++) uid[j]= *(rcvr+offset+j);
       processUser(uid);
       offset += 12;                 /* Size of the format is 12 bytes       */
   }
}

/******************************************************************************/
/* processReceiver                                                            */
/* Process the server authorization entries returned from a call to the       */
/* QsyRetrieveServerEntries API.                                              */
/* @param char* Pointer to the receiver variable from the API call.           */
/* @param char* Pointer to the user ID the receiver variable is for.          */
/* @param int Number of the current authorization entry for this user.        */
/* @param int Number of the last authorization entry for this user.           */
/* @return int Number of bytes used from the receiver.                        */
/******************************************************************************/
int processReceiver(char* rcvr, char* user, int current, int last) {
   /**************************************************************************/
   /* FORMAT OF RECEIVER VARIABLE                                            */
   /* OFFSET  SIZE    DESCRIPTION                                            */
   /* ------  ------  ------------------------------------------------------ */
   /*      0       4  Length of entry                                        */
   /*      4       4  Length of server name                                  */
   /*      8       4  CCSID of server name                                   */
   /*     12     200  Server name                                            */
   /*    212       4  Displacement to user ID                                */
   /*    216       4  Length of user ID                                      */
   /*    220       4  CCSID of user ID                                       */
   /*    224       1  Password stored indicator                              */
   /*      *       *  User ID                                                */
   /**************************************************************************/
   char server[SVR_LEN+1];
   char sid[UID_LEN+1];                   /* SID = server user id            */
   int  len, i, disp;

   memset(server, '\0', sizeof(server));  /* Initialize server name to nulls */
   len = *((int*)(rcvr+4));               /* Save off the server name length */
   if(len>SVR_LEN) len = SVR_LEN;         /* Safety check                    */
   for(i=0; i<len; i++) server[i] = *(rcvr+12+i); /* Copy the server name    */

   if(serverlen_==0) {                    /* If not filtered for one server  */
       /* Print the user for the first entry.                                */
       if(current==1) fprintf(qprint_, "%s%s\n", LINE_UID, user);
       /* Print a divider if more than one server.                           */
       if(current > 1) fprintf(qprint_, "%s\n", LINE_DIV);    
       fprintf(qprint_, "%s%s\n", LINE_SVR, server);  /* Print name to file  */
       memset(sid, '\0', sizeof(sid));        /* Initialize UID to nulls     */
       len = *((int*)(rcvr+216));             /* Save off UID length         */
       if(len>UID_LEN) len = UID_LEN;         /* Safety check.               */
       disp = *((int*)(rcvr+212));            /* Save off displacement to UID*/
       for(i=0; i<len; i++) sid[i] = *(rcvr+disp+i);  /* Copy the UID        */

       /* Print the user ID to file.                                         */
       if(current < last) fprintf(qprint_, "%s%s\n", LINE_SID2, sid);
       else               fprintf(qprint_, "%s%s\n", LINE_SID, sid);

       /* Print password stored status to file.                              */
       if(current < last) fprintf(qprint_, "%s", LINE_PWD2);
       else               fprintf(qprint_, "%s", LINE_PWD);
       if((*(rcvr+224))==PWD_YES)     fprintf(qprint_, "%s\n", "YES");
       else if((*(rcvr+224))==PWD_NO) fprintf(qprint_, "%s\n", "NO");
       else                           fprintf(qprint_, "%s\n", "UNKNOWN");
       if(current==last) fprintf(qprint_, "%s\n", LINE_FOOTER);
   } else {
       /* Check to see if the authorization entry is for the filtered server */
       if(compareServerName(server) > 0)
       {
           fprintf(qprint_, "%s%s\n", LINE_UID, user);   /* Log the UID      */
           fprintf(qprint_, "%s%s\n", LINE_SVR, server); /* Log the SERVER   */
       
           memset(sid, '\0', sizeof(sid));  /* Initialize server UID to null */
           len = *((int*)(rcvr+216));       /* Save off UID length.          */
           if(len>UID_LEN) len = UID_LEN;   /* Safety check                  */
           disp = *((int*)(rcvr+212));      /* Save offset to UID            */
           for(i=0; i<len; i++) sid[i] = *(rcvr+disp+i); /* Copy server UID  */
           fprintf(qprint_, "%s%s\n", LINE_SID, sid);    /* Print server UID */
           fprintf(qprint_, "%s", LINE_PWD);             /* Print PWD status */
           if((*(rcvr+224))==PWD_YES)     fprintf(qprint_, "%s\n", "YES");
           else if((*(rcvr+224))==PWD_NO) fprintf(qprint_, "%s\n", "NO");
           else                           fprintf(qprint_, "%s\n", "UNKNOWN");
           fprintf(qprint_, "%s\n", LINE_FOOTER);
       }
   }    
   return *((int*)rcvr);
}

/******************************************************************************/
/* processUser                                                                */
/* This method will retrieve server authorization entries for a single user   */
/* profile on the system.                                                     */
/* @param char* Pointer to the user profile to look up entries for.  Must be  */
/*              null terminated.                                              */
/******************************************************************************/
void processUser(char* user) {
   int  len;                         /* Length of the UID passed in.         */
   int  i, last;                     /* Used in loops                        */
   int  offset;                      /* Used in loop of server entries       */
   char uid[UID_LEN];                /* Char array for the API               */
   char rcvr[BUFFER_SIZE];           /* Receiver variable for aut entries    */
   Qsy_RSVRE_Feedback_Info_T fdbk;   /* Feedback information from API call   */
   Qus_EC_t errio;                   /* Error structure                      */

   len = strlen(user);               /* Determine the length of UID provided */
   if(len > UID_LEN) len = UID_LEN;  /* Safety check.                        */
   memset(rcvr, '\0', sizeof(rcvr)); /* Initialize the receiver variable.    */
   memset(uid, ' ', sizeof(uid));    /* Initialize user array to blanks.     */
   errio.Bytes_Provided = sizeof(errio);    /* Set up the error structure    */
   for(i=0; i<len; i++) uid[i] = *(user+i); /* Copy parm to the array.       */

   QsyRetrieveServerEntries((void*)rcvr,    /* Call the API to list entries  */
                            sizeof(rcvr),   /* Length of receiver variable   */
                            &fdbk,          /* Feedback structure            */
                            RCVR_FORMAT,    /* Format expected in rcvr       */
                            SVR_NAME,       /* Name to start with            */
                            strlen(SVR_NAME), /* Length of the server name   */
                            SVR_OPT,        /* Option for returning entries  */
                            uid,            /* UID to list entries for.      */
                            (void*)&errio); /* Error code structure          */

   if(fdbk.Server_Auth_Number <= 0) return; /* Don't log UID's without AUTE  */
   last = fdbk.Server_Auth_Number;          /* Save off the Server #         */
   offset = 0;                              /* Initialize offset to 0.       */

   for(i=0; i<last; i++)             /* For each entry, process and increment*/
       offset += processReceiver(rcvr+offset, user, i+1, last);
}

/******************************************************************************/
/* retrieveSystemValue                                                        */
/* Looks up the value of the QRETSVRSEC system value and log to the spool file*/
/******************************************************************************/
void retrieveSystemValue() {
   char rcvr[SMALL_BUFFER];       /* Receiver variable for system value info */
   char* sysval = "QRETSVRSEC";   /* Only going after one system value       */
   int offset;                    /* Offset to the system value table        */
   int avail;                     /* Number of system values returned        */
   int qretsvrsec;                /* Where the value will be stored.         */
   Qus_EC_t errio;                /* Error structure                         */

   errio.Bytes_Provided = sizeof(errio);
   QWCRSVAL((void*)rcvr,          /* Call API to get the system value.       */
            sizeof(rcvr),         /* Bytes available in receiver             */
            1,                    /* Retrieving one system value             */
            (void*)sysval,        /* System value to retrieve.               */
            (void*)&errio);       /* Error code structure                    */

   /**************************************************************************/
   /* FORMAT OF RECEIVER VARIABLE                                            */
   /* OFFSET  SIZE    DESCRIPTION                                            */
   /* ------  ------  ------------------------------------------------------ */
   /*      0       4  Number of system values returned                       */
   /*      4       *  Array of BIN(4)                                        */
   /*      *       *  System value information tables                        */
   /**************************************************************************/
   avail = *((int*)rcvr);         /* Get the number of system values returned*/
   if(avail < 1) return;          /* Something went wrong, stop here.        */
   offset = *((int*)(rcvr+4));    /* Get offset to first system value table. */

   /**************************************************************************/
   /* FORMAT OF SYSTEM VALUE TABLE                                           */
   /* OFFSET  SIZE    DESCRIPTION                                            */
   /* ------  ------  ------------------------------------------------------ */
   /*      0      10  System value name                                      */
   /*     10       1  Type of data                                           */
   /*     11       1  Information status ('L'==locked)                       */
   /*     12       4  Length of data                                         */
   /*     16       *  Data (for QRETSVRSEC it is CHAR(1))                    */
   /**************************************************************************/
   if(*(rcvr+offset+11)!=' ') return; /* Blank means data was available      */
   fprintf(qprint_, "%s%c ---> ", LINE_SYSVAL, *(rcvr+offset+16));
   switch(*(rcvr+offset+16)) {
   case '0': fprintf(qprint_, "%s\n", SYS_VAL_0); break;
   case '1': fprintf(qprint_, "%s\n", SYS_VAL_1); break;
   default:  fprintf(qprint_, "%s\n", "UNKNOWN VALUE"); break;
   }
   fprintf(qprint_, "%s\n", LINE_FOOTER);
}

[{"Product":{"code":"SWG60","label":"IBM i"},"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Component":"Data Access","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"Version Independent","Edition":"","Line of Business":{"code":"LOB57","label":"Power"}}]

Historical Number

431662501

Document Information

Modified date:
18 December 2019

UID

nas8N1014688