 |
HP OpenVMS Programming Concepts Manual
33.4.4 Principal Names
So long as there is no targeting by the caller of the SYS$ACM[W] system service
(discussed in Section 33.4.5), the decision regarding which
ACME agent handles a
particular request is governed by the following factors:
- The ordering of ACME agents selected by the system manager
- The syntax of the principal name
- The spelling of the principal name
If the syntax provided to the SYS$ACM[W] system service can be handled by only one
ACME agent, that settles the matter.
If it can be handled by more than one ACME agent, then
the decision also depends on which ACME agent (in
order) is the first to be able to map the particular principal name
to a VMS user name.
Whether a particular ACME agent can map a particular
principal name also depends on the mapping tables or
algorithms specific to that ACME agent, but this is
typically more time-consuming than simple decisions made on the basis
of the syntax presented in the principal name.
Consider the acceptable syntax presented in the following table:
Domain of Interpretation |
Principal Name Syntax |
VMS
|
username
|
Windows NT
|
domain\user
OR
user@domain
OR
user
|
Given those two ACME agents, it is possible to specify
a principal name that can only be handled by the Windows NT DOI
(by a full specification including the execute (@) command), but it is
not possible to specify a principal name that can only be handled by the
VMS DOI.
But that table only describes the situation for the combination of
those two ACME agents, the initial ones produced by
HP. The VMS ACME is always present on any
OpenVMS system, but on some systems you might omit the NT ACME and/or
include some other ACME agents, one of which might
honor some of the same syntax as the NT ACME agent.
33.4.5 Targeting Your System Service Calls
Most Authenticate Principal and Change Password calls are handled by
one or more ACME agents chosen in
accordance with selection criteria set by the system manager.
Your calling program can specify a target DOI
using one of the following item
codes:
- ACME$_TARGET_DOI_ID
- ACME$_TARGET_DOI_NAME
These item codes are used when your program requires that a particular
DOI handle your request.
33.4.5.1 DOI Names
The following two DOI names supplied by HP are currently defined:
Domain of Interpretation |
Name |
Source of the ACME Agent |
VMS
|
VMS
|
OpenVMS
|
Windows NT
|
MSV1_0
|
Advanced Server
|
33.4.5.2 When to Use DOI_NAME vs. DOI_ID
The following item codes affect the SYS$ACM[W] system service operations in the
same way:
- ACME$_TARGET_DOI_ID
- ACME$_TARGET_DOI_NAME
A similar relationship exists between the following item codes:
- ACME$_CONTEXT_ACME_ID
- ACME$_CONTEXT_ACME_NAME
The system manager specifies DOI names in configuring the ACME server,
although in most cases the system manager uses the registered names
specified by a vendor.
DOI IDs are implicitly specified by the system manager by the order in
which each is specified for the first time after each boot of the
system. That means that a particular DOI ID may have an entirely
different meaning on the same machine after the next reboot.
Specifying a DOI_NAME clearly gives better ease-of-use, while
specifying a DOI_ID gives slightly better performance with an overhead
penalty paid up front to look up a DOI_ID based on a DOI_NAME. Some
programs that call the SYS$ACM[W] system service, however, need to perform that
lookup in order to interpret the contents of the ACM communications buffer,
so in those cases the DOI_ID is already available and can be used in
calls to the SYS$ACM[W] system service.
33.4.5.3 Looking Up DOI and ACME IDs
Use the Query function code with a Target DOI ID of 0 (meaning the
SYS$ACM[W] system service itself) to determine what DOI_ID corresponds to a given
name.
The item list to do this would be as follows:
- SYS$ACM[W] server query - ID value 0:
ITMCOD = ACME$_TARGET_DOI_ID
BUFSIZ = 4
BUFADR = Address of longword containing 0
- Query based on ACME name:
ITMCOD = ACME$_QUERY_KEY_TYPE
BUFSIZ = 4
BUFADR = Address of longword containing ACME$K_QUERY_ACME_NAME
- Specify ACME name:
ITMCOD = ACME$_QUERY_KEY_VALUE
BUFSIZ = Characters in ACME name (times 4 if setting ACME$M_UCS2_4)
BUFADR = Address of buffer containing ACME name
- Specify ACME ID as the return value:
ITMCOD = ACME$_QUERY_TYPE
BUFSIZ = 4
BUFADR = Address of longword containing ACME$K_QUERY_ACME_ID
- Specify the output buffer
ITMCOD = ACME$_QUERY_DATA
BUFSIZ = 4
BUFADR = Address of longword to receive the ACME_ID
33.4.6 Determining ACME Information with the Query Function
The general nature of the Query function is that your code supplies the
following items:
- ACME$_TARGET_DOI_ID (or ACME$_TARGET_DOI_NAME)
- ACME$_QUERY_TYPE
- ACME$_QUERY_KEY_TYPE
- ACME$_QUERY_KEY_VALUE
Your program receives back the item ACME$_QUERY_DATA.
Semantics of those items and where the data comes from is entirely up
to the ACME agent that you specify as the
target of the Query function.
See the documentation for that ACME agent for more
information.
33.4.7 Reporting an Event
The general nature of the Event function is that your code supplies the
following items:
- ACME$_EVENT_TYPE
- ACME$_EVENT_DATA_IN
Your program possibly receives back item ACME$_EVENT_DATA_OUT.
Whether ACME$_EVENT_DATA_OUT is supported and the exact nature
of what the SYS$ACM[W] system service is supposed to do for an event is up to the
ACME agent that you specify as the
target of the Event function.
See the documentation for that ACME agent for more
information.
33.5 Authentication Scenarios
You can use the SYS$ACM[W] system service to accomplish the following functions:
- Authenticate a specified user.
- Change a password.
- Reauthenticate the current user.
- Create a process on behalf of a user.
It was possible to perform many of these functions prior to
introduction of the SYS$ACM[W] system service by combining the use of the
following techniques:
- SYS$GETUAI
- SYS$SETUAI
- SYS$HASH_PASSWORD
- SYS$SCAN_INTRUSION
- Modal restriction enforcement (network, batch, interactive, and so
on)
- Checks for account disabled, account expired, and so on
These steps made it difficult to provide a complete and bug-free
implementation. Furthermore, such an approach dealt only with
traditional VMS password-based authentication rather than including
add-on mechanisms. With the introduction of the SYS$ACM[W] system service, those
scenarios can be handled in a uniform, supported manner.
33.5.1 Simple User Authentication
If all information is known in advance, a call to SYS$ACMW is quite
simple, as in the following example:
LOCAL
STATUS,
ACME_STATUS_BLOCK : VECTOR [4,LONG],
NON_DIALOGUE_ITMLST : ALIAS_ON_AXP $ITMLST_DECL (ITEMS=2);
!
! Populate that item list
!
$ITMLST_INIT(ITMLST = NON_DIALOGUE_ITMLST,
!
! What is the Principal Name
!
(ITMCOD = ACME$_PRINCIPAL_NAME_IN,
BUFSIZ = %CHARCOUNT('JENKINS'),
BUFADR = UPLIT BYTE('JENKINS')),
!
! What Password was given to this routine ?
!
(ITMCOD = ACME$_PASSWORD_1,
BUFSIZ = .INPUT_STRING [DSC$W_LENGTH],
BUFADR = .INPUT_STRING [DSC$A_POINTER] ) );
!
! Now call the System Service
!
STATUS = $ACMW (EFN=EFN$C_ENF,
FUNC=ACME$_FC_AUTHENTICATE_PRINCIPAL,
ITMLST=NON_DIALOGUE_ITMLST,
ACMSB=ACME_STATUS_BLOCK );
|
33.5.2 Evaluating Status Codes
After any call to the SYS$ACM[W] system service, you must check
the return status from the call and the
primary status in the ACM Status Block.
Following is a sample check:
IF NOT .STATUS
THEN
SIGNAL_STOP ( STATUS );
IF NOT .ACME_STATUS_BLOCK [ACMESB$L_STATUS]
AND ( .ACME_STATUS_BLOCK [ACMESB$L_STATUS] NEQ ACME$_OPINCOMPL )
THEN
BEGIN
IF .ACME_STATUS_BLOCK [ACMESB$L_ACME_ID] NEQ 0
THEN
REPORT_ACME_SPECIFIC_ERROR ( ACME_STATUS_BLOCK )
ELSE
IF .ACME_STATUS_BLOCK [ACMESB$L_SECONDARY_STATUS]
EQL .ACME_STATUS_BLOCK [ACMESB$L_STATUS]
THEN
SIGNAL_STOP (
.ACME_STATUS_BLOCK [ACMESB$L_STATUS] )
ELSE
SIGNAL_STOP (
.ACME_STATUS_BLOCK [ACMESB$L_STATUS], 0,
.ACME_STATUS_BLOCK [ACMESB$L_SECONDARY_STATUS], 0 );
END;
|
The details of handling the field ACMESB$L_ACME_STATUS depend on
the nature of the ACME agent indicated in field ACMESB$L_ACME_ID.
If that ACME agent is not specifically known to the program that
calls the SYS$ACM[W] system service, there is no way to interpret that field. The
previous example presumes there is special knowledge regarding
at least one ACME agent held in
routine REPORT_ACME_SPECIFIC_ERROR, which is not supplied.
33.5.3 Password Change Dialogue
Particularly with the function code ACME$_FC_CHANGE_PASSWORD,
you cannot reliably predict all the necessary input at the time of the
initial call, because the first password chosen might be found in the
password history file or be unacceptable in some other way.
Following is a sample of how you might decode and process a dialogue
response:
BIND
ACMECB = .CONTEXT : BLOCK[,BYTE],
ITEM_SET = .ACMECB[ACMECB$PS_ITEM_SET] : BLOCKVECTOR[,ACMEIS$K_LENGTH,BYTE],
RESPONSE_ITEM_COUNTER : INITIAL [0],
!
! A real program should calculate the size for the following
! by basing it on .ACMECB[ACMECB$L_ITEM_SET_COUNT].
!
RESPONSE_ITEM_LIST : ALIAS_ON_AXP $ITMLST_DECL (ITEMS=9999);
!
! Store a terminator in case there are no input items.
!
RESPONSE_ITEM_LIST [0,ITM$L_TERMINATOR] = 0;
!
! Iterate over Itemset Array
!
INCRU ITEM_SET_INDEX FROM 1 TO .ACMECB[ACMECB$L_ITEM_SET_COUNT] DO
BEGIN
BIND
ITEM_SET_ENTRY = ITEM_SET [.ITEM_SET_INDEX,0,0,0,0],
ITEM_FLAGS = ITEM_SET_ENTRY [ACMEIS$L_FLAGS] : BLOCK[4,BYTE],
ITEM_CODE = ITEM_SET_ENTRY [ACMEIS$W_ITEM_CODE] : BLOCK[2,BYTE];
IF NOT .ITEM_CODE[ACMEIC$V_UCS]
THEN
SIGNAL_STOP ( THIS_PROGRAM_HANDLES_ONLY_TEXT );
IF NOT .ITEM_CODE[ACMEIC$V_OUTPUT]
THEN
BEGIN ! Respond to an input item
!
! Call subroutines to read input and put it in the item list.
!
IF .ITEM_FLAGS[ACMEDLOGFLG$V_NOECHO]
THEN
!
! Read the input - Last parameter (if any) indicates the prompt
! to be used on a confirmation read. That confirmation must
! match the initial response before returning here.
!
CONSTRUCT_ITEM_NOECHO_FROM_TERMINAL (
RESPONSE_ITEM_LIST [.RESPONSE_ITEM_COUNTER,0,0,0,0],
.ITEM_SET_ENTRY [acmeis$w_max_length],
ITEM_SET_ENTRY [acmeis$q_data_1],
ITEM_SET_ENTRY [acmeis$q_data_2] )
ELSE
!
! Just read the input - Last parameter indicates a default
! that will be taken by SYS$ACM if a blank line is supplied.
!
CONSTRUCT_ITEM_FROM_TERMINAL (
RESPONSE_ITEM_LIST [.RESPONSE_ITEM_COUNTER,0,0,0,0],
.ITEM_SET_ENTRY [acmeis$w_max_length],
ITEM_SET_ENTRY [acmeis$q_data_1],
ITEM_SET_ENTRY [acmeis$q_data_2] );
!
! Advance past this item.
!
RESPONSE_ITEM_COUNTER = .RESPONSE_ITEM_COUNTER + 1;
!
! Store a terminator in case this was the last input item.
!
RESPONSE_ITEM_LIST [.RESPONSE_ITEM_COUNTER,ITM$L_TERMINATOR] = 0;
BEGIN
END;
!
! Now call the System Service again, with the same FUNC argument.
!
! If all the item set entries were for output, we send a null item list.
!
STATUS = $ACMW (EFN=EFN$C_ENF,
FUNC=ACME$_FC_CHANGE_PASSWORD,
CONTXT=CONTEXT,
ITMLST=RESPONSE_ITEM_LIST,
ACMSB=ACMESB );
|
This example leaves the details of handling an optional confirmation
prompt to the routine CONSTRUCT_ITEM_NOECHO_FROM_TERMINAL, which is not
supplied. In addition, the code to process and display output items is
not shown.
Confirmation prompts are more common in Change Password than in
Authenticate Principal, but the program that calls SYS$ACM[W] system service
should be prepared to handle them in either situation (that is, any
time dialogue mode is used).
33.5.4 Reauthentication of Current User
The following code illustrates what you might do within an application
to ensure that the same user was still at the terminal. An example of
reauthentication would be a check-writing application that requires
reauthentication for any check over a certain value.
LOCAL
STATUS,
ACME_STATUS_BLOCK : VECTOR [4,LONG],
NON_DIALOGUE_ITMLST : ALIAS_ON_AXP $ITMLST_DECL (ITEMS=1);
!
! Populate that item list
!
$ITMLST_INIT(ITMLST = NON_DIALOGUE_ITMLST,
!
! What Password was given to this routine ?
!
(ITMCOD = ACME$_PASSWORD_1,
BUFSIZ = .INPUT_STRING [DSC$W_LENGTH],
BUFADR = .INPUT_STRING [DSC$A_POINTER] ) );
!
! Now call the System Service
!
STATUS = $ACMW (EFN=EFN$C_ENF,
FUNC=ACME$_FC_AUTHENTICATE_PRINCIPAL
+ACME$M_DEFAULT_PRINCIPAL,
ITMLST=NON_DIALOGUE_ITMLST,
ACMSB=ACME_STATUS_BLOCK );
|
33.5.5 Manipulating Personas
The following example is a slight variant on the example in
Section 33.5.1:
LOCAL
STATUS,
OLD_PERSONA,
NEW_PERSONA,
ACME_STATUS_BLOCK : VECTOR [4,LONG],
NON_DIALOGUE_ITMLST : ALIAS_ON_AXP $ITMLST_DECL (ITEMS=3);
!
! Populate that item list
!
$ITMLST_INIT(ITMLST = NON_DIALOGUE_ITMLST,
!
! What is the Principal Name
!
(ITMCOD = ACME$_PRINCIPAL_NAME_IN,
BUFSIZ = %CHARCOUNT('JENKINS'),
BUFADR = UPLIT BYTE('JENKINS')),
!
! What Password was given to this routine ?
!
(ITMCOD = ACME$_PASSWORD_1,
BUFSIZ = .INPUT_STRING [DSC$W_LENGTH],
BUFADR = .INPUT_STRING [DSC$A_POINTER] ) ),
!
! Where do we want the new Persona ID ?
!
(ITMCOD = ACME$_PERSONA_HANDLE_OUT,
BUFADR = NEW_PERSONA ) );
!
! Now call the System Service
!
STATUS = $ACMW (EFN=EFN$C_ENF,
FUNC=ACME$_FC_AUTHENTICATE_PRINCIPAL
+ACME$M_ACQUIRE_CREDENTIALS,
ITMLST=NON_DIALOGUE_ITMLST,
ACMSB=ACME_STATUS_BLOCK );
CHECK_STATUS ( .STATUS );
CHECK_ACME_STATUS ( ACME_STATUS_BLOCK );
!
! Now assume the new Persona
!
STATUS = $PERSONA_ASSUME (PERSONA=NEW_PERSONA,
FLAGS=0,
previous=OLD_PERSONA);
!
|
This example does not use item code ACME$_PERSONA_HANDLE_IN.
That is for manipulating the characteristics of an existing
persona, which is not the objective of this example.
33.5.6 Using CREPRC on Behalf of a User
After authentication, you can use the SYS$ACM[W] system service to
create a process on behalf of the user, with process quotas set
according the values in SYSUAF, as in the following example:
LOCAL
STATUS,
OLD_PERSONA,
NEW_PERSONA,
PIDADR,
CREPRC_QUOTA : VECTOR [255,BYTE], ! hopefully long enough
ACME_STATUS_BLOCK : VECTOR [4,LONG],
NON_DIALOGUE_ITMLST : ALIAS_ON_AXP $ITMLST_DECL (ITEMS=4);
!
! Populate that item list
!
$ITMLST_INIT(ITMLST = NON_DIALOGUE_ITMLST,
!
! What is the Principal Name
!
(ITMCOD = ACME$_PRINCIPAL_NAME_IN,
BUFSIZ = %CHARCOUNT('JENKINS'),
BUFADR = UPLIT BYTE('JENKINS')),
!
! What Password was given to this routine ?
!
(ITMCOD = ACME$_PASSWORD_1,
BUFSIZ = .INPUT_STRING [DSC$W_LENGTH],
BUFADR = .INPUT_STRING [DSC$A_POINTER] ) ),
!
! Where do we want the new persona ID?
!
(ITMCOD = ACME$_PERSONA_HANDLE_OUT,
BUFADR = NEW_PERSONA),
!
! Where do we want quota requirements stored ?
!
(ITMCOD = ACMEVMS$_CREPRC_QUOTA,
BUFSIZ = %ALLOCATION(CREPRC_QUOTA),
BUFADR = CREPRC_QUOTA ) );
!
! Now call the System Service
!
STATUS = $ACMW (EFN=EFN$C_ENF,
FUNC=ACME$_FC_AUTHENTICATE_PRINCIPAL,
ITMLST=NON_DIALOGUE_ITMLST,
ACMSB=ACME_STATUS_BLOCK );
CHECK_STATUS ( .STATUS );
CHECK_ACME_STATUS ( ACME_STATUS_BLOCK );
!
! That routine just detected any buffer too short error
!
! Temporarily assume the new Persona
!
STATUS = $PERSONA_ASSUME (PERSONA=NEW_PERSONA,
FLAGS=0,
previous=OLD_PERSONA);
CHECK_STATUS ( .STATUS );
!
! Now create the process under that persona
!
STATUS = $CREPRC (PIDADR=PIDADR,
IMAGE=$DESCRIPTOR('SYS$SYSTEM:LOGINOUT'),
INPUT=$DESCRIPTOR('TXA3:'),
OUTPUT=$DESCRIPTOR('TXA3:'),
ERROR=$DESCRIPTOR('TXA3:'),
QUOTA=CREPRC_QUOTA,
STSFLG=PRC$M_NOUAF+PRC$M_INHERIT_PERSONA);
CHECK_STATUS ( .STATUS );
!
! Revert to our old Persona
!
STATUS = $PERSONA_ASSUME (PERSONA=OLD_PERSONA);
CHECK_STATUS ( .STATUS );
!
! Delete the new persona from this process
!
STATUS = $PERSONA_DELETE (PERSONA=NEW_PERSONA );
CHECK_STATUS ( .STATUS );
!
|
The PRC$M_NOUAF flag prevents LOGINOUT from modifying process quotas,
while the PRC$M_INHERIT_PERSONA prevents LOGINOUT from modifying the
process persona,
allowing use of the persona (and persona extension) of the parent
process. The main purpose of LOGINOUT in this case becomes setting up
the DCL environment.
33.6 Authentication Examples
This section provides two complete examples of using the SYS$ACM[W]
system service. In addition to these examples, a utility program called
ACMEUTIL is available for issuing authentication and change-password
SYS$ACM system service calls and examining the results in both dialogue
and nondialogue mode.
You interact with the ACMEUTIL utility using the DCL interface. For
example, to issue a dialogue request for authentication, use the
following syntax:
$acme auth/dial=(input,noecho)
|
See the comments in ACMEUTIL_SETUP.COM for additional information on
ACMEUTIL DCL syntax and capabilities.
ACMEUTIL is located in the SYS$EXAMPLES directory and is built by
running the ACMEUTIL.COM procedure. To define the DCL verb ACMEUTIL,
run the ACMEUTIL_SETUP.COM procedure.
33.6.1 Example Using Nondialogue Mode (C)
This theoretical example supports a hardware badge reader and provides
all necessary authentication information with a single call to the
SYS$ACM[W] system service. The simple linear programming style used here would
also be appropriate for a situation in which that authentication
information is received from a network connection using a fixed
protocol that does not allow queries back to the originator.
Line |
Activity |
Special Notes |
45
|
Declare local storage
|
This subroutine avoids static storage.
|
105
|
Determine MAXBUF
|
MAXBUF limits hardware interaction.
|
105
|
Determine MAXBUF
|
MAXBUF limits hardware interaction.
|
158
|
Prepare a SYS$ACM item list
|
We will add data as we go.
|
210
|
Prepare to use the badge reader
|
Subsequent steps use it.
|
233
|
Compare DNA
|
Invoking a hardware function.
|
264
|
Read the principal name
|
Data from the badge reader.
|
298
|
Read the primary password
|
Data from the badge reader.
|
324
|
Read the secondary password
|
Data from the badge reader.
|
357
|
Free the badge reader
|
We do not know when image will exit.
|
372
|
Call SYS$ACMW
|
Here is where we authenticate.
|
389
|
Return status to our caller
|
We choose to provide no details.
|
1 #pragma module ACM_BADGE "V1.0"
2 /*
3 ** ACM_BADGE.C
4 */
5 #define __NEW_STARLET 1
6
7 #include <string> // NULL and memset
8 #include <starlet.h> // for calling SYS$ACM
9 #include <iledef.h> // Item Lists
10 #include <iodef.h> // for calling $QIO
11 #include <iosbdef.h> // IO status blocks
12 #include <stsdef> // decoding status code fields
13 #include <efndef> // For event flag number definitions
14 #include <descrip.h> // for descriptor definitions
15 #include <utcblkdef.h> // required for acmedef.h
16 #include <acmedef.h> // ACME codes
17 #include <syidef.h> // GETSYI codes
18
19 /*
20 ** ACM_BADGE
21 **
22 ** This subroutine obtains a user name and password from a
23 ** hardware badge reader and passes them in a nondialogue call to
24 ** SYS$ACM for evaluation. It returns success or failure status
25 ** to its caller.
26 **
27 ** Obviously the hardware badge reader construction must be secure
28 ** enough to never divulge the password without validating a DNA
29 ** sample from the person who places the badge in the reader,
30 ** and that is why this is just a code sample in SYS$EXAMPLES:
31 ** rather than something that comes with a real hardware product.
32 **
33 ** Arguments:
34 **
35 ** None.
36 **
37 ** Return values:
38 **
39 ** ACME$_NORMAL - authentic
40 ** ACME$_AUTHFAILURE - not authentic
41 ** anything else - processing failure
42 */
43 int ACM_BADGE()
44 {
45 int RetStatus;
46 int DasStatus;
47 char devnam[5]="BRA0:";
48 struct dsc$descriptor_s devnam_desc = { 0, // length
49 DSC$K_DTYPE_T, // type
50 DSC$K_CLASS_S, // class
51 0}; // buf address
52 IOSB iosb;
53 ACMESB acmsb;
54 unsigned short int badge_reader_channel;
55 int logon_type = ACME$K_NETWORK;
56 int maxbuf;
57 int read_size;
58
59 /*
60 ** We will call SYS$ACM with multiple entries in an item list.
61 */
62 enum acm_items
63 {
64 acm_logon_type,
65 acm_principal_name_in,
66 acm_password_1,
67 acm_password_2,
68 acm_terminator
69 };
70 ILE3 acm_itmlst[acm_terminator+1];
71 enum getsyi_items
72 {
73 getsyi_maxbuf,
74 getsyi_terminator
75 };
76 ILE3 getsyi_itmlst[getsyi_terminator+1];
77
78 /*
79 ** Our badge reader might provide very long input items,
80 ** because a user does not have to type them. Internally
81 ** the items will be carried in Unicode format, so the
82 ** length limit imposed by the 16-bit length field is
83 ** 1/4 of what one might first expect.
84 **
85 ** Internal limits on the size of a single SYS$ACM request
86 ** actually constrain the total of all items to this size,
87 ** but we cannot predict how imbalanced the item lengths
88 ** will be, so we make all buffers be this maximum size.
89 **
90 ** Depending on the value of system parameter MAXBUF, this
91 ** subroutine may try to read as many as buffer_size bytes
92 ** from the badge reader, so the Buffered IO Byte Limit
93 ** quota should be as large as buffer_size if the badge
94 ** reader is not a Direct IO device.
95 */
96 enum sizes
97 {
98 buffer_size = 65535/4
99 };
100 char principal_name_in[buffer_size];
101 char password_1[buffer_size];
102 char password_2[buffer_size];
103
104
105 /*
106 ** Get the SYS$GETSYI item list ready. First zero it out, then fill it in.
107 */
108 memset ( // clear out memory
109 getsyi_itmlst, // - Address to write to
110 0, // - Character to fill
111 sizeof (getsyi_itmlst)); // - size to fill
112
113 /*
114 ** System Parameter MAXBUF constrains the size of Buffered IO
115 **
116 ** Buffer maxbuf will be filled in by SYS$GETSYI.
117 */
118 getsyi_itmlst[getsyi_maxbuf].ile3$w_code = SYI$_MAXBUF;
119 getsyi_itmlst[getsyi_maxbuf].ile3$w_length = sizeof (maxbuf);
120 getsyi_itmlst[getsyi_maxbuf].ile3$ps_bufaddr = &maxbuf;
121 getsyi_itmlst[getsyi_maxbuf].ile3$ps_retlen_addr = NULL;
122
123 /*
124 ** End the item list with a terminator
125 */
126 getsyi_itmlst[getsyi_terminator].ile3$w_code = 0;
127 getsyi_itmlst[getsyi_terminator].ile3$w_length = 0;
128 getsyi_itmlst[getsyi_terminator].ile3$ps_bufaddr = NULL;
129 getsyi_itmlst[getsyi_terminator].ile3$ps_retlen_addr = NULL;
130
131 RetStatus = sys$getsyiw (
132 EFN$C_ENF, /* no event flag */
133 NULL, /* CSID address */
134 NULL, /* Node Name */
135 &getsyi_itmlst, /* Item List */
136 &iosb, /* IO Status block */
137 NULL, /* AST routine */
138 0 ); /* AST Parameter */
139 if (RetStatus & STS$M_SUCCESS)
140 {
141 /*
142 ** We use the smaller of maxbuf or the buffer size
143 */
144 if (maxbuf < buffer_size)
145 {
146 read_size = maxbuf;
147 }
148 else
149 {
150 read_size = buffer_size;
151 }
152 }
153 else
154 {
155 return RetStatus;
156 }
157
158 /*
159 ** Get the SYS$ACM item list ready. First zero it out, then fill it in.
160 */
161 memset ( // clear out memory
162 acm_itmlst, // - Address to write to
163 0, // - Character to fill
164 sizeof (acm_itmlst)); // - size to fill
165
166 /*
167 ** Buffer logon_type contains a constant ACME$K_NETWORK.
168 **
169 ** Using an interactive Logon Type would subject us to password
170 ** change requests, which are not viable in nondialogue mode (or
171 ** from our hypothetical badge reader, for that matter).
172 */
173 acm_itmlst[acm_logon_type].ile3$w_code = ACME$_LOGON_TYPE;
174 acm_itmlst[acm_logon_type].ile3$w_length = sizeof (logon_type);
175 acm_itmlst[acm_logon_type].ile3$ps_bufaddr = &logon_type;
176 acm_itmlst[acm_logon_type].ile3$ps_retlen_addr = NULL;
177
178 /*
179 ** Buffer principal_name_in will be filled in from the badge reader.
180 */
181 acm_itmlst[acm_principal_name_in].ile3$w_code = ACME$_PRINCIPAL_NAME_IN;
182 acm_itmlst[acm_principal_name_in].ile3$w_length = maxbuf;
183 acm_itmlst[acm_principal_name_in].ile3$ps_bufaddr = &principal_name_in;
184 acm_itmlst[acm_principal_name_in].ile3$ps_retlen_addr = NULL;
185
186 /*
187 ** Buffer password_1 will be filled in from the badge reader.
188 */
189 acm_itmlst[acm_password_1].ile3$w_code = ACME$_PASSWORD_1;
190 acm_itmlst[acm_password_1].ile3$w_length = maxbuf;
191 acm_itmlst[acm_password_1].ile3$ps_bufaddr = &password_1;
192 acm_itmlst[acm_password_1].ile3$ps_retlen_addr = NULL;
193
194 /*
195 ** Buffer password_2 will be filled in from the badge reader.
196 */
197 acm_itmlst[acm_password_2].ile3$w_code = ACME$_PASSWORD_2;
198 acm_itmlst[acm_password_2].ile3$w_length = maxbuf;
199 acm_itmlst[acm_password_2].ile3$ps_bufaddr = &password_2;
200 acm_itmlst[acm_password_2].ile3$ps_retlen_addr = NULL;
201
202 /*
203 ** End the item list with a terminator
204 */
205 acm_itmlst[acm_terminator].ile3$w_code = 0;
206 acm_itmlst[acm_terminator].ile3$w_length = 0;
207 acm_itmlst[acm_terminator].ile3$ps_bufaddr = NULL;
208 acm_itmlst[acm_terminator].ile3$ps_retlen_addr = NULL;
209
210 /*
211 ** Assign a channel to the Badge Reader.
212 */
213
214 devnam_desc.dsc$w_length = sizeof(devnam);
215 devnam_desc.dsc$a_pointer = &devnam[0];
216 RetStatus = sys$assign (
217 &devnam_desc, /* Device Name */
218 &badge_reader_channel, /* channel to badge reader */
219 0, /* access mode */
220 0 ); /* Mailbox Name */
221 if (!(RetStatus & STS$M_SUCCESS))
222 {
223 return RetStatus;
224 }
225
226 /*
227 ** Exit from this one pass loop to deassign the channel and return.
228 */
229
230 do
231 {
232
233 /*
234 ** Have the reader compare DNA.
235 **
236 ** A failed DNA comparison from the hardware is reported
237 ** to the user the same as any other authentication failure,
238 ** withholding details regarding what went wrong.
239 */
240
241 RetStatus = sys$qiow (
242 EFN$C_ENF, /* no event flag */
243 badge_reader_channel, /* channel to badge reader */
244 IO$_ACCESS, /* IO function code */
245 &iosb, /* IO Status block */
246 NULL, /* AST routine */
247 0, /* AST Parameter */
248 0, /* p1 */
249 0, /* p2 */
250 0, /* p3 */
251 0, /* p4 */
252 0, /* p5 */
253 0 ); /* p6 */
254 if (RetStatus & STS$M_SUCCESS)
255 {
256 RetStatus = iosb.iosb$w_status;
257 }
258 if (!(RetStatus & STS$M_SUCCESS))
259 {
260 RetStatus = ACME$_AUTHFAILURE; /* hide the exact cause */
261 continue; /* exit from the do loop */
262 }
263
264 /*
265 ** Read the Principal Name.
266 */
267
268 RetStatus = sys$qiow (
269 EFN$C_ENF, /* no event flag */
270 badge_reader_channel, /* channel to badge reader */
271 IO$_READVBLK, /* IO function code */
272 &iosb, /* IO Status block */
273 NULL, /* AST routine */
274 0, /* AST Parameter */
275 &principal_name_in, /* Buffer address */
276 read_size, /* Buffer length */
277 0, /* p3 */
278 0, /* p4 */
279 0, /* p5 */
280 0 ); /* p6 */
281 if (RetStatus & STS$M_SUCCESS)
282 {
283 RetStatus = iosb.iosb$w_status;
284 }
285 if (RetStatus & STS$M_SUCCESS)
286 {
287 acm_itmlst[acm_principal_name_in].ile3$w_length = iosb.iosb$w_bcnt;
288 }
289 else
290 {
291 continue; /* exit from the do loop */
292 }
293
294 /*
295 ** Read the Primary Password.
296 */
297
298 RetStatus = sys$qiow (
299 EFN$C_ENF, /* no event flag */
300 badge_reader_channel, /* channel to badge reader */
301 IO$_READVBLK, /* IO function code */
302 &iosb, /* IO Status block */
303 NULL, /* AST routine */
304 0, /* AST Parameter */
305 &password_1, /* Buffer address */
306 read_size, /* Buffer length */
307 0, /* p3 */
308 0, /* p4 */
309 0, /* p5 */
310 0 ); /* p6 */
311 if (RetStatus & STS$M_SUCCESS)
312 {
313 RetStatus = iosb.iosb$w_status;
314 }
315 if (RetStatus & STS$M_SUCCESS)
316 {
317 acm_itmlst[acm_password_1].ile3$w_length = iosb.iosb$w_bcnt;
318 }
319 else
320 {
321 continue; /* exit from the do loop */
322 }
323
324 /*
325 ** Read the Secondary Password.
326 */
327
328 RetStatus = sys$qiow (
329 EFN$C_ENF, /* no event flag */
330 badge_reader_channel, /* channel to badge reader */
331 IO$_READVBLK, /* IO function code */
332 &iosb, /* IO Status block */
333 NULL, /* AST routine */
334 0, /* AST Parameter */
335 &password_2, /* Buffer address */
336 read_size, /* Buffer length */
337 0, /* p3 */
338 0, /* p4 */
339 0, /* p5 */
340 0 ); /* p6 */
341 if (RetStatus & STS$M_SUCCESS)
342 {
343 RetStatus = iosb.iosb$w_status;
344 }
345 if (RetStatus & STS$M_SUCCESS)
346 {
347 acm_itmlst[acm_password_2].ile3$w_length = iosb.iosb$w_bcnt;
348 }
349 else
350 {
351 continue; /* exit from the do loop */
352 }
353
354 }
355 while (1 == 2);
356
357 /*
358 ** Deassign the channel to the Badge Reader.
359 */
360
361 DasStatus = sys$dassgn (
362 badge_reader_channel ); /* channel to badge reader */
363 if (RetStatus & STS$M_SUCCESS)
364 {
365 RetStatus = DasStatus;
366 }
367 if (!(RetStatus & STS$M_SUCCESS))
368 {
369 return RetStatus;
370 }
371
372 /*
373 ** Attempt authentication.
374 */
375
376 RetStatus = sys$acmw (
377 EFN$C_ENF, /* no event flag */
378 ACME$_FC_AUTHENTICATE_PRINCIPAL, /* ACM function code */
379 NULL, /* pointer to Context pointer */
380 &acm_itmlst, /* Item List */
381 &acmsb, /* ACM Status block */
382 NULL, /* AST routine */
383 0 ); /* AST Parameter */
384 if (RetStatus & STS$M_SUCCESS)
385 {
386 RetStatus = acmsb.acmesb$l_status;
387 }
388
389 return RetStatus; // return with ACM status
390 }
|
|