/*++

Copyright (c) 1995  Microsoft Corporation

Module Name:

    NdsProcs.h

Abstract:

    This defines the necessary NDS data structures and
    symbolic constants.

Author:

    Cory West    [CoryWest]    23-Feb-1995

Revision History:

--*/

#include "data.h"
#include "nodetype.h"
#include "struct.h"
#include <stdarg.h>

#include "crypto.h"

//
// Security information.
//

#define ENC_TYPE_RSA_PUBLIC             0x90001
#define ENC_TYPE_RC2_CBC                0x60001

#define RAND_KEY_DATA_LEN               28
#define RAND_FL_DATA_LEN                1024
#define RC2_KEY_LEN                     8

#define MAX_PUBLIC_KEY_LEN              1300
#define MAX_BSAFE_PUBLIC_KEY_LEN        200                // Typically 179.
#define MAX_BSAFE_PRIV_KEY_LEN          280                // Typically 273.

#define MAX_PW_CHARS                    16

//
// The max size for various NDS components.
//

#define MAX_RSA_BITS            512                        // Really 420.

#define NDS_TREE_NAME_LEN         32
#define NDS_BINDERY_TREE_NAME     48

#define MAX_CREDENTIAL_LEN      ( sizeof( NDS_CREDENTIAL ) + MAX_NDS_NAME_SIZE )
#define MAX_SIGNATURE_LEN       ( sizeof( NDS_SIGNATURE ) + MAX_RSA_BYTES )
#define MAX_ENC_PRIV_KEY_LEN    ( MAX_BSAFE_PRIV_KEY_LEN + 64 )

#define BSAFE_CHECKSUM_LEN              5

#define DEFAULT_RESOLVE_FLAGS RSLV_DEREF_ALIASES | RSLV_WALK_TREE | RSLV_WRITABLE

#include <packon.h>

typedef struct {

    DWORD syntaxId;          // OCTET STRING (9)

    struct {
        DWORD nameLength;
        WORD name[11];       // "Public Key"
        WORD filler;
    } attribName;

    DWORD entries;           // = 1
    DWORD totalLength;       // of attribute value OCTET STRING
    DWORD unknown1;          // = 1
    DWORD unknown2;          // = 4
    WORD _issuerDNLength;
    WORD totalDNLength;
    WORD length2;
    WORD length3;
    WORD issuerDNLength;
    WORD userDNLength;
    WORD bsafeSectionLength;
    DWORD length4;

} PUBLIC_KEY_ATTRIB;

#include <packoff.h>

typedef struct {

    DWORD blockLength;   // cipherLength + size of following hdr fields
    DWORD version;       // = 1
    DWORD encType;       // 0x060001 for RC2; 0x090001 and 0x0A0001 for RSA
    WORD  cipherLength;  // of ciphertext
    WORD  dataLength;    // of plaintext

} ENC_BLOCK_HDR, *PENC_BLOCK_HDR;

typedef struct {

    DWORD rand1;
    DWORD rand2Len;
    BYTE  rand2[RAND_FL_DATA_LEN];

} NDS_RAND_BYTE_BLOCK, *PNDS_RAND_BYTE_BLOCK;

typedef struct {

    DWORD version;
    DWORD verb;
    DWORD svrRand;
    DWORD credentialLength;

} NDS_AUTH_MSG, *PNDS_AUTH_MSG;

//
// VLM Uses the Tagged Data Store as a sort of registry on the fly.
// We, of course, don't use it, but still need the headers.
//
// We need these to be packed.
//

#include <packon.h>

typedef struct {
    DWORD version;
    WORD tag;
} TAG_DATA_HEADER;

#define TAG_PRIVATE_KEY 2
#define TAG_PUBLIC_KEY  4
#define TAG_CREDENTIAL  6
#define TAG_SIGNATURE   7
#define TAG_PROOF       8

typedef struct {

    TAG_DATA_HEADER tdh;
    DWORD validityBegin;
    DWORD validityEnd;
    DWORD random;
    WORD optDataSize;
    WORD userNameLength;

    // BYTE optData[optDataSize];
    // BYTE userName[userNameLength];

} NDS_CREDENTIAL, *PNDS_CREDENTIAL;

typedef struct {

    TAG_DATA_HEADER tdh;
    WORD signDataLength;

    //BYTE signData[signLength];

} NDS_SIGNATURE, *PNDS_SIGNATURE;

typedef struct {

    TAG_DATA_HEADER tdh;
    WORD keyDataLength;

    //BYTE BsafeKeyData[keyDataLength];

} NDS_PRIVATE_KEY, *PNDS_PRIVATE_KEY;

typedef struct {

    DWORD dwMaxFragSize;
    DWORD dwRequestSize;
    DWORD dwFragmentFlags;
    DWORD dwNdsVerb;
    DWORD dwReplyBufferSize;

} NDS_REQUEST_HEADER, *PNDS_REQUEST_HEADER;

typedef struct {

    DWORD dwFragmentSize;
    DWORD dwFraggerHandle;

} NDS_REPLY_HEADER, *PNDS_REPLY_HEADER;

#include <packoff.h>

typedef struct _NDS_CONTEXT_HEAD {

    //
    // Node id and list entries.
    //

    NODE_TYPE_CODE ntc;
    NODE_BYTE_SIZE nts;

    //
    // We can set this flag if we need to pause
    // all tree activity (like, for a logout).
    //

    BOOLEAN CredentialLocked;

    LIST_ENTRY Next;

    //
    // NDS tree name.  Leave enough room for the munged credential name.
    //

    UNICODE_STRING NdsTreeName;
    WCHAR NdsTreeNameBuffer[NDS_TREE_NAME_LEN + MAX_NDS_NAME_CHARS + 2];

    //
    // User's credentials.
    //

    PNDS_CREDENTIAL Credential;

    //
    // User's signature.
    //

    PNDS_SIGNATURE Signature;

    //
    // Password for this tree connection.
    //

    OEM_STRING Password;

    //
    // User's public key.
    //

    DWORD PublicKeyLen;
    BYTE *PublicNdsKey;

    //
    // The current context for this tree.
    //

    UNICODE_STRING CurrentContext;
    WCHAR CurrentContextString[MAX_NDS_NAME_CHARS];

} NDS_SECURITY_CONTEXT, *PNDS_SECURITY_CONTEXT;

typedef struct _NDS_CHPW_MSG {

    DWORD challenge;
    DWORD oldPwLength;
    BYTE oldPwHash[16];
    DWORD unknown;
    DWORD newPwLength;
    BYTE newPwHash[16];
    ENC_BLOCK_HDR encPrivKeyHdr;

    // BYTE encPrivKey[];

} NDS_CHPW_MSG, *PNDS_CHPW_MSG;

//
// Credential list handling routines.
//

#define NwAcquireExclusiveCredList( pLogon) \
    ExAcquireResourceExclusive( &((pLogon)->CredentialListResource), TRUE )

#define NwAcquireSharedCredList( pLogon ) \
    ExAcquireResourceShared( &((pLogon)->CredentialListResource), TRUE )

#define NwReleaseCredList( pLogon ) \
    ExReleaseResource( &((pLogon)->CredentialListResource) )

#include <packon.h>

typedef struct {

    DWORD verb;
    UINT count;
    char  *bufEnd;
    PVOID nextItem;

} NDS_TAG, *PNDS_TAG;

#include <packoff.h>

typedef struct _nds_list_response {

    DWORD ccode;
    DWORD iterationHandle;
    DWORD numEntries;

    //
    // Followed by an array of these.
    //
    // struct {
    //  DWORD entryId;
    //  DWORD flags;
    //  DWORD subCount;
    //  DWORD modTime;
    //  NDS_STRING BaseClass;
    //  NDS_STRING entryName;
    // } [];
    //

} NDS_LIST_RESPONSE, *PNDS_LIST_RESPONSE;

typedef struct _locked_buffer {

   //
   // Describes a writeable response buffer
   // that we have locked down for the transport.
   //

   PVOID pRecvBufferVa;
   DWORD dwRecvLen;
   PMDL pRecvMdl;
   DWORD dwBytesWritten;

} LOCKED_BUFFER, *PLOCKED_BUFFER;

//
// Some of the response packet formats from ndsapi32.h
//

typedef struct {

    DWORD CompletionCode;
    DWORD RemoteEntry;
    DWORD EntryId;
    DWORD ServerAddresses;
    DWORD AddressType;
    DWORD AddressLength;

    //
    // The address is of length
    // AddressLength, of course.
    //

    BYTE  Address[1];

} NDS_WIRE_RESPONSE_RESOLVE_NAME, *PNDS_WIRE_RESPONSE_RESOLVE_NAME;

typedef struct {

    DWORD CompletionCode;
    DWORD RemoteEntry;
    DWORD EntryId;
    DWORD Unknown;
    DWORD ServerAddresses;
    DWORD AddressType;
    DWORD AddressLength;

    //
    // The address is of length
    // AddressLength, of course.
    //

    BYTE  Address[1];

} NDS_WIRE_RESPONSE_RESOLVE_NAME_REFERRAL,
*PNDS_WIRE_RESPONSE_RESOLVE_NAME_REFERRAL;

//
// Strings for searching ds attributes.
//

#define PUBLIC_KEY_ATTRIBUTE    L"Public Key"
#define VOLUME_ATTRIBUTE        L"Volume"
#define QUEUE_ATTRIBUTE         L"Queue"
#define DIR_MAP_ATTRIBUTE       L"Directory Map"
#define HOST_SERVER_ATTRIBUTE   L"Host Server"
#define HOST_VOLUME_ATTRIBUTE   L"Host Resource Name"
#define HOST_QUEUE_ATTRIBUTE    L"CN"
#define HOST_PATH_ATTRIBUTE     L"Path"
#define NT_GATEWAY_GROUP        L"NTGATEWAY"
#define GROUPS_ATTRIBUTE        L"Group Membership"

//
// Prototypes from ndslogin.c
//

NTSTATUS
NdsCanonUserName(
    IN PNDS_SECURITY_CONTEXT pNdsContext,
    IN PUNICODE_STRING puUserName,
    IN OUT PUNICODE_STRING puCanonUserName
);

NTSTATUS
NdsCheckCredentials(
    IN PIRP_CONTEXT pIrpContext,
    IN PUNICODE_STRING puUserName,
    IN PUNICODE_STRING puPassword
);

NTSTATUS
NdsCheckCredentialsEx(
    IN PIRP_CONTEXT pIrpContext,
    IN PLOGON pLogon,
    IN PNDS_SECURITY_CONTEXT pNdsContext,
    IN PUNICODE_STRING puUserName,
    IN PUNICODE_STRING puPassword
);

#define CREDENTIAL_READ         0
#define CREDENTIAL_WRITE        1

NTSTATUS
NdsLookupCredentials(
    IN PUNICODE_STRING puTreeName,
    IN PLOGON pLogon,
    OUT PNDS_SECURITY_CONTEXT *ppCredentials,
    DWORD dwDesiredAccess,
    BOOLEAN fCreate
);

NTSTATUS
NdsGetCredentials(
    IN PIRP_CONTEXT pIrpContext,
    IN PLOGON pLogon,
    IN PUNICODE_STRING puUserName,
    IN PUNICODE_STRING puPassword
);

NTSTATUS
ChangeNdsPassword(
    PIRP_CONTEXT     pIrpContext,
    DWORD            dwUserOID,
    DWORD            dwChallenge,
    PBYTE            pbOldPwHash,
    PBYTE            pbNewPwHash,
    PNDS_PRIVATE_KEY pUserPrivKey,
    PBYTE            pServerPublicBsafeKey,
    UINT             ServerPubKeyLen
);

NTSTATUS
DoNdsLogon(
    IN PIRP_CONTEXT pIrpContext,
    IN PUNICODE_STRING UserName,
    IN PUNICODE_STRING Password
);

NTSTATUS
NdsTreeLogin(
    IN PIRP_CONTEXT           pIrpContext,
    IN PUNICODE_STRING        puUser,
    IN POEM_STRING            pOemPassword,
    IN POEM_STRING            pOemNewPassword,
    IN PLOGON                 pUserLogon
);

NTSTATUS
BeginLogin(
   IN PIRP_CONTEXT pIrpContext,
   IN DWORD        userId,
   OUT DWORD       *loginId,
   OUT DWORD       *challenge
);

NTSTATUS
FinishLogin(
    IN PIRP_CONTEXT pIrpContext,
    IN DWORD        dwUserOID,
    IN DWORD        dwLoginFlags,
    IN BYTE         pbEncryptedChallenge[16],
    IN BYTE         *pbServerPublicBsafeKey,
    IN int          cbServerPublicBsafeKeyLen,
    OUT BYTE        *pbUserEncPrivateNdsKey,
    OUT int         *pcbUserEncPrivateNdsKeyLen,
    OUT DWORD       *pdwCredentialStartTime,
    OUT DWORD       *pdwCredentialEndTime
);

NTSTATUS
NdsServerAuthenticate(
    IN PIRP_CONTEXT pIrpContext,
    IN PNDS_SECURITY_CONTEXT pNdsContext
);

NTSTATUS BeginAuthenticate(
    IN PIRP_CONTEXT pIrpContext,
    IN DWORD        dwUserId,
    OUT DWORD       *pdwSvrRandom
);

NTSTATUS
NdsLicenseConnection(
    PIRP_CONTEXT pIrpContext
);

NTSTATUS
NdsUnlicenseConnection(
    PIRP_CONTEXT pIrpContext
);

NTSTATUS
NdsLogoff(
    IN PIRP_CONTEXT pIrpContext
);

//
// Prototypes from fragex.c
//

NTSTATUS
FragExWithWait(
    IN PIRP_CONTEXT    pIrpContext,
    IN DWORD           NdsVerb,
    IN PLOCKED_BUFFER  pReplyBuffer,
    IN BYTE            *NdsRequestStr,
    ...
);

int
_cdecl
FormatBuf(
    char *buf,
    int bufLen,
    const char *format,
    va_list args
);

int
_cdecl
FormatBufS(
    char *buf,
    int bufLen,
    const char *format,
    ...
);

//
// Prototypes from ndsfsctl.c
//

NTSTATUS
NdsCreateTreeScb(
    IN PIRP_CONTEXT pIrpContext,
    IN OUT PSCB *ppScb,
    IN PUNICODE_STRING puTree,
    IN PUNICODE_STRING puUserName,
    IN PUNICODE_STRING puPassword,
    IN BOOLEAN DeferredLogon,
    IN BOOLEAN DeleteOnClose
);

NTSTATUS
NdsLookupServerName(
    PSCB pTreeScb,
    PIRP_CONTEXT pIrpContext,
    IPXaddress *pDirServerAddress,
    POEM_STRING pOemServerServerName
);

NTSTATUS
DispatchNds(
    IN ULONG IoctlCode,
    IN PIRP_CONTEXT IrpContext
);

NTSTATUS
PrepareLockedBufferFromFsd(
    PIRP_CONTEXT pIrpContext,
    PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
DoBrowseFsctl( PIRP_CONTEXT pIrpContext,
               ULONG IoctlCode,
               BOOL LockdownBuffer
);

NTSTATUS
ConnectBinderyVolume(
    PIRP_CONTEXT pIrpContext,
    PUNICODE_STRING puServerName,
    PUNICODE_STRING puVolumeName
);

NTSTATUS
HandleVolumeAttach(
    PIRP_CONTEXT pIrpContext,
    PUNICODE_STRING puServerName,
    PUNICODE_STRING puVolumeName
);

NTSTATUS
NdsGetDsObjectFromPath(
    IN PIRP_CONTEXT pIrpContext,
    OUT PUNICODE_STRING puDsObject
);

#define NDS_OBJECTTYPE_VOLUME   1
#define NDS_OBJECTTYPE_QUEUE    2
#define NDS_OBJECTTYPE_DIRMAP   3

NTSTATUS
NdsVerifyObject(
    IN PIRP_CONTEXT pIrpContext,
    IN PUNICODE_STRING puVolumeObject,
    IN BOOLEAN fAllowServerJump,
    IN DWORD dwResolverFlags,
    OUT PDWORD pdwVolumeOid,
    OUT PDWORD pdwObjectType
);

NTSTATUS
NdsMapObjectToServerShare(
    PIRP_CONTEXT pIrpContext,
    PSCB *ppScb,
    PUNICODE_STRING puServerSharePath,
    BOOLEAN CreateTreeConnection,
    PDWORD pdwObjectId
);

NTSTATUS
NdsVerifyContext(
    PIRP_CONTEXT pIrpContext,
    PUNICODE_STRING puTree,
    PUNICODE_STRING puContext
);

NTSTATUS
NdsRawFragex(
    PIRP_CONTEXT pIrpContext
);

NTSTATUS
NdsChangePass(
    PIRP_CONTEXT pIrpContext
);

NTSTATUS
NdsListTrees(
    PIRP_CONTEXT pIrpContext
);

//
// Browsing prototypes from ndsread.c
//

NTSTATUS
NdsGetServerBasicName(
    IN PUNICODE_STRING pServerX500Name,
    IN OUT PUNICODE_STRING pServerName
);

NTSTATUS
NdsCheckGroupMembership(
    PIRP_CONTEXT pIrpContext,
    DWORD dwUserOid,
    PUNICODE_STRING puGroupName
);

NTSTATUS
NdsResolveName(
    IN PIRP_CONTEXT pIrpContext,
    IN PNWR_NDS_REQUEST_PACKET pNdsRequest,
    IN PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
NdsGetObjectInfo(
    IN PIRP_CONTEXT pIrpContext,
    IN PNWR_NDS_REQUEST_PACKET pNdsRequest,
    IN PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
NdsListSubordinates(
    IN PIRP_CONTEXT pIrpContext,
    IN PNWR_NDS_REQUEST_PACKET pNdsRequest,
    IN PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
NdsReadAttributes(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest,
    PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
NdsReadAttributesKm(
    PIRP_CONTEXT pIrpContext,
    DWORD dwObjectId,
    PUNICODE_STRING puAttribute,
    PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
NdsOpenStream(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest
);

NTSTATUS
NdsSetContext(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest
);

NTSTATUS
NdsGetContext(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest
);

NTSTATUS
NdsVerifyTreeHandle(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest
);

NTSTATUS
NdsGetPrintQueueInfo(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest
);

NTSTATUS
NdsGetVolumeInformation(
    PIRP_CONTEXT pIrpContext,
    PNWR_NDS_REQUEST_PACKET pNdsRequest
);

//
// Kernel mode browsing prototypes from ndsread.c
//

NTSTATUS
NdsResolveNameKm (
    PIRP_CONTEXT       pIrpContext,
    IN PUNICODE_STRING puObjectName,
    OUT DWORD          *dwObjectId,
    BOOLEAN            AllowDsJump,
    DWORD              dwFlags
);

NTSTATUS
NdsReadStringAttribute(
    PIRP_CONTEXT        pIrpContext,
    IN DWORD            dwObjectId,
    IN PUNICODE_STRING  puAttributeName,
    OUT PUNICODE_STRING puAttributeVal
);

NTSTATUS
NdsGetServerName(
    IN PIRP_CONTEXT pIrpContext,
    OUT PUNICODE_STRING pUnicodeString
);

NTSTATUS
NdsGetUserName(
    IN PIRP_CONTEXT pIrpContext,
    IN DWORD dwUserOid,
    OUT PUNICODE_STRING puUserName
);

//
// Other helper prototypes from ndsread.c
//

VOID
FreeNdsContext(
    PNDS_SECURITY_CONTEXT pNdsContext
);

VOID
NdsPing(
    IN PIRP_CONTEXT pIrpContext,
    IN PSCB pScb
);

NTSTATUS
NdsSelectConnection(
    PIRP_CONTEXT pIrpContext,
    PUNICODE_STRING puTreeName,
    PUNICODE_STRING puUserName,
    PUNICODE_STRING puPassword,
    BOOL DeferredLogon,
    BOOL UseBinderyConnections,
    PNONPAGED_SCB *ppNpScb
);

NTSTATUS
NdsCompletionCodetoNtStatus(
    IN PLOCKED_BUFFER pLockedBuffer
);

NTSTATUS
NdsReadPublicKey(
    IN PIRP_CONTEXT pIrpContext,
    IN DWORD entryId,
    OUT BYTE *pPubKeyVal,
    IN DWORD *pPubKeyLen
);

int
NdsGetBsafeKey(
    UCHAR       *pPubKey,
    const int   pubKeyLen,
    UCHAR       **ppBsafeKey
);

NTSTATUS
NdsAllocateLockedBuffer(
    PLOCKED_BUFFER NdsRequest,
    DWORD BufferSize
);

NTSTATUS
NdsFreeLockedBuffer(
    PLOCKED_BUFFER NdsRequest
);