
                      FIGURE 3        
$ !  
$ ! CHECKNODE.COM
$ ! FUNCTION:
$ !        Check for an identifier to allow user 
$ !             to login to a cluster node
$ !
$ ! Author: J McNamara  Cooperative Services, Inc.  Santa Fe, NM  
$ !
$ ! USAGE:
$ !        In SYLOGIN.COM, one of the first lines of code:
$ !            $ SET NOCONTROL=Y
$ !            $ @<disk:[directory]>CHECKNODE
$ !            $ SET CONTROL = Y
$ !
$ ! Requires:
$ !     Unique identifiers of the form LOGIN_node
$ !     be granted to users who are to log in to given node
$ !     Ex: to log in to node POWER the user needs the identifer 
$ !	  LOGIN_POWER
$ !
$   OPERATOR_NAME = "OPER12"       ! operator to notify of problem
$   NODE = F$GETSYI("NODENAME")    ! get cluster node name
$   NOT_FOUND = %X08D78053         ! DCL SEARCH "not found" code
$   SHOW PROCESS /PRIVILEGES /OUTPUT = SYS$SCRATCH:XX.XX
$   NODE_IDENTIFIER = "LOGIN_" + NODE
$   SEARCH /EXACT /NOOUTPUT SYS$SCRATCH:XX.XX 'NODE_IDENTIFIER'
$   STAT = $STATUS
$   DELETE/NOLOG SYS$SCRATCH:XX.XX;*
$   IF STAT .EQ. NOT_FOUND THEN GOTO ALOHA  ! branch if the identifer is not
$					    ! there
$   EXIT
$ 
$ ALOHA:
$ !  if we got here then we have a bad guy
$   PID = F$GETJPI(0,"PID")        	! pid of this process
$ !
$   CR[0,8] = 13	! carriage return
$   LF[0,8] = 10	! line feed
$
$   MESSAGE_STRING =  -
       CR + LF + "Security Alert on Node ''NODE'" + -
       CR + LF + "   User  ''F$USER()'     ''F$TIME()' " + -
       CR + LF + "   Cluster node login attempt rejected "
$   REQUEST /TO = 'OPERATOR_NAME'  "''MESSAGE_STRING'"
$
$   WRITE SYS$OUTPUT - 
       "%SYLOGIN-E-BADNODE, You are not authorized to log into this node"
$   STOP/ID='PID'
$ ! -------------------------------------







;        Figure 2                             J McNamara
;
	.TITLE   CHECK REMOTE NODE
	.IDENT	 /1.0/
;
        .SBTTL   Notes on Check_remote_node.mar
;
;      Author J McNamara
;
;      Date  24-OCT-1989
;
;    
;
;	Function:
;            Acts as a filter on a DECNET WAN with lots of
;		unwanted node partners that may have
;		free goodies, like viruses, to spread your way...
;		Prevents access by default accounts like
;		NETNONPRIV, DECNET. Stops any user from
;               any account, if used in either SYLOGIN.COM and/or
;               SYS$SPECIFIC:[DECNET]NETSERVER.COM.  In NETSERVER.COM
;               stops only remote access to COPY, BATCH, etc.
;                       
;
;		1. get PID of current process
;		2. translate sys$rem_node
;		3. see if sys$rem_node translation
;  		  is in list of trusted nodes
;                 or is not defined. Not defined means a local,
;		  batch, etc. user.
;		4. if okay, exit gracefully
;		5. not from trusted node, delete process....
;
;	Usage:
;		Meant to be run from SYLOGIN.COM as the
;               first executable line, before ARSAP_LOGIN.
;		To modify for use with more "trusted nodes"
;               add the node name to the list called Good_nodes:.
;		For example, say you want to allow logins
;		from node GOOD1.  You add 
;               .ASCII /GOOD1::/ anywhere in the buffer named
;		Good_nodes.  Recompile the code:
;               $MAC CHECK_NODE
;               $LINK CHECK_NODE
;               Put the code where it can be run by all who want  
;			entry to your system:
;               $COPY CHECK_NODE.EXE SYS$MANAGER/LOG
;               $SET FILE CHECK_NODE.EXE/PROT=W:E
;              
;                
;               In either NETSERVER.COM or SYLOGIN.COM put
;               $SET NOCONTROL=Y
;               $RUN SYS$MANAGER:CHECK_NODE
; 
;               right up near the very top of the .COM file
;
;               If you want to get rid of access from  node, then
;               just remove the whole line of code with that node
;		in it. Recompile & copy over to sys$manager.
;
;       Concept:
;              In a wide area network, you are often stuck with
;		unwanted node partners.  This proc
;		allows you to define which nodes you
;		want to have access via DECNET (PHONE, 
;		remote TASK, MAIL, etc.). It is essentially
;		a MACRO network filter, modified from DCL code.
;
;	Calls:
;		SYS$ASCTIM, SYS$EXIT, SYS$DELPRC, SYS$SNDOPR, 
;               SYS$TRNLNM
;               and possibly SYS$HIBER.
;
;       Revisions:
;
;
;
;
	.SBTTL  Macros, and data sets
;
;
;       Macros:
;
	.MACRO ON_ERR,THERE,?HERE
         BLBS	R0,HERE
         BRW    THERE
HERE:   .ENDM   ON_ERR
;
	.PSECT DATA,LONG
;
;       include values for $SNDOPR, $TRNLNM, etc.
;
;
        $LNMDEF
        $SSDEF
        $OPCDEF
;
;
;
;
	.PSECT DATA,LONG,WRT
;
;       data set for $TRNLNM
;
Lognam:	
	.ASCID	/SYS$REM_NODE/			; name of logical to translate
						; for remote node access only
Tabnam: 
	.ASCID  /LNM$JOB/			; SYS$REM_NODE is in LNM$JOB
;
LOGNAM_ITMLST:					; name for the beast -
Log_buffer_length:
	.WORD     8				; 8 character node name
Log_item_code:
	.WORD     				; tells $TRNLNM what to do
Log_buffer_address:
	.ADDRESS  Log_buffer			; where to write output -address
Log_return_length:
	.ADDRESS  Log_length			; length of output - address
Log_length:
	.LONG
Log_buffer:
	.BLKB	8
;
	.ALIGN LONG                             ; MATCHC works better
;
;      This is a list of "trusted" nodes for ALBU01:: as of
;		October 1989.  You must add or delete
;               nodes for your needs.  Make sure you include
;               the node name that CHECK_NODE will run on, so you
;		can SET HOST 0.
;
Good_nodes:
	.ASCII	/WEST01::/
	.ASCII	/WEST02::/
	.ASCII	/WCWIN1::/
	.ASCII	/WCWIN2::/
	.ASCII	/WASH02::/
	.ASCII	/ALBU01::/			; home node for this code
        .ASCII  /ALBDS2::/
	.ASCII	/WCHR01::/
        .ASCII  /ALBRTR::/    
	.ASCII  /SEATIG::/
Good_nodes_len =.-Good_nodes
;
String_length:
        .WORD  
;
;        data used for reporting bad login & killing the bad login process
;
;       
;       local, seldom-used ( we hope ) data
;
MSGBUF:
     	.LONG
        .ADDRESS Request_buffer_1
Request_buffer_1:
      	.BYTE						; OPC$ code for message
Request_buffer_2:					; 3 byte vector
	.BYTE						; to tell $SNDOPR who
Request_buffer_3:  					; to notify
        .BYTE
Request_buffer_4:
        .BYTE
Request_buffer_request_id:				; you can put any 
							; number here....
        .LONG  0					; (user def msg numbers )
Request_buffer_text:					; contents of 
        .ASCII  /Security alarm/			; message that goes to
        .BYTE	13					;  folks in above 3
	.BYTE	10					; byte vector
	.BYTE	9					;  13= carriage ret
        .ASCII  /Remote Intrusion Alert/		;  10 line feed
	.BYTE	13					;   9 = tab
	.BYTE	10
	.BYTE	9
	.BYTE	9  
        .ASCII  /Node of Origin: /
Bad_node_name:						; we put 6 char
        .BLKB   8					; node name plus "::"
	.BYTE	13					; in here
	.BYTE	10
	.BYTE	9
	.BYTE	9
        .ASCII  /User: /
Bad_guy:						; 12 character 
        .BLKB   12					; remote username
	.BYTE	13					; if we can get one
	.BYTE	10
        .BYTE    9
        .BYTE	 9
Time:							; time of
        .BLKB   23					; intrusion
RQ_len =.-Request_buffer_1				; length of MSGBUF
RQ_mask= OPC$M_NM_CENTRL!OPC$M_NM_SECURITY!OPC$M_NM_NTWORK
							; bit mask of
							; who gets notified by
							; the $SNDOPR call
;
;       data for $ASCTIM call
;
Timbuf:
	.LONG	  23			; descriptor for time - length
        .ADDRESS  Time			; time buffer in MSGBUF, above
;
;
;       data for call to $TRNLNM for remote user name
;
Lognam1:
	.ASCID	/SYS$REM_ID/     	; name of logical to translate
;
;
LOGNAM_ITMLST1:
Log_buffer_length1:			; 12 character user name on remote node
	.WORD     12			; length of available buffer space
Log_item_code1:
	.WORD     			; tell $TRNLNM what to do
Log_buffer_address1:
	.ADDRESS  Log_buffer1		; where to write log name trans
Log_return_length1:
	.ADDRESS  Log_length1		; length actually returned by $TRNLNM
Log_length1:
	.LONG
Log_buffer1:
	.BLKB	12			; home of trans. of SYS$REM_ID
	
;
        .SBTTL Main code section
;
;
	.PSECT MAIN,LONG,NOWRT,EXE
;
	.ENTRY CHECK_REMOTE_NODE,^M<>
;
;       Get the value of SYS$REM_NODE
;       from the LNM$JOB logical table
;
        MOVW    #LNM$_STRING,Log_item_code		; We want string value
							; of SYS$REM_NODE
        $TRNLNM_S TABNAM=Tabnam, LOGNAM=Lognam,-	; Macro to call
			ITMLST=LOGNAM_ITMLST
		    					;  $TRNLNM
;
        CMPL    R0,#SS$_NOLOGNAM			; If no logical name 
							;  found we are
							;  not remote; shortest
							;  possible code path is
							;  for local login
;
        BNEQ    Continue				; we are remote - 
							;  do more checking
;       
;       Well, since most processes are local let's quit early if we are
;	a local process....
;
        MOVL    #SS$_NORMAL,R0				; We got here because
							; R0 had the I-can't-
							; find-logical-name-
							; error. Set error
							; status=ok.
;
        BRW     Exit					; Quit early, this
							;  is shortest code
							;  path.
;
;       At this point the user is not local, so we run a thorough check.
;
;       Development note:
;       To test this part of the proc, you can do this as a local user:
;
;       $DEFINE/JOB  SYS$REM_NODE  PPPP01  ( or other garbage )
;       $DEFINE/JOB  SYS$REM_ID    BIGBADWORM ( or other fun stuff )
;       and then $RUN CHECK_NODE
;       The proc will notify security and then kill your process, if it
;              is working properly.
;
;       Back to business:
;       First,  we check to make sure our NODE name ( from sys$rem_node )
;		is approved.
;       If it ain't on the good list, we delete our own process, ie.,
;		 suicide!
;
	
Continue:
        ON_ERR  Exit					; check for other
							; errors besides
							; no logical name found
;
;
;       Let's see if our remote node is on the list of edible nodes:
;
 
        MOVL    Log_length,R2                           ; length of our 
							;   remote node name
        MOVAB   Log_buffer,R3                           ; address of remote 
							;   node
        MOVW    #Good_nodes_len,R4                      ; length of good node
							;  buffer
        MOVAB   Good_nodes,R5				; address of good nodes
        MATCHC  R2,(R3),R4,(R5)				; string search
        CMPL    #0,R0					; in the list ?
							; R0=0 means name is
							; okay
        BEQL    Exit					; yes, quit
;
;       If we got here then some turkey is entering from
;       who knows where.  Complain to SECURITY via $SNDOPR.
;       and kill the process        
        
        JMP     Eliminate				; no, we got a bad
							;  guy

;
;       Normal exit point for good guys only
;
	.ALIGN LONG
Exit:	CMPL    #0,R0					; did we pass 
							; MATCHC ?
        BNEQ    Exit1					; go on with R0=1
							; or R0=error status
        MOVL    #SS$_NORMAL,R0				; else, set status=ok
							; so we don't get 
							; stupid 
							; nomsg-noname from
							; EXIT (0) condition
Exit1:
        PUSHL	R0					; remember status
	CALLS   #1,SYS$EXIT				; graceful exit...
;
;
;

;
	.ALIGN LONG
Eliminate:
;
;      first fill in Node_name with our remote node
;        and username
;
;
	MOVC3   #8,Log_buffer,Bad_node_name		; park offending node
							; name in MSGBUF
;
;       now find the remote user name 
;
        MOVW    #LNM$_STRING,Log_item_code1		; We want a string 
							;  value from $TRNLNM
        $TRNLNM_S TABNAM=Tabnam, LOGNAM=Lognam1,-
			ITMLST=LOGNAM_ITMLST1         	; get userid logical
							;  translated
        ON_ERR  Setup_message   			; did log name trans
							; fail? - skip
							; name, then
                                       
        MOVC5   log_length1,log_buffer1,#^A/ /,#12,-
                Bad_guy					; put bad guy's 
							; name into  msgbuf

Setup_message:
        MOVC5 #0,Time,#^A/ /,#23,Time                   ; Fill Time with blanks
        $ASCTIM_S TIMBUF=Timbuf				; Put current time into
							; MSGBUF.time, we hope
Create_buf:						; go on even if error...
        MOVL    #RQ_len,MSGBUF				; length of msgbuf
        MOVB    #OPC$_RQ_RQST,Request_buffer_1		; type of operator
							;  request = message
        BISL2   #RQ_mask,Request_buffer_2               ; set bits of
							; oper types to notify  
	MOVL	#0,Request_buffer_request_id		; fiber filler
							; you can put any 
							; here
        $SNDOPR_S MSGBUF=MSGBUF				; Dial "0" for intrusion

Suicide:
        $DELPRC_S   					; commit suicide
        $HIBER_S					; wait around to get
							;  killed or in case
							; $DELPRC fails
;
        .END	CHECK_LOGIN
;

