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 $ ! $ @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 ;