C	    PRIVS.FOR
C
C This module centalizes all privilege management for the DISKCHARGE package
C to ensure safe and consistent handling of the use of privilege. 
C
C DISKCHARGE needs to be INSTALLed with SYSPRV (or whatever corresponds to the 
C privilege needed to access the accounting database => ACCDB_PRIV).
C
C The first thing that needs to be done is to look at the privs the process 
C running DISKCHARGE already has by doing a GETJPI for JPI$_PROCPRIV. A mask
C is then built (REQ_RESET_PROC_PRIV) which turns off any privilege the process
C does not have set. This has the effect of turning OFF SYSPRV unless the
C process already has it, and of not bothering a legitimate user with SYSPRV.
C This initial determination of privilege is done by calling GET_PRIVS and
C should be done before any file I/O is performed. In particular, we CANNOT 
C call GETOPT prior to this call since it would potentially allow a user to
C open the TRACE file where they should not be able to write!!
C
C Any call to access the accounting database via IVALIDATE_ACCOUNT, or opening
C the summary file directly, should be immediately preceeded by a call to
C SET_ACCDB_PRIV and immediately followed by a call to RESET_ACCDB_PRIV to avoid
C exposure to elevated priv. SET_ACCDB_PRIV will set the privilege, and
C RESET_ACCDB_PRIV will reset the privs to what the process had on entrance.
C
C This module contains the following routines/entry points:
C
C	RESET_PROC_PRIV }- Resets privileges back to process privileges (disable
C	RESET_ACCDB_PRIV}  installed image privileges
C	SET_ACCDB_PRIV   - Set the necessary privilege to read the accounting
C			   database
C	SET_SYSPRV_PRIV  - Sets SYSPRV
C	CHECK_PRIVS      - Check to see that user has enough privs to do what's
C			   needed.
C-----------------------------------------------------------------------------
	SUBROUTINE CHECK_PRIVS(username,cur_account,
     +	  read_any, write_any, charge_any,
     +	  accdb_priv,proc_priv,
     +    qual_remove,qual_default,qual_Scan,qual_repair,
     +	  qual_summary, summary_user, summary_account,trace)
C 
C FUNCTIONAL DESCRIPTION:	
C
C Check to see what privileges the user has. In particular, the routine 
C will determine whether the user may READ or WRITE all files
C and whether the user may charge any account number. This is useful to 
C determine if we can skip protection checks on a file-by-file basis, or if
C we can avoid checking a specific charge number. Generally, this will be the
C condition if run by a System Manager, etc. This routine could be customized 
C by different sites for their own criteria.  
C 
C At (W) Baltimore, the following criteria apply:
C	1) If READALL or BYPASS is set, user may READ ANY file
C
C	2) If BYPASS is set, user may WRITE ANY file
C
C	3) If OPERATOR is set, user may CHARGE ANY charge number
C
C If the user specifies the /DEFAULT qualifier to indicate that he wants to
C tag files with the account field from SYSUAF ACCOUNT field, he must possess
C SYSPRV or BYPASS in order to successfully use SYS$GETUAI for file owners
C other than himself. Since there is no reason to use /DEFAULT except by system
C managers, etc. to go through and initially tag files, this should not be a
C problem.
C
C DUMMY ARGUMENTS:
C	USERNAME    Character	Write	Username invoking this routine 
C	CUR_ACCOUNT Character	Write   Current account being charged
C	READ_ANY    Logical	Write	User may access any file for READ 
C					with needing to perform access checks
C	WRITE_ANY   Logical	Write	User may access any file for WRITE 
C                                       with needing to perform access checks
C	CHARGE_ANY  Logical	Write	User may charge any account
C	ACCDB_PRIV  Logical	Write	User has privilege to read accounting 
C					database files 
C					(At Baltimore ESG, this requires SYSPRV)
C	PROC_PRIV   Quadword	Write	Process privilege quadword
C	QUAL_REMOVE
C		    Logical	Read	User wants to REMOVE account. Needs
C					SYSPRV
C       QUAL_DEFAULT
C		    Logical     Read    User has specified that he wants to
C                                       tag files with the account in SYSUAF.
C	QUAL_SCAN   Logical	Read	User attempting to scan entire disk
C					and record usage. Requires BYPASS/READALL,
C                                       SYSPRV, and OPER
C	QUAL_REPAIR Logical	Read	Wants to be able to assign charge number
C					to files that don't have it. Only valid
C                                       with /SCAN, requires BYPASS plus those
C					required by SCAN
C	QUAL_SUMMARY
C		    Logical     Read	Wants summary info
C	SUMMARY_USER
C		    Character   Read	If not blank, wants summary info for
C					some other user. Needs WORLD or GROUP
C	SUMMARY_ACCOUNT
C		    Character   Read	If not blank, wants summary info for
C					some other account.
C	TRACE	    Character	Read	Debug info. If the string contains 
C					"CHECK_PRIVS", turn on debug
C
C IMPLICIT INPUTS:
C    none
C
C IMPLICIT OUTPUTS:
C    none
C
C SIDE EFFECTS:
C    none
C 
C CREATION DATE:        March 1, 1989
C
C
C            C H A N G E   L O G
C
C       Date     | Name  | Description
C----------------+-------+-----------------------------------------------------
C  01-Mar-1989   |  ATS  | Initial coding
C----------------+-------+-----------------------------------------------------
C  22-Mar-1989   |  ATS  | Add checks for /DEFAULT qualifier & privilege
C----------------+-------+----------------------------------------------------
C  27-Mar-1989   |  ATS  | Add checks for /SCAN, change arguments
C----------------+-------+-----------------------------------------------------
C  22-May-1989   |  ATS  | Incorporated into PRIVS module
C----------------+-------+-----------------------------------------------------
C  23-Jun-1989   |  ATS  | Correct LIB$SIGNAL calls with ERRSRC
C----------------+-------+-----------------------------------------------------
C   [change_entry]
C
	IMPLICIT NONE
	INCLUDE '($JPIDEF)'
	INCLUDE '($UAIDEF)'
	INCLUDE '($PRVDEF)'
	INCLUDE '($SSDEF)'
	
	STRUCTURE/ITMLST/
         UNION
          MAP
                INTEGER*2 BUFLEN
                INTEGER*2 ITMCOD
                INTEGER*4 BUFADR
                INTEGER*4 RETADR
          END MAP
          MAP
                INTEGER*4 END_LIST
          END MAP
         END UNION
	END STRUCTURE

	STRUCTURE/IOSBLK/
          INTEGER*4 STS,RESERVED
	END STRUCTURE
	RECORD/IOSBLK/IOSB
	RECORD/ITMLST/GETJPI_LIST(7)
	RECORD/ITMLST/GETUAI_LIST(2)

	INTEGER*4 jpi_proc_priv(2),req_reset_proc_priv(2)
	INTEGER*4 jpi_cur_priv(2)
	INTEGER*4 jpi_imag_priv(2),req_accdb_priv(2)
	INTEGER*4 SYS$GETJPIW,ist,SYS$SETPRV,SYS$GETUAI
	CHARACTER jpi_username*12,jpi_account*8

	LOGICAL read_any, write_any, charge_any, accdb_priv,qual_default
	LOGICAL bypass, sysprv, readall, oper, world, group
	LOGICAL qual_scan, qual_repair, qual_remove, qual_summary
	INTEGER*4 proc_priv(2),user_grp
	INTEGER*2 summary_user_uic(2)
	CHARACTER*(*) trace,username,cur_account,summary_user
	CHARACTER*(*) summary_account
        INTEGER*4 DISKCHG_ERRSRC,DISKCHG_NODEFPRIV,DISKCHG_NOSCANPRIV
        EXTERNAL  DISKCHG_ERRSRC,DISKCHG_NODEFPRIV,DISKCHG_NOSCANPRIV
	INTEGER*4 DISKCHG_NOREPPRIV,DISKCHG_NOREMPRIV,DISKCHG_NOSUMUSR
	EXTERNAL  DISKCHG_NOREPPRIV,DISKCHG_NOREMPRIV,DISKCHG_NOSUMUSR
	INTEGER*4 DISKCHG_CONFLICT,DISKCHG_NOSUMACC
	EXTERNAL  DISKCHG_CONFLICT,DISKCHG_NOSUMACC

	DATA req_accdb_priv/'10000000'X,0/	!SYSPRV privilege
C
C Get all privs associated with this process and the image as well
C
	getjpi_list(1).buflen=8
	getjpi_list(1).itmcod=JPI$_PROCPRIV
	getjpi_list(1).bufadr=%loc(jpi_proc_priv)
	getjpi_list(1).retadr=0
	getjpi_list(2).buflen=8
	getjpi_list(2).itmcod=JPI$_CURPRIV
	getjpi_list(2).bufadr=%loc(jpi_cur_priv)
	getjpi_list(2).retadr=0
	getjpi_list(3).buflen=8
	getjpi_list(3).itmcod=JPI$_IMAGPRIV
	getjpi_list(3).bufadr=%loc(jpi_imag_priv)
	getjpi_list(3).retadr=0
	getjpi_list(4).buflen=12
	getjpi_list(4).itmcod=JPI$_USERNAME
	getjpi_list(4).bufadr=%loc(jpi_username)
	getjpi_list(4).retadr=0
	getjpi_list(5).buflen=8
	getjpi_list(5).itmcod=JPI$_ACCOUNT
	getjpi_list(5).bufadr=%loc(jpi_account)
	getjpi_list(5).retadr=0
	getjpi_list(6).buflen=4
	getjpi_list(6).itmcod=JPI$_GRP
	getjpi_list(6).bufadr=%loc(user_grp)
	getjpi_list(6).retadr=0
	getjpi_list(7).end_list=0
C
	ist=SYS$GETJPIW(,,,getjpi_list,iosb,,)
        IF(ist) ist=iosb.sts
        IF(.NOT.ist) CALL LIB$SIGNAL(%VAL(ist),%VAL(0),
     +	  DISKCHG_ERRSRC,%VAL(2),'CHECK_PRIVS',
     +    'Error obtaining userinfo via SYS$GETJPI')

	proc_priv(1)=jpi_proc_priv(1)
	proc_priv(2)=jpi_proc_priv(2)
	username=jpi_username
	cur_account=jpi_account
C
C Test the appropriate bits of the current privilege vector to see if
C the user has enough privileges active to skip protection or account
C checking.
C
	bypass=BTEST(proc_priv(1),PRV$V_BYPASS)
	sysprv=BTEST(proc_priv(1),PRV$V_SYSPRV)
	readall=BTEST(proc_priv(2),PRV$V_READALL-32)
	oper=BTEST(proc_priv(1),PRV$V_OPER)
	world=BTEST(proc_priv(1),PRV$V_WORLD)
	group=BTEST(proc_priv(1),PRV$V_GROUP)
	
	read_any=.FALSE.
	write_any=.FALSE.
	charge_any=.FALSE.
	accdb_priv=.FALSE.

	IF(readall) read_any=.TRUE.
	IF(bypass) read_any=.TRUE.
	IF(bypass) write_any=.TRUE.
	IF(oper) charge_Any=.TRUE.
	IF(read_any) accdb_priv=.TRUE.
	IF((proc_priv(1).AND.req_accdb_priv(1)).NE.0) accdb_priv=.TRUE.

        IF(INDEX(TRACE,'CHECK_PRIVS').NE.0 .OR. 
     +	  INDEX(TRACE,'ALL').NE.0) 
     +      WRITE(99,9000) username,cur_account,user_grp,proc_priv,
     +      bypass, readall, oper, sysprv, group, world,
     +	    read_any,write_any,charge_any,accdb_priv

	IF(qual_repair .AND. .NOT. write_any)     
     +	  CALL LIB$STOP(DISKCHG_NOREPPRIV, 
     +	    %VAL(0),%VAL(SS$_NOPRIV))

	IF(qual_remove .AND. .NOT. sysprv)     
     +	  CALL LIB$STOP(DISKCHG_NOREMPRIV, 
     +	    %VAL(0),%VAL(SS$_NOPRIV))

	IF(qual_scan .AND..NOT.( (read_any .OR. write_any) 
     +	  .AND. accdb_priv .AND. charge_any) )
     +	  CALL LIB$STOP(DISKCHG_NOSCANPRIV,
     +	    %VAL(0),%VAL(SS$_NOPRIV))
	
	IF(qual_summary) THEN
	  IF(summary_user(1:1).EQ.'*'.AND..NOT.world) 
     +      CALL LIB$STOP(DISKCHG_NOSUMUSR,
     +      %VAL(1),summary_user,%VAL(SS$_NOPRIV))
	  IF((summary_account(1:1).EQ.'*'.AND.summary_user(1:1).EQ.'*')
     +	      .AND. .NOT.(world.AND.oper))
     +        CALL LIB$STOP(DISKCHG_NOSUMUSR,
     +        %VAL(1),summary_user,%VAL(SS$_NOPRIV))
	ENDIF

	IF(qual_summary.AND.summary_user(1:1).NE.' '.AND.
     +		summary_user.NE.username) THEN
	  IF(world) THEN	!Can look at anyone
	    CONTINUE
	  ELSE IF(group) THEN
	    CALL SET_SYSPRV_PRIV    !So can do GETUAI for SUMMARY_USER
	    getuai_list(1).buflen=4
	    getuai_list(1).itmcod=UAI$_UIC
	    getuai_list(1).bufadr=%LOC(summary_user_uic)
	    getuai_list(1).retadr=0
	    getuai_list(2).end_list=0
	    ist=SYS$GETUAI(,,summary_user,getuai_list,,,)
	    CALL RESET_PROC_PRIV	    
            IF(.NOT.ist) CALL LIB$STOP(%VAL(ist),%VAL(0),
     +		DISKCHG_ERRSRC,%VAL(2),'GET_PRIVS',
     +        'Error getting SUMMARY_USER UIC info')
	    IF(summary_user_uic(2).NE.user_grp) 
     +	      CALL LIB$STOP(DISKCHG_NOSUMUSR,
     +		    %VAL(1),summary_user,%VAL(SS$_NOPRIV))
	    IF(summary_user_uic(2).NE.user_grp) 
     +	      CALL LIB$STOP(DISKCHG_NOSUMUSR,
     +		    %VAL(1),summary_user,%VAL(SS$_NOPRIV))
	  ELSE
     	      CALL LIB$STOP(DISKCHG_NOSUMUSR,
     +		    %VAL(1),summary_user,%VAL(SS$_NOPRIV))
	  ENDIF	      
	ENDIF


 9000	FORMAT('CHECK_PRIVS:'/
     +   ' username: ',A,' cur_account:',A, ' user''s GRP:%O',O3.3/
     +	 ' proc_priv: %X',Z8.8,2x,'%X',Z8.8/
     +   ' bypass:',L1,' readall:',L1,' oper:',L1,' sysprv:',L1/
     +   ' group :',L1,' world:  ',L1
     +   ' read_any:   ',L1,' write_any:',L1,' charge_any:',L1/
     +	 ' accdb_priv: ',L1)
	RETURN
	END

	SUBROUTINE SET_SYSPRV_PRIV
	INTEGER*4 ist,req_sysprv_priv(2),SYS$SETPRV
	INTEGER*4 DISKCHG_ERRSC
	EXTERNAL  DISKCHG_ERRSRC
	DATA req_sysprv_priv/'10000000'X,0/	!SYSPRV privilege
C
C Adds SYSPRV privilege
C
        ist=SYS$SETPRV(%VAL(1),req_sysprv_priv,,,)
        IF(.NOT.ist) CALL LIB$STOP(%VAL(ist),%VAL(0),
     +		DISKCHG_ERRSRC,%VAL(2),'SET_SYSPRV_PRIV',
     +    'Error setting SYSPRV priv')
        RETURN
	END

	SUBROUTINE SET_ACCDB_PRIV
	INTEGER*4 req_accdb_priv(2),ist,SYS$SETPRV
	INTEGER*4 DISKCHG_ERRSRC
	EXTERNAL  DISKCHG_ERRSRC

	DATA req_accdb_priv/'10000000'X,0/	!SYSPRV privilege
C
C Adds the privilege necessary to access the accounting database
C
        ist=SYS$SETPRV(%VAL(1),req_accdb_priv,,,)
        IF(.NOT.ist) CALL LIB$STOP(%VAL(ist),%VAL(0),
     +	DISKCHG_ERRSRC,
     +    %VAL(2),'GET_PRIVS',
     +    'Error setting ACCDB priv')
        RETURN
	END

	SUBROUTINE RESET_PROC_PRIV
	ENTRY RESET_ACCDB_PRIV
C
C Resets privilege to process defaults
C
	INCLUDE '($JPIDEF)'

	INTEGER*4 ist,SYS$SETPRV,SYS$GETJPIW
	INTEGER*4 jpi_proc_priv(2),req_reset_proc_priv(2)
	INTEGER*4 DISKCHG_ERRSC
	EXTERNAL  DISKCHG_ERRSRC
	STRUCTURE/ITMLST/
         UNION
          MAP
                INTEGER*2 BUFLEN
                INTEGER*2 ITMCOD
                INTEGER*4 BUFADR
                INTEGER*4 RETADR
          END MAP
          MAP
                INTEGER*4 END_LIST
          END MAP
         END UNION
	END STRUCTURE

	STRUCTURE/IOSBLK/
          INTEGER*4 STS,RESERVED
	END STRUCTURE
 
	RECORD/ITMLST/GETJPI_LIST(2)
	RECORD/IOSBLK/IOSB

	getjpi_list(1).buflen=8
	getjpi_list(1).itmcod=JPI$_PROCPRIV
	getjpi_list(1).bufadr=%loc(jpi_proc_priv)
	getjpi_list(1).retadr=0
	getjpi_list(2).end_list=0
	ist=SYS$GETJPIW(,,,getjpi_list,iosb,,)
        IF(ist) ist=iosb.sts
        IF(.NOT.ist) CALL LIB$SIGNAL(%VAL(ist),%VAL(0),
     +	  DISKCHG_ERRSRC,
     +    %VAL(2),'RESET_PROC_PRIVS',
     +    'Error obtaining userinfo via SYS$GETJPI')
C
C Form the reset privilege mask & fall through to reset the privs...
C
	req_reset_proc_priv(1)=NOT(jpi_proc_priv(1))
	req_reset_proc_priv(2)=NOT(jpi_proc_priv(2))
C
C Remove any temporary privs
C
        ist=SYS$SETPRV(%VAL(0),req_reset_proc_priv,,,)
        IF(.NOT.ist) CALL LIB$STOP(%VAL(ist),%VAL(0),
     +	  DISKCHG_ERRSRC,
     +    %VAL(2),'RESET_PROC_PRIV',
     +    'Error resetting privs')
        RETURN
	END
