Document revision date: 30 March 2001

## OpenVMS Utility Routines Manual

Previous | Contents | Index

## Chapter 13
LOGINOUT (LGI) Routines

The information in this chapter is intended for programmers implementing the requirements of site security administrators or third-party security software producers.

This chapter differs from other parts of this book because it does not deal strictly with callable routines that are internal to the OpenVMS system. The LOGINOUT callout routines are designed by site security administrators. The callback routines are invoked by the callout routines.

## 13.1 Introduction to LOGINOUT

The OpenVMS login security program (LOGINOUT.EXE) supports calls to site-specific routines (LOGINOUT callout routines). These callout routines support custom login security programs such as smart card programs, pocket authenticator programs, and other alternative identification and authentication programs. The callout routines permit sites to combine portions of the LOGINOUT security policy functions with site login security functions to establish a customized login security environment.

### 13.1.1 The LOGINOUT Process

The site security administrator provides LOGINOUT with the following:

- One or more shareable images comprised of modules that include callout routines
- A list of the shareable images

As login events occur, LOGINOUT invokes the applicable callout, thus enabling the site to replace or augment each event using site-specific modifications.

The site may provide multiple callout images. The images are invoked in the order in which they are declared to the system. Each image contains an independently developed set of policy routines.

Each callout routine may do one of the following:

- Enforce site-specific policy functions
- Defer to subsequent routines
- Use elements of the standard OpenVMS policy functions

Each callout routine may access LOGINOUT's internal state and callback routines using a vector of entry points. The callback routines allow the callout routines to communicate with the user and to incorporate elements of the standard OpenVMS policy functions in a modular fashion.

### 13.1.2 Using LOGINOUT with External Authentication

The following sections describe LOGINOUT's interaction with the external authentication policy supported by OpenVMS. For more information about single sign-on and user authentication, see the OpenVMS Guide to System Security.

Note The use of LOGINOUT callouts disables external authentication, making only the standard OpenVMS authentication policy available.

Overview of External Authentication

At sites using external authentication, all authentication decisions for users are actually made by the LAN manager rather than OpenVMS; however, OpenVMS account restrictions and quota checks remain in effect.

To access the system, users must provide their LAN manager user ID and password at the login prompt. If local password synchronization is required, one of the following messages is displayed indicating the outcome of the synchronization attempt:

    OpenVMS password has been synchronized with network password

    Not able to synchronize OpenVMS password with network password

These messages can be suppressed on a per-user basis by setting the DISREPORT flag.

Specifying Local Authentication

The login command line supports the /LOCAL_PASSWORD qualifier. This qualifier indicates to LOGINOUT that the user intends to override external authentication by using their OpenVMS user name and password. This is considered a temporary means for logging in to the system when the external authentication service is unavailable. To use this qualifier, you must have SYSPRV privilege.

When a user has logged in locally, the following message is displayed:

    Local logon successful; network logon service not used

Locally authenticated users are not subject to OpenVMS password policy, since the system manager specified that these users are subject to external authentication policy only.

### 13.1.3 The LOGINOUT Data Flow

Figure 13-1 provides an overview of the data flow between LOGINOUT, the callout routines, and site-specific shareable images that can include one or more callout modules.

Figure 13-1 LOGINOUT Callout Routines Data Flow

## 13.2 LOGINOUT Callouts

This section introduces the callouts that LOGINOUT uses to interface with the site-specific callout modules in the shareable images. The section also describes a set of callback routines that the callout routines can use to invoke services provided within LOGINOUT.

### 13.2.1 LOGINOUT Callout Routines

LOGINOUT calls a different site-provided callout routine at each important step in its execution. Table 13-1 briefly describes the LOGINOUT callouts. See Section 13.4 for detailed descriptions of these routines.

