SCCSID  equ     "@(#)secure.asm 6.4 92/03/15"

;***    secure.asm - OS/2 Security Routines

;       MLM     11/27/95        72417
;               reduce fscrit serialization
;       DHJ     04/29/96        153157
;               remove invalid SSToDS instruction from SecDeletePre
include fnofs.inc
include basemaca.inc
include osmaca.inc
include dosseg.inc
include dossymc.inc
include error.inc
include mi.inc
include tkexport.inc
include protmode.inc
include sft.inc
include osconst.inc
include pgexport.inc
include vmexport.inc
include codelock.inc
include secure2.inc        ; private to kernel
include secure.inc         ; public interfaces
include fsc.inc
include filemode.inc       ; make somebody happy
include seldesc.inc        ; make virtsym.inc happy
include virtsym.inc        ; make fsh.inc happy
include fsh.inc            ; make filemacs happy
include filemacs.inc       ; for get_advise macro
include argframe.inc       ; for FindFromName (FFN) structure
include secioctl.inc
include devsym.inc
include ioctl.inc

        EXTRN32   _Sec32ReadPre
        EXTRN32   _Sec32ReadPost
        EXTRN32   _Sec32OpenPost
        EXTRN32   _Sec32OpenPre
        EXTRN32   _Sec32WritePost
        EXTRN32   _Sec32WritePre
        EXTRN32   _Sec32Close
        EXTRN32   _Sec32ChgFilePtr
        EXTRN32   _Sec32DeletePre
        EXTRN32   _Sec32DeletePost
        EXTRN32   _Sec32MovePre
        EXTRN32   _Sec32MovePost
        EXTRN32   _Sec32FindFirst
        EXTRN32   _Sec32FindFirst3x
        EXTRN32   _Sec32FindFirstNext3x
        EXTRN32   _Sec32FindClose3x
        EXTRN32   _Sec32FindNext
        EXTRN32   _Sec32FindClose                                       ;DGE02
ifdef REMOVED
        EXTRN32   _Sec32Shutdown
endif
        EXTRN32   _Sec32NewSize
        EXTRN32   _Sec32QueryFileInfo
        EXTRN32   _Sec32MakeDir
        EXTRN32   _Sec32ChangeDir
        EXTRN32   _Sec32RemoveDir
        EXTRN32   _Sec1
        EXTRN32   _Sec2
        EXTRN32   _Sec32SetDateTime
        EXTRN32   _Sec32SetFileInfo
        EXTRN32   _Sec32SetFileMode
        EXTRN32   _Sec32SetPathInfo
        EXTRN32   _Sec32DevIoctl
        EXTRN32   _Sec32AuditHook
        EXTRN32   _SecHlpTrustedPathNotify
        EXTRN32   _Sec32GetInfo
        EXTRN32   _SELLdrDesc                                           ;DGE02
        EXTRN32   PhysDiskTablePtr

        EXTRN     fc01:far

;       ReferTask Ren_WFP,WORD            ; 72417 removed- now in tcb
;       ReferTask WFP_Start,WORD          ; 72417 removed- now in tcb
        ReferTask CurrTCB,WORD            ; Current thread control block

        ReferFlat _fImport,BYTE
        ReferFlat _fImportPDF,BYTE
        ReferFlat _fImportAV,BYTE
        ReferFlat _pSec32Worker,DWORD
        ReferFlat _pSec16Worker,DWORD
        ReferFlat _fSec,BYTE
        ReferFlat _pTCBCur,DWORD
        ReferFlat _StartLock32,DWORD
        ReferFlat _EndLock32,DWORD

        EXTRN16   SFFromSFN
        EXTRN16   SFLock
        EXTRN16   SFUnlock
        EXTRN16   FSD_ChgFilePtr
        EXTRN32   _SELVirtToLin
        EXTRN32   _VMLockMem
        EXTRN16   SFFromSFNNoRefChk
        EXTRN16   w_FindNext                                            ;DGE02
        EXTRN16   w_FindFromName

        ModName , FNO_SECURE_ASM
        CpuMode 386



        FARCODE HIGH4
RASSWAPCODE  SEGMENT
ASSUME  CS:RASSWAPCODE
        PUBLIC    _StartLockIn
        _StartLockIn  LABEL BYTE
        Assume DS:Nothing,ES:Nothing

;***    SecReadPre   .. Validate a read request before it happens
;
;  ENTRY   ES:DI        -> SFT
;             CX        -> Byte Count
;          [TCBDMAAdd]  -> Buffer to Fill
;          DS           -> FLAT
;
;  EXIT    AX =  0, NC  Let call proceed
;          AX != 0, CY  return error code to caller
;
;
;  ALGORITHM
;    RC = Call Sec32ReadPre
;
;    USES:   AX, EBX
;
Procedure SecReadPre,faronly
        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <BX,CX,DX,ESI,EDI,ES>

        ; Extract the SFN number out of the SFT
        movzx   ebx,ES:[di].sf_fsi.sfi_selfsfn

        FlatContext <ES>,ax
        movzx   ecx,cx

        ; EBX has SFN
        ; ECX has Number of Bytes
        ; DS,ES are FLAT
        CCALL32  _Sec32ReadPre , < EBX, ECX >, nocheck

        clc                  ;Assume no error
        or      ax,ax
        jz      SRP_01
        stc                  ;Set error

SRP_01: RestoreReg <ES,EDI,ESI,DX,CX,BX>
SRP_02: ret

EndProc   SecReadPre

;***    SecReadPost  .. Give security subsystem chance to decrypt
;
;  ENTRY:
; ES            -> FLAT
; DS            -> ??
; CX            -> Byte count
; [TCBDMAAdd]   -> buffer
; [TCBThisSFT]  -> Sft
; AX            -> Return Code
;
;  Exit:
;   User Buffer might have been decrypted.
;
;  ALGORITHM
;    if (fSec)  //Security Enabled?
;       Convert Params to 32bit
;       RC = Call Sec32FSDReadPre
;    else
;       ret
;
;    USES:   EBX
;
;  NOTES:  Try to force as much code into Sec32ReadPost as it is in memory
;          that will be swapped out if security is not enabled.  Just do
;          minimal security enabled checking here and GET OUT!.
;
;
Procedure SecReadPost,faronly
ASSUME CS:RASSWAPCODE

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <AX,BX,CX,DX,ESI,EDI,ES,DS>

        FlatContext <DS>,bx

        movzx   eax,ax
        movzx   ecx,cx

        ; EAX has RC
        ; ECX has Number of Bytes Read
        ; DS,ES are FLAT
        CCALL32  _Sec32ReadPost , < EAX, ECX >, nocheck

        RestoreReg <DS,ES,EDI,ESI,DX,CX,BX,AX>
        ret

EndProc   SecReadPost


;***  SecWritePre
;
;     Allows security subsystem to validate DosWrite Requests
;
;     Entry
;       [TCBThisSFT]
;       [TCBDMAAdd ]
;       CX  - Bytes to Write
;       DS  - FLAT
;
;       Exit - AX = Return Code (CY set if error)
;
;       USES:
;       PRESERVES:  SI,CX
Procedure SecWritePre,faronly
ASSUME  CS:RASSWAPCODE

        FlatContext <ES>,ax
        SaveReg     <si,cx>
        movzx       ecx,cx
        CCALL32     _Sec32WritePre < ecx>, nocheck
        RestoreReg  <cx,si>
        clc
        or          ax,ax
        jz          swprx
        stc
