
/*++

Copyright (c) 1997  Microsoft Corporation

Module Name:

    sessdev.c

Abstract:

    Per Session Dos Device access routines

Author:


Revision History:

--*/

#include "basedll.h"


#define SESSION0_ROOT L"GLOBALROOT"
#define SESSIONX_ROOT L"GLOBALROOT\\Sessions\\"



BOOL
WINAPI
DosPathToSessionPathA(
    IN DWORD   SessionId,
    IN LPCSTR pInPath,
    OUT LPSTR  *ppOutPath
    )

/*++

Routine Description:

    Converts a DOS path relative to the current session to a DOS path
    that allows access to a specific session.

Arguments:

    SessionId - SessionId to access.

    pInPath   - WIN32 DOS path. Could be of the form "C:", "LPT1:",
                "C:\file\path", etc.

    ppOutPath - Output path that accesses the specified session.
                If pIniPath is "C:" and SessionId is 6, the output would be
                "GLOBALROOT\Sessions\6\DosDevices\C:".

Return Value:

    TRUE - Path returned in *ppOutPath in newly allocated memory from
           LocalAlloc.
    FALSE - Call failed. Error code returned via GetLastError()

--*/

{
    BOOL rc;
    DWORD Len;
    PCHAR Buf;
    NTSTATUS Status;
    PWCHAR pOutPath;
    ANSI_STRING AnsiString;
    UNICODE_STRING UnicodeString;

    // if the input path is null or the pointer is a bad pointer, return
    // an error.

    if( (pInPath == 0) ||
        (IsBadReadPtr( pInPath, sizeof( CHAR ))) ||
        (IsBadWritePtr( ppOutPath, sizeof(LPSTR) )) ) {

        SetLastError(ERROR_INVALID_PARAMETER);
        return(FALSE);
    }

    try {

        RtlInitAnsiString( &AnsiString, pInPath );
        Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );

    } except (EXCEPTION_EXECUTE_HANDLER) {

        Status = GetExceptionCode();
    }

    if (!NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return FALSE;
    }

    rc = DosPathToSessionPathW(
             SessionId,
             UnicodeString.Buffer,
             &pOutPath
             );

    RtlFreeUnicodeString( &UnicodeString );

    if( !rc ) {
        return( rc );
    }

    RtlInitUnicodeString( &UnicodeString, pOutPath );
    Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, TRUE );
    if (!NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        LocalFree( pOutPath );
        return FALSE;
    }

    Len = strlen( AnsiString.Buffer ) + 1;
    Buf = LocalAlloc(LMEM_FIXED, Len);

    if( Buf == NULL ) {
        LocalFree( pOutPath );
        RtlFreeAnsiString( &AnsiString );
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return(FALSE);
    }

    strcpy( Buf, AnsiString.Buffer );

    *ppOutPath = Buf;

    LocalFree( pOutPath );
    RtlFreeAnsiString( &AnsiString );

    return(TRUE);
}


BOOL
WINAPI
DosPathToSessionPathW(
    IN DWORD   SessionId,
    IN LPCWSTR  pInPath,
    OUT LPWSTR  *ppOutPath
    )

/*++

Routine Description:

    Converts a DOS path relative to the current session to a DOS path
    that allows access to a specific session.

Arguments:

    SessionId - SessionId to access.

    pInPath   - WIN32 DOS path. Could be of the form "C:", "LPT1:",
                "C:\file\path", etc.

    ppOutPath - Output path that accesses the specified session.
                If pIniPath is "C:" and SessionId is 6, the output would be
                "GLOBALROOT\Sessions\6\DosDevices\C:".

Return Value:

    TRUE - Path returned in *ppOutPath in newly allocated memory from
           LocalAlloc.
    FALSE - Call failed. Error code returned via GetLastError()

--*/