Table 13-1 LOGINOUT Callouts
Callout | Description
--- | ---
LGI$ICR_AUTHENTICATE | Authenticates the user account at login
LGI$ICR_CHKRESTRICT | Checks additional security restrictions
LGI$ICR_DECWINIT | Prepares for interactive contact with DECwindows users
LGI$ICR_FINISH | Gives site-specific code final control of the login process
LGI$ICR_IACT_START | Prepares for interactive contact with users who are not using the DECwindows interface
LGI$ICR_IDENTIFY | Identifies the user at login
LGI$ICR_INIT | Initializes context variable
LGI$ICR_JOBSTEP | Indicates the start of each step in a batch job
LGI$ICR_LOGOUT | Prepares for logout

### 13.2.2 LOGINOUT Callback Routines

The callback routines enable the site's callout routines to communicate interactively with the user or to invoke other services provided by LOGINOUT. Table 13-2 briefly describes the LOGINOUT callback routines. See Section 13.5 for detailed descriptions of these routines.

Table 13-2 LOGINOUT Callback Routines
Routine | Description
--- | ---
LGI$ICB_ACCTEXPIRED | Checks for account expiration
LGI$ICB_AUTOLOGIN | Verifies that standard rules for autologin apply
LGI$ICB_CHECK_PASS | Checks the entered password against the user authorization file (UAF) record
LGI$ICB_DISUSER | Checks for DISUSER flag
LGI$ICB_GET_INPUT | Enables interaction with the user
LGI$ICB_GET_SYSPWD | Checks system password for character-cell interactive logins
LGI$ICB_MODALHOURS | Checks for restrictions on access modes and access hours
LGI$ICB_PASSWORD | Generates prompts, reads input, and optionally validates input against system user authorization file (SYSUAF.DAT)
LGI$ICB_PWDEXPIRED | Checks for password expiration
LGI$ICB_USERPROMPT | Prompts for and reads input for character-cell interactive logins
LGI$ICB_USERPARSE | Parses input buffer data for character-cell interactive logins
LGI$ICB_VALIDATE | Validates the user name and password against the system user authorization file (SYSUAF.DAT)

## 13.3 Using Callout Routines

This section describes:

- The calling environment
- The callout routines and how they are organized and activated
- The callout routines interface

Section 13.3.5 contains a sample LOGINOUT program.

### 13.3.1 Calling Environment

The general form for invoking the callout routines is as follows:

`return-status = routine (standard_arguments_vector, context, routine_specific_args)`

The call elements include the following:

- Standard argument vector: contains pointers to LOGINOUT data structures and callback routines for communicating with the user
- Context: a longword that the site-specific program may use to store a pointer to local context
- Routine-specific arguments: arguments directly related to the specific routine

The callout routine's return status must be one of the following:

Return Status | Interpretation
--- | ---
SS$_NORMAL | Access permitted; continue policy checks. Execute next policy image or OpenVMS policy function associated with this callout, if applicable.
LGI$_SKIPRELATED | Access permitted; discontinue checks. Continue with the login without further processing of login policy functions associated with this callout, including relevant OpenVMS policy functions built into LOGINOUT.
Other | Disallow the login: Perform break-in detection and intrusion evasion, if appropriate. Perform security audit. Allow additional login attempts up to system-specified repeat limit, if appropriate.

Note When a fatal error occurs, the policy module may terminate the login by signaling a severe error using the BLISS built-in SIGNAL_STOP or by calling LIB$SIGNAL. (See the OpenVMS RTL Library (LIB$) Manual for a description of the LIB$SIGNAL routine.) LOGINOUT will do a security audit, but it will not perform break-in detection or intrusion evasion. Avoid using a severe error termination unless the LOGINOUT process state is in jeopardy. LOGINOUT should terminate with a clean exit and a disallowed login whenever possible.

### 13.3.2 Callout Organization

A site may use several callout modules. For example, assume that the site is working with another program that uses logins or the site involves logins for various devices or logins at various security levels.

LOGINOUT invokes the callout routines using a vector of entry points rather than the routine name. Each vector entry point corresponds to a policy function, and the first vector entry contains a count of the entry points in the vector, thus making the vector extendable. Figure 13-2 shows how a callout routine vector is organized.

Figure 13-2 Callout Organization

Note that entry points may be accessed randomly. When a site-provided callout module does not provide a routine for a particular callout, the site must enter a 0 value as a placeholder into the corresponding vector location.

Callout modules may modify the vector during execution so that following events invoke different routines. For example, one of the initialization callout routines could modify the vector in anticipation of a following call to a different terminal or different job type, or it might zero the number of entry points to disable further calls to callout routines contained in the current callout module.

### 13.3.3 Activating the Callout Routines

A site activates the LOGINOUT callouts by identifying its callout images using the system executive-mode logical name LGI$LOGINOUT_CALLOUTS. The logical name may contain one value or a list of values that identify the callout images using either the:

- File name of a module located in SYS$SHARE:*.EXE
- Name of an executive-mode system logical name representing a full file specification

Note LOGINOUT is installed with privileges. Therefore, any image containing LOGINOUT callout routines must be installed.

If the identifying logical is a list of several images, the images are sequentially activated in the listed order. If a specified image is not activated, the login fails.

To protect against intrusion, the site uses the system parameter LGI_CALLOUTS to specify the number of callout images. If this value is nonzero and the supplied number of callout images does not correspond to the value, the login fails.

Sites that want to control their job creation process and authenticate each network login by implementing LOGINOUT callouts must set the NET_CALLOUTS system parameter to 255. This ensures that LOGINOUT is called for every network login --- bypassing any existing server processes.

The default value of NET_CALLOUTS (0) could bypass the LOGINOUT callouts and allow NET$ACP to perform its own proxy and login authentication. See the file SYS$SYSTEM:NETSERVER.COM for an example of how NET$ACP performs its own authentication and management of server processes.

Parameter values 1 to 254 are reserved by Compaq for future use.

Note Callouts are not invoked when LOGINOUT initiates the STARTUP process during system bootstrap. For the logical name LGI$LOGINOUT_CALLOUTS, a clusterwide logical name cannot be used. The number of names in the system logical name LGI$LOGINOUT_CALLOUTS must always match the value of the system parameter LGI_CALLOUTS. LGI$LOGINOUT_CALLOUTS must be in the regular system logical name table and not in a clusterwide logical name table. When applications that support LGI_CALLOUTS are starting and stopping, they manipulate LGI$LOGINOUT_CALLOUTS as well as LGI_CALLOUTS. A clusterwide logical name would be incorrect since not all nodes in a cluster would have the same LGI_CALLOUTS at the same time. Nodes where the values did not match would experience login and logout failures.

### 13.3.4 Callout Interface

Each image containing LOGINOUT callouts must define a universal symbol LGI$LOGINOUT_CALLOUTS. This symbol represents a vector of longwords that points to the entry points for the various callout routines, as shown in the following illustration:

The vector is headed by a longword count that delimits the number of callout routines supported by the callout module. Unused vector entries are identified by a 0 value.

Each callout routine has access to a vector of LOGINOUT internal variables, including the addresses of callback routines and other useful information. The vector entries are defined as offsets from the beginning of the vector. The vector has the following format:

Symbols of the form LGI$ICB_x are the addresses of the callback routines that the callout routines use to communicate with the user (see Table 13-2). Other offsets are addresses of useful variable information internal to LOGINOUT. These are described in Table 13-3.