swprx:  ret

EndProc SecWritePre

;***  SecWritePost
;
;     Called After file write to let security restore user buffer
;
;     Entry
;          AX = Return Code user is going to see
;          CX = 0 or BytesWritten depending on AX
;          BX = Byte Count of initial request                        ;lin
;
;       DS: FLAT
;       [TCBDMAAddr]  -> User buffer
;       [TCBThisSft]
;
;     Exit
;       AX, and CX setup as on entry
;
;
;     USES:
;     PRESERVES:   AX,CX

Procedure SecWritePost,faronly
ASSUME  CS:RASSWAPCODE

      FlatContext  <es>,dx
      Assume DS:FLAT,ES:FLAT

      movzx     eax,ax                  ; EAX = Error Code
      movzx     ecx,cx                  ; ECX = Bytes Written
      movzx     ebx,bx                  ; EBX = Initial Buffer Size
      SaveReg   <eax,ecx>
      CCALL32   _Sec32WritePost < eax,ecx,ebx >,nocheck
      RestoreReg <ecx,eax>
      ret

EndProc SecWritePost

;***    SecNewSize
;
;       Called in DosSetFileSize processing
;
;       ENTRY   es:di -> sft            (locked by caller)
;               TCBThisSFT
;               DS:FLAT
;       EXIT    EAX RETURNCODE
;
;       USES    EAX,ECX,EDX
;
Procedure SecNewSize,faronly
ASSUME  CS:RASSWAPCODE

        mov     ax,es
        ror     eax,16
        mov     ax,di
        SaveReg  <es,di>
        FlatContext <es>,di
        CCALL32  _Sec32NewSize,<eax>,nocheck
        RestoreReg <di,es>
        ret
EndProc SecNewSize

        public   _EndLockIn
        _EndLockIn label byte


;***  SecOpenPre
;
;     Called Before file open to let Security validate the event.
;
;     Entry
;       DI  : Open Flags
;       ESI : Open Mode
;       [TCBThisSFT]
;       [WFP_Start]
;       DS  : FLAT
;
;     Exit
;       CX  : Return Code
;
;     USES:        ES ,DI            (Preserved before we came here)
;     PRESERVES    BX,CX,DI,DS,AX,DX

Procedure SecOpenPre,faronly
        Assume DS:FLAT
        SaveReg <ax,bx,es,dx>

        FlatContext <es> ,ax
        movzx   edi,di

        CCALL32 _Sec32OpenPre  < edi,esi >, nocheck

        ; store return code in CX  (AX is in use by FSD_OPEN)
        mov     cx,ax
        RestoreReg <dx,es,bx,ax>
        ret
EndProc SecOpenPre

;***  SecOpenPost
;
;     Called after open to let security know RC and Action taken
;
;     Entry
;       AX   = RC
;       CX   = ActionTaken
;       DS   = FLAT
;       ESI  = Mode
;       DI   = Flags
;       [TCBThisSFT]
;
;     Exit
;       EAX  = New return code
;
;     USES:        SI
;     PRESERVES    AX,BX,CX,DI,ES

Procedure SecOpenPost,faronly
        SaveReg <es,si,di,bx,cx>        ; Save the world

        FlatContext <es> ,bx
        movzx   eax,ax
        movzx   ecx,cx
        movzx   edi,di
        mov     bx,ax
        CCALL32 _Sec32OpenPost < eax,ecx,esi,edi>, nocheck

        or      bx,bx                      ; was initial RC BAD?
        jnz     SOP_7                      ; yes, no need to cleanup
        or      ax,ax                      ; Did security fail call
        jz      SOP_3                      ; No, leave
        ; Security Failed the Call but the OS/2 kernel has it open.
        ; This isn't a big deal but if the file was opened by an
        ; fsd then we need to call FSD to close file

        mov     cx, ax                  ; Store ax before it is thrashed  @RM
        TaskContext <ds>,di
        mov     di,CurrTCB
        les     di,TASKAREA:[di].TCBThisSFT     ; (ES:DI) -> SFT
        cmp     es:[di].sf_FSC.Offst,FSC_LOCAL  ; what file system?
        jae     short SOP_3                     ; fat filesys no special cleanup

; @RM 04-27-94
; Fix for ERROR_ACCESS_DENIED being returned in the case of HPFS
        push    FS_CL_ORDINARY          ; Normal close
        get_advise                      ; ax = advisory bits
        push    ax                      ; push IOFlag (advisory bits)
        lea     ax,es:[di].sf_fsi       ; es:ax -> sf_fsi
        push    es
        push    ax                      ; push pointer to fsi
        lea     ax,es:[di].sf_fsd       ; es:ax -> sf_fsd
        push    es
        push    ax                      ; push pointer to fsd
        lds     si,es:[di].sf_FSC       ; ds:si -> FSC
        call    ds:[si].FS_CLOSE        ; ax = 0 or error code
        mov     ax, cx                  ; restore ax                      @RM
        jmp     short SOP_3             ; get out of this routine         @RM


SOP_3:  RestoreReg <cx,bx,di,si,es>     ; Restore World
        ret

SOP_7:  ; initail RC was bad.. return it to user
        mov     ax,bx
        jmp     short SOP_3

EndProc SecOpenPost



;***    SecMovePre
;
;       Called in DosMove "pre" processing
;       Will only get called when source and dest are on same volume
;
;       ENTRY
;           [WFP_Start]  -> Old Path
;           [Ren_WFP  ]  -> New Path
;           DS:FLAT
;       Exit  AX = Error Code (Carry set on error)
;
;       USES:   eax,edx,ecx,es
Procedure SecMovePre,faronly
        Assume DS:FLAT,ES:NOTHING

        TaskContext <es>,ax
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        SSToDS  eax
        movzx   edx,es:[di].TCBRen_WFP
        SSToDS  edx
        pop     di
        ; End   72417
        FlatContext <es>
        CCALL32 _Sec32MovePre, <edx,eax>, nocheck
        or      ax,ax
        jz      smprex
        stc
smprex: ret

EndProc SecMovePre

;***    SecMovePost
;
;       Called in DosMove "post" processing
;       Will only get called when source and dest are on same volume
;
;       ENTRY
;           AX           = Return code from move attempt (rc user will get)
;           [WFP_Start]  -> Old Path
;           [Ren_WFP  ]  -> New Path
;           DS:FLAT
;
Procedure SecMovePost,faronly
        Assume DS:FLAT,ES:NOTHING

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <EBX,ECX,EDX,ESI,EDI,ES>
        TaskContext <es>,bx
        movzx   eax,ax                        ; rc
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   ebx,es:[di].TCBWFP_Start
        SSToDS  ebx
        movzx   edx,es:[di].TCBRen_WFP
        SSToDS  edx
        pop     di
        ; End   72417
        FlatContext <es>
        CCALL32 _Sec32MovePost, <edx,ebx,eax>, nocheck
        RestoreReg <ES,EDI,ESI,EDX,ECX,EBX>
        ret

