Document revision date: 30 March 2001 | |
Previous | Contents | Index |
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:
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:
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.
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
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.
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.
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) |
This section describes:
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:
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:
|
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. |
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:
LOGINOUT is installed with privileges. Therefore, any image containing LOGINOUT callout routines must be installed. |
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.
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. |
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.
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:
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:
|
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 |