Table 13-3 Useful LOGINOUT Internal Variables
Symbols | Definition
--- | ---
LGI$A_ICR_CREPRC_FLAGS | PPD_CREPRC_FLAGS controls program flow based on the major job types of PRC$V_BATCH, PRC$V_NETWRK, PRC$V_INTER, and other values such as PRC$V_NOPASSWORD (used for interactive jobs created on logged-in terminals).
LGI$A_ICR_JOB_TYPE | The job type from the JIB (byte). LOGINOUT does the following: Retrieves the job type with a GETJPI during initialization. Modifies it during execution. (Its value may change between the LGI$ICR_INIT and later callouts.) Writes it back into the JIB before exiting. For interactive jobs, this flag indicates JIB$C_LOCAL, JIB$C_REMOTE, or JIB$C_DIALUP.
LGI$A_ICR_SUBPROCESS | The subprocess flag (byte) indicates whether a subprocess is being logged in.
LGI$A_ICR_TERMINAL_DEV | The terminal device flag (byte).
LGI$A_ICR_TT_PHYDEVNAM | A descriptor containing the terminal's physical device name (null if input is not from a terminal).
LGI$A_ICR_TT_ACCPORNAM | A descriptor containing the terminal's access port name (null if input is not from a terminal or is from a terminal without an associated access port).
LGI$A_ICR_CLINAME | A descriptor containing the command language interpreter (CLI) name, parsed from the user name qualifiers. Valid only for interactive jobs.
LGI$A_ICR_CLITABLES | A descriptor containing the CLI tables, parsed from the user name qualifiers. Valid only for interactive jobs.
LGI$A_ICR_NCB | A descriptor containing the network control block. Valid only for network jobs.
LGI$A_ICR_LOGLINK | A longword containing the local link number. Valid only for network jobs and when doing a SET HOST command from a DECnet-Plus remote terminal.
LGI$A_ICR_REM_NODE_NAM | A descriptor containing the remote node name or a printable representation of its node number if the name is not available. Valid only for network jobs and when doing a SET HOST command from a DECnet-Plus remote terminal.
LGI$A_ICR_REM_ID | A descriptor containing the remote ID. This may be the user ID on the remote system if the source operating system sends the user name. Otherwise, it is as defined for the source system. Valid only for network jobs and when doing a SET HOST command from a DECnet-Plus remote terminal.
LGI$A_ICR_UAF_RECORD | Address of the LOGINOUT internal variable containing the address of the user authorization file (UAF) record. Note that because the record will be written back to the UAF record, callout routines must not modify the contents of the UAF record.
LGI$A_ICR_INPUT_RAB | A RAB (record access block) that may be used to communicate with an interactive user.
LGI$A_ICR_AUTOLOGIN | A flag (byte) indicating whether an autologin is being used for this interactive job.
LGI$A_ICR_USERNAME | A descriptor for handling the user name.
LGI$A_ICR_PWD1 | A descriptor for handling the primary password.
LGI$A_ICR_PWD2 | A descriptor for handling the secondary password.
LGI$A_ICR_PWDCOUNT | A longword containing the count of passwords expected for this user. Valid only for interactive jobs.
LGI$A_ICR_NETFLAGS | A flag (word) containing authorization information. Valid only for network jobs. The bits that have been defined are: NET_PROXY: A proxy request. NET_PREAUTH: DECnet-Plus has preauthorized the login. NET_DEFAULT_USER: The session or object database has a default user and no password checking is required. NET_PROXY_OK: The requested proxy has been allowed by either LOGINOUT or the site-provided callout routines.

### 13.3.5 Sample Program