{
    PWCHAR Buf;
    ULONG  Len;

    //
    // SessionId 0 has no per session object directories.
    //
    if (BaseStaticServerData->LUIDDeviceMapsEnabled == TRUE) {

        Len = 0;

    } else {

        if( SessionId == 0 ) {
            Len =  wcslen(SESSION0_ROOT);
        }
        else {
            Len =  wcslen(SESSIONX_ROOT);
            Len += 10;                     // Max DWORD width
        }
    }

    Len += 13;                         // \DosDevices\ ... <NULL>

    // if the input path is null or the pointer is a bad pointer, return
    // an error.

    if( (pInPath == 0) ||
        (IsBadReadPtr( pInPath, sizeof( WCHAR ))) ||
        (IsBadWritePtr( ppOutPath, sizeof(LPWSTR) )) ) {

        SetLastError(ERROR_INVALID_PARAMETER);
        return(FALSE);
    }

    Len += wcslen(pInPath);

    Buf = LocalAlloc(LMEM_FIXED, Len * sizeof(WCHAR));
    if( Buf == NULL ) {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return(FALSE);
    }

    try {
        if (BaseStaticServerData->LUIDDeviceMapsEnabled == TRUE) {

            // C: -> C:
            swprintf(
                Buf,
                L"%ws",
                pInPath
                );

        } else {

            if( SessionId == 0 ) {
                // C: -> GLOBALROOT\DosDevices\C:
                swprintf(
                    Buf,
                    L"%ws\\DosDevices\\%ws",
                    SESSION0_ROOT,
                    pInPath
                    );
            }
            else {
                // C: -> GLOBALROOT\Sessions\6\DosDevices\C:
                swprintf(
                    Buf,
                    L"%ws%u\\DosDevices\\%ws",
                    SESSIONX_ROOT,
                    SessionId,
                    pInPath
                    );
            }
        }

        *ppOutPath = Buf;

    } except (EXCEPTION_EXECUTE_HANDLER) {

        BaseSetLastNTError(GetExceptionCode());
        return(FALSE);
    }


    return(TRUE);
}


BOOL
WINAPI
ProcessIdToSessionId(
    IN  DWORD  dwProcessId,
    OUT DWORD *pSessionId
    )

/*++

Routine Description:

    Given a ProcessId, return the SessionId.

    This is useful for services that impersonate a caller, and
    redefine a drive letter for the caller. An example is the
    workstation service. Transport specific routines allow the
    ProcessId of the caller to be retrieved.

Arguments:

    Process -  Process identifies process to
                return the SessionId for.

    pSessionId - returned SessionId.

Return Value:

    TRUE - SessionId returned in *pSessionId
    FALSE - Call failed. Error code returned via GetLastError()

--*/

{
    HANDLE Handle;
    NTSTATUS Status;
    CLIENT_ID ClientId;
    OBJECT_ATTRIBUTES Obja;
    PROCESS_SESSION_INFORMATION Info;


    if( IsBadWritePtr( pSessionId, sizeof(DWORD) ) )   {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }


    InitializeObjectAttributes(
        &Obja,
        NULL,
        0,
        NULL,
        NULL
        );

    ClientId.UniqueProcess = (HANDLE) LongToHandle(dwProcessId);
    ClientId.UniqueThread = (HANDLE)NULL;

    Status = NtOpenProcess(
                 &Handle,
                 (ACCESS_MASK)PROCESS_QUERY_INFORMATION,
                 &Obja,
                 &ClientId
                 );

    if( !NT_SUCCESS(Status) ) {
        SetLastError(RtlNtStatusToDosError(Status));
        return(FALSE);
    }

    Status = NtQueryInformationProcess(
                 Handle,
                 ProcessSessionInformation,
                 &Info,
                 sizeof(Info),
                 NULL
                 );

    if( !NT_SUCCESS(Status) ) {
        NtClose( Handle );
        SetLastError(RtlNtStatusToDosError(Status));
        return(FALSE);
    }

    *pSessionId = Info.SessionId;

    NtClose( Handle );

    return(TRUE);
}


DWORD
WINAPI
WTSGetActiveConsoleSessionId ()
/*++

Routine Description:

    returns the Session ID for the session, attached to Console.

Arguments:

    none

Return Value:

    SessionID for the console (session attached to console not necessarily session 0 ) session.
    return 0xFFFFFFFF if there is no session attached to console.
    This could happen if session disconnect / connect is taking place

    This is a session id for the session currently connected to console, it changes when
    new session is connected at console. to keep track of the current console sesion, use
    WTSRegisterSessionNotification


--*/
{
    return (USER_SHARED_DATA->ActiveConsoleId);

}