EndProc SecMovePost

;***    SecDeletePre
;
;       Called in DosDelete "pre" processing
;
;       ENTRY
;           [WFP_START]  -> pathname
;           DS:FLAT
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;       USES:  AX,CX,DX,ES
Procedure SecDeletePre,faronly
        Assume DS:FLAT,ES:NOTHING

        TaskContext <es>,cx
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        SSToDS  eax
        pop     di
        ; End   72417
;       SSToDS  eax                                                       @153157
        FlatContext <es>,cx

        CCALL32 _Sec32DeletePre, <eax> , nocheck
        or      ax,ax
        jz      sde10
        stc
sde10:  ret

EndProc SecDeletePre

;***    SecDeletePost
;
;       Called in DosDelete "post" processing
;
;       ENTRY
;           AX           = return code from delete (rc user will get)
;           [WFP_START]  -> pathname
;           DS:FLAT
;
Procedure SecDeletePost,faronly
        Assume DS:FLAT,ES:NOTHING
        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <EAX,EBX,ECX,EDX,ESI,EDI,ES>

        movzx   eax,ax                        ; eax = RC from delete
        TaskContext <es>,cx
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   edx,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS  edx
        FlatContext <es>,cx

        CCALL32 _Sec32DeletePost, <edx, eax> , nocheck
        RestoreReg <ES,EDI,ESI,EDX,ECX,EBX,EAX>
        ret

EndProc SecDeletePost


;***    SecChgFilePtr
;
;       Called in DosSetFilePtr processing
;
;       ENTRY   es:di -> sft            (locked by caller)
;               dx:ax = absolute offset (used by fat worker)
;               cx:si = distance        (used by fsd worker)
;               bx    = seek type       (used by fsd worker)
;               DS:FLAT
;       EXIT    CX:SI, BX may be updated
;               EDI contains Logical Offset to return to application.
;       USES:   EDI (see above)
;
Procedure SecChgFilePtr,faronly
        LocalVar  pSFT,DWORD
        LocalVar   off,DWORD
        LocalVar  Dist,DWORD
        LocalVar  SeekType,WORD
        LocalVar  LOff,DWORD

        EnterProc <es,di,dx,ax,cx,si,bx>
        assume  DS:FLAT,ES:NOTHING
        ; the security subsystem may embed data in the user file
        ; for access control lists.  For them to be able to do this
        ; we need to allow them to play games with dos change fileptr
        ; Namely we need the ability to have a physical and a Logical
        ; offset into the file.  The physical offset is what the file
        ; system will use.  The logical offset is what we report to
        ; the application.

        mov     eax, off
        mov     LOff,eax                        ; LOff == off , for now

        SSToDS  ESI, off                        ; ESI -> physical Offset
        SSToDS  EDX, LOff                       ; EDX -> logical  Offset
        SSToDS  EDI, Dist                       ; EDI -> Dist
        SSToDS  EBX, SeekType                   ; EBX -> Type
        mov     ecx, pSFT                       ; ECX -> SFT

        FlatContext <ES>,ax

        ; Sec32ChgFilePtr ( SFT,&Dist, &SeekType, &off,&LOff);
        CCALL32 _Sec32ChgFilePtr  < ECX, EDI,EBX,ESI,EDX > , nocheck

        mov     edi,LOff
        mov     cx,pSFT.hiword
        mov     es,cx
        mov     cx,Dist.hiword
        mov     si,Dist.loword
        mov     bx,SeekType
        mov     ax,off.loword
        mov     dx,off.hiword
        LeaveProc
        ret
EndProc  SecChgFilePtr



;***    SecQueryFileInfo
;
;       Called in DosQueryFileInfo
;
;       ENTRY   EAX   :  16:16 ptr to user buffer
;                DX   :  User Buffer Size
;                CX   :  InfoLevel
;               DS:FLAT
;               [TcbThisSFT]
;       EXIT    EAX RETURNCODE and Carry Clear/Set
;
;       USES    EAX,ECX,EDX,EBX,ES,DI
;
Procedure SecQueryFileInfo,faronly
        movzx       edx,dx          ; EDX User Buffer Size
        movzx       ecx,cx          ; ECX Info level
        FlatContext <es>,di
        ; _Sec32QueryFileInfo( p16Buffer, sizeof(Buffer), infolevel)
        CCALL32     _Sec32QueryFileInfo,<eax,edx,ecx>,nocheck
        or      ax,ax             ;106078
        jz      qfix              ;106078
        stc                       ;106078
qfix:   ret                       ;106078
EndProc SecQueryFileInfo


;***    SecSetFileInfo
;
;       Called in DosSetFileInfo
;
;       ENTRY    CX   :  User Buffer Size
;                DX   :  InfoLevel
;               EAX   :  16:16 ptr to user buffer (not validated)
;               [TcbThisSFT]
;               DS:FLAT
;       EXIT    EAX RETURNCODE and Carry Clear/Set
;
;       USES    ds,esi,ebx,eax
;
Procedure SecSetFileInfo,faronly

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <CX,DX,EDI,ES>

        movzx       ecx,cx          ; ECX User Buffer Size
        movzx       edx,dx          ; EDX Info level
        FlatContext <es>,di

        ; _Sec32SetFileInfo(p16Buffer, sizeof(Buffer), infolevel)
        CCALL32     _Sec32SetFileInfo,<eax,ecx,edx>,nocheck

        or      ax,ax
        jz      sfinc
        stc

sfinc:  RestoreReg <ES,EDI,DX,CX>
        ret
EndProc SecSetFileInfo

;***    SecSetFileMode
;
;       Called in DosSetFileMode
;
;       ENTRY
;               EAX      16:16 ptr to new attributes
;           [WFP_Start]  -> path name
;               DS:FLAT
;       EXIT    EAX RETURNCODE and Carry Clear/Set
;
Procedure SecSetFileMode,faronly

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <BX,CX,DX,ESI,EDI,ES>

        Assume DS:FLAT,ES:NOTHING

        TaskContext <es>,bx
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   ecx,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS  ecx

        FlatContext <es>,bx

        ; _Sec32SetFileMode()
        CCALL32     _Sec32SetFileMode,<ecx,eax>,nocheck

        or      ax,ax
        jz      sminc
        stc

sminc:  RestoreReg <ES,EDI,ESI,DX,CX,BX>
        ret
EndProc SecSetFileMode

;***    SecSetPathInfo
;
;       Called in DosSetPathInfo (DoPathInfo subroutine)
;
;       ENTRY    BX   ;  Path Info flags
;                CX   :  Info Buffer Size
;                DX   :  InfoLevel
;             ES:DI   :  16:16 pInfoBuf (has already been "ProbeBuff'ed")
;             [WFP_Start]
;               DS:FLAT
;       EXIT    EAX RETURNCODE and Carry Clear/Set
;
;       USES    EAX,ECX,EDX,EBX,ES,DI
;
Procedure SecSetPathInfo,faronly

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <BX,CX,DX,ESI,EDI,ES>

        movzx       ebx,bx          ; EBX Path Info flags
        movzx       ecx,cx          ; ECX User Buffer Size
        movzx       edx,dx          ; EDX Info level
        mov         si,es
        shl         esi,16
        mov         si,di           ; ESI 16:16 pInfoBuf
        TaskContext <es>,ax
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS      eax
        FlatContext <es>,di

        ; _Sec32SetPathInfo(p16PathName, infolevel, p16Buffer,
        ;                   sizeof(Buffer), infoflags)
        CCALL32     _Sec32SetPathInfo,<eax,edx,esi,ecx,ebx>,nocheck

        or      ax,ax
        jz      spinc
        stc

spinc:  RestoreReg <ES,EDI,ESI,DX,CX,BX>
        ret
EndProc SecSetPathInfo


;***    SecClose
;
;       Called in FSD_CLOSE processing
;
;       Entry
;         [TCBThisSft]
;         BX    ->  user handle, (or -1 when no SFT)
;         DS    ->  FLAT
;
;       PRESERVES:  BX
;
Procedure SecClose,faronly
        FlatContext <es>,di
        SaveReg <bx>
        movsx   ebx,bx
        CCALL32 _Sec32Close ,<EBX>, nocheck
        RestoreReg <bx>
        ret

EndProc SecClose


;***  SecFindFirst
;
;     Called After FSD_FindFirst has completed and the RMP SStruc
;     has been updated.  Only called on sucsessful find_first
;
;     Entry
;
;         ax    = return code user will get
;         bx    =  Search Handle
;         cx  high word =  actual number of entries
;         cx  low  word =  Info Level
;         dx    =  User Result Buffer
;         edi  high word = Result Buffer Segment
;         edi  low  word = Result Buffer Offset within Segment
;         si    =  numer of entries user requested
;         DS : Flat
;
;
;     Exit
;       CX - Result Count
;       AX - Return Code
;
;     USES:
;     PRESERVES: BX

Procedure SecFindFirst,faronly

        LocalVar  ResultCntInfoLevel, DWORD
        EnterProc

        FlatContext  <es>
        Assume DS:FLAT,ES:FLAT

        mov       ResultCntInfoLevel,ecx
        SSToDS    ecx,ResultCntInfoLevel ; ECX -> ResultCntInfoLevel
;
; Set up to call _Sec32FindFirst with registers as follows:
;       eax = return code
;       ebx = search handle                                      IN
;       ecx = address of ResultCountInfoLevel                    IN/OUT
; NOTE: ResultCountInfoLevel high word has result count on input
; NOTE: ResultCountInfoLevel low  word has info level on input
; NOTE: ResultCountInfoLevel has 32-bit result count on return
;       edi = buffer segment 16:16                               IN
;
        movzx   ebx,bx
        movzx   edx,dx
        movzx   eax,ax
        movzx   esi,si
        CCALL32   _Sec32FindFirst <EBX, EAX, ECX, EDI, EDX, ESI>, nocheck

        mov     ecx, ResultCntInfoLevel   ; In case buffer modified

SFF_01:
        LeaveProc
        ret

EndProc SecFindFirst



;***    Sec3xFindFirst
;
;       Called from DOS Do_3xSearch_First
;
;       ENTRY
;           EDI = search handle
;           [WFP_START]  -> pathname
;           DS:FLAT
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;       USES:  AX
Procedure Sec3xFindFirst,faronly
        Assume DS:FLAT,ES:NOTHING

        TaskContext <es>,ax
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS  eax
        FlatContext <es>

        CCALL32 _Sec32FindFirst3x, <edi, eax> , nocheck
        or      ax,ax
        jz      s3xff10
        stc
s3xff10:
        ret

EndProc Sec3xFindFirst

;***    Sec3xFindFirstNext
;
;       Called from DOS Do_3xSearch_First and Do_3xSearch_Next
;
;       ENTRY
;           EDI = search handle
;           DS:FLAT
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;       USES:  AX
Procedure Sec3xFindFirstNext,faronly
        Assume DS:FLAT,ES:NOTHING

        FlatContext <es>,ax
        CCALL32 _Sec32FindFirstNext3x, <edi> , nocheck
        or      ax,ax
        jz      s3xffn10
        stc
s3xffn10:
        ret

EndProc Sec3xFindFirstNext

;***    Sec3xFindClose
;
;       Called from
;
;       ENTRY
;           DS:FLAT
;           edi = search handle
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;       USES:  AX
Procedure Sec3xFindClose,faronly
        Assume DS:FLAT,ES:NOTHING

        FlatContext <es>,ax
        CCALL32 _Sec32FindClose3x, <edi>, nocheck
        or      ax,ax
        jz      s3xfc10
        stc
s3xfc10:
        ret

EndProc Sec3xFindClose

;***  SecFindNext
;
;     Called After FSD_FindNext has completed and the RMP SStruc
;     has been updated.  Only called on sucessful find-next calls.
;
;
;     Entry
;         ax    =  return code for user
;         bx    =  Search Handle
;         cx  high word =  number of buffers user actually received
;         cx  low  word =  Info Level
;         dx    =  User Result Buffer length
;         edi  high word = Result Buffer Segment
;         edi  low  word = Result Buffer Offset within Segment
;          si  count of buffers user requested
;         DS : Flat
;
;     Exit
;       CX - Result Count
;       AX - Return Code, carry set if need be
;
;     USES:       The world
;     PRESERVES:  Zip

Procedure SecFindNext,faronly

      LocalVar  ResultCntInfoLevel, DWORD

      EnterProc
      FlatContext  <es>
      Assume DS:FLAT,ES:FLAT

      mov       ResultCntInfoLevel,ecx
      SSToDS    ecx,ResultCntInfoLevel ; ECX -> ResultCntInfoLevel

      movzx     ebx,bx
      movzx     edx,dx
      movzx     eax,ax
      movzx     esi,si
      CCALL32   _Sec32FindNext <EBX, EAX, ECX, EDI, EDX, ESI>, nocheck

      mov     ecx, ResultCntInfoLevel   ; In case buffer modified
      ; EAX has return code for user..
      ; no need to set carry as w_findnext/w_findfromname will handle it

SFN_01:
      LeaveProc
      ret

EndProc SecFindNext


;***    SecFindClose
;
;       Called after FSD_FindClose has completed
;
;       ENTRY
;           ES:FLAT
;           AX  = search handle
;
;       EXIT:
;           DS: TASK
;           SI: Preserved
Procedure SecFindClose,faronly
        Assume DS:FLAT,ES:NOTHING

        SaveReg     <si>
        movzx       eax,ax
        FlatContext <ds>,cx
        CCALL32 _Sec32FindClose, <eax>, nocheck
        TaskContext <ds>,ax
        RestoreReg  <si>
        ret

EndProc SecFindClose

ifdef REMOVED
;***    SecShutdown
;
;       Called in Shutdown processing
;
;       For now we aren't passing any parms to the security device
;       driver.  This is only a notification that the system is
;       going down.
;
;
;       PRESERVES: AX,BX,CX,EDX,ES,EDI,DS
;
Procedure SecShutdown,faronly

        SaveReg  <AX,BX,CX,DX,ESI,EDI,ES,DS>
        FlatContext <es>,bx
        CCALL32 _Sec32Shutdown ,, nocall
        RestoreReg <DS,ES,EDI,ESI,DX,CX,BX,AX>
        ret

EndProc SecShutdown
endif


;***    SecMakeDir
;
;       Called from w_MkDir
;
;       ENTRY
;           [WFP_START]  -> pathname
;           DS:FLAT
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;
;       USES:      EAX,
;       PRESERVES: BX,DX,SI,DI,ES
;
Procedure SecMakeDir,faronly
        Assume DS:FLAT,ES:NOTHING

        SaveReg  <BX,DX,SI,DI,ES>
        TaskContext <es>
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS  eax
        FlatContext <es>

        CCALL32 _Sec32MakeDir, <eax> , nocheck
        or      ax,ax
        jz      smd10
        stc
smd10:
        RestoreReg <ES,DI,SI,DX,BX>
        ret

EndProc SecMakeDir


;***    SecChangeDir
;
;       Called from w_ChDir
;
;       ENTRY
;           [WFP_START]  -> pathname
;           DS:FLAT
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;
;       USES:      EAX,
;       PRESERVES: DX,SI,DI,ES
;
Procedure SecChangeDir,faronly
        Assume DS:FLAT,ES:NOTHING

;;;;; We need to save AX here or before call... FSD_ChDir uses as input?
        SaveReg  <DX,SI,DI,ES>
        TaskContext <es>
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS  eax
        FlatContext <es>

        CCALL32 _Sec32ChangeDir, <eax> , nocheck
        or      ax,ax
        jz      scd10
        stc
scd10:
        RestoreReg <ES,DI,SI,DX>
        ret

EndProc SecChangeDir


;***    SecRemoveDir
;
;       Called from w_RmDir
;
;       ENTRY
;           [WFP_START]  -> pathname
;           DS:FLAT
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;
;       USES:      EAX,
;       PRESERVES: DX,DI
;
Procedure SecRemoveDir,faronly
        Assume DS:FLAT,ES:NOTHING

        SaveReg  <DX,DI>
        TaskContext <es>
        ; Start 72417
        push    di
        mov     di,es:CurrTCB
        movzx   eax,es:[di].TCBWFP_Start
        pop     di
        ; End   72417
        SSToDS  eax
        FlatContext <es>

        CCALL32 _Sec32RemoveDir, <eax> , nocheck
        or      ax,ax
        jz      srd10
        stc
srd10:
        RestoreReg <DI,DX>
        ret

EndProc SecRemoveDir

;***    SecSetDateTime
;
;       Called from w_SetDateTime (\dos\task\time.asm)
;       This is a "pre" callout, before the date and time are actually set.
;
;       ENTRY
;           ES:DI - address of datetimebuf (buf is on ring0 stack)
;           DS - flat
;
;       EXIT:
;          AX = Error Code (Carry set on error)
;
Procedure SecSetDateTime,faronly

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <BX,CX,DX,ESI,EDI,ES,DS>

        movzx edi,di             ; Offset to datetime buffer (on stack).
        SSToDS  edi

        FlatContext <es>,ax
        CCALL32 _Sec32SetDateTime , <edi> , nocheck

        or      ax,ax
        jz      sdt10
        stc
sdt10:
        RestoreReg <DS,ES,EDI,ESI,DX,CX,BX>
        ret

EndProc SecSetDateTime

;***    SecDevIoctl
;
;       Called by w_DevIOCtl
;
;       ENTRY    BX   :  offset to SecIoctlParms_s struct (see secioctl.inc)
;                        (selector is TASKAREA)
;               SS:TASKAREA
;       EXIT    EAX RETURNCODE and Carry Clear/Set
;
Procedure SecDevIoctl,faronly
        ASSUME  DS:NOTHING,ES:NOTHING,SS:TASKAREA

        LocalVar  ParmLen,   DWORD
        LocalVar  DataLen,   DWORD
        LocalVar  DiskNumber,DWORD          ; category 9 only

        EnterProc

        push        ds
        FlatContext <ds>
        cmp         _fSec,0                 ; security enabled?
        jz          diexit2                 ; no. get out (CY flag not set).

        ; Only handle category 8 and 9 ioctls.
        push        ax                      ; save in case wrong category.
        mov         al,ss:[bx].sec_Category
        cmp         al,IOC_DC               ; Category 8?
        jz          short di01              ; Go do it.
        cmp         al,IOC_PD               ; Category 9?
        jz          short di01              ; Go do it.
        pop         ax
        clc                                 ; Good return.
        jmp         diexit2                 ; exit

di01:
        pop         ax

        ; Save everything for now, no guarantees as to what Subsys will mod
        SaveReg  <CX,DX,ESI,EDI,ES>

        ; The SFN isn't real useful for a category 9 devioctl.
        ; The callout really needs is the physical disk number.        119479
        cmp         al,IOC_PD               ; Category 9?
        jnz         short di03              ; no. DiskNumber not meaningful.

        ; The sf_devptr points to the physical disk table entry. Calculating
        ; which entry in the table relative to the beginning of the table
        ; gets us the disk number.

        les         di,ss:[bx].sec_SFTLockAddr      ; get SFT pointer
        mov         ax, word ptr es:[di].sf_devptr  ; get the diskentry offset
        mov         cx, word ptr [PhysDiskTablePtr]
        add         cx, 4                 ; BUGBUG - length of PhysDiskTblHdr

        sub         ax, cx
        mov         cl, size diskentry
        div         cl                      ; size of each PhysDiskTbl entry
        inc         ax
        movzx       eax, ax
        mov         DiskNumber, eax         ; save physical disk number
        jmp         short di05
di03:
        mov         DiskNumber, 0           ; initialize (for Category 8)
di05:
        mov         cx,ss:[bx].sec_cwData
        movzx       ecx,cx
        mov         DataLen,ecx

        mov         edi,ss:[bx].sec_DataPackAddr

        mov         cx,ss:[bx].sec_cwParm
        movzx       ecx,cx
        mov         ParmLen,ecx

        mov         edx,ss:[bx].sec_ParmPackAddr

        mov         cl,ss:[bx].sec_Function
        movzx       ecx,cl

        mov         al,ss:[bx].sec_Category
        movzx       eax,al

        mov         bx,ss:[bx].sec_SFN
        movzx       ebx,bx

        FlatContext <es>

        ; _Sec32DevIoctl( SFN, Category, Function, pParmList,
        ;                 cbParmList, pDataArea, cbDataArea, DiskNumber )
        CCALL32 _Sec32DevIoctl , <ebx,eax,ecx,edx,ParmLen,edi,DataLen,DiskNumber> , nocheck

        or      ax,ax
        jz      diexit
        stc
diexit: RestoreReg <ES,EDI,ESI,DX,CX>
diexit2:pop     ds
        LeaveProc
        ret

EndProc SecDevIoctl


;***    Sec16Router
;
;       Called from threadop farcall IFF 16-bit callgates have been hooked.
;
;       If 16-bit callgates have been hooked
;       Then this routine will route *ALL* 16-bit worker calls to the
;       Security Subsystem's 16-bit CallGate Handler.  This allows them
;       to hook any necessary worker routines we did not provide
;       FSD_ callouts for.
;
;       Assumes  the subsystems 16-bit CallGate Handler is in 16-bit ASM
;
;       ENTRY:
;         ??     (ss)                =  user's TCB (PTDA) stack segment
;         ??     (ss:bp)             -> shadow register frame
;                (ax,bx,cx,dx,si,di) =  working values
;
;                EAX - Highword contains ORDINAL used to identify
;                      worker routine.
;
;         Stack Frame
;                      BP
;                sp+6  @Worker SEG   - Address of worker routine, SEGMENT
;                SP+4  @Worker OFF   - Address of worker routine, OFFSET
;                SP+2  Return@ SEG   - Return address, SEGMENT
;                SP    Return@ OFF   - Return address, OFFSET
;
;       EXIT:   Never returns.  The RETF jumps to the callgate handler
;               who will return to the farcall address on the stack.
;
;       USES:   Nothing

Procedure Sec16Router,faronly
        FlatContext <ds>


        ; Due to a severe register shortage, we push the segment, and
        ; offset of the subsystems 16-bit callgate handler onto the
        ; stack and use RETF to accomplish the jump.

        push  word ptr _pSec16Worker
        push  word ptr _pSec16Worker+2

        retf             ;;** Are seg/off pushed correctly for retf?????

EndProc Sec16Router

RASSWAPCODE   ENDS




        FARCODE HIGH32
HIGH32SWAP_TEXT  SEGMENT
ASSUME CS:FLAT, DS:FLAT, ES:FLAT

;***    Sec32Router
;
;       The sysentry32 macro was modified to route ALL 32-bit
;       kernel worker routines through Sec32Router.
;
;       If 32-bit callgates have NOT been hooked (default),
;       We simply clean up the stack, and call the worker.
;
;       If 32-bit callgates have been hooked
;       Then this routine will route *ALL* 32-bit worker calls to the
;       Security Device Driver's 32-bit CallGate Handler.  This gives
;       the security subsystem a chance to hook any necessary worker
;       routines we did not provide FSD_ callouts for.
;
;
;       ENTRY:
;         Stack Frame   Arg xxx
;                        .
;                        .
;                       Arg 1      SP+10
;                       Arg 0      SP+C
;                       @Worker    SP+8    ; Address of Worker
;                       Ordinal    SP+4    ; Used to identify worker
;                       Ret Addr   SP      ; So we don't come back here...
;       EXIT:
;
;       USES:
;       PRESERVES:

Procedure Sec32Router,near

        ; If the security subsystem has not hooked 32-bit callgates then
        ; we clean up the stack and call the worker.  The following 5
        ; instructions will be no-op'ed if 32-bit callgates are enabled.

S32R01 label  byte
        pop     eax         ; Return address
        pop     ebx         ; Ordinal Number (Don't care about)
        pop     ebx         ; Address of Worker Routine
        push    eax         ; Put return address on stack for worker
        jmp     ebx         ; "CALL" worker ...( we won't return)

        ; If we get this far then 32-bit CallGates have been Enabled...
        ;
        ; Load EBX with a pointer to the security subsystem's 32-bit
        ;CallGate Handler routine and jump to it.

        mov     ebx, dword ptr _pSec32Worker
        jmp     ebx               ; "Call"  security CG handler

        ; NOTE:  The CG handler will return back to the address on the
        ;        stack,  NOT here.

        ret

EndProc Sec32Router

;***    SecHook32CG
;
;       Called from Sec2 when the security subsystem Imports the
;       addresses of routines to be notified..  (If an address was
;       provided for CALLGATE32).
;
;       Overwrites the first 5 instructions in Sec32Router with
;       No-op instructions to enable 32-bit CallGates.
;       Once this is done, all calls to 32-bit worker routines
;       will be routed to the security subsystem.
;
;       ENTRY
;             CG32Handler  - Address of security subsystem's
;                            32-bit callgate handler routine
;
;       USES:
;
;       PRESERVES: EDI, ECX, EAX
;

Procedure _SecHook32CG,near

        ArgVar  CG32Handler,DWORD

        EnterProc
        SaveReg  <EDI,ECX,EAX>

         mov    eax, CG32Handler
         mov    _pSec32Worker,eax
         xor    ecx,ecx             ; Clean up count reg

         ; Turn OFF page protection so we can overwrite code segment
         call TurnOffPageProtection

         lea    edi, S32R01         ; Starting point of code to patch
         mov    cx, 6               ; Number of bytes to zap
         mov    al, OPCODE_NOP      ; Replace with x90
         rep stosb

         ; Turn protection back ON
         call TurnOnPageProtection

         RestoreReg <EAX,ECX,EDI>
         LeaveProc
         ret

EndProc _SecHook32CG


;***    SecHook1632CG
;
;       Called from Sec2 when the security subsystem Imports the
;       addresses of routines to be notified..  (If an address was
;       provided for CALLGATE16).
;
;       The threadop farcall was modified to add the following instructions:
;        fc01  label  byte
;              clc
;              jnc   fc02 (security enabled)
;
;       This routine patches the clc instruction to stc to enable 16-bit
;       callgates. Once this is done, all calls to 16-bit worker routines
;       will be routed to the security subsystem.
;
;       ENTRY
;             CG16Handler  - Address of security subsystem's
;                            16-bit callgate handler routine
;
;       PRESERVES:
;
Procedure _SecHook16CG,near

        ArgVar  CG16Handler,DWORD

         EnterProc
         SaveReg  <EDI,EBX,ES>


         mov    ebx,CG16Handler     ; Get address of 16-bit Callgate Handler
         mov    _pSec16Worker,ebx   ; Save away for Sec16Router

         ; Turn OFF page protection so we can overwrite code segment
         call TurnOffPageProtection

         mov    bx,  HIGH3CODE       ; Access farcall code segment
         mov    es,  bx
         lea    edi, es:fc01         ; EDI points to clc instruction

         mov    byte ptr [edi], OPCODE_STC   ; change clc to stc

         ; Turn protection back ON
         call TurnOnPageProtection

         RestoreReg <ES,EBX,EDI>
         LeaveProc
         ret

EndProc _SecHook16CG


;***    TurnOffPageProtection
;
;       Called By:  SecHook16CG
;                   SecHook32CG
;
;       Make sure page protection is off so we can write to a code segment.
;
;       PRESERVES: EAX
;
Procedure TurnOffPageProtection,near
Assume DS:FLAT, ES:Nothing

        push    EAX
        mov     EAX, CR0        ; Get the Control Register
        test    EAX, CR0_WP_BIT ; Is the Write-protect bit on?
        jz      TO_Done         ; Nope.. ignore.

        and     EAX, NOT CR0_WP_BIT  ; Turn it off
        mov     CR0, EAX        ; and reset CR0

TO_Done:
        pop     EAX
        ret
EndProc TurnOffPageProtection


;***    TurnOnPageProtection
;
;       Called By:  SecHook16CG
;                   SecHook32CG
;
;       Turn protection back on
;
;       PRESERVES: EAX
;
Procedure TurnOnPageProtection,near
Assume DS:FLAT, ES:Nothing


        push    EAX
        mov     EAX, CR0        ; Get the Control Register
        test    EAX, CR0_WP_BIT ; Is the Write-protect bit on?
        jnz     TO2_Done        ; Yes.. ignore.

        or      EAX, CR0_WP_BIT ; Turn it on
        mov     CR0, EAX        ; and reset CR0

TO2_Done:
        pop     EAX
        ret

EndProc TurnOnPageProtection
HIGH32SWAP_TEXT ends



DATA segment
LockSwapHandle  db size vmlh_s  dup (?)
LockSwapHandle2 db size vmlh_s  dup (?)
DATA ends

HIGH32SWAP_TEXT  SEGMENT
;***    LockSwapStuff
;
;       Lock routines that can be called at swap time
;       into memory
;
;       USES    eax,edx,ecx
Procedure LockSwapStuff,near
Assume DS:FLAT, ES:FLAT
LSS_0:  mov     eax, offset FLAT: _EndLockIn
        mov     ecx,eax
        mov     edx, offset FLAT: _StartLockIn
        sub     eax,edx
        lea     edx, LockSwapHandle
        ; VMLockMem(Addr, size, VML_LONG,
        CCall   _VMLockMem < ecx, eax, VML_LONG, edx , VM_NO_ADDR, VM_NO_ADDR >
        cmp     eax, ERROR_INTERRUPT
        je      LSS_0

        ; now lock 32bit code
LSS_1:  mov     eax, offset FLAT: _EndLock32
        mov     ecx,eax
        mov     edx, offset FLAT: _StartLock32
        sub     eax, edx
        lea     edx, LockSwapHandle2
        CCall   _VMLockMem < ecx, eax, VML_LONG,edx, VM_NO_ADDR, VM_NO_ADDR>
        cmp     eax, ERROR_INTERRUPT
        je      LSS_1


        ret
EndProc LockSwapStuff


HIGH32SWAP_TEXT  ENDS




        FARCODE HIGH32
HIGH32CODE segment
; We don't want SecDevRoute to go away, because audit hook code will
; be calling this after init time, and the KBD DD (trusted path
; control) code will be calling this at interrupt time.
;CINIT_TEXT  SEGMENT

;***  SecDevRoute
;
;     Called by the Security DevHlp. Routes to appropriate security
;     worker routine.
;
;     We play some games are in here (SHL, OR with magic numbers..)
;     to make it a bit more difficult for someone to reverse engineer
;     using the kernel debugger.
;
;     DHSEC_SETPDFIMPORT is a private interface added to allow PDF to
;     co-exist (receive callouts also) with a security subsystem.
;     The SecSetImport routine allocates and adds to a linked list
;     of Import structures. Now everyone in the list will receive callouts
;
;     DHSEC_SCSAUDITHOOK is a private interface added to allow the
;     SES device driver to invoke the audit callouts for the SCS APIs.
;
;     To control access (prevent other programs from adding to the list)
;     a flag is set to disable the function
;     after 1 call to each of the import DevHlps:
;
;       DHSEC_SETIMPORT       Installable Security Subsystem
;       DHSEC_SETPDFIMPORT    Personal Desktop Facility (DPS device driver)
;       DHSEC_SETAVIMPORT     AntiVirus Subsystem
;       DHSEC_SCSAUDITHOOK    Audit hook callouts for SCS APIs
;       DHSEC_TRUSTEDPATH     Cntl-Alt-Del trusted path
;       DHSEC_GETINFO         Get information from system cbs (ptda, etc.)
;
;
; INPUTS:  EAX - Major Function Code
;          ECX - Pointer to buffer
;          Other inputs depend on function.
;

Procedure SecDevRoute,far32
        SaveReg <DS,ES,FS,GS>
        FlatContext <DS,ES>,SI

        cmp     eax,DHSEC_SCSAUDITHOOK
        jnz     short SDR_0
;  Sec32AuditHook ( pArgs, pParmPacket, AuditRC )
        CCall   _Sec32AuditHook < EBX, EDX, ECX >
        jmp     SDR_9

SDR_0:  cmp     eax,DHSEC_GETINFO
        jnz     short SDR_1
;     ebx is pPTDA
;     ecx is pSecGetInfo (offset based on ss)
        SSToDS  ecx                   ; convert to 32-bit
;  Sec32GetInfo ( pPTDA, pSecGetInfo )
        CCall   _Sec32GetInfo < EBX, ECX >
        jmp     SDR_9                 ; all done. get out.

SDR_1:  cmp     eax,DHSEC_TRUSTEDPATH
        jnz     short SDR_2
;  Sec32TrustedPath ( void )
        CCall   _SecHlpTrustedPathNotify
        jmp     SDR_9                 ; pass RC back to caller.

SDR_2:  cmp     eax,DHSEC_GETEXPORT
        jnz     short SDR_3
        CCall   _Sec1 < ECX >         ; SecGetExport
        jmp     SDR_9

SDR_3:  shl     eax,1
        cmp     eax,DHSEC_SETIMPORT SHL 1
        jnz     short SDR_5
        cmp     _fImport,0            ; First time through?
        jnz     short SDR_7           ; No, don't initialize
        CCall   _Sec2 < ECX >         ; SecSetImport
        or      eax,eax
        jnz     short SDR_7
        mov     _fImport,1            ; Set flag. Only 1 security sub allowed
        call    LockSwapStuff         ; locked if in use
        jmp     short  SDR_9

SDR_5:  or      eax, 043fda93ch
        cmp     eax,(DHSEC_SETPDFIMPORT SHL 1) OR 043fda93ch
        jnz     short SDR_6
        cmp     _fImportPDF,0         ; First time through for PDF?
        jnz     short SDR_7           ; No, don't initialize
        CCall   _Sec2 < ECX >         ; SecSetImport for PDF
        or      eax,eax
        jnz     short SDR_7
        mov     _fImportPDF,1         ; Set flag. 1 shot deal
        jmp     short SDR_9

SDR_6:  cmp     eax,(DHSEC_SETAVIMPORT SHL 1) OR 043fda93ch
        jnz     short SDR_7           ; Not valid Security Devhlp..Outahere
        cmp     _fImportAV,0          ; First time through for AntiVirus?
        jnz     short SDR_7           ; No, don't initialize
        CCall   _Sec2 < ECX >         ; SecSetImport for AntiVirus
        or      eax,eax
        jnz     short SDR_7
        mov     _fImportPDF,1         ; Set flag. 1 shot deal
        jmp     short SDR_9

SDR_7:  Panic <'DevHlp:  Usage Error - Security Device Driver already installed'>

;;SDR_8:  Panic <'DevHlp:  Set Import - Out of memory'>

SDR_9:
        RestoreReg <GS,FS,ES,DS>
        RETC
EndProc SecDevRoute

;CINIT_TEXT   ENDS
HIGH32CODE ENDS


FARCODE HIGH32
HIGH32CODE segment
Procedure _ChgFilePtr
        ArgVar   SFN,   DWORD
        ArgVar   Off,   DWORD
        ArgVar   SeekType,  DWORD
        ArgVar   pAbs,  DWORD       ; Added one more parm to call   @RM
        LocalVar pSft,  DWORD
        LocalVar Absolute,  DWORD   ; Absolute offset in file

        EnterProc

        SaveReg <esi,edi,ebx,es,ds>
        ; First Get a pointer to the SFT from the SFN
        mov     ebx,[SFN]
        CALL16  SFFromSFN             ; pointer to the SFT returned in [es:di]
        ASSUME  ES:NOTHING
        mov     eax,ERROR_INVALID_HANDLE ; has the SFT gone away ?
        jc      CHG_X

        ; Lock the SFT down so it doesn't Vanish on us.
        CALL16  SFLock
        mov     eax,ERROR_INVALID_HANDLE ; Something went wrong
        jc      CHG_X
        ; Save SFT as it might get trashed in call
        mov     ax,es
        shl     eax,16
        mov     ax,di
        mov     pSft,eax
        ; ES:DI -> SFT

        ; Calculate Absolute position based on seek type and offset
        mov     bx, SeekType.loword         ; bx    = Seek Type
        or      bx,bx
        jnz     CHG_02
        ; Type 0 Seek from begining of file
        ; Absolute = Offset
        mov     eax,Off
        jmp     short CHG_08

CHG_02: dec     bx
        jnz     CHG_03
        ;Type 1 Seek from Current Position
        ; Absolute = Current + Off
        mov     eax,es:[di].sf_fsi.sfi_position
        add     eax,Off
        jmp     short CHG_08


CHG_03: dec     bx
        jnz     CHG_ERR1
        ; Type 2 Seek from File End
        ; Absolute = FileSize + Off
        mov     eax,es:[di].sf_fsi.sfi_size
        add     eax,Off

CHG_08: ; EAX = Absolute Position in File
        ; Now stuff registers for FSD_ChgFilePtrCall
        mov     Absolute,eax
        mov     edx,eax
        shr     edx,16                  ; dx:ax = Abs Offset
        mov     esi,Off
        mov     ecx,esi
        shr     ecx,16                  ; cx:si = Distance
        mov     bx, SeekType.loword     ; bx    = Seek Type

        CALL16  FSD_ChgFilePtr
        ASSUME  DS:NOTHING, ES:NOTHING
;        movzx   eax,ax                 ; ?????                       @RM
        jc      CHG_XU                  ; returned carry set on error,
        sub     eax, eax                ; Everything is OK            @RM
        mov     ecx, [pAbs]             ; get pointer to abs value    @RM
        mov     edx, Absolute
        mov     [ecx], edx              ; return abs value            @RM
;        mov     eax,Absolute

CHG_XU: ;Exit with unlock
        les     di,pSft
        CALL16  SFUnlock

CHG_X:  RestoreReg <ds,es,ebx,edi,esi>
        LeaveProc
        RETC
CHG_ERR1:  ; Bad Seek Type
        mov     EAX,ERROR_INVALID_FUNCTION
        jmp     short CHG_XU

EndProc _ChgFilePtr


; *******************************************************************
; _SFFromSFN
;
; Return linear pointer to SFT from SFN or -1 on error
;
; *******************************************************************
Procedure _SFTFromSFN
        ArgVar  SFN,DWORD
        EnterProc
        SaveReg <ebx,esi,edi>
        mov     ebx,sfn
        CALL16  SFFromSFNNoRefChk
        Assume  ES:NOTHING
        mov     EAX,-1
        jc      SFS_Exit
        ;       es:di ->sfn
        mov     ax,es
        movzx   eax,ax
        movzx   edi,di
        CCall   _SELVirtToLin < edi,eax >

SFS_Exit:
        ; EAX -> SFT or -1 on error
        FlatContext <es>,di
        RestoreReg <edi,esi,ebx>
        LeaveProc
        RETC

EndProc _SFTFromSFN



; *******************************************************************
; _FindNextHlp
;
; *******************************************************************
Procedure _FindNextHlp
        ArgVar   SrchHandle, DWORD
        ArgVar   pSrchCnt, DWORD
        ArgVar   Level, DWORD
        ArgVar   pResultBuf, DWORD     ; 16:16
        ArgVar   BufSize, DWORD

        EnterProc
        SaveReg <esi,edi,ebx,es,ds>

        les     di,  pResultBuf

        mov     eax, pSrchCnt
        mov     eax, [eax]              ; search count
        mov     ebx, SrchHandle         ; search handle
        mov     ecx, BufSize            ; buffer size

        SaveReg <ds,es>
        CALL16  w_FindNext
        RestoreReg <es,ds>

        mov     ebx, pSrchCnt
        mov     [ebx], cx               ; # entries found
        jc      fn_10                   ; if no error
        xor     eax,eax                 ;   rc = 0
fn_10:

fn_x:   RestoreReg <ds,es,ebx,edi,esi>
        LeaveProc
        RETC

EndProc _FindNextHlp

; *******************************************************************
; FindNextHlp2
;
; Security helper to find next file that calls FindFromName instead
; of FindNext.
; Callin:
;     rc = FindNextHlp2(ulHandle, pResultCnt,pcBuffer,
;                 ulBufferSize, ulPosition, pszFile);
; *******************************************************************
Procedure _FindNextHlp2
        ArgVar  ulHandle, DWORD
        ArgVar  pResultCnt,DWORD    ; ss:16 result count
                                    ; note ss is not filled in here
        ArgVar  pcBuffer,DWORD      ; 16:16 to user buffer
        ArgVar  ulBufferSize,DWORD
        ArgVar  ulPosition,DWORD
        ArgVar  pszFile,DWORD       ; 16:16 ptr to filename
        LocalVar FFN, <SIZE FFNameStruc>

        EnterProc
        SaveReg <esi,edi,ebx,es,ds>

        xor     esi,esi
        mov     eax, ulHandle
        mov     FFN.FFN_DirHandle, ax

        mov     eax,pcBuffer
        mov     FFN.FFN_RsltBufPtr,eax

        mov     eax,ulBufferSize
        mov     FFN.FFN_RsltBufLen,ax
        mov     eax,ulPosition
        mov     FFN.FFN_Position,eax

        mov     eax, pszFile
        mov     FFN.FFN_FileNamePtr,eax

        mov     edi, pResultCnt
        mov     ax,ss:[di]      ; AX    ->Search Count
        mov     FFN.FFN_SearchCountPtr.loword, di
        mov     di,ss
        mov     FFN.FFN_SearchCountPtr.hiword, di

        ; note resultcnt is truncated to word here
        lea     bx,FFN     ; SS:BX ->FFN
        CALL16  w_FindFromName
        jc      fn2_10
        xor     eax,eax         ; set ax to zero on non-error

fn2_10:

        ; return result count to caller
        mov     edi, pResultCnt
        mov     ss:[di],cx      ; Save result count

        RestoreReg <ds,es,ebx,edi,esi>
        LeaveProc
        RETC
EndProc _FindNextHlp2


HIGH32CODE ends

end