The following C program illustrates the use of LOGINOUT callouts. The sample program changes the user name and password prompts to "Who are you?" and "Prove it." The program also adds the message "Goodbye." at logout.

    #module LGI$CALLOUT_EXAMPLE "TOY LOGINOUT callout example"
    /*
    **++
    **  FACILITY:
    **
    **      System help
    **

    ** This program can be compiled with the following command
    **
    **   $ CC/STANDARD=VAXC/LIST/PREFIX_LIBRARY_ENTRIES=ALL LGI$CALLOUT_EXAMPLE.C
    **
    ** This program can be linked with the following example command procedure
    **
    **    $ LINK/SHARE=LGI$CALLOUT_EXAMPLE SYS$INPUT/OPT
    **    LGI$CALLOUT_EXAMPLE.OBJ

    **    SYMBOL_VECTOR=(LGI$LOGINOUT_CALLOUTS=DATA)
    **
    ** The following steps are used to install the program:
    **
    **    $ DEFINE/SYSTEM/EXEC LGI$LOGINOUT_CALLOUTS LGI$CALLOUT_EXAMPLE
    **
    ** If the program is not located in SYS$SHARE, define it as follows:
    **
    **    $ DEFINE/SYSTEM/EXEC LGI$CALLOUT_EXAMPLE filespec
    **
    ** [Remember that, without SYSNAM privilege, the /EXEC qualifier is ignored.]
    **
    **    $ INSTALL ADD LGI$CALLOUT_EXAMPLE
    **    $ RUN SYS$SYSTEM:SYSGEN
    **    SYSGEN> USE ACTIVE
    **    SYSGEN> SET LGI_CALLOUTS 1
    **    SYSGEN> WRITE ACTIVE
    **
    ** The value of LGI_CALLOUTS is the number of separate callout images
    ** (of which this example is one) that are to be invoked.  If there is
    ** more than one image, the logical LGI$LOGINOUT_CALLOUTS must have a
    ** list of equivalence names, one for each separate callout image.
    **
    */

    /*
    **
    **  INCLUDE FILES
    **
    */

    #include descrip
    #include rms
    #include stsdef
    #include ssdef
    #include prcdef

    /* Declare structures for the callout vector and the callout arguments vector */

    struct LGI$CALLOUT_VECTOR  {
            long int LGI$L_ICR_ENTRY_COUNT;
            int (*LGI$ICR_INIT) ();
            int (*LGI$ICR_IACT_START) ();
            int (*LGI$ICR_DECWINIT) ();
            int (*LGI$ICR_IDENTIFY) ();
            int (*LGI$ICR_AUTHENTICATE) ();
            int (*LGI$ICR_CHKRESTRICT) ();
            int (*LGI$ICR_FINISH) ();
            int (*LGI$ICR_LOGOUT) ();
            int (*LGI$ICR_JOBSTEP) ();
            };

    struct LGI$ARG_VECTOR  {
            int (*LGI$ICB_GET_INPUT) ();

            int (*reserved1) ();
            int (*reserved2) ();
            void (*LGI$ICB_GET_SYSPWD) ();
            int (*LGI$ICB_USERPROMPT) ();
            int (*LGI$ICB_USERPARSE) ();
            int (*LGI$ICB_AUTOLOGIN) ();
            int (*LGI$ICB_PASSWORD) ();
            int (*LGI$ICB_CHECK_PASS) ();
            int (*LGI$ICB_VALIDATE) ();
            void (*LGI$ICB_ACCTEXPIRED) ();
            void (*LGI$ICB_PWDEXPIRED) ();
            int (*LGI$ICB_DISUSER) ();
            void (*LGI$ICB_MODALHOURS) ();
            short *LGI$A_ICR_CREPRC_FLAGS;
            char *LGI$A_ICR_JOB_TYPE;
            char *LGI$A_ICR_SUBPROCESS;
            char *LGI$A_ICR_TERMINAL_DEV;
            struct dsc$descriptor_s *LGI$A_ICR_TT_PHYDEVNAM;
            struct dsc$descriptor_s *LGI$A_ICR_TT_ACCPORNAM;
            struct dsc$descriptor_s *LGI$A_ICR_CLINAME;
            struct dsc$descriptor_s *LGI$A_ICR_CLITABLES;
            struct dsc$descriptor_s *LGI$A_ICR_NCB;
            int *LGI$A_ICR_LOGLINK;
            struct dsc$descriptor_s *LGI$A_ICR_REM_NODE_NAM;
            struct dsc$descriptor_s *LGI$A_ICR_REM_ID;
            unsigned char *LGI$A_ICR_UAF_RECORD;
            struct RAB *LGI$A_ICR_INPUT_RAB;
            char *LGI$A_ICR_AUTOLOGIN;
            struct dsc$descriptor_s *LGI$A_ICR_USERNAME;
            struct dsc$descriptor_s *LGI$A_ICR_PWD1;
            struct dsc$descriptor_s *LGI$A_ICR_PWD2;
            int *LGI$A_ICR_PWDCOUNT;
            short int *LGI$A_ICR_NETFLAGS;
            };

    globalvalue int LGI$_SKIPRELATED,       /* callout's return status */
                    LGI$_DISUSER,
                    LGI$_INVPWD,
                    LGI$_NOSUCHUSER,
                    LGI$_NOTVALID,
                    LGI$_INVINPUT,
                    LGI$_CMDINPUT,
                    LGI$_FILEACC;

    static int callout_logout();
    static int callout_decwinit();
    static int callout_identify();
    static int callout_authenticate();

    globaldef struct LGI$CALLOUT_VECTOR LGI$LOGINOUT_CALLOUTS =
                    {
                    9,
                    0,                              /* init */
                    0,                              /* iact_start */
                    callout_decwinit,               /* decwinit */
                    callout_identify,               /* identify */
                    callout_authenticate,           /* authenticate */
                    0,                              /* chkrestrict */
                    0,                              /* finish */
                    callout_logout,                 /* logout */
                    0,                              /* jobstep */
                    };

    /* DECwindows initialization */

    static int callout_decwinit()
        {
            /* Disable any further calls */
            LGI$LOGINOUT_CALLOUTS.LGI$L_ICR_ENTRY_COUNT = 0;
            /* Return and do standard DECwindows processing */
            return (SS$_NORMAL);
        }

    /* Identification */

    static int callout_identify(struct LGI$ARG_VECTOR *arg_vector)
        {

        int status;
        $DESCRIPTOR(wru,"\r\nWho are you? ");

        /* This example deals only with interactive jobs */
        if (!(*arg_vector->LGI$A_ICR_CREPRC_FLAGS & PRC$M_INTER))
            return(SS$_NORMAL);  /* Not interactive, do normal processing */
        if (*arg_vector->LGI$A_ICR_CREPRC_FLAGS & PRC$M_NOPASSWORD)
            return(SS$_NORMAL);  /* Invoked as logged in, don't prompt */
        if (*arg_vector->LGI$A_ICR_SUBPROCESS != 0)
            return(SS$_NORMAL);  /* Don't prompt on subprocesses */

        /* Check for autologin */

        if ($VMS_STATUS_SUCCESS(arg_vector->LGI$ICB_AUTOLOGIN()))
            return (LGI$_SKIPRELATED);       /* Yes, it's an autologin */

        if (!$VMS_STATUS_SUCCESS(status = arg_vector->LGI$ICB_USERPROMPT(&wru)))
            return (status); /* On error, return error status */

        /* Successful prompt and parse; skip OpenVMS policy */

        return(LGI$_SKIPRELATED);
        }

    /* Authentication */

    static int callout_authenticate(struct LGI$ARG_VECTOR *arg_vector)
        {

        int status;
        $DESCRIPTOR(proveit,"\r\nProve it: ");

        /* This example deals only with interactive jobs */
        if (!(*arg_vector->LGI$A_ICR_CREPRC_FLAGS & PRC$M_INTER))
            return(SS$_NORMAL);  /* Not interactive, do normal processing */
        if (*arg_vector->LGI$A_ICR_CREPRC_FLAGS & PRC$M_NOPASSWORD)
            return(SS$_NORMAL);  /* Invoked as logged in, don't prompt */
        if (*arg_vector->LGI$A_ICR_SUBPROCESS != 0)
            return(SS$_NORMAL);  /* Don't prompt on subprocesses */

        if (*arg_vector->LGI$A_ICR_PWDCOUNT != 0)
            /* This account has at least one password */
            if (!$VMS_STATUS_SUCCESS(status =
                            arg_vector->LGI$ICB_PASSWORD(0,&proveit)))
            return (status); /* On error, return error status */

        if (*arg_vector->LGI$A_ICR_PWDCOUNT == 2)
            /* This account has two passwords */
            if (!$VMS_STATUS_SUCCESS(status =
                            arg_vector->LGI$ICB_PASSWORD(1,&proveit)))
            return (status); /* On error, return error status */

        /* Successful prompt and password validation; skip OpenVMS policy */

        return(LGI$_SKIPRELATED);
        }

    /* LOGOUT command */

    static int callout_logout(username, procname,  creprc_flags, write_fao)
        struct dsc$descriptor_s *username, *procname;
        short *creprc_flags;
        void (*write_fao) ();
        {
            char *Goodbye = "   Goodbye.";          /* This will become an ASCIC */
            if ((int) write_fao != 0)               /* If output is permitted... */
            {
                Goodbye[0]=strlen(Goodbye)-1;       /* Fill in ASCIC count */
                write_fao(Goodbye);                 /* and write it */
            }
            return(SS$_NORMAL);
        }

Previous | Next | Contents | Index

| privacy and legal statement |
4493PRO_032.HTML