diff options
Diffstat (limited to 'private/os2/client/dllnet16.c')
-rw-r--r-- | private/os2/client/dllnet16.c | 5295 |
1 files changed, 5295 insertions, 0 deletions
diff --git a/private/os2/client/dllnet16.c b/private/os2/client/dllnet16.c new file mode 100644 index 000000000..e6d972815 --- /dev/null +++ b/private/os2/client/dllnet16.c @@ -0,0 +1,5295 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + dllnet16.c + +Abstract: + + This module implements 32 bit equivalents of OS/2 V1.21 + LANMAN API Calls. + The APIs are called from 16->32 thunks (i386\doscalls.asm). + +Author: + + Beni Lavi (BeniL) 15-Jan-1992 + +Revision History: + +--*/ + +#define INCL_OS2V20_ERRORS +#define INCL_OS2V20_ERRORMSG +#define INCL_OS2V20_MEMORY +#define INCL_OS2V20_TASKING +#define UNICODE 1 +#include <stdlib.h> +#include "os2dll.h" +#include "os2dll16.h" +#define WIN32_ONLY +#include "netrqust.h" +#include "os2net16.h" +#include <nb30.h> +#include "nb30p.h" +#define APINAMES +#include <apinums.h> // API_W numbers +// #include <rxp.h> // RxpTransactSmb + +#if DBG +extern USHORT Os2DebugTID; +#endif + +// +// some constants +// + +// +// LanMan API related constants +// + +#define LARGE_BUFFER_SIZE 16384 // used for copying large user buffer to internal buffer +#define SMALL_BUFFER_SIZE 4096 // used for copying small user buffer to internal buffer +#define PREFMAXLEN 8192 // parameter used to control internal LanMan buffer size + +// +// Netbios API related constants +// + +#define USERS_STACK_SIZE 4096 // stack size for user's Netbios 3.0 post routine +#define NETBIOS2_SEMANTICS_SIGNATURE 0xF91E0873 // used as a special flag for Net16bios + +/* + We need a hard coded maximum parallel asynch ncbs limit for netbios 2 + requests. The reason is a problem with the NT netbios driver -- Once + you fill up some maximal number (observed - 0xac) of ncbs, and run out + of memory, it is no longer possible to send even a cancel request for + those ncbs. On Os/2 it is still possible to cancel the pending requests. + Some programs try to test the driver's limits by issuing a lot of ncbs, + and when they get an error, they cancel them all. This will fail due to + the above reason. Limiting artificially to a smaller number will allow + the cancel ncbs to go through. Note that if more than one process fills + up the driver at the same time, this per-process limit will not do any good. + Let's hope this situation is unlikely. +*/ +#define MAX_ASYNCH_NCBS 0x80L + + +// +// macro to probe string arguments passed to APIs +// +#define PROBE_STRING(s) ((VOID) ((s) == NULL ? 0 : strlen(s))) + + +// +// Extended NCB to be passed to Win32 Netbios API +// It contains parameters that are needed by the ASYNCH processing +// +typedef struct _NCBX { + NCB n; + PNCB original_pncb; // Original Os/2 program NCB + ULONG original_ncb_post; // Os/2 program 16 bit far pointer post address + // or a semaphore handle to clear + HANDLE Net16BiosHasCompleted; // an event used to sync the post routine with Net16bios +} NCBX, *PNCBX; + + +// +// some important service names for LanMan related APIs +// +static CHAR N_LanmanWorkstati[] = "LanmanWorkstati"; +static CHAR N_LanmanWorkstation[] = "LanmanWorkstation"; +static CHAR N_LanmanServer[] = "LanmanServer"; +static CHAR N_Workstation[] = "Workstation"; +static CHAR N_Server[] = "Server"; + + +// +// netbios related global variables +// + +BOOLEAN Od2Netbios2Initialized = FALSE; // netbios 2 initialization flag +RTL_CRITICAL_SECTION Od2NbSyncCrit; // This CS is used to protect several data structures + // It's initialized/cleanedup from dllnb.c + +// +// Od2LanaEnum holds the permanent enumeration of lana numbers (received from server) +// Od2LanaState is a per-lana flag that has the following value: +// bit 0 -- 1 if the lana is open/0 if the lana is closed +// bit 1 -- 1 if the lana has been opened by this process before/0 if not (and therefore may need a reset thru the server) +// +static LANA_ENUM Od2LanaEnum; +static UCHAR Od2LanaState[MAX_LANA]; +HANDLE Od2NbDev; // handle to NT netbios driver +LONG Od2MaxAsynchNcbs; // a counter for implementing max asynch ncbs limit +PVOID Od2Nb2Heap; // special heap for netbios 2 requests + +// +// a flag indicating if we've already attached the win32 netbios worker thread to our subsystem +// +static BOOLEAN Od2WorkerThreadIsAttached = FALSE; +static SEL Od2UserStackSel, // selector for netbios post routine user's stack + Od2UserStackAlias; // code alias for Od2UserStackSel + + +// imports + +APIRET +DosCreateCSAlias( + IN SEL selDS, + OUT PSEL pselCS + ); + +APIRET +GetSystemDirectoryW( + LPWSTR lpBuffer, + ULONG uSize + ); + +VOID +Od2JumpTo16NetBiosPostDispatcher( + IN PVOID pUsersPostRoutine, // CS:IP format + IN PVOID UserStackFlat, // Flat pointer to user stack + IN USHORT UserStackSize, // User stack size + IN SEL UserStackSel, // Data selector to user stack + IN SEL UserStackAlias, // Code selector to user stack + IN PVOID pNcb, // 16 bit SEG:OFF ptr to NCB + IN UCHAR NcbRetCode // return code from NCB + ); + +APIRET +Od2AttachWinThreadToOs2(VOID); + +UCHAR +Od2Netbios( + IN PNCB pncb, + IN HANDLE hDev, + OUT PBOOLEAN WillPost OPTIONAL + ); + +// +// the following 2 are imported from win32 +// + +LONG +InterlockedIncrement( + PLONG lpAddend + ); + +LONG +InterlockedDecrement( + PLONG lpAddend + ); + + +// +// the following is from net\inc\rxp.h +// +APIRET +RxpTransactSmb( + IN LPTSTR UncServerName, + IN LPTSTR TransportName, + IN LPVOID SendParmPtr, + IN DWORD SendParmSize, + IN LPVOID SendDataPtr OPTIONAL, + IN DWORD SendDataSize, + OUT LPVOID RetParmPtr OPTIONAL, + IN DWORD RetParmSize, + OUT LPVOID RetDataPtr OPTIONAL, + IN OUT LPDWORD RetDataSize, + IN BOOL NoPermissionRequired + ); + +APIRET +VrRemoteApi( + IN DWORD ApiNumber, + IN LPSTR ServerNamePointer, + IN LPSTR ParameterDescriptor, + IN LPSTR DataDescriptor, + IN LPSTR AuxDescriptor, + IN BOOL NullSessionFlag + ); + +APIRET +VrEncryptSES( + IN LPSTR ServerNamePointer, + IN LPSTR passwordPointer, // Input password (Not encripted) + IN LPSTR encryptedLmOwfPassword // output password (encripted) + ); + + + + +//***************************************************************************** +// +//Following are a number of Unicode conversion routines used in the LanMan APIs +// +//***************************************************************************** + + +// +// Get the length of a Unicode string (Adjusted) +// +ULONG +UWstrlen(LPWSTR s) +{ + ULONG i = 0; + + if (s == NULL) { + return(0); + } + + while (*s++ != UNICODE_NULL) { + i++; + } + return(i); +} + + +ULONG +UTstrlen(LPTSTR s) +{ + ULONG i = 0; + + if (s == NULL) { + return(0); + } + + while (*s++ != 0) { + i++; + } + return(i); +} + + +// +// Copy a Unicode string to Ansi string +// +PCHAR +UW2ANSIstrcpy(PCHAR d, LPWSTR s) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = '\0'; + return(d); + } + + RtlInitUnicodeString(&str_u, (PWSTR) s); + + str_a.Buffer = d; + str_a.MaximumLength = 0xffff; + + Od2UnicodeStringToMBString(&str_a, &str_u, FALSE); + + d[str_a.Length] = '\0'; + + return(d); +} + + +PCHAR +UT2ANSIstrcpy(PCHAR d, LPTSTR s) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = '\0'; + return(d); + } + + RtlInitUnicodeString(&str_u, (PWSTR) s); + + str_a.Buffer = d; + str_a.MaximumLength = 0xffff; + + Od2UnicodeStringToMBString(&str_a, &str_u, FALSE); + + d[str_a.Length] = '\0'; + + return(d); +} + + +// +// Copy a Unicode string to Ansi string with a limit on the # of copied chars +// +PCHAR +UW2ANSIstrncpy(PCHAR d, LPWSTR s, ULONG Limit) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = '\0'; + return(d); + } + + RtlInitUnicodeString(&str_u, (PWSTR) s); + + str_a.Buffer = d; + str_a.MaximumLength = (USHORT) Limit; + + if (Od2UnicodeStringToMBString(&str_a, &str_u, FALSE) == NO_ERROR) { + + if ((ULONG) str_a.Length < Limit) { + d[str_a.Length] = '\0'; + } + + } else { + + if (Od2UnicodeStringToMBString(&str_a, &str_u, TRUE) == NO_ERROR) { + + RtlMoveMemory(d, str_a.Buffer, Limit); + Od2FreeMBString(&str_a); + + } else { + d[0] = '\0'; + } + } + + return(d); +} + + +PCHAR +UT2ANSIstrncpy(PCHAR d, LPTSTR s, ULONG Limit) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = '\0'; + return(d); + } + + RtlInitUnicodeString(&str_u, (PWSTR) s); + + str_a.Buffer = d; + str_a.MaximumLength = (USHORT) Limit; + + if (Od2UnicodeStringToMBString(&str_a, &str_u, FALSE) == NO_ERROR) { + + if ((ULONG) str_a.Length < Limit) { + d[str_a.Length] = '\0'; + } + + } else { + + if (Od2UnicodeStringToMBString(&str_a, &str_u, TRUE) == NO_ERROR) { + + RtlMoveMemory(d, str_a.Buffer, Limit); + Od2FreeMBString(&str_a); + + } else { + d[0] = '\0'; + } + } + + return(d); +} + + +// +// Copy an ANSI string to Unicode string +// +LPWSTR +ANSI2UWstrcpy(LPWSTR d, PCHAR s) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = UNICODE_NULL; + return(d); + } + + Od2InitMBString(&str_a, (PCSZ) s); + + str_u.Buffer = (PWSTR) d; + str_u.MaximumLength = 0xffff; + + Od2MBStringToUnicodeString(&str_u, &str_a, FALSE); + + d[str_u.Length/sizeof(WCHAR)] = UNICODE_NULL; + + return(d); +} + + +LPTSTR +ANSI2UTstrcpy(LPTSTR d, PCHAR s) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = UNICODE_NULL; + return(d); + } + + Od2InitMBString(&str_a, (PCSZ) s); + + str_u.Buffer = (PWSTR) d; + str_u.MaximumLength = 0xffff; + + Od2MBStringToUnicodeString(&str_u, &str_a, FALSE); + + d[str_u.Length/sizeof(WCHAR)] = 0; + + return(d); +} + + +// +// Copy an Ansi string to a Unicode string with a limit on the # of copied chars +// +LPWSTR +ANSI2UWstrncpy(LPWSTR d, PCHAR s, ULONG Limit) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = UNICODE_NULL; + return(d); + } + + Od2InitMBString(&str_a, s); + + str_u.Buffer = (PWSTR) d; + str_u.MaximumLength = (USHORT) (Limit * sizeof(WCHAR)); + + if (Od2MBStringToUnicodeString(&str_u, &str_a, FALSE) == NO_ERROR) { + + if (str_u.Length < str_u.MaximumLength) { + d[str_u.Length/sizeof(WCHAR)] = UNICODE_NULL; + } + + } else { + + if (Od2MBStringToUnicodeString(&str_u, &str_a, TRUE) == NO_ERROR) { + + RtlMoveMemory(d, str_u.Buffer, Limit * sizeof(WCHAR)); + RtlFreeUnicodeString(&str_u); + + } else { + d[0] = UNICODE_NULL; + } + } + + return(d); +} + + +LPTSTR +ANSI2UTstrncpy(LPTSTR d, PCHAR s, ULONG Limit) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + *d = 0; + return(d); + } + + Od2InitMBString(&str_a, s); + + str_u.Buffer = (PWSTR) d; + str_u.MaximumLength = (USHORT) (Limit * sizeof(WCHAR)); + + if (Od2MBStringToUnicodeString(&str_u, &str_a, FALSE) == NO_ERROR) { + + if (str_u.Length < str_u.MaximumLength) { + d[str_u.Length/sizeof(WCHAR)] = 0; + } + + } else { + + if (Od2MBStringToUnicodeString(&str_u, &str_a, TRUE) == NO_ERROR) { + + RtlMoveMemory(d, str_u.Buffer, Limit * sizeof(WCHAR)); + RtlFreeUnicodeString(&str_u); + + } else { + d[0] = 0; + } + } + + return(d); +} + + +LPTSTR +ANSI2UTmemcpy(LPTSTR d, PCHAR s, ULONG count) +{ + ANSI_STRING str_a; + UNICODE_STRING str_u; + + if (s == NULL) { + return(d); + } + + str_a.Buffer = s; + str_a.MaximumLength = str_a.Length = (USHORT) count; + + str_u.Buffer = (PWSTR) d; + str_u.MaximumLength = 0xffff; + + Od2MBStringToUnicodeString(&str_u, &str_a, FALSE); + + return(d); +} + + + +//***************************************************************************** +// +//Following are the LanMan API +// +//***************************************************************************** + +// Most LanMan APIs are implemented with the following sequence: +// copy input from user's buffer to internal buffer while convertine ansi to unicode +// call win32 lanman api +// copy output from lanman api internal buffer to user's buffer +// +// for Enum type APIs, a loop is used to get as much data as possible. + + + +// a small macro to copy a string from the internal net buffer to user's buffer +#define CopyUW2ANSI(d, s) \ + StringLen = UWstrlen(s) + 1; \ + CurEndOfBuffer -= StringLen; \ + d = (char *)FLATTOFARPTR(CurEndOfBuffer); \ + UW2ANSIstrcpy(CurEndOfBuffer, s); + + +APIRET +Od2QueryNPHInfo( + HPIPE hpipe, + PULONG pCollectDataTime, + PULONG pMaxCollectionCount + ) +{ + NTSTATUS Status; + APIRET RetCode; + IO_STATUS_BLOCK IoStatusBlock; + PFILE_HANDLE hFileRecord; + FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfoBuf; + LARGE_INTEGER LargeCollectDataTime; + #if DBG + PSZ RoutineName; + RoutineName = "Od2QueryNPHInfo"; + #endif + + AcquireFileLockShared( + #if DBG + RoutineName + #endif + ); + + // + // Check for invalid handle. + // + RetCode = DereferenceFileHandle(hpipe, &hFileRecord); + if (RetCode) { + ReleaseFileLockShared( + #if DBG + RoutineName + #endif + ); + return ERROR_INVALID_HANDLE; + } + + ReleaseFileLockShared( + #if DBG + RoutineName + #endif + ); + + if (hFileRecord->FileType != FILE_TYPE_NMPIPE) { +#if DBG + IF_OD2_DEBUG( PIPES ) { + KdPrint(("DosQueryPNHState: File Type != NMPIPE hpipe %d\n", + hpipe)); + } +#endif + return ERROR_BAD_PIPE; + } + + Status = NtQueryInformationFile(hFileRecord->NtHandle, + &IoStatusBlock, + &PipeRemoteInfoBuf, + sizeof(FILE_PIPE_REMOTE_INFORMATION), + FilePipeRemoteInformation); + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( PIPES ) { + KdPrint(("DosQueryPNHState: NtqueryInformation error: Status %ld\n", + Status)); + } +#endif + return ERROR_BAD_PIPE; // BUGBUG bogus + } + + // + // Translate Information to OS/2 style values + // + + LargeCollectDataTime = RtlExtendedLargeIntegerDivide( + PipeRemoteInfoBuf.CollectDataTime, 10000, NULL); + *pCollectDataTime = LargeCollectDataTime.LowPart; + *pMaxCollectionCount = PipeRemoteInfoBuf.MaximumCollectionCount; + + return (NO_ERROR); +} + + +APIRET +Net16GetDCName( + IN PCHAR pszServer, + IN PCHAR pszDomain, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer + ) +{ + WCHAR Server[UNCLEN]; + WCHAR Domain[DNLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszDomain); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + ANSI2UWstrncpy(Server, pszServer, UNCLEN); + ANSI2UWstrncpy(Domain, pszDomain, DNLEN); + + rc = NetGetDCName(Server, Domain, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + if (UWstrlen((LPWSTR) BufPtr) + 1 > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UW2ANSIstrcpy((PCHAR) pbBuffer, (LPWSTR) BufPtr); + + NetApiBufferFree(BufPtr); + + return(NO_ERROR); +} + + +APIRET +Net16HandleGetInfo( + IN HANDLE hHandle, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + NET_API_STATUS rc; + struct handle_info_1 *pOs2Info1; + ULONG CharTime; + ULONG CharCount; + + if (sLevel != 1) { + return(ERROR_INVALID_PARAMETER); + } + + try { + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + *pcbTotalAvail = sizeof(struct handle_info_1); + if (sizeof(struct handle_info_1) > cbBuffer) { + return(NERR_BufTooSmall); + } + + rc = Od2QueryNPHInfo(hHandle, &CharTime, &CharCount); + if (rc != NO_ERROR) { + return (rc); + } + pOs2Info1 = (struct handle_info_1*)pbBuffer; + pOs2Info1->hdli1_chartime = CharTime; + pOs2Info1->hdli1_charcount = (unsigned short)CharCount; + + return(NO_ERROR); +} + + +APIRET +Net16ServerDiskEnum( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcEntriesRead, + OUT PUSHORT pcTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PWCHAR pInfo; + PCHAR pOs2Info; + ULONG OutBufSize; + DWORD EntriesRead; + DWORD i; + DWORD ResumeHandle; + DWORD TotalEntries; + ULONG StringLen; + int TotalAvailNotSet = TRUE; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1); + Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 0) { + return(ERROR_INVALID_PARAMETER); + } + + OutBufSize = cbBuffer; + ResumeHandle = 0; + pOs2Info = (PCHAR)pbBuffer; + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + rc = ERROR_MORE_DATA; + + while (rc == ERROR_MORE_DATA) { + + rc = NetServerDiskEnum(Server, 0, &BufPtr, PREFMAXLEN, + &EntriesRead, &TotalEntries, &ResumeHandle); + + if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) { + return(rc); + } + + if (TotalAvailNotSet) { + *pcTotalAvail = (USHORT) TotalEntries; + *pcEntriesRead = 0; + TotalAvailNotSet = FALSE; + } + + pInfo = (PWCHAR) BufPtr; + + for (i = 0; i < EntriesRead; i++) { + + StringLen = UWstrlen(pInfo) + 1; + + if ((StringLen + 1) > OutBufSize) { + if (cbBuffer > 0) { // if 0 length buffer, unable to return anything + *pOs2Info = '\0'; // The terminating NUL + } + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= StringLen; + + UW2ANSIstrcpy(pOs2Info, pInfo); + + pOs2Info += strlen(pOs2Info) + 1; + pInfo += StringLen; + + (*pcEntriesRead)++; + } + *pOs2Info = '\0'; // The terminating NUL + NetApiBufferFree(BufPtr); + } + + return(rc); +} + + +APIRET +Net16ServerEnum2( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcEntriesRead, + OUT PUSHORT pcTotalAvail, + IN ULONG flServerType, + IN PCHAR pszDomain + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Domain[CNLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSERVER_INFO_101 pInfo101; + struct server_info_0 *pOs2Info0; + struct server_info_1 *pOs2Info1; + PCHAR pEndOfBuffer; + ULONG StringLen; + DWORD ResumeHandle; + ULONG OutBufSize; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD i; + int TotalAvailNotSet = TRUE; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszDomain); + Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1); + Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1)) { + return(ERROR_INVALID_PARAMETER); + } + + pEndOfBuffer = pbBuffer + cbBuffer; + OutBufSize = cbBuffer; + ResumeHandle = 0; + pOs2Info0 = (struct server_info_0 *)pbBuffer; + pOs2Info1 = (struct server_info_1 *)pbBuffer; + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(Domain, pszDomain, CNLEN); + rc = ERROR_MORE_DATA; + + while (rc == ERROR_MORE_DATA) { + + rc = NetServerEnum(Server, 101L, &BufPtr, PREFMAXLEN, + &EntriesRead, &TotalEntries, + flServerType, Domain, &ResumeHandle); + + if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) { + return(rc); + } + + if (TotalAvailNotSet) { + *pcTotalAvail = (USHORT) TotalEntries; + *pcEntriesRead = 0; + TotalAvailNotSet = FALSE; + } + + pInfo101 = (PSERVER_INFO_101) BufPtr; + + for (i = 0; i < EntriesRead; i++) { + if (sLevel == 0) { + if (sizeof(struct server_info_0) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct server_info_0); + + UT2ANSIstrncpy(pOs2Info0->sv0_name, (pInfo101 + i)->sv101_name, CNLEN_LM20); + pOs2Info0->sv0_name[CNLEN_LM20] = '\0'; + pOs2Info0++; + } + else if (sLevel == 1) { + StringLen = UTstrlen((pInfo101 + i)->sv101_comment) + 1; + if ((sizeof(struct server_info_1) + StringLen) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct server_info_1) + StringLen; + + UT2ANSIstrncpy(pOs2Info1->sv1_name, (pInfo101 + i)->sv101_name, CNLEN_LM20); + pOs2Info1->sv1_name[CNLEN_LM20] = '\0'; + pEndOfBuffer -= StringLen; + UT2ANSIstrcpy(pEndOfBuffer, (pInfo101 + i)->sv101_comment); + pOs2Info1->sv1_comment = (char *)FLATTOFARPTR(pEndOfBuffer); + + pOs2Info1->sv1_version_major = (unsigned char)(pInfo101 + i)->sv101_version_major; + pOs2Info1->sv1_version_minor = (unsigned char)(pInfo101 + i)->sv101_version_minor; + pOs2Info1->sv1_type = (pInfo101 + i)->sv101_type; + pOs2Info1++; + } + (*pcEntriesRead)++; + } + + NetApiBufferFree(BufPtr); + } + + return(rc); +} + + +APIRET +Net16ServerGetInfo( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + LPBYTE BufPtr1; + LPBYTE BufPtr2; + NET_API_STATUS rc; + PSERVER_INFO_102 pInfo102; + PSERVER_INFO_502 pInfo502; + struct server_info_0 *pOs2Info0; + struct server_info_1 *pOs2Info1; + struct server_info_2 *pOs2Info2; + struct server_info_3 *pOs2Info3; + PCHAR pStrings; + PCHAR pEndOfBuffer; + ULONG StringLen; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel > 3) { +#if DBG + KdPrint(("NetServerGetInfo: non supported sLevel %d\n", sLevel)); +#endif + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + rc = NetServerGetInfo(Server, 102L, &BufPtr1); + + if (rc != NO_ERROR) { + return(rc); + } + + rc = NetServerGetInfo(Server, 502L, &BufPtr2); + + if (rc != NO_ERROR) { + NetApiBufferFree(BufPtr1); + return(rc); + } + + RtlZeroMemory(pbBuffer, cbBuffer); + pInfo102 = (PSERVER_INFO_102) BufPtr1; + pInfo502 = (PSERVER_INFO_502) BufPtr2; + pEndOfBuffer = pbBuffer + cbBuffer; + pOs2Info0 = (struct server_info_0 *)pbBuffer; + pOs2Info1 = (struct server_info_1 *)pbBuffer; + pOs2Info2 = (struct server_info_2 *)pbBuffer; + pOs2Info3 = (struct server_info_3 *)pbBuffer; + + switch (sLevel) { + + case 0: + + *pcbTotalAvail = (USHORT)(sizeof(struct server_info_0)); + if (sizeof(struct server_info_0) > cbBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + break; + + case 1: + + pStrings = pbBuffer + sizeof(struct server_info_1); + + StringLen = UTstrlen(pInfo102->sv102_comment) + 1; + *pcbTotalAvail = (USHORT)(StringLen + sizeof(struct server_info_1)); + if (pStrings + StringLen > pEndOfBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + break; + + case 2: + + pStrings = pbBuffer + sizeof(struct server_info_2); + + StringLen = UTstrlen(pInfo102->sv102_userpath) + 1; + *pcbTotalAvail = (USHORT)(StringLen + sizeof(struct server_info_2)); + if (pStrings + StringLen > pEndOfBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + break; + + case 3: + + pStrings = pbBuffer + sizeof(struct server_info_3); + + StringLen = UTstrlen(pInfo102->sv102_userpath) + 1; + *pcbTotalAvail = (USHORT)(StringLen + sizeof(struct server_info_3)); + if (pStrings + StringLen > pEndOfBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + break; + } + + switch (sLevel) { + + case 3: + + /* + pOs2Info3->sv3_auditedevents = pInfo403->sv403_auditedevents; + pOs2Info3->sv3_autoprofile = (unsigned short)pInfo403->sv403_autoprofile; + + StringLen = UTstrlen(pInfo403->sv403_autopath) + 1; + UT2ANSIstrcpy(pStrings, pInfo403->sv403_autopath); + pOs2Info3->sv3_autopath = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + */ + + case 2: + + /* + pOs2Info2->sv2_ulist_mtime = pInfo403->sv403_ulist_mtime; + pOs2Info2->sv2_glist_mtime = pInfo403->sv403_glist_mtime; + pOs2Info2->sv2_alist_mtime = pInfo403->sv403_alist_mtime; + */ + pOs2Info2->sv2_users = (unsigned short)pInfo102->sv102_users; + pOs2Info2->sv2_disc = (unsigned short)pInfo102->sv102_disc; + + /* + StringLen = UTstrlen(pInfo403->sv403_alerts) + 1; + UT2ANSIstrcpy(pStrings, pInfo403->sv403_alerts); + pOs2Info2->sv2_alerts = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + pOs2Info2->sv2_security = (unsigned short)pInfo403->sv403_security; + pOs2Info2->sv2_auditing = 0; + pOs2Info2->sv2_numadmin = (unsigned short)pInfo403->sv403_numadmin; + pOs2Info2->sv2_lanmask = (unsigned short)pInfo403->sv403_lanmask; + */ + pOs2Info2->sv2_hidden = (unsigned short)pInfo102->sv102_hidden; + pOs2Info2->sv2_announce = (unsigned short)pInfo102->sv102_announce; + pOs2Info2->sv2_anndelta = (unsigned short)pInfo102->sv102_anndelta; + + /* + UT2ANSIstrncpy(pOs2Info2->sv2_guestacct, pInfo403->sv403_guestacct, UNLEN_LM20); + pOs2Info2->sv2_guestacct[UNLEN_LM20] = '\0'; + */ + + StringLen = UTstrlen(pInfo102->sv102_userpath) + 1; + UT2ANSIstrcpy(pStrings, pInfo102->sv102_userpath); + pOs2Info2->sv2_userpath = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + +// PQPQ pOs2Info2->sv2_chdevs = (unsigned short)pInfo403->sv403_chdevs; + pOs2Info2->sv2_chdevs = 100; + /* + pOs2Info2->sv2_chdevq = (unsigned short)pInfo403->sv403_chdevq; + pOs2Info2->sv2_chdevjobs = (unsigned short)pInfo403->sv403_chdevjobs; + pOs2Info2->sv2_connections = (unsigned short)pInfo403->sv403_connections; + pOs2Info2->sv2_shares = (unsigned short)pInfo403->sv403_shares; + pOs2Info2->sv2_openfiles = (unsigned short)pInfo403->sv403_openfiles; + */ + pOs2Info2->sv2_sessopens = (unsigned short)pInfo502->sv502_sessopens; + pOs2Info2->sv2_sessvcs = (unsigned short)pInfo502->sv502_sessvcs; + /* + pOs2Info2->sv2_sessreqs = (unsigned short)pInfo403->sv403_sessreqs; + */ + pOs2Info2->sv2_opensearch = (unsigned short)pInfo502->sv502_opensearch; + /* + pOs2Info2->sv2_activelocks = (unsigned short)pInfo403->sv403_activelocks; + pOs2Info2->sv2_numreqbuf = (unsigned short)pInfo403->sv403_numreqbuf; + */ + pOs2Info2->sv2_sizreqbuf = (unsigned short)pInfo502->sv502_sizreqbuf; + /* + pOs2Info2->sv2_numbigbuf = (unsigned short)pInfo403->sv403_numbigbuf; + pOs2Info2->sv2_numfiletasks= (unsigned short)pInfo403->sv403_numfiletasks; + pOs2Info2->sv2_alertsched = (unsigned short)pInfo403->sv403_alertsched; + pOs2Info2->sv2_erroralert = (unsigned short)pInfo403->sv403_erroralert; + pOs2Info2->sv2_logonalert = (unsigned short)pInfo403->sv403_logonalert; + pOs2Info2->sv2_accessalert = (unsigned short)pInfo403->sv403_accessalert; + pOs2Info2->sv2_diskalert = (unsigned short)pInfo403->sv403_diskalert; + pOs2Info2->sv2_netioalert = (unsigned short)pInfo403->sv403_netioalert; + pOs2Info2->sv2_maxauditsz = (unsigned short)pInfo403->sv403_maxauditsz; + + StringLen = UTstrlen(pInfo403->sv403_srvheuristics) + 1; + UT2ANSIstrcpy(pStrings, pInfo403->sv403_srvheuristics); + pOs2Info2->sv2_srvheuristics = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + */ + + case 1: + + StringLen = UTstrlen(pInfo102->sv102_comment) + 1; + UT2ANSIstrcpy(pStrings, pInfo102->sv102_comment); + pOs2Info1->sv1_comment = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + pOs2Info1->sv1_version_major = (unsigned char)pInfo102->sv102_version_major; + pOs2Info1->sv1_version_minor = (unsigned char)pInfo102->sv102_version_minor; + pOs2Info1->sv1_type = (unsigned long)pInfo102->sv102_type; + + case 0: + + UT2ANSIstrncpy(pOs2Info0->sv0_name, pInfo102->sv102_name, CNLEN_LM20); + pOs2Info0->sv0_name[CNLEN_LM20] = '\0'; + break; + } + + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + + return(NO_ERROR); +} + + +APIRET +Net16ServiceControl( + IN PCHAR pszServer, + IN PCHAR pszService, + IN ULONG fbOpCode, + IN ULONG fbArg, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Service[SNLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSERVICE_INFO_2 pInfo2; + struct service_info_2 *pOs2Info2; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszService); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + // OS/2 services are limited to 15 chars + // workaround an important NT service whose name is longer than 15 chars + + if (!_stricmp(pszService, N_Workstation)) { + ANSI2UTstrcpy(Service, N_LanmanWorkstation); + } + if (!_stricmp(pszService, N_Server)) { + ANSI2UTstrcpy(Service, N_LanmanServer); + } + else { + ANSI2UTstrncpy(Service, pszService, SNLEN); + } + + rc = NetServiceControl(Server, Service, fbOpCode, fbArg, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + if (sizeof(struct service_info_2) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + pInfo2 = (PSERVICE_INFO_2) BufPtr; + pOs2Info2 = (struct service_info_2 *)pbBuffer; + UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20); + pOs2Info2->svci2_name[SNLEN_LM20] = '\0'; + if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Workstation); + } + else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Server); + } + UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20); + pOs2Info2->svci2_text[STXTLEN_LM20] = '\0'; + pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status; + pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code; + pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid; + + NetApiBufferFree(BufPtr); + + return(NO_ERROR); +} + + +APIRET +Net16ServiceEnum( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcEntriesRead, + OUT PUSHORT pcTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSERVICE_INFO_0 pInfo0; + PSERVICE_INFO_1 pInfo1; + PSERVICE_INFO_2 pInfo2; + struct service_info_0 *pOs2Info0; + struct service_info_1 *pOs2Info1; + struct service_info_2 *pOs2Info2; + DWORD ResumeHandle; + ULONG OutBufSize; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD i; + int TotalAvailNotSet = TRUE; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1); + Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2)) { + return(ERROR_INVALID_PARAMETER); + } + + OutBufSize = cbBuffer; + ResumeHandle = 0; + pOs2Info0 = (struct service_info_0 *)pbBuffer; + pOs2Info1 = (struct service_info_1 *)pbBuffer; + pOs2Info2 = (struct service_info_2 *)pbBuffer; + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + rc = ERROR_MORE_DATA; + + while (rc == ERROR_MORE_DATA) { + + rc = NetServiceEnum(Server, sLevel, &BufPtr, PREFMAXLEN, + &EntriesRead, &TotalEntries, &ResumeHandle); + + if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) { + return(rc); + } + + if (TotalAvailNotSet) { + *pcTotalAvail = (USHORT) TotalEntries; + *pcEntriesRead = 0; + TotalAvailNotSet = FALSE; + } + + for (i = 0; i < EntriesRead; i++) { + if (sLevel == 0) { + if (sizeof(struct service_info_0) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct service_info_0); + + pInfo0 = (PSERVICE_INFO_0) BufPtr + i; + UT2ANSIstrncpy(pOs2Info0->svci0_name, pInfo0->svci0_name, SNLEN_LM20); + pOs2Info0->svci0_name[SNLEN_LM20] = '\0'; + if (!_stricmp(N_LanmanWorkstati, pOs2Info0->svci0_name)) { + strcpy(pOs2Info0->svci0_name, N_Workstation); + } + else if (!_stricmp(N_LanmanServer, pOs2Info0->svci0_name)) { + strcpy(pOs2Info0->svci0_name, N_Server); + } + + pOs2Info0++; + } + else if (sLevel == 1) { + if (sizeof(struct service_info_1) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct service_info_1); + + pInfo1 = (PSERVICE_INFO_1) BufPtr + i; + UT2ANSIstrncpy(pOs2Info1->svci1_name, pInfo1->svci1_name, SNLEN_LM20); + pOs2Info1->svci1_name[SNLEN_LM20] = '\0'; + if (!_stricmp(N_LanmanWorkstati, pOs2Info1->svci1_name)) { + strcpy(pOs2Info1->svci1_name, N_Workstation); + } + else if (!_stricmp(N_LanmanServer, pOs2Info1->svci1_name)) { + strcpy(pOs2Info1->svci1_name, N_Server); + } + + pOs2Info1->svci1_status = (unsigned short)pInfo1->svci1_status; + pOs2Info1->svci1_code = (unsigned long)pInfo1->svci1_code; + pOs2Info1->svci1_pid = (unsigned short)pInfo1->svci1_pid; + + pOs2Info1++; + } + else { /* sLevel == 2 */ + if (sizeof(struct service_info_2) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct service_info_2); + + pInfo2 = (PSERVICE_INFO_2) BufPtr + i; + UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20); + pOs2Info2->svci2_name[SNLEN_LM20] = '\0'; + if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Workstation); + } + else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Server); + } + + pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status; + pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code; + pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid; + + UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20); + pOs2Info2->svci2_name[STXTLEN_LM20] = '\0'; + + pOs2Info2++; + } + (*pcEntriesRead)++; + } + + NetApiBufferFree(BufPtr); + } + + return(NO_ERROR); +} + + +APIRET +Net16ServiceGetInfo( + IN PCHAR pszServer, + IN PCHAR pszService, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Service[SNLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSERVICE_INFO_2 pInfo2; + struct service_info_2 *pOs2Info2; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszService); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2)) { + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + // OS/2 services are limited to 15 chars + // workaround an important NT service whose name is longer than 15 chars + + if (!_stricmp(pszService, N_Workstation)) { + ANSI2UTstrcpy(Service, N_LanmanWorkstation); + } + if (!_stricmp(pszService, N_Server)) { + ANSI2UTstrcpy(Service, N_LanmanServer); + } + else { + ANSI2UTstrncpy(Service, pszService, SNLEN); + } + + rc = NetServiceGetInfo(Server, Service, 2L, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + pOs2Info2 = (struct service_info_2 *)pbBuffer; + pInfo2 = (PSERVICE_INFO_2) BufPtr; + + switch (sLevel) { + case 0: + *pcbTotalAvail = (USHORT)sizeof(struct service_info_0); + break; + + case 1: + *pcbTotalAvail = (USHORT)sizeof(struct service_info_1); + break; + + case 2: + *pcbTotalAvail = (USHORT)sizeof(struct service_info_2); + break; + } + + if (sizeof(struct service_info_0) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20); + pOs2Info2->svci2_name[SNLEN_LM20] = '\0'; + if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Workstation); + } + else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Server); + } + + if (sLevel >= 1) { + if (sizeof(struct service_info_1) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status; + pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code; + pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid; + } + + if (sLevel >= 2) { + if (sizeof(struct service_info_2) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20); + pOs2Info2->svci2_text[STXTLEN_LM20] = '\0'; + } + + NetApiBufferFree(BufPtr); + + return(NO_ERROR); +} + + +APIRET +Net16ServiceInstall( + IN PCHAR pszServer, + IN PCHAR pszService, + IN PCHAR pszCmdArgs, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Service[SNLEN]; + TCHAR *CmdArgs; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSERVICE_INFO_2 pInfo2; + struct service_info_2 *pOs2Info2; + DWORD Argc; + DWORD TotalSizeOfStrings; + PCHAR pStrings; + PCHAR pszTmpCmdArgs; + LPTSTR StartOfString; + ULONG i; + LPTSTR Argv[64]; + + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszService); + PROBE_STRING(pszCmdArgs); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sizeof(struct service_info_2) > cbBuffer) { + return(NERR_BufTooSmall); + } + + pOs2Info2 = (struct service_info_2 *)pbBuffer; + + if (pszCmdArgs == NULL) { + pszTmpCmdArgs = ""; + } + else { + pszTmpCmdArgs = pszCmdArgs; + } + + Argc = 0; + pStrings = pszTmpCmdArgs; + + while (*pStrings) { + pStrings += strlen(pStrings) + 1; + Argc++; + } + pStrings++; // for the terminating nul character + + if (Argc > 64) { + return(ERROR_ACCESS_DENIED); + } + + TotalSizeOfStrings = pStrings - pszTmpCmdArgs; + + CmdArgs = (TCHAR *) RtlAllocateHeap(Od2Heap, 0, TotalSizeOfStrings * sizeof(TCHAR)); + + if (CmdArgs == NULL) { + return(ERROR_NOT_ENOUGH_MEMORY); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + // OS/2 services are limited to 15 chars + // workaround an important NT service whose name is longer than 15 chars + + if (!_stricmp(pszService, N_Workstation)) { + ANSI2UTstrcpy(Service, N_LanmanWorkstation); + } + if (!_stricmp(pszService, N_Server)) { + ANSI2UTstrcpy(Service, N_LanmanServer); + } + else { + ANSI2UTstrncpy(Service, pszService, SNLEN); + } + + ANSI2UTmemcpy(CmdArgs, pszTmpCmdArgs, TotalSizeOfStrings); + + StartOfString = CmdArgs; + for (i = 0; i < Argc; i++) { + Argv[i] = StartOfString; + while (*StartOfString++ != L'\0') { + ; + } + } + + rc = NetServiceInstall(Server, Service, Argc, Argv, &BufPtr); + + RtlFreeHeap(Od2Heap, 0, CmdArgs); + + if (rc != NO_ERROR) { + return(rc); + } + + pInfo2 = (PSERVICE_INFO_2) BufPtr; + + UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20); + pOs2Info2->svci2_name[SNLEN_LM20] = '\0'; + if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Workstation); + } + else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) { + strcpy(pOs2Info2->svci2_name, N_Server); + } + pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status; + pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code; + pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid; + UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20); + pOs2Info2->svci2_text[STXTLEN_LM20] = '\0'; + + NetApiBufferFree(BufPtr); + + return(NO_ERROR); +} + + +APIRET +Net16ShareEnum( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcEntriesRead, + OUT PUSHORT pcTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSHARE_INFO_2 pInfo2; + struct share_info_0 *pOs2Info0; + struct share_info_1 *pOs2Info1; + struct share_info_2 *pOs2Info2; + PCHAR pEndOfBuffer; + ULONG StringLen; + DWORD ResumeHandle; + ULONG OutBufSize; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD i; + int TotalAvailNotSet = TRUE; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1); + Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2)) { + return(ERROR_INVALID_PARAMETER); + } + + pEndOfBuffer = pbBuffer + cbBuffer; + OutBufSize = cbBuffer; + ResumeHandle = 0; + pOs2Info0 = (struct share_info_0 *)pbBuffer; + pOs2Info1 = (struct share_info_1 *)pbBuffer; + pOs2Info2 = (struct share_info_2 *)pbBuffer; + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + rc = ERROR_MORE_DATA; + + while (rc == ERROR_MORE_DATA) { + + rc = NetShareEnum(Server, 2L, &BufPtr, PREFMAXLEN, + &EntriesRead, &TotalEntries, &ResumeHandle); + + if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) { + return(rc); + } + + if (TotalAvailNotSet) { + *pcTotalAvail = (USHORT) TotalEntries; + *pcEntriesRead = 0; + TotalAvailNotSet = FALSE; + } + + for (i = 0; i < EntriesRead; i++) { + pInfo2 = (PSHARE_INFO_2) BufPtr + i; + if (sLevel == 0) { + if (sizeof(struct share_info_0) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct share_info_0); + + UT2ANSIstrncpy(pOs2Info0->shi0_netname, pInfo2->shi2_netname, NNLEN_LM20); + pOs2Info0->shi0_netname[NNLEN_LM20] = '\0'; + pOs2Info0++; + } + else if (sLevel == 1) { + StringLen = UTstrlen(pInfo2->shi2_remark) + 1; + if ((sizeof(struct share_info_1) + StringLen) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct share_info_1) + StringLen; + + UT2ANSIstrncpy(pOs2Info1->shi1_netname, pInfo2->shi2_netname, NNLEN_LM20); + pOs2Info1->shi1_netname[NNLEN_LM20] = '\0'; + pEndOfBuffer -= StringLen; + UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark); + pOs2Info1->shi1_remark = (char *)FLATTOFARPTR(pEndOfBuffer); + + pOs2Info1->shi1_type = (unsigned short)pInfo2->shi2_type; + pOs2Info1++; + } + else { + StringLen = UTstrlen(pInfo2->shi2_remark) + 1 + + UTstrlen(pInfo2->shi2_path) + 1 ; + if ((sizeof(struct share_info_2) + StringLen) > OutBufSize) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + OutBufSize -= sizeof(struct share_info_2) + StringLen; + + UT2ANSIstrncpy(pOs2Info2->shi2_netname, pInfo2->shi2_netname, NNLEN_LM20); + pOs2Info2->shi2_netname[NNLEN_LM20] = '\0'; + UT2ANSIstrncpy(pOs2Info2->shi2_passwd, pInfo2->shi2_passwd, SHPWLEN_LM20); + pOs2Info2->shi2_passwd[SHPWLEN_LM20] = '\0'; + pEndOfBuffer -= UTstrlen(pInfo2->shi2_remark) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark); + pOs2Info2->shi2_remark = (char *)FLATTOFARPTR(pEndOfBuffer); + pEndOfBuffer -= UTstrlen(pInfo2->shi2_path) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_path); + pOs2Info2->shi2_path = (char *)FLATTOFARPTR(pEndOfBuffer); + + pOs2Info2->shi2_type = (unsigned short)pInfo2->shi2_type; + pOs2Info2->shi2_permissions = (unsigned short)pInfo2->shi2_permissions; + pOs2Info2->shi2_max_uses = (unsigned short)pInfo2->shi2_max_uses; + pOs2Info2->shi2_current_uses = (unsigned short)pInfo2->shi2_current_uses; + pOs2Info2++; + } + (*pcEntriesRead)++; + } + + NetApiBufferFree(BufPtr); + } + + return(NO_ERROR); +} + + +APIRET +Net16ShareGetInfo( + IN PCHAR pszServer, + IN PCHAR pszNetName, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + TCHAR NetName[NNLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PSHARE_INFO_2 pInfo2; + PCHAR pEndOfBuffer; + ULONG TotalStringLen; + ULONG StringLen; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszNetName); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 3)) { + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(NetName, pszNetName, NNLEN); + + rc = NetShareGetInfo(Server, NetName, 2L, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + pEndOfBuffer = pbBuffer; + pInfo2 = (PSHARE_INFO_2) BufPtr; + + if (sLevel == 0) { + struct share_info_0 *pOs2Info0; + + *pcbTotalAvail = (USHORT)sizeof(struct share_info_0); + if (sizeof(struct share_info_0) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + pOs2Info0 = (struct share_info_0 *)pbBuffer; + UT2ANSIstrncpy(pOs2Info0->shi0_netname, pInfo2->shi2_netname, NNLEN_LM20); + pOs2Info0->shi0_netname[NNLEN_LM20] = '\0'; + } + else if (sLevel == 1) { + struct share_info_1 *pOs2Info1; + + TotalStringLen = UTstrlen(pInfo2->shi2_remark) + 1; + *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct share_info_1)); + if ((sizeof(struct share_info_1) + TotalStringLen) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + pOs2Info1 = (struct share_info_1 *)pbBuffer; + UT2ANSIstrncpy(pOs2Info1->shi1_netname, pInfo2->shi2_netname, NNLEN_LM20); + pOs2Info1->shi1_netname[NNLEN_LM20] = '\0'; + pEndOfBuffer += sizeof(struct share_info_1); + StringLen = UTstrlen(pInfo2->shi2_remark) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark); + pOs2Info1->shi1_remark = (char *)FLATTOFARPTR(pEndOfBuffer); + pEndOfBuffer += StringLen; + + pOs2Info1->shi1_type = (unsigned short)pInfo2->shi2_type; + } + else { + struct share_info_2 *pOs2Info2; + + TotalStringLen = UTstrlen(pInfo2->shi2_remark) + 1 + + UTstrlen(pInfo2->shi2_path) + 1 ; + *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct share_info_2)); + if ((sizeof(struct share_info_2) + TotalStringLen) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + pOs2Info2 = (struct share_info_2 *)pbBuffer; + UT2ANSIstrncpy(pOs2Info2->shi2_netname, pInfo2->shi2_netname, NNLEN_LM20); + pOs2Info2->shi2_netname[NNLEN_LM20] = '\0'; + UT2ANSIstrncpy(pOs2Info2->shi2_passwd, pInfo2->shi2_passwd, SHPWLEN_LM20); + pOs2Info2->shi2_passwd[SHPWLEN_LM20] = '\0'; + pEndOfBuffer += sizeof(struct share_info_2); + StringLen = UTstrlen(pInfo2->shi2_remark) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark); + pOs2Info2->shi2_remark = (char *)FLATTOFARPTR(pEndOfBuffer); + pEndOfBuffer += StringLen; + StringLen = UTstrlen(pInfo2->shi2_path) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_path); + pOs2Info2->shi2_path = (char *)FLATTOFARPTR(pEndOfBuffer); + pEndOfBuffer += StringLen; + + pOs2Info2->shi2_type = (unsigned short)pInfo2->shi2_type; + pOs2Info2->shi2_permissions = (unsigned short)pInfo2->shi2_permissions; + pOs2Info2->shi2_max_uses = (unsigned short)pInfo2->shi2_max_uses; + pOs2Info2->shi2_current_uses = (unsigned short)pInfo2->shi2_current_uses; + } + + NetApiBufferFree(BufPtr); + + return(NO_ERROR); +} + + +APIRET +Net16UseAdd( + IN PCHAR pszServer, + IN LONG sLevel, + IN PCHAR pbBuffer, + IN ULONG cbBuffer + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Local[DEVLEN]; + TCHAR Remote[RMLEN]; + TCHAR Password[PWLEN]; + USE_INFO_1 Info1; + struct use_info_1 *pInfo1; + + try { + PROBE_STRING(pszServer); + Od2ProbeForRead(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 1) { + return(ERROR_INVALID_PARAMETER); + } + + if (cbBuffer < sizeof(struct use_info_1)) { + return(NERR_BufTooSmall); + } + + pInfo1 = (struct use_info_1 *) pbBuffer; + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(Local, pInfo1->ui1_local, DEVLEN); + Info1.ui1_local = Local; + ANSI2UTstrncpy(Remote, FARPTRTOFLAT(pInfo1->ui1_remote), RMLEN); + Info1.ui1_remote = Remote; + + if (pInfo1->ui1_password == NULL) { + Info1.ui1_password = NULL; + } + else { + ANSI2UTstrncpy(Password, FARPTRTOFLAT(pInfo1->ui1_password), PWLEN); + Info1.ui1_password = Password; + } + + Info1.ui1_status = pInfo1->ui1_status; + Info1.ui1_asg_type = pInfo1->ui1_asg_type; + Info1.ui1_refcount = pInfo1->ui1_refcount; + Info1.ui1_usecount = pInfo1->ui1_usecount; + + return (NetUseAdd(Server, sLevel, (LPBYTE)&Info1, NULL)); +} + + +APIRET +Net16UseDel( + IN PCHAR pszServer, + IN PCHAR pszUseName, + IN ULONG usForce + ) +{ + TCHAR Server[UNCLEN]; + TCHAR UseName[RMLEN]; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszUseName); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(UseName, pszUseName, RMLEN); + + return (NetUseDel(Server, UseName, usForce)); +} + + +APIRET +Net16UseEnum( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcEntriesRead, + OUT PUSHORT pcTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + struct use_info_0 *pOs2Info0; + struct use_info_1 *pOs2Info1; + PUSE_INFO_0 pInfo0; + PUSE_INFO_1 pInfo1; + DWORD EntriesRead; + DWORD ResumeHandle; + DWORD TotalAvail; + DWORD i; + ULONG RemoteNameLen; + ULONG PasswordNameLen; + PCHAR CurEndOfBuffer; + ULONG OutBufSize; + int TotalAvailNotSet = TRUE; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1); + Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1)) { + return(ERROR_INVALID_PARAMETER); + } + + OutBufSize = cbBuffer; + CurEndOfBuffer = pbBuffer + cbBuffer; + pOs2Info0 = (struct use_info_0 *)pbBuffer; + pOs2Info1 = (struct use_info_1 *)pbBuffer; + + ResumeHandle = 0; + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + rc = ERROR_MORE_DATA; + + while (rc == ERROR_MORE_DATA) { + + rc = NetUseEnum(Server, sLevel, &BufPtr, PREFMAXLEN, + &EntriesRead, &TotalAvail, &ResumeHandle); + + if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) { + return(rc); + } + + if (TotalAvailNotSet) { + *pcTotalAvail = (USHORT) TotalAvail; + *pcEntriesRead = 0; + TotalAvailNotSet = FALSE; + } + + for (i = 0; i < EntriesRead; i++) { + if (sLevel == 0) { + pInfo0 = (PUSE_INFO_0) BufPtr + i; + RemoteNameLen = UTstrlen(pInfo0->ui0_remote) + 1; + if ((sizeof(struct use_info_0) + RemoteNameLen) > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= sizeof(struct use_info_0) + RemoteNameLen; + UT2ANSIstrncpy(pOs2Info0->ui0_local, pInfo0->ui0_local, DEVLEN_LM20); + pOs2Info0->ui0_local[DEVLEN_LM20] = '\0'; + CurEndOfBuffer -= RemoteNameLen; + UT2ANSIstrcpy(CurEndOfBuffer, pInfo0->ui0_remote); + pOs2Info0->ui0_remote = (char *)FLATTOFARPTR(CurEndOfBuffer); + + pOs2Info0++; + } + else { + pInfo1 = (PUSE_INFO_1) BufPtr + i; + RemoteNameLen = UTstrlen(pInfo1->ui1_remote) + 1; + PasswordNameLen = UTstrlen(pInfo1->ui1_password) + 1; + if ((sizeof(struct use_info_1) + RemoteNameLen + PasswordNameLen) > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= sizeof(struct use_info_1) + RemoteNameLen + PasswordNameLen; + UT2ANSIstrncpy(pOs2Info1->ui1_local, pInfo1->ui1_local, DEVLEN_LM20); + pOs2Info1->ui1_local[DEVLEN_LM20] = '\0'; + CurEndOfBuffer -= RemoteNameLen; + UT2ANSIstrcpy(CurEndOfBuffer, pInfo1->ui1_remote); + pOs2Info1->ui1_remote = (char *)FLATTOFARPTR(CurEndOfBuffer); + CurEndOfBuffer -= PasswordNameLen; + UT2ANSIstrcpy(CurEndOfBuffer, pInfo1->ui1_password); + pOs2Info1->ui1_password = (char *)FLATTOFARPTR(CurEndOfBuffer); + pOs2Info1->ui1_status = (unsigned short)pInfo1->ui1_status; + pOs2Info1->ui1_asg_type = (short)pInfo1->ui1_asg_type; + pOs2Info1->ui1_refcount = (unsigned short)pInfo1->ui1_refcount; + pOs2Info1->ui1_usecount = (unsigned short)pInfo1->ui1_usecount; + + pOs2Info1++; + } + (*pcEntriesRead)++; + } + + NetApiBufferFree(BufPtr); + } + + return(rc); +} + + +APIRET +Net16UseGetInfo( + IN PCHAR pszServer, + IN PCHAR pszUseName, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + TCHAR UseName[RMLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PCHAR pEndOfBuffer; + ULONG TotalStringLen; + ULONG StringLen; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszUseName); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1)) { + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(UseName, pszUseName, RMLEN); + + rc = NetUseGetInfo(Server, UseName, sLevel, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + pEndOfBuffer = pbBuffer; + + if (sLevel == 0) { + PUSE_INFO_0 pInfo0 = (PUSE_INFO_0) BufPtr; + struct use_info_0 *pOs2Info0 = (struct use_info_0 *)pbBuffer; + + TotalStringLen = UTstrlen(pInfo0->ui0_remote) + 1; + *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct use_info_0)); + if ((ULONG) *pcbTotalAvail > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UT2ANSIstrncpy(pOs2Info0->ui0_local, pInfo0->ui0_local, DEVLEN_LM20); + pOs2Info0->ui0_local[DEVLEN_LM20] = '\0'; + pEndOfBuffer += sizeof(struct use_info_0); + StringLen = TotalStringLen; + UT2ANSIstrcpy(pEndOfBuffer, pInfo0->ui0_remote); + pOs2Info0->ui0_remote = (char *)FLATTOFARPTR(pEndOfBuffer); + } + else { + PUSE_INFO_1 pInfo1 = (PUSE_INFO_1) BufPtr; + struct use_info_1 *pOs2Info1 = (struct use_info_1 *)pbBuffer; + + TotalStringLen = UTstrlen(pInfo1->ui1_remote) + 1 + + UTstrlen(pInfo1->ui1_password) + 1; + *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct use_info_1)); + if ((ULONG) *pcbTotalAvail > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UT2ANSIstrncpy(pOs2Info1->ui1_local, pInfo1->ui1_local, DEVLEN_LM20); + pOs2Info1->ui1_local[DEVLEN_LM20] = '\0'; + pEndOfBuffer += sizeof(struct use_info_1); + StringLen = UTstrlen(pInfo1->ui1_remote) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo1->ui1_remote); + pOs2Info1->ui1_remote = (char *)FLATTOFARPTR(pEndOfBuffer); + pEndOfBuffer += StringLen; + StringLen = UTstrlen(pInfo1->ui1_password) + 1; + UT2ANSIstrcpy(pEndOfBuffer, pInfo1->ui1_password); + pOs2Info1->ui1_password = (char *)FLATTOFARPTR(pEndOfBuffer); + pEndOfBuffer += StringLen; + + pOs2Info1->ui1_status = (unsigned short)pInfo1->ui1_status; + pOs2Info1->ui1_asg_type = (short)pInfo1->ui1_asg_type; + pOs2Info1->ui1_refcount = (unsigned short)pInfo1->ui1_refcount; + pOs2Info1->ui1_usecount = (unsigned short)pInfo1->ui1_usecount; + } + + NetApiBufferFree(BufPtr); + return(rc); +} + + +APIRET +Net16UserEnum( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcEntriesRead, + OUT PUSHORT pcTotalAvail + ) +{ + WCHAR Server[UNCLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + struct user_info_0 *pOs2Info0; + struct user_info_1 *pOs2Info1; + struct user_info_2 *pOs2Info2; + struct user_info_10 *pOs2Info10; + PUSER_INFO_0 pInfo0; + PUSER_INFO_1 pInfo1; + PUSER_INFO_2 pInfo2; + PUSER_INFO_10 pInfo10; + PCHAR CurEndOfBuffer; + ULONG StringLen; + DWORD EntriesRead; + DWORD ResumeHandle; + DWORD TotalEntries; + ULONG OutBufSize; + int TotalAvailNotSet = TRUE; + DWORD i; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1); + Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2) && + (sLevel != 10)) { + return(ERROR_INVALID_PARAMETER); + } + + OutBufSize = cbBuffer; + CurEndOfBuffer = pbBuffer + cbBuffer; + ResumeHandle = 0; + pOs2Info0 = (struct user_info_0 *)pbBuffer; + pOs2Info1 = (struct user_info_1 *)pbBuffer; + pOs2Info2 = (struct user_info_2 *)pbBuffer; + pOs2Info10 = (struct user_info_10 *)pbBuffer; + + + ANSI2UWstrncpy(Server, pszServer, UNCLEN); + + rc = ERROR_MORE_DATA; + + while (rc == ERROR_MORE_DATA) { + + rc = NetUserEnum(Server, sLevel, + FILTER_TEMP_DUPLICATE_ACCOUNT | FILTER_NORMAL_ACCOUNT, + &BufPtr, + PREFMAXLEN, + &EntriesRead, &TotalEntries, &ResumeHandle); + + if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) { + return(rc); + } + + if (TotalAvailNotSet) { + *pcTotalAvail = (USHORT) TotalEntries; + *pcEntriesRead = 0; + TotalAvailNotSet = FALSE; + } + + for (i = 0; i < EntriesRead; i++) { + if (sLevel == 0) { + pInfo0 = (PUSER_INFO_0) BufPtr + i; + if (sizeof(struct user_info_0) > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= sizeof(struct user_info_0); + UW2ANSIstrncpy(pOs2Info0->usri0_name, pInfo0->usri0_name, UNLEN_LM20); + pOs2Info0->usri0_name[UNLEN_LM20] = '\0'; + + pOs2Info0++; + } + else if (sLevel == 1) { + pInfo1 = (PUSER_INFO_1) BufPtr + i; + StringLen = sizeof(struct user_info_1) + + UWstrlen(pInfo1->usri1_home_dir) + 1 + + UWstrlen(pInfo1->usri1_comment) + 1 + + UWstrlen(pInfo1->usri1_script_path) + 1; + if (StringLen > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= StringLen; + UW2ANSIstrncpy(pOs2Info1->usri1_name, pInfo1->usri1_name, UNLEN_LM20); + pOs2Info1->usri1_name[UNLEN_LM20] = '\0'; + UW2ANSIstrncpy(pOs2Info1->usri1_password, pInfo1->usri1_password, ENCRYPTED_PWLEN_LM20); + pOs2Info1->usri1_password[ENCRYPTED_PWLEN_LM20] = '\0'; + + pOs2Info1->usri1_password_age = (long)pInfo1->usri1_password_age; + pOs2Info1->usri1_priv = (unsigned short)pInfo1->usri1_priv; + + CopyUW2ANSI(pOs2Info1->usri1_home_dir, pInfo1->usri1_home_dir); + CopyUW2ANSI(pOs2Info1->usri1_comment, pInfo1->usri1_comment); + CopyUW2ANSI(pOs2Info1->usri1_script_path, pInfo1->usri1_script_path); + + pOs2Info1++; + } + else if (sLevel == 2) { + pInfo2 = (PUSER_INFO_2) BufPtr + i; + StringLen = sizeof(struct user_info_2) + + UWstrlen(pInfo2->usri2_home_dir) + 1 + + UWstrlen(pInfo2->usri2_comment) + 1 + + UWstrlen(pInfo2->usri2_script_path) + 1 + + UWstrlen(pInfo2->usri2_full_name) + 1 + + UWstrlen(pInfo2->usri2_usr_comment) + 1 + + UWstrlen(pInfo2->usri2_parms) + 1 + + UWstrlen(pInfo2->usri2_workstations) + 1 + + strlen(pInfo2->usri2_logon_hours) + 1 + + UWstrlen(pInfo2->usri2_logon_server) + 1; + if (StringLen > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= StringLen; + UW2ANSIstrncpy(pOs2Info2->usri2_name, pInfo2->usri2_name, UNLEN_LM20); + pOs2Info2->usri2_name[UNLEN_LM20] = '\0'; + UW2ANSIstrncpy(pOs2Info2->usri2_password, pInfo2->usri2_password, ENCRYPTED_PWLEN_LM20); + pOs2Info2->usri2_password[ENCRYPTED_PWLEN_LM20] = '\0'; + pOs2Info2->usri2_password_age = (long)pInfo2->usri2_password_age; + pOs2Info2->usri2_priv = (unsigned short)pInfo2->usri2_priv; + + CopyUW2ANSI(pOs2Info2->usri2_home_dir, pInfo2->usri2_home_dir); + CopyUW2ANSI(pOs2Info2->usri2_comment, pInfo2->usri2_comment); + CopyUW2ANSI(pOs2Info2->usri2_script_path, pInfo2->usri2_script_path); + + pOs2Info2->usri2_auth_flags = (unsigned long)pInfo2->usri2_auth_flags; + + CopyUW2ANSI(pOs2Info2->usri2_full_name, pInfo2->usri2_full_name); + CopyUW2ANSI(pOs2Info2->usri2_usr_comment, pInfo2->usri2_usr_comment); + CopyUW2ANSI(pOs2Info2->usri2_parms, pInfo2->usri2_parms); + CopyUW2ANSI(pOs2Info2->usri2_workstations, pInfo2->usri2_workstations); + + pOs2Info2->usri2_last_logon = (long)pInfo2->usri2_last_logon; + pOs2Info2->usri2_last_logoff = (long)pInfo2->usri2_last_logoff; + pOs2Info2->usri2_acct_expires = (long)pInfo2->usri2_acct_expires; + pOs2Info2->usri2_max_storage = (unsigned long)pInfo2->usri2_max_storage; + pOs2Info2->usri2_units_per_week = (unsigned short)pInfo2->usri2_units_per_week; + StringLen = strlen(pInfo2->usri2_logon_hours) + 1; + CurEndOfBuffer -= StringLen; + pOs2Info2->usri2_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer); + RtlMoveMemory(CurEndOfBuffer, pInfo2->usri2_logon_hours, StringLen); + pOs2Info2->usri2_bad_pw_count = (unsigned short)pInfo2->usri2_bad_pw_count; + pOs2Info2->usri2_num_logons = (unsigned short)pInfo2->usri2_num_logons; + + CopyUW2ANSI(pOs2Info2->usri2_logon_server, pInfo2->usri2_logon_server); + + pOs2Info2->usri2_country_code = (unsigned short)pInfo2->usri2_country_code; + pOs2Info2->usri2_code_page = (unsigned short)pInfo2->usri2_code_page; + + pOs2Info2++; + } + else if (sLevel == 10) { + pInfo10 = (PUSER_INFO_10) BufPtr + i; + StringLen = sizeof(struct user_info_10) + + UWstrlen(pInfo10->usri10_comment) + 1 + + UWstrlen(pInfo10->usri10_usr_comment) + 1 + + UWstrlen(pInfo10->usri10_full_name) + 1; + if (StringLen > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= StringLen; + UW2ANSIstrncpy(pOs2Info10->usri10_name, pInfo10->usri10_name, UNLEN_LM20); + pOs2Info10->usri10_name[UNLEN_LM20] = '\0'; + + CopyUW2ANSI(pOs2Info10->usri10_comment, pInfo10->usri10_comment); + CopyUW2ANSI(pOs2Info10->usri10_usr_comment, pInfo10->usri10_usr_comment); + CopyUW2ANSI(pOs2Info10->usri10_full_name, pInfo10->usri10_full_name); + + pOs2Info10++; + } +#if 0 + else if (sLevel == 11) { + pInfo11 = (PUSER_INFO_11) BufPtr + i; + StringLen = sizeof(struct user_info_11) + + UWstrlen(pInfo11->usri11_comment) + 1 + + UWstrlen(pInfo11->usri11_usr_comment) + 1 + + UWstrlen(pInfo11->usri11_full_name) + 1 + + UWstrlen(pInfo11->usri11_home_dir) + 1 + + UWstrlen(pInfo11->usri11_parms) + 1 + + UWstrlen(pInfo11->usri11_logon_server) + 1 + + UWstrlen(pInfo11->usri11_workstations) + 1 + + strlen(pInfo11->usri11_logon_hours) + 1; + if (StringLen > OutBufSize ) { + NetApiBufferFree(BufPtr); + return(ERROR_MORE_DATA); + } + + OutBufSize -= StringLen; + UW2ANSIstrncpy(pOs2Info11->usri11_name, pInfo11->usri11_name, UNLEN_LM20); + pOs2Info11->usri11_name[UNLEN_LM20] = '\0'; + + CopyUW2ANSI(pOs2Info11->usri11_comment, pInfo11->usri11_comment); + CopyUW2ANSI(pOs2Info11->usri11_usr_comment, pInfo11->usri11_usr_comment); + CopyUW2ANSI(pOs2Info11->usri11_full_name, pInfo11->usri11_full_name); + + pOs2Info11->usri11_priv = (unsigned short)pInfo11->usri11_priv; + pOs2Info11->usri11_auth_flags = (unsigned long)pInfo11->usri11_auth_flags; + pOs2Info11->usri11_password_age = (long)pInfo11->usri11_password_age; + + CopyUW2ANSI(pOs2Info11->usri11_home_dir, pInfo11->usri11_home_dir); + CopyUW2ANSI(pOs2Info11->usri11_parms, pInfo11->usri11_parms); + + pOs2Info11->usri11_last_logon = (long)pInfo11->usri11_last_logon; + pOs2Info11->usri11_last_logoff = (long)pInfo11->usri11_last_logoff; + pOs2Info11->usri11_bad_pw_count = (unsigned short)pInfo11->usri11_bad_pw_count; + pOs2Info11->usri11_num_logons = (unsigned short)pInfo11->usri11_num_logons; + + CopyUW2ANSI(pOs2Info11->usri11_logon_server, pInfo11->usri11_logon_server); + + pOs2Info11->usri11_country_code = (unsigned short)pInfo11->usri11_country_code; + + CopyUW2ANSI(pOs2Info11->usri11_workstations, pInfo11->usri11_workstations); + + pOs2Info11->usri11_max_storage = (unsigned long)pInfo11->usri11_max_storage; + pOs2Info11->usri11_units_per_week = (unsigned short)pInfo11->usri11_units_per_week; + + StringLen = strlen(pInfo11->usri11_logon_hours) + 1; + CurEndOfBuffer -= StringLen; + pOs2Info11->usri11_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer); + RtlMoveMemory(CurEndOfBuffer, pInfo11->usri11_logon_hours, StringLen); + + pOs2Info11->usri11_code_page = (unsigned short)pInfo11->usri11_code_page; + + pOs2Info11++; + } +#endif + (*pcEntriesRead)++; + } + + NetApiBufferFree(BufPtr); + } + + return(rc); +} + + +APIRET +Net16WkstaGetInfo( + IN PCHAR pszServer, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + LPBYTE BufPtr1; + LPBYTE BufPtr2; + NET_API_STATUS rc; + PWKSTA_INFO_101 pInfo101; + PWKSTA_USER_INFO_1 pInfo1; + struct wksta_info_0 *pOs2Info0; + struct wksta_info_1 *pOs2Info1; + struct wksta_info_10 *pOs2Info10; + PCHAR pStrings; + WCHAR LanRoot[CCHMAXPATH]; + PCHAR pEndOfBuffer; + ULONG StringLen; + ULONG TotalStringLen; + + try { + PROBE_STRING(pszServer); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 10)) { + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + rc = NetWkstaGetInfo(Server, 101L, &BufPtr1); + + if (rc != NO_ERROR) { + return(rc); + } + + rc = NetWkstaUserGetInfo(NULL, 1L, &BufPtr2); + + if (rc != NO_ERROR) { + NetApiBufferFree(BufPtr1); + return(rc); + } + + RtlZeroMemory(pbBuffer, cbBuffer); + pEndOfBuffer = pbBuffer + cbBuffer; + pInfo101 = (PWKSTA_INFO_101) BufPtr1; + pInfo1 = (PWKSTA_USER_INFO_1) BufPtr2; + + if (sLevel == 0) { + pOs2Info0 = (struct wksta_info_0 *)pbBuffer; + + // + // note about wkix_root - NT returns an empty field. + // We should return system directory + // in case of lacal machine, and NULL + // in case of remote call. + // + if ((pszServer == NULL) || (*pszServer == (CHAR) NULL)) { + StringLen = GetSystemDirectoryW(LanRoot, sizeof(LanRoot)) + 1; + LanRoot[StringLen] = UNICODE_NULL; + } + else { + StringLen = 1; + LanRoot[0] = UNICODE_NULL; + } + TotalStringLen = UTstrlen(LanRoot) + 1 + + UTstrlen(pInfo101->wki101_computername) + 1 + + UTstrlen(pInfo101->wki101_langroup) + 1 + + UTstrlen(pInfo1->wkui1_username) + 1 + + UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2; + *pcbTotalAvail = (USHORT)(sizeof(struct wksta_info_0) + TotalStringLen); + pStrings = (PCHAR)(pOs2Info0 + 1); + if (pStrings + TotalStringLen > pEndOfBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + + UT2ANSIstrcpy(pStrings, LanRoot); + pOs2Info0->wki0_root = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo101->wki101_computername) + 1; + UT2ANSIstrcpy(pStrings, pInfo101->wki101_computername); + pOs2Info0->wki0_computername = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo101->wki101_langroup) + 1; + UT2ANSIstrcpy(pStrings, pInfo101->wki101_langroup); + pOs2Info0->wki0_langroup = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + pOs2Info0->wki0_ver_major = (unsigned char)pInfo101->wki101_ver_major; + pOs2Info0->wki0_ver_minor = (unsigned char)pInfo101->wki101_ver_minor; + + StringLen = UTstrlen(pInfo1->wkui1_username) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_username); + pOs2Info0->wki0_username = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + strcpy(pStrings, "\\\\"); + StringLen = UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2; + UT2ANSIstrcpy(pStrings + 2, pInfo1->wkui1_logon_server); + pOs2Info0->wki0_logon_server = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + } + else if (sLevel == 1) { + pOs2Info1 = (struct wksta_info_1 *)pbBuffer; + + // + // note about wkix_root - NT returns an empty field. + // We should return system directory + // in case of lacal machine, and NULL + // in case of remote call. + // + if ((pszServer == NULL) || (*pszServer == (CHAR) NULL)) { + StringLen = GetSystemDirectoryW(LanRoot, sizeof(LanRoot)) + 1; + LanRoot[StringLen] = UNICODE_NULL; + } + else { + StringLen = 1; + LanRoot[0] = UNICODE_NULL; + } + TotalStringLen = UTstrlen(LanRoot) + 1 + + UTstrlen(pInfo101->wki101_computername) + 1 + + UTstrlen(pInfo101->wki101_langroup) + 1 + + UTstrlen(pInfo1->wkui1_username) + 1 + + UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2 + + UTstrlen(pInfo1->wkui1_logon_domain) + 1 + + UTstrlen(pInfo1->wkui1_oth_domains) + 1; + *pcbTotalAvail = (USHORT)(sizeof(struct wksta_info_1) + TotalStringLen); + pStrings = (PCHAR)(pOs2Info1 + 1); + if (pStrings + TotalStringLen > pEndOfBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + + UT2ANSIstrcpy(pStrings, LanRoot); + pOs2Info1->wki1_root = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo101->wki101_computername) + 1; + UT2ANSIstrcpy(pStrings, pInfo101->wki101_computername); + pOs2Info1->wki1_computername = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo101->wki101_langroup) + 1; + UT2ANSIstrcpy(pStrings, pInfo101->wki101_langroup); + pOs2Info1->wki1_langroup = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + pOs2Info1->wki1_ver_major = (unsigned char)pInfo101->wki101_ver_major; + pOs2Info1->wki1_ver_minor = (unsigned char)pInfo101->wki101_ver_minor; + + StringLen = UTstrlen(pInfo1->wkui1_username) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_username); + pOs2Info1->wki1_username = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + strcpy(pStrings, "\\\\"); + StringLen = UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2; + UT2ANSIstrcpy(pStrings + 2, pInfo1->wkui1_logon_server); + pOs2Info1->wki1_logon_server = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo1->wkui1_logon_domain) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_logon_domain); + pOs2Info1->wki1_logon_domain = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo1->wkui1_oth_domains) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_oth_domains); + pOs2Info1->wki1_oth_domains = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + } + else if (sLevel == 10) { + pOs2Info10 = (struct wksta_info_10 *)pbBuffer; + TotalStringLen = UTstrlen(pInfo101->wki101_computername) + 1 + + UTstrlen(pInfo1->wkui1_username) + 1 + + UTstrlen(pInfo101->wki101_langroup) + 1 + + UTstrlen(pInfo1->wkui1_logon_domain) + 1 + + UTstrlen(pInfo1->wkui1_oth_domains) + 1; + *pcbTotalAvail = (USHORT)(sizeof(struct wksta_info_10) + TotalStringLen); + pStrings = (PCHAR)(pOs2Info10 + 1); + if (pStrings + TotalStringLen > pEndOfBuffer) { + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + return(NERR_BufTooSmall); + } + + StringLen = UTstrlen(pInfo101->wki101_computername) + 1; + UT2ANSIstrcpy(pStrings, pInfo101->wki101_computername); + pOs2Info10->wki10_computername = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo1->wkui1_username) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_username); + pOs2Info10->wki10_username = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo101->wki101_langroup) + 1; + UT2ANSIstrcpy(pStrings, pInfo101->wki101_langroup); + pOs2Info10->wki10_langroup = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + pOs2Info10->wki10_ver_major = (unsigned char)pInfo101->wki101_ver_major; + pOs2Info10->wki10_ver_minor = (unsigned char)pInfo101->wki101_ver_minor; + + StringLen = UTstrlen(pInfo1->wkui1_logon_domain) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_logon_domain); + pOs2Info10->wki10_logon_domain = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + + StringLen = UTstrlen(pInfo1->wkui1_oth_domains) + 1; + UT2ANSIstrcpy(pStrings, pInfo1->wkui1_oth_domains); + pOs2Info10->wki10_oth_domains = (char *)FLATTOFARPTR(pStrings); + pStrings += StringLen; + } + + NetApiBufferFree(BufPtr1); + NetApiBufferFree(BufPtr2); + + return(NO_ERROR); +} + + +APIRET +Net16AccessAdd( + IN PCHAR pszServer, + IN LONG sLevel, + IN PCHAR pbBuffer, + IN ULONG cbBuffer + ) +{ + TCHAR Server[UNCLEN]; + PCHAR Buffer; + PCHAR ResourceName; + LPTSTR pStrings; + ULONG StringLen; + PACCESS_INFO_1 pInfo1; + PACCESS_LIST pInfo; + struct access_info_1 *pOs2Info1; + struct access_list *pOs2Info; + int i; + NET_API_STATUS rc; + + try { + PROBE_STRING(pszServer); + Od2ProbeForRead(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 1) { + return(ERROR_INVALID_PARAMETER); + } + + Buffer = (PCHAR) RtlAllocateHeap(Od2Heap, 0, LARGE_BUFFER_SIZE); + + if (Buffer == NULL) { + return(ERROR_NOT_ENOUGH_MEMORY); + } + + pOs2Info1 = (struct access_info_1 *) pbBuffer; + pOs2Info = (struct access_list *) (pOs2Info1 + 1); + pInfo1 = (PACCESS_INFO_1) Buffer; + pInfo = (PACCESS_LIST) (pInfo1 + 1); + pStrings = (LPTSTR)(pInfo + (pOs2Info1->acc1_count * sizeof(ACCESS_LIST))); + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + ResourceName = FARPTRTOFLAT(pOs2Info1->acc1_resource_name); + pInfo1->acc1_resource_name = pStrings; + StringLen = strlen(ResourceName) + 1; + ANSI2UTstrcpy(pStrings, ResourceName); + pStrings += StringLen; + + pInfo1->acc1_attr = pOs2Info1->acc1_attr; + pInfo1->acc1_count = pOs2Info1->acc1_count; + + for (i = 0; i < pOs2Info1->acc1_count; i++) { + pInfo->acl_access = pOs2Info->acl_access; + pInfo->acl_ugname = pStrings; + ANSI2UTstrcpy(pStrings, pOs2Info->acl_ugname); + pStrings += UNLEN_LM20+1; + pInfo++; + pOs2Info++; + } + + rc = NetAccessAdd(Server, sLevel, Buffer, NULL); + + RtlFreeHeap(Od2Heap, 0, Buffer); + + return(rc); +} + + +APIRET +Net16AccessSetInfo( + IN PCHAR pszServer, + IN PCHAR pszResource, + IN LONG sLevel, + IN PCHAR pbBuffer, + IN ULONG cbBuffer, + IN LONG sParmNum + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Resource[NNLEN]; + PCHAR Buffer = NULL; + NET_API_STATUS rc; + ACCESS_INFO_1002 AccessInfo1002; + PCHAR ResourceName; + LPTSTR pStrings; + ULONG StringLen; + PACCESS_INFO_1 pInfo1; + PACCESS_LIST pInfo; + struct access_info_1 *pOs2Info1; + struct access_list *pOs2Info; + int i; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszResource); + Od2ProbeForRead(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 1) { + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(Resource, pszResource, NNLEN); + + if (sParmNum == ACCESS_ATTR_PARMNUM) { + AccessInfo1002.acc1002_attr = *(PSHORT) pbBuffer; + rc = NetAccessSetInfo(Server, Resource, (ULONG) 1002, (PCHAR) &AccessInfo1002, NULL); + } else { + + Buffer = (PCHAR) RtlAllocateHeap(Od2Heap, 0, LARGE_BUFFER_SIZE); + + if (Buffer == NULL) { + return(ERROR_NOT_ENOUGH_MEMORY); + } + + pOs2Info1 = (struct access_info_1 *) pbBuffer; + pOs2Info = (struct access_list *) (pOs2Info1 + 1); + pInfo1 = (PACCESS_INFO_1) Buffer; + pInfo = (PACCESS_LIST) (pInfo1 + 1); + pStrings = (LPTSTR)(pInfo + (pOs2Info1->acc1_count * sizeof(ACCESS_LIST))); + + ResourceName = FARPTRTOFLAT(pOs2Info1->acc1_resource_name); + pInfo1->acc1_resource_name = pStrings; + StringLen = strlen(ResourceName) + 1; + ANSI2UTstrcpy(pStrings, ResourceName); + pStrings += StringLen; + + pInfo1->acc1_attr = pOs2Info1->acc1_attr; + pInfo1->acc1_count = pOs2Info1->acc1_count; + + for (i = 0; i < pOs2Info1->acc1_count; i++) { + pInfo->acl_access = pOs2Info->acl_access; + pInfo->acl_ugname = pStrings; + ANSI2UTstrcpy(pStrings, pOs2Info->acl_ugname); + pStrings += UNLEN_LM20+1; + pInfo++; + pOs2Info++; + } + rc = NetAccessSetInfo(Server, Resource, sLevel, Buffer, NULL); + + RtlFreeHeap(Od2Heap, 0, Buffer); + } + + return(rc); +} + + +APIRET +Net16AccessGetInfo( + IN PCHAR pszServer, + IN PCHAR pszResource, + IN LONG sLevel, + OUT PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + TCHAR Server[UNCLEN]; + ANSI_STRING Str_MB; + UNICODE_STRING Str_U; + LPBYTE BufPtr; + NET_API_STATUS rc; + APIRET RetCode; + PACCESS_INFO_0 pInfo0; + PACCESS_INFO_1 pInfo1; + PACCESS_LIST pInfo; + struct access_info_0 *pOs2Info0; + struct access_info_1 *pOs2Info1; + struct access_list *pOs2Info; + ULONG strucsize; + ULONG Length; + ULONG FullLength; + ULONG StringLen; + ULONG AclsThatFit; + ULONG Count; + PCHAR pScratch; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszResource); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16AccessGetInfo: Invalid level = %d\n", sLevel)); + } +#endif + return(ERROR_INVALID_LEVEL); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + // + // Since Resource can be a very long string (up to PATHLEN), we allocate + // space for it on the heap instead of the stack, which might be too short + // + + if (pszResource != NULL) { + + Or2InitMBString(&Str_MB, pszResource); + + if ((RetCode = Or2MBStringToUnicodeString(&Str_U, &Str_MB, TRUE)) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16AccessGetInfo: Unicode converstion of Resource failed, RetCode = %x\n", RetCode)); + } +#endif + return(ERROR_NOT_ENOUGH_MEMORY); + } + + Str_U.Buffer[Str_U.Length/sizeof(WCHAR)] = UNICODE_NULL; + + } else { + + Str_U.Buffer = NULL; + } + + rc = NetAccessGetInfo(Server, (LPTSTR) Str_U.Buffer, sLevel, &BufPtr); + + if (Str_U.Buffer != NULL) { + RtlFreeUnicodeString(&Str_U); + } + + if (rc != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16AccessGetInfo: System function returned %lx\n", rc)); + } +#endif + return((APIRET)rc); + } + + if (sLevel == 0) { + + strucsize = sizeof(struct access_info_0); + pInfo0 = (PACCESS_INFO_0) BufPtr; + + RtlInitUnicodeString(&Str_U, pInfo0->acc0_resource_name); + + if (Str_U.Buffer == NULL) { + + StringLen = 0; + + } else { + + if ((RetCode = Or2UnicodeStringToMBString(&Str_MB, &Str_U, TRUE)) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16AccessGetInfo: Unicode converstion of returned resource name failed, RetCode = %x\n", RetCode)); + } +#endif + NetApiBufferFree(BufPtr); + return(ERROR_NOT_ENOUGH_MEMORY); + } + + StringLen = Str_MB.Length + 1; + } + + *pcbTotalAvail = (USHORT) (strucsize + StringLen); + + if (cbBuffer < strucsize + StringLen) { + if (StringLen != 0) { + Or2FreeMBString(&Str_MB); + } + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + pOs2Info0 = (struct access_info_0 *) pbBuffer; + + if (StringLen) { + + pScratch = (PCHAR) (pOs2Info0 + 1); + pOs2Info0->acc0_resource_name = (PVOID) FLATTOFARPTR(pScratch); + RtlMoveMemory(pScratch, Str_MB.Buffer, StringLen); + Or2FreeMBString(&Str_MB); + + } else { + + pOs2Info0->acc0_resource_name = NULL; + } + + } else { // sLevel == 1 + + strucsize = sizeof(struct access_info_1); + pInfo1 = (PACCESS_INFO_1) BufPtr; + + RtlInitUnicodeString(&Str_U, pInfo1->acc1_resource_name); + + if (Str_U.Buffer == NULL) { + + StringLen = 0; + + } else { + + if ((RetCode = Or2UnicodeStringToMBString(&Str_MB, &Str_U, TRUE)) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16AccessGetInfo: Unicode converstion of returned resource name failed, RetCode = %x\n", RetCode)); + } +#endif + NetApiBufferFree(BufPtr); + return(ERROR_NOT_ENOUGH_MEMORY); + } + + StringLen = Str_MB.Length + 1; + } + + AclsThatFit = (ULONG) pInfo1->acc1_count; + FullLength = Length = AclsThatFit * sizeof(struct access_list); + + *pcbTotalAvail = (USHORT) (strucsize + FullLength + StringLen); + + if (cbBuffer < strucsize + StringLen) { + if (StringLen != 0) { + Or2FreeMBString(&Str_MB); + } + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + if (cbBuffer < strucsize + StringLen + Length) { + + // + // Cut the info down to size... + // + + AclsThatFit = (cbBuffer - strucsize - StringLen) / sizeof(struct access_list); + + Length = AclsThatFit * sizeof(struct access_list); + + rc = ERROR_MORE_DATA; + } + + pOs2Info1 = (struct access_info_1 *) pbBuffer; + + if (StringLen) { + + pScratch = pbBuffer + strucsize + Length; + pOs2Info1->acc1_resource_name = (PVOID) FLATTOFARPTR(pScratch); + RtlMoveMemory(pScratch, Str_MB.Buffer, StringLen); + Or2FreeMBString(&Str_MB); + + } else { + + pOs2Info1->acc1_resource_name = NULL; + } + + pOs2Info1->acc1_attr = (SHORT) pInfo1->acc1_attr; + pOs2Info1->acc1_count = (SHORT) AclsThatFit; + + // + // Fill in the ACL structures + // + + pInfo = (PACCESS_LIST) (pInfo1 + 1); + pOs2Info = (struct access_list *) (pOs2Info1 + 1); + + for (Count = 0; Count < AclsThatFit; Count++) { + + pOs2Info[Count].acl_access = (SHORT) pInfo[Count].acl_access; + UT2ANSIstrncpy(pOs2Info[Count].acl_ugname, pInfo[Count].acl_ugname, LM20_UNLEN); + pOs2Info[Count].acl_ugname[LM20_UNLEN] = '\0'; + } + + } + + NetApiBufferFree(BufPtr); + return((APIRET)rc); +} + + +APIRET +Net16AccessDel( + IN PCHAR pszServer, + IN PCHAR pszResource + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Resource[NNLEN]; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszResource); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(Resource, pszResource, NNLEN); + + return (NetAccessDel(Server, Resource)); +} + + +APIRET +Net16ShareAdd( + IN PCHAR pszServer, + IN LONG sLevel, + IN PCHAR pbBuffer, + IN ULONG cbBuffer + ) +{ + TCHAR Server[UNCLEN]; + PCHAR Buffer; + NET_API_STATUS rc; + LPTSTR pStrings; + PSHARE_INFO_2 pInfo2; + struct share_info_2 *pOs2Info2; + + try { + PROBE_STRING(pszServer); + Od2ProbeForRead(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 2) { + return(ERROR_INVALID_PARAMETER); + } + + Buffer = (PCHAR) RtlAllocateHeap(Od2Heap, 0, SMALL_BUFFER_SIZE); + + if (Buffer == NULL) { + return(ERROR_NOT_ENOUGH_MEMORY); + } + + pOs2Info2 = (struct share_info_2 *) pbBuffer; + pInfo2 = (PSHARE_INFO_2) Buffer; + pStrings = (LPTSTR) (pInfo2 + 1); + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + + pInfo2->shi2_netname = pStrings; + ANSI2UTstrcpy(pStrings, pOs2Info2->shi2_netname); + pStrings += strlen(pOs2Info2->shi2_netname) + 1; + + pInfo2->shi2_remark = pStrings; + ANSI2UTstrcpy(pStrings, FARPTRTOFLAT(pOs2Info2->shi2_remark)); + pStrings += strlen(FARPTRTOFLAT(pOs2Info2->shi2_remark)) + 1; + + pInfo2->shi2_path = pStrings; + ANSI2UTstrcpy(pStrings, FARPTRTOFLAT(pOs2Info2->shi2_path)); + pStrings += strlen(FARPTRTOFLAT(pOs2Info2->shi2_path)) + 1; + + pInfo2->shi2_passwd = pStrings; + ANSI2UTstrcpy(pStrings, pOs2Info2->shi2_passwd); + pStrings += strlen(pOs2Info2->shi2_passwd) + 1; + + pInfo2->shi2_type = pOs2Info2->shi2_type; + pInfo2->shi2_permissions = pOs2Info2->shi2_permissions; + pInfo2->shi2_max_uses = pOs2Info2->shi2_max_uses; + pInfo2->shi2_current_uses = pOs2Info2->shi2_current_uses; + + rc = NetShareAdd(Server, sLevel, Buffer, NULL); + + RtlFreeHeap(Od2Heap, 0, Buffer); + + return(rc); +} + + +APIRET +Net16ShareDel( + IN PCHAR pszServer, + IN PCHAR pszNetName, + IN ULONG usReserved + ) +{ + TCHAR Server[UNCLEN]; + TCHAR NetName[NNLEN]; + + UNREFERENCED_PARAMETER(usReserved); + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszNetName); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(NetName, pszNetName, NNLEN); + + return (NetShareDel(Server, NetName, 0L)); +} + + +APIRET +Net16UserGetInfo( + IN PCHAR pszServer, + IN PCHAR pszUserName, + IN LONG sLevel, + IN PCHAR pbBuffer, + IN ULONG cbBuffer, + OUT PUSHORT pcbTotalAvail + ) +{ + WCHAR Server[UNCLEN]; + WCHAR UserName[UNLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PUSER_INFO_0 pInfo0; + PUSER_INFO_1 pInfo1; + PUSER_INFO_2 pInfo2; + PUSER_INFO_10 pInfo10; + PUSER_INFO_11 pInfo11; + struct user_info_0 *pOs2Info0; + struct user_info_1 *pOs2Info1; + struct user_info_2 *pOs2Info2; + struct user_info_10 *pOs2Info10; + struct user_info_11 *pOs2Info11; + PCHAR CurEndOfBuffer; + ULONG StringLen; + ULONG TotalStringLen; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszUserName); + Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1); + Od2ProbeForWrite(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2) && + (sLevel != 10) && (sLevel != 11)) { + return(ERROR_INVALID_PARAMETER); + } + + ANSI2UWstrncpy(Server, pszServer, UNCLEN); + ANSI2UWstrncpy(UserName, pszUserName, UNLEN); + + rc = NetUserGetInfo(Server, UserName, sLevel, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + CurEndOfBuffer = pbBuffer + cbBuffer; + + if (sLevel == 0) { + pInfo0 = (PUSER_INFO_0) BufPtr; + pOs2Info0 = (struct user_info_0 *)pbBuffer; + *pcbTotalAvail = (USHORT)sizeof(struct user_info_0); + if ((ULONG)sizeof(struct user_info_0) > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + UW2ANSIstrncpy(pOs2Info0->usri0_name, pInfo0->usri0_name, UNLEN_LM20); + pOs2Info0->usri0_name[UNLEN_LM20] = '\0'; + } + else if (sLevel == 1) { + pInfo1 = (PUSER_INFO_1) BufPtr; + pOs2Info1 = (struct user_info_1 *)pbBuffer; + TotalStringLen = sizeof(struct user_info_1) + + UWstrlen(pInfo1->usri1_home_dir) + 1 + + UWstrlen(pInfo1->usri1_comment) + 1 + + UWstrlen(pInfo1->usri1_script_path) + 1; + *pcbTotalAvail = (USHORT)TotalStringLen; + if (TotalStringLen > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UW2ANSIstrncpy(pOs2Info1->usri1_name, pInfo1->usri1_name, UNLEN_LM20); + pOs2Info1->usri1_name[UNLEN_LM20] = '\0'; + + UW2ANSIstrncpy(pOs2Info1->usri1_password, pInfo1->usri1_password, ENCRYPTED_PWLEN_LM20); + pOs2Info1->usri1_password[ENCRYPTED_PWLEN_LM20] = '\0'; + + CopyUW2ANSI(pOs2Info1->usri1_home_dir, pInfo1->usri1_home_dir); + CopyUW2ANSI(pOs2Info1->usri1_comment, pInfo1->usri1_comment); + CopyUW2ANSI(pOs2Info1->usri1_script_path, pInfo1->usri1_script_path); + + pOs2Info1->usri1_password_age = (long)pInfo1->usri1_password_age; + pOs2Info1->usri1_priv = (unsigned short)pInfo1->usri1_priv; + pOs2Info1->usri1_flags = (unsigned short)pInfo1->usri1_flags; + } + else if (sLevel == 2) { + pInfo2 = (PUSER_INFO_2) BufPtr; + pOs2Info2 = (struct user_info_2 *)pbBuffer; + TotalStringLen = sizeof(struct user_info_2) + + UWstrlen(pInfo2->usri2_home_dir) + 1 + + UWstrlen(pInfo2->usri2_comment) + 1 + + UWstrlen(pInfo2->usri2_script_path) + 1 + + UWstrlen(pInfo2->usri2_full_name) + 1 + + UWstrlen(pInfo2->usri2_usr_comment) + 1 + + UWstrlen(pInfo2->usri2_parms) + 1 + + UWstrlen(pInfo2->usri2_workstations) + 1 + + strlen(pInfo2->usri2_logon_hours) + + UWstrlen(pInfo2->usri2_logon_server) + 1; + *pcbTotalAvail = (USHORT)TotalStringLen; + if (TotalStringLen > cbBuffer) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UW2ANSIstrncpy(pOs2Info2->usri2_name, pInfo2->usri2_name, UNLEN_LM20); + pOs2Info2->usri2_name[UNLEN_LM20] = '\0'; + + UW2ANSIstrncpy(pOs2Info2->usri2_password, pInfo2->usri2_password, ENCRYPTED_PWLEN_LM20); + pOs2Info2->usri2_password[ENCRYPTED_PWLEN_LM20] = '\0'; + + CopyUW2ANSI(pOs2Info2->usri2_home_dir, pInfo2->usri2_home_dir); + CopyUW2ANSI(pOs2Info2->usri2_comment, pInfo2->usri2_comment); + CopyUW2ANSI(pOs2Info2->usri2_script_path, pInfo2->usri2_script_path); + CopyUW2ANSI(pOs2Info2->usri2_full_name, pInfo2->usri2_full_name); + CopyUW2ANSI(pOs2Info2->usri2_usr_comment, pInfo2->usri2_usr_comment); + CopyUW2ANSI(pOs2Info2->usri2_parms, pInfo2->usri2_parms); + CopyUW2ANSI(pOs2Info2->usri2_workstations, pInfo2->usri2_workstations); + CopyUW2ANSI(pOs2Info2->usri2_logon_server, pInfo2->usri2_logon_server); + StringLen = strlen(pInfo2->usri2_logon_hours) + 1; + CurEndOfBuffer -= StringLen; + pOs2Info2->usri2_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer); + RtlMoveMemory(CurEndOfBuffer, pInfo2->usri2_logon_hours, StringLen); + + pOs2Info2->usri2_password_age = (long)pInfo2->usri2_password_age; + pOs2Info2->usri2_priv = (unsigned short)pInfo2->usri2_priv; + pOs2Info2->usri2_flags = (unsigned short)pInfo2->usri2_flags; + pOs2Info2->usri2_auth_flags = (unsigned long)pInfo2->usri2_auth_flags; + pOs2Info2->usri2_last_logon = (long)pInfo2->usri2_last_logon; + pOs2Info2->usri2_last_logoff = (long)pInfo2->usri2_last_logoff; + pOs2Info2->usri2_acct_expires = (long)pInfo2->usri2_acct_expires; + pOs2Info2->usri2_max_storage = (unsigned long)pInfo2->usri2_max_storage; + pOs2Info2->usri2_units_per_week = (unsigned short)pInfo2->usri2_units_per_week; + pOs2Info2->usri2_bad_pw_count = (unsigned short)pInfo2->usri2_bad_pw_count; + pOs2Info2->usri2_num_logons = (unsigned short)pInfo2->usri2_num_logons; + pOs2Info2->usri2_country_code = (unsigned short)pInfo2->usri2_country_code; + pOs2Info2->usri2_code_page = (unsigned short)pInfo2->usri2_code_page; + } + else if (sLevel == 10) { + pInfo10 = (PUSER_INFO_10) BufPtr; + pOs2Info10 = (struct user_info_10 *)pbBuffer; + TotalStringLen = sizeof(struct user_info_10) + + UWstrlen(pInfo10->usri10_comment) + 1 + + UWstrlen(pInfo10->usri10_usr_comment) + 1 + + UWstrlen(pInfo10->usri10_full_name) + 1; + *pcbTotalAvail = (USHORT)TotalStringLen; + if (TotalStringLen > cbBuffer ) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UW2ANSIstrncpy(pOs2Info10->usri10_name, pInfo10->usri10_name, UNLEN_LM20); + pOs2Info10->usri10_name[UNLEN_LM20] = '\0'; + + CopyUW2ANSI(pOs2Info10->usri10_comment, pInfo10->usri10_comment); + CopyUW2ANSI(pOs2Info10->usri10_usr_comment, pInfo10->usri10_usr_comment); + CopyUW2ANSI(pOs2Info10->usri10_full_name, pInfo10->usri10_full_name); + } + else if (sLevel == 11) { + pInfo11 = (PUSER_INFO_11) BufPtr; + pOs2Info11 = (struct user_info_11 *)pbBuffer; + TotalStringLen = sizeof(struct user_info_11) + + UWstrlen(pInfo11->usri11_comment) + 1 + + UWstrlen(pInfo11->usri11_usr_comment) + 1 + + UWstrlen(pInfo11->usri11_full_name) + 1 + + UWstrlen(pInfo11->usri11_home_dir) + 1 + + UWstrlen(pInfo11->usri11_parms) + 1 + + UWstrlen(pInfo11->usri11_logon_server) + 1 + + UWstrlen(pInfo11->usri11_workstations) + 1 + + strlen(pInfo11->usri11_logon_hours); + *pcbTotalAvail = (USHORT)TotalStringLen; + if (TotalStringLen > cbBuffer ) { + NetApiBufferFree(BufPtr); + return(NERR_BufTooSmall); + } + + UW2ANSIstrncpy(pOs2Info11->usri11_name, pInfo11->usri11_name, UNLEN_LM20); + pOs2Info11->usri11_name[UNLEN_LM20] = '\0'; + + CopyUW2ANSI(pOs2Info11->usri11_comment, pInfo11->usri11_comment); + CopyUW2ANSI(pOs2Info11->usri11_usr_comment, pInfo11->usri11_usr_comment); + CopyUW2ANSI(pOs2Info11->usri11_full_name, pInfo11->usri11_full_name); + + pOs2Info11->usri11_priv = (unsigned short)pInfo11->usri11_priv; + pOs2Info11->usri11_auth_flags = (unsigned long)pInfo11->usri11_auth_flags; + pOs2Info11->usri11_password_age = (long)pInfo11->usri11_password_age; + + CopyUW2ANSI(pOs2Info11->usri11_home_dir, pInfo11->usri11_home_dir); + CopyUW2ANSI(pOs2Info11->usri11_parms, pInfo11->usri11_parms); + + pOs2Info11->usri11_last_logon = (long)pInfo11->usri11_last_logon; + pOs2Info11->usri11_last_logoff = (long)pInfo11->usri11_last_logoff; + pOs2Info11->usri11_bad_pw_count = (unsigned short)pInfo11->usri11_bad_pw_count; + pOs2Info11->usri11_num_logons = (unsigned short)pInfo11->usri11_num_logons; + + CopyUW2ANSI(pOs2Info11->usri11_logon_server, pInfo11->usri11_logon_server); + + pOs2Info11->usri11_country_code = (unsigned short)pInfo11->usri11_country_code; + + CopyUW2ANSI(pOs2Info11->usri11_workstations, pInfo11->usri11_workstations); + + pOs2Info11->usri11_max_storage = (unsigned long)pInfo11->usri11_max_storage; + pOs2Info11->usri11_units_per_week = (unsigned short)pInfo11->usri11_units_per_week; + + StringLen = strlen(pInfo11->usri11_logon_hours) + 1; + CurEndOfBuffer -= StringLen; + pOs2Info11->usri11_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer); + RtlMoveMemory(CurEndOfBuffer, pInfo11->usri11_logon_hours, StringLen); + + pOs2Info11->usri11_code_page = (unsigned short)pInfo11->usri11_code_page; + } + + + NetApiBufferFree(BufPtr); + + return(NO_ERROR); +} + + +APIRET +Net16MessageBufferSend( + IN PSZ pszServer, + IN PSZ pszRecipient, + IN PBYTE pbBuffer, + IN ULONG cbBuffer + ) +{ + TCHAR Server[UNCLEN]; + TCHAR Recipient[CNLEN+1]; + ANSI_STRING Tmp_MB; + UNICODE_STRING Tmp_U; + APIRET rc; + + try { + PROBE_STRING(pszServer); + PROBE_STRING(pszRecipient); + Od2ProbeForRead(pbBuffer,cbBuffer,1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + ANSI2UTstrncpy(Server, pszServer, UNCLEN); + ANSI2UTstrncpy(Recipient, pszRecipient, CNLEN+1); + + // + // We now need to convert the message buffer + // itself to unicode... + // + + Tmp_MB.Buffer = (PCHAR) pbBuffer; + Tmp_MB.MaximumLength = Tmp_MB.Length = (USHORT) cbBuffer; + + rc = Od2MBStringToUnicodeString( + &Tmp_U, + &Tmp_MB, + TRUE); + + if (rc != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16MessageBufferSend: Failed to convert buffer to unicode, rc = %lx\n", rc)); + } +#endif + return(rc); + } + + rc = (APIRET) NetMessageBufferSend(Server, Recipient, NULL, (PBYTE) Tmp_U.Buffer, (ULONG) Tmp_U.Length); + + RtlFreeUnicodeString(&Tmp_U); + + return(rc); +} + + +//***************************************************************************** +// +//Following is the implementation of the Netbios APIs +// +//***************************************************************************** + + +#if 1 +#if DBG +// This is a small debug routine to dump a buffer +static +VOID +Od2BufDbgPrint( + PBYTE p, + ULONG c + ) +{ + ULONG i, m; + + for (i=0; i < c; i++) { + m = i%16; + + if (m == 0) { + KdPrint((" ")); + } + + KdPrint(("%2.2x ",p[i])); + + if (m == 15) { + KdPrint(("\n")); + } + } + + if (m != 15) { + KdPrint(("\n")); + } +} + +// This is a small debug routine to print an NCB +static +VOID +Od2NcbDbgPrint( + IN PNCB pNcb, + IN PNCB pOs2Ncb, + IN ULONG EntryPoint + ) +{ + CHAR CallName[NCBNAMSZ+1]; + CHAR Name[NCBNAMSZ+1]; + UCHAR SynchCommand = pNcb->ncb_command & ~ASYNCH; + UCHAR Asynch = pNcb->ncb_command & ASYNCH; + + switch (EntryPoint) { + case 1: + KdPrint(("BEFORE, User Ncb addr = %lx\n", (ULONG)pOs2Ncb)); + break; + case 2: + KdPrint(("AFTER\n")); + break; + case 3: + KdPrint(("POST-END\n")); + break; + } + + memcpy(CallName, pNcb->ncb_callname, NCBNAMSZ); + CallName[NCBNAMSZ] = '\0'; + memcpy(Name, pNcb->ncb_name, NCBNAMSZ); + Name[NCBNAMSZ] = '\0'; + KdPrint(("Netbios call frame:\n")); + KdPrint(("------------------\n")); + if (EntryPoint != 3) { + KdPrint(("TID : 0x%lx\n", NtCurrentTeb()->EnvironmentPointer ? Od2CurrentThreadId() : -1)); + } + KdPrint(("Command: 0x%x\n", pNcb->ncb_command)); + KdPrint(("Retcode: 0x%x\n", pNcb->ncb_retcode)); + KdPrint(("LSN : 0x%x\n", pNcb->ncb_lsn)); + KdPrint(("NUM : 0x%x\n", pNcb->ncb_num)); + KdPrint(("LanaNum: 0x%x\n", pNcb->ncb_lana_num)); + KdPrint(("Length : 0x%x\n", pNcb->ncb_length)); + KdPrint(("Callnam: %s\n", CallName)); + KdPrint(("Name : %s\n", Name)); + if (EntryPoint == 1 && Asynch) { + KdPrint(("Post : 0x%lx\n", (ULONG)pOs2Ncb->ncb_post)); + } + + switch (EntryPoint) { + case 1: + if (SynchCommand != NCBSEND && + SynchCommand != NCBCHAINSEND) { + return; + } + break; + case 2: + if (Asynch) { + return; + } + case 3: + if (SynchCommand != NCBRECV) { + return; + } + } + + KdPrint(("Buffer : \n")); + Od2BufDbgPrint((PBYTE) pNcb->ncb_buffer, (ULONG) pNcb->ncb_length); + if (SynchCommand == NCBCHAINSEND || + SynchCommand == NCBCHAINSENDNA) { + + ULONG l = (ULONG) (*(PUSHORT)pNcb->ncb_callname); + + KdPrint(("Length2: 0x%lx\n", l)); + KdPrint(("Buffer2: \n")); + + Od2BufDbgPrint(*(PBYTE *)&pNcb->ncb_callname[2], l); + + } + +} +#endif +#endif + + +// This routine transfers results from a completed internal NCB to the user's NCB +static +VOID +Od2CopyNcbResults( + OUT PNCB Dest, + IN PNCB Src, + IN BOOLEAN Nb2Semantics + ) +{ + UCHAR SynchCommand = Src->ncb_command & ~ASYNCH; + + // + // For Netbios 3.0 just copy the NCB block + // + if (!Nb2Semantics) { + RtlMoveMemory(Dest, Src, sizeof(NCB)); + return; + } + + // + // Netbios 2.0 + + Dest->ncb_lsn = Src->ncb_lsn; + Dest->ncb_num = Src->ncb_num; + Dest->ncb_length = Src->ncb_length; + if (SynchCommand != NCBCHAINSEND && SynchCommand != NCBCHAINSENDNA) { + RtlMoveMemory(Dest->ncb_callname, Src->ncb_callname, NCBNAMSZ); + } + Dest->ncb_rto = Src->ncb_rto; + Dest->ncb_sto = Src->ncb_sto; + + // + // Translate an error code in a special case where netbios 2 + // doesn't return an error + // + + if (SynchCommand == NCBHANGUP && + Src->ncb_retcode == NRC_SNUMOUT) { + + Dest->ncb_retcode = NRC_GOODRET; + Dest->ncb_cmd_cplt = NRC_GOODRET; + } else { + Dest->ncb_retcode = Src->ncb_retcode; + Dest->ncb_cmd_cplt = Src->ncb_cmd_cplt; + } +} + + +// This is the post routine which is used by NetBiosSubmit +// It clears the user's semaphore (after doing the internal copy and cleanup) +static +VOID +_stdcall +Od2NetBiosSemaphoreClearPostRoutine( + IN PNCB pNcb + ) +{ + // A user's command has completed. copy the result to his NCB and clear his semaphore. + + PNCB pOs2Ncb = ((PNCBX)pNcb)->original_pncb; // get user's NCB + HSYSSEM hUsersSemaphore = (HSYSSEM) ((PNCBX)pNcb)->original_ncb_post; // and semaphore handle + HANDLE Net16BiosHasCompleted = ((PNCBX)pNcb)->Net16BiosHasCompleted; // and notification event + APIRET RetCode; + + // Wait for Net16Bios to complete its job + + (VOID) NtWaitForSingleObject(Net16BiosHasCompleted, FALSE, NULL); + (VOID) NtClose(Net16BiosHasCompleted); + + (VOID) InterlockedIncrement(&Od2MaxAsynchNcbs); + + // Check if user's NCB space is still valid + + try { + Od2ProbeForWrite(pOs2Ncb, sizeof(NCB), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + // invalidate user's cancellation address + *(PNCB *)pOs2Ncb->ncb_reserve = NULL; + + // copy the results to the user's NCB + + Od2CopyNcbResults(pOs2Ncb, pNcb, TRUE); + +#if 1 +#if DBG + IF_OD2_DEBUG( NET ) { + Od2NcbDbgPrint(pNcb, pOs2Ncb, 3); + } +#endif +#endif + + // free our internal NCB + + RtlFreeHeap(Od2Nb2Heap, 0, pNcb); + + if (hUsersSemaphore == NULL) { + return; + } + + // clear user's semaphore + + if ((RetCode = DosSemClear(FARPTRTOFLAT(hUsersSemaphore))) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2NetBiosSemaphoreClearPostRoutine: Failed to Clear User Semaphore RetCode = %d\n", RetCode)); + } +#endif + } +} + + +// This is the post routine which is used by Netbios (= 3.0) +// It calls the user's post routine (after doing the internal copy and cleanup) +static +VOID +_stdcall +Od2NetBiosPostRoutine( + IN PNCB pNcb + ) +{ + // + // A user's command has completed. copy the result to his NCB and launch his post routine. + // + + PNCB pOs2Ncb = ((PNCBX)pNcb)->original_pncb; // get user's NCB + PVOID pUsersPostRoutine = (PVOID) ((PNCBX)pNcb)->original_ncb_post; // and post routine address + HANDLE Net16BiosHasCompleted = ((PNCBX)pNcb)->Net16BiosHasCompleted; // and notification event + APIRET RetCode; + BOOLEAN SpecialThread; // used to indicate a special addname thread + SEL TmpUserStackSel; // selector for netbios post routine user's stack in addname threads + SEL TmpUserStackAlias; // code alias for TmpUserStackSel + UCHAR SynchCommand; + + // + // Wait for Net16Bios to complete its job + // + + (VOID) NtWaitForSingleObject(Net16BiosHasCompleted, FALSE, NULL); + (VOID) NtClose(Net16BiosHasCompleted); + + // + // Grab the command for later + // + + SynchCommand = pNcb->ncb_command & ~ASYNCH; + + // + // Check if user's NCB space is still valid + // + + try { + Od2ProbeForWrite(pOs2Ncb, sizeof(NCB), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + // + // invalidate user's cancellation address + // + + *(PNCB *)pOs2Ncb->ncb_reserve = NULL; + + // + // copy the results to the user's NCB + // + + Od2CopyNcbResults(pOs2Ncb, pNcb, FALSE); + +#if 1 +#if DBG + IF_OD2_DEBUG( NET ) { + Od2NcbDbgPrint(pNcb, pOs2Ncb, 3); + } +#endif +#endif + + // + // free our internal NCB + // + + RtlFreeHeap(Od2Heap, 0, pNcb); + + if (pUsersPostRoutine == NULL) { + return; + } + + // + // Figure out if this is a special netbios addname thread. + // It must be attached separatly. If the TEB already has + // an environment then this is the worker thread, and it + // has already been attached. + // It is possible that this is the worker thread even though + // it's an addname-type command (this happens in case the + // worker fails to create an addname thread). This is OK + // The worker will be attached and detached now, and later + // re-attached if needed. + // + + if (NtCurrentTeb()->EnvironmentPointer == NULL && + (SynchCommand == NCBADDNAME || + SynchCommand == NCBADDGRNAME || + SynchCommand == NCBASTAT) + ) { + + SpecialThread = TRUE; + + } else { + + SpecialThread = FALSE; + } + + if (SpecialThread || + !Od2WorkerThreadIsAttached) { + + // + // Do this only one time for worker thread, or + // once for every special addname thread + // This code adopts the thread and makes it + // an OS/2 thread. + // + + // + // attach the thread to server tables + // + + if ((RetCode = Od2AttachWinThreadToOs2()) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2NetBiosPostRoutine: Failed to attach to Os2, RetCode = %d\n", RetCode)); + } +#endif + return; + } + + // + // allocate a stack + // + + if ((RetCode = DosAllocSeg(USERS_STACK_SIZE, &TmpUserStackSel, SEG_NONSHARED)) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2NetBiosPostRoutine: Failed to allocate stack for user, unable to launch\n")); + KdPrint((" user's post routine. DosAllocSeg rc = %u\n", RetCode)); + } +#endif + (VOID) Od2DosExit(EXIT_THREAD, 0L, 0xF0000000L); // this detaches the thread + return; + } + + if ((RetCode = DosCreateCSAlias(TmpUserStackSel, &TmpUserStackAlias)) != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2NetBiosPostRoutine: Failed to code alias user's stack, DosCreateCSAlias rc = %u\n", RetCode)); + } +#endif + (VOID) DosFreeSeg(TmpUserStackSel); + (VOID) Od2DosExit(EXIT_THREAD, 0L, 0xF0000000L); // this detaches the thread + return; + } + + if (!SpecialThread) { + + Od2UserStackSel = TmpUserStackSel; + Od2UserStackAlias = TmpUserStackAlias; + Od2WorkerThreadIsAttached = TRUE; + } + + } else { + + TmpUserStackSel = Od2UserStackSel; + TmpUserStackAlias = Od2UserStackAlias; + } + + // set up and run user's post routine + + Od2JumpTo16NetBiosPostDispatcher(pUsersPostRoutine, // 16-bit routine to jump to + SELTOFLAT(TmpUserStackSel), // flat ptr to user stack + USERS_STACK_SIZE, // stack size + TmpUserStackSel, // selector to user stack + TmpUserStackAlias, // code alias for user stack + (PVOID)FLATTOFARPTR(pOs2Ncb), // pointer to user's NCB + // pass it thru ES:BX + pOs2Ncb->ncb_retcode // pass through AX + ); + + if (SpecialThread) { + + // + // Deallocate stack and detach thread. + // The worker thread always remains attached. + // + + (VOID) DosFreeSeg(TmpUserStackAlias); + (VOID) DosFreeSeg(TmpUserStackSel); + (VOID) Od2DosExit(EXIT_THREAD, 0L, 0xF0000000L); // this only detaches the thread + } +} + + + +// This is the master Netbios 3.0 API. It checks the user's parameters, +// copies the NCB to an internal aligned NCB and calls win32 Netbios. +// some internal paramaters are attached to the NCB (see NCBX) on async calls + +APIRET +Net16bios( + IN PNCB pOs2Ncb + ) +{ + PNCB pNcb; + PNCB pCancelNcb; + UCHAR rc; + UCHAR SynchCommand; + UCHAR Asynch; + HANDLE Net16BiosHasCompleted; + BOOLEAN Nb2Semantics; + BOOLEAN WillPost; + PVOID NbHeap; + NTSTATUS Status; + + try { + Od2ProbeForWrite(pOs2Ncb, sizeof(NCB), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + pOs2Ncb->ncb_retcode = NRC_PENDING; + pOs2Ncb->ncb_cmd_cplt = NRC_PENDING; + + SynchCommand = pOs2Ncb->ncb_command & ~ASYNCH; + Asynch = pOs2Ncb->ncb_command & ASYNCH; + + if (*(PULONG)&pOs2Ncb->ncb_reserve[4] == NETBIOS2_SEMANTICS_SIGNATURE) { + *(PULONG)&pOs2Ncb->ncb_reserve[4] = 0; + Nb2Semantics = TRUE; + } else { + Nb2Semantics = FALSE; + } + + // + // Allocate internal NCB + // + + if (Nb2Semantics) { + NbHeap = Od2Nb2Heap; + } else { + NbHeap = Od2Heap; + } + + pNcb = (PNCB) RtlAllocateHeap(NbHeap, 0, sizeof(NCBX)); + + ASSERT(((ULONG)pNcb & 3) == 0); // pointer must be DWORD aligned + + if (pNcb == NULL) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16bios: Failed to RtlAllocateHeap internal NCB\n")); + } +#endif + pOs2Ncb->ncb_retcode = NRC_NORES; + pOs2Ncb->ncb_cmd_cplt = NRC_NORES; + // BUGBUG: should call post routine here if asynch. + return(NRC_NORES); + } + + RtlMoveMemory(pNcb, pOs2Ncb, sizeof(NCB)); + + // + // If it is a netbios 2 reset then modify the new NCB to the protect mode parameters + // + // Note: this is not currently used, since we allow open for NB_REGULAR only + // + if (Nb2Semantics && + SynchCommand == NCBRESET) { + if (pNcb->ncb_lsn == 0) { + pNcb->ncb_callname[0] = 6; + } else { + pNcb->ncb_callname[0] = pNcb->ncb_lsn; + } + if (pNcb->ncb_num == 0) { + pNcb->ncb_callname[1] = 12; + } else { + pNcb->ncb_callname[1] = pNcb->ncb_num; + } + pNcb->ncb_callname[2] = 16; + pNcb->ncb_callname[3] = 1; + pNcb->ncb_lsn = 0; + } + + // Check user's input + + switch (SynchCommand) { + case NCBSEND: + case NCBSENDNA: + case NCBDGSEND: + case NCBDGSENDBC: + + if (pNcb->ncb_buffer != NULL) { + + pNcb->ncb_buffer = FARPTRTOFLAT(pNcb->ncb_buffer); + + try { + Od2ProbeForRead(pNcb->ncb_buffer, pNcb->ncb_length, 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + } + break; + + case NCBCHAINSEND: + case NCBCHAINSENDNA: + + if (pNcb->ncb_buffer != NULL) { + + PCHAR TmpPtr; + + pNcb->ncb_buffer = FARPTRTOFLAT(pNcb->ncb_buffer); + + try { + Od2ProbeForRead(pNcb->ncb_buffer, pNcb->ncb_length, 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if ((TmpPtr = *(PCHAR *)&pOs2Ncb->ncb_callname[2]) != NULL) { + + TmpPtr = FARPTRTOFLAT(TmpPtr); + + try { + Od2ProbeForRead(TmpPtr, *(PUSHORT)pNcb->ncb_callname, 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + *(PCHAR *)&pNcb->ncb_callname[2] = TmpPtr; + } + } + break; + + case NCBFINDNAME: + case NCBRECV: + case NCBRECVANY: + case NCBDGRECV: + case NCBDGRECVBC: + case NCBASTAT: + case NCBSSTAT: + + if (pNcb->ncb_buffer != NULL) { + + pNcb->ncb_buffer = FARPTRTOFLAT(pNcb->ncb_buffer); + + try { + Od2ProbeForWrite(pNcb->ncb_buffer, pNcb->ncb_length, 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + } + break; + + case NCBCANCEL: + + if (pNcb->ncb_buffer != NULL) { + + // + // Note: no need to call post routine on error + // return from here, because the cancel command + // is not allowed to be asynch. + // + + pCancelNcb = (PNCB) FARPTRTOFLAT(pNcb->ncb_buffer); + + try { + Od2ProbeForWrite(pCancelNcb, sizeof(NCB), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (pCancelNcb->ncb_cmd_cplt != NRC_PENDING) { // is the command still pending? +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16bios: Got request to cancel a non-pending NCB, ignoring it\n")); + } +#endif + RtlFreeHeap(NbHeap, 0, pNcb); + pOs2Ncb->ncb_retcode = NRC_CANCEL; + pOs2Ncb->ncb_cmd_cplt = NRC_CANCEL; + return(NRC_CANCEL); + } + + pNcb->ncb_buffer = *(PUCHAR *)pCancelNcb->ncb_reserve; + + if (pNcb->ncb_buffer == NULL) { // assume we've just completed it + // this is reasonable, since cmd_cplt == NRC_PENDING +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16bios: NCB completed during request to cancel\n")); + } +#endif + RtlFreeHeap(NbHeap, 0, pNcb); + pOs2Ncb->ncb_retcode = NRC_CANOCCR; + pOs2Ncb->ncb_cmd_cplt = NRC_CANOCCR; + return(NRC_CANOCCR); + } + + try { + Od2ProbeForWrite(pNcb->ncb_buffer, sizeof(NCBX), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + + // + // The user gave an invalid address + // + +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16bios: Got an invalid NCB address to cancel, ignoring it\n")); + } +#endif + RtlFreeHeap(NbHeap, 0, pNcb); + pOs2Ncb->ncb_retcode = NRC_BADDR; + pOs2Ncb->ncb_cmd_cplt = NRC_BADDR; + return(NRC_BADDR); + } + } + break; + } + + RtlZeroMemory(pNcb->ncb_reserve, 14); + + // + // Set up async processing + // + + if (Asynch) { + + Status = NtCreateEvent(&Net16BiosHasCompleted, + EVENT_ALL_ACCESS, + NULL, + NotificationEvent, + FALSE); + + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Net16Bios: Can't create an event for synchronization of post routine, rc = %X\n", Status)); + } +#endif + RtlFreeHeap(NbHeap, 0, pNcb); + pOs2Ncb->ncb_retcode = NRC_OSRESNOTAV; + pOs2Ncb->ncb_cmd_cplt = NRC_OSRESNOTAV; + // BUGBUG: should call post routine here. + return(NRC_OSRESNOTAV); + } + + // BUGBUG: we must make sure the event is properly cleaned up if the thread terminates + // between here and the point it's signalled. + + ((PNCBX)pNcb)->original_pncb = pOs2Ncb; + ((PNCBX)pNcb)->original_ncb_post = (ULONG) pNcb->ncb_post; + ((PNCBX)pNcb)->Net16BiosHasCompleted = Net16BiosHasCompleted; + *(PNCB *)pOs2Ncb->ncb_reserve = pNcb; + + if (Nb2Semantics) { + pNcb->ncb_post = Od2NetBiosSemaphoreClearPostRoutine; + } else { + pNcb->ncb_post = Od2NetBiosPostRoutine; + } + } else { + pNcb->ncb_post = NULL; + } + +#if 1 +#if DBG + IF_OD2_DEBUG( NET ) { + Od2NcbDbgPrint(pNcb, pOs2Ncb, 1); + } +#endif +#endif + + // + // and go do it + // + + if (Nb2Semantics) { + + rc = Od2Netbios(pNcb, Od2NbDev, &WillPost); + + } else { + + rc = Netbios(pNcb); + + // + // The following are the cases where win32 netbios does not call + // the post routine when called asynch: + // 1) bad ncb alignment (NRC_BADDR) -- won't happen + // 2) ncb_event and ncb_post both given (NRC_ILLCMD) -- won't happen + // 3) returns NRC_OPENERR + // this happens when win32 can't open \device\netbios + // or can't create a reserved event for sync processing. + // 4) sometimes when returns NRC_SYSTEM + // if win32 returns -- no post routine + // this happens when can't create worker thread + // or when can't create related events + // (event, addnameevent) + // if driver returns -- will call post routine + // 5) an access violation after chain send ncb completion when copying + // BigBuffer back to user space, or accessing the ncb + // internals (post, event). + // + // The only case we can't be sure about is NRC_SYSTEM. In this + // case it is better to assume the post routine will get called. + // the only damage that can be incurred in this way is that the + // ncb remains left behind on NbHeap, and Net16BiosHasCompleted + // event is not deleted. this isn't too bad, assuming this is + // a rare problem. + // + + if (Asynch && rc != NRC_OPENERR) { + WillPost = TRUE; + } else { + WillPost = FALSE; + } + } + + // copy results from internal NCB to user's NCB + + Od2CopyNcbResults(pOs2Ncb, pNcb, Nb2Semantics); + +#if 1 +#if DBG + IF_OD2_DEBUG( NET ) { + Od2NcbDbgPrint(pNcb, pOs2Ncb, 2); + KdPrint(("rc : %d\n", rc)); + } +#endif +#endif + +// Note that if the command was a CANCEL, the post routine of the cancelled NCB still gets called, +// and will clean up the cancelled NCB as needed + + if (Asynch) { + if (WillPost) { + (VOID) NtSetEvent(Net16BiosHasCompleted, NULL); + } else { + (VOID) NtClose(Net16BiosHasCompleted); + RtlFreeHeap(NbHeap, 0, pNcb); + if (Nb2Semantics) { + (VOID) InterlockedIncrement(&Od2MaxAsynchNcbs); + } + } + } else { + RtlFreeHeap(NbHeap, 0, pNcb); + } + + return((APIRET) rc); +} + + +//******************* +// Following are old Netbios APIs (lanman 2.x). We create a fictional logical network +// for each lan adapter in the system. This is done by using NCBENUM. NCBENUM gives +// us a list of all valid lana numbers in the system. We assign NET1 to the 1st lana +// NET2 to the 2nd lana and so on. The "default device" for NetBiosOpen and Submit is always +// NET DEFAULT_NET. +// The device handle which is used to operate a logical network is simply the NET +// number + 1. Handle 0 is equivalent to the default net. +//******************* + + +ULONG +Od2NetNumberToLanaIndex( + IN ULONG NetNumber + ) +{ + if (NetNumber == 0L) { // use default net ? + if (Od2LanaEnum.length >= DEFAULT_NET) { + return((ULONG)(DEFAULT_NET - 1)); + } else { + return(0L); + } + } else { + if ((ULONG)Od2LanaEnum.length >= NetNumber) { + return(NetNumber - 1); + } else { + return((ULONG)-1); + } + } +} + + +NTSTATUS +Od2ActivateLana( + IN ULONG NetNumber, + OUT PULONG pLanaIndex OPTIONAL + ) +{ + // + // This routine takes a net number, and makes sure netbios 2 is initialized + // and ready on that lana. overall netbios 2 initialization is done if necessary. + // if NetNumber is (-1), overall initialization is done, but not for a particular + // lana. + // + + OS2_API_MSG m; + POS2_NETBIOS_MSG a = &m.u.Netbios2Request; + BOOLEAN InCrit = FALSE; + ULONG LanaIndex; + PVOID BaseAddress; + APIRET RetCode; + BOOLEAN RemoveLDTEntry = FALSE; + + if (!Od2Netbios2Initialized) { + + RtlEnterCriticalSection(&Od2NbSyncCrit); + + if (!Od2Netbios2Initialized) { // check again in case we just did it + + // + // allocate a special heap to hold the netbios 2 packets. + // we allocate this as a shared memory object in order that + // the heap have a unique address within each process. no + // sharing of memory is actually being done. the reason + // unique addresses are necessary is because the netbios + // driver gets confused about cancel requests when 2 processes + // have the same netbios packet address. + // + + RetCode = DosAllocSharedMem( + &BaseAddress, + NULL, // no name + 0x10000L, // reserve 64K for the heap + OBJ_GIVEABLE | PAG_READ | PAG_WRITE, + FALSE // Don't create LDT entry + ); + + if (RetCode != NO_ERROR) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2ActivateLana: DosAllocSharedMem failed, RetCode = %x\n", RetCode)); + } +#endif + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(STATUS_NO_MEMORY); + } + + Od2Nb2Heap = RtlCreateHeap( + HEAP_GROWABLE, + BaseAddress, + 0x10000L, // initial reserved amount + 0L, // initial commit = 1 page + NULL, // standard lock + 0L); // reserved + + if (Od2Nb2Heap == NULL) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2ActivateLana: RtlCreateHeap failed\n")); + } +#endif + DosFreeMem(BaseAddress, &RemoveLDTEntry); + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(STATUS_NO_MEMORY); + } + + // + // call server to get initial device handle, lana enumeration + // initialize internal lanastate + // + + if (NetNumber == (ULONG)-1) { + a->RequestType = NB2_INIT; + } else { + a->RequestType = NB2_INIT_LANA; + a->NetNumber = (UCHAR) NetNumber; + } + + m.ReturnedErrorValue = NO_ERROR; + Od2CallSubsystem(&m, NULL, Os2Netbios2Reqst, sizeof(*a)); + + if (!NT_SUCCESS(a->ReturnStatus)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("Od2ActivateLana: Call to server for init failed, Status = %lx\n", a->ReturnStatus)); + } +#endif + RtlDestroyHeap(Od2Nb2Heap); + DosFreeMem(BaseAddress, &RemoveLDTEntry); + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(a->ReturnStatus); + } + + Od2LanaEnum.length = a->LanaEnumLength; + RtlMoveMemory(Od2LanaEnum.lana, a->LanaEnum, MAX_LANA); + RtlZeroMemory(Od2LanaState, sizeof(Od2LanaState)); + Od2NbDev = a->hDev; + Od2MaxAsynchNcbs = (LONG) MAX_ASYNCH_NCBS; + + Od2Netbios2Initialized = TRUE; + + if (NetNumber != (ULONG)-1) { + if (a->RetCode != NB2ERR_INVALID_LANA) { + + LanaIndex = Od2NetNumberToLanaIndex(NetNumber); + + Od2LanaState[LanaIndex] |= 0x1; + + if (ARGUMENT_PRESENT(pLanaIndex)) { + *pLanaIndex = LanaIndex; + } + } else { + if (ARGUMENT_PRESENT(pLanaIndex)) { + *pLanaIndex = (ULONG) -1; + } + } + } + + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(STATUS_SUCCESS); + + } + + InCrit = TRUE; + } + + if (NetNumber == (ULONG)-1) { + if (InCrit) { + RtlLeaveCriticalSection(&Od2NbSyncCrit); + } + return(STATUS_SUCCESS); + } + + LanaIndex = Od2NetNumberToLanaIndex(NetNumber); + + if (LanaIndex == (ULONG)-1) { + + if (ARGUMENT_PRESENT(pLanaIndex)) { + *pLanaIndex = (ULONG) -1; + } + if (InCrit) { + RtlLeaveCriticalSection(&Od2NbSyncCrit); + } + return(STATUS_SUCCESS); + } + + if (!(Od2LanaState[LanaIndex] & 0x1)) { + + if (!InCrit) { + + RtlEnterCriticalSection(&Od2NbSyncCrit); + InCrit = TRUE; + + if (Od2LanaState[LanaIndex] & 0x1) { // check again in case we just did it + goto Od2LanaNumGood; + } + } + + // + // call server to init lana + // + + if (Od2LanaState[LanaIndex] & 0x2) { + Od2LanaState[LanaIndex] &= ~0x2; + Od2LanaState[LanaIndex] |= 0x1; + goto Od2LanaNumGood; + } + + a->RequestType = NB2_LANA; + a->NetNumber = (UCHAR) NetNumber; + + m.ReturnedErrorValue = NO_ERROR; + Od2CallSubsystem(&m, NULL, Os2Netbios2Reqst, sizeof(*a)); + + if (!NT_SUCCESS(a->ReturnStatus)) { + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(a->ReturnStatus); + } + + if (a->RetCode != NB2ERR_INVALID_LANA) { + + Od2LanaState[LanaIndex] |= 0x1; + goto Od2LanaNumGood; + + } else { + if (ARGUMENT_PRESENT(pLanaIndex)) { + *pLanaIndex = (ULONG) -1; + } + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(STATUS_SUCCESS); + } + } + +Od2LanaNumGood: + + if (ARGUMENT_PRESENT(pLanaIndex)) { + *pLanaIndex = LanaIndex; + } + + if (InCrit) { + RtlLeaveCriticalSection(&Od2NbSyncCrit); + } + + return(STATUS_SUCCESS); +} + + +APIRET +Net16BiosClose( + ULONG hDevName + ) +{ +// NCB Ncb; + ULONG LanaIndex; + +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosClose() called, hDevName = %lu\n", hDevName)); + } +#endif + + if (hDevName == 0) { + return(NERR_Success); // dummy close for the "default handle" + } + + if (!Od2Netbios2Initialized) { // we haven't been initialized at all + return(NERR_NetNotStarted); + } + + LanaIndex = Od2NetNumberToLanaIndex(hDevName); + + if (LanaIndex == (ULONG)-1) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosClose: invalid hDevName = %lu\n", hDevName)); + } +#endif + return(ERROR_INVALID_HANDLE); + } + + // + // check if it's already closed... + // + + if (!(Od2LanaState[LanaIndex] & 0x1)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosClose: already closed hDevName = %lu\n", hDevName)); + } +#endif + return(ERROR_INVALID_HANDLE); + } + + RtlEnterCriticalSection(&Od2NbSyncCrit); + + // + // recheck in case we just closed it. + // + + if (!(Od2LanaState[LanaIndex] & 0x1)) { + RtlLeaveCriticalSection(&Od2NbSyncCrit); +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosClose: already closed hDevName = %lu\n", hDevName)); + } +#endif + return(ERROR_INVALID_HANDLE); + } + + // + // we mark the lana as pseudo-closed. It won't be used anymore + // until it's reopened. + // + + Od2LanaState[LanaIndex] &= ~0x1; + Od2LanaState[LanaIndex] |= 0x2; + + + // + // BUGBUG: We can no longer reset the adapter in order to + // cancel all pending ncbs on a particular lana. Currently, + // there is no other way to do this, so we skip cancelling + // pending ncbs, and hope there won't be a problem. + // + // Note: a way to do this might be to issue an NtCancelIoFile() + // from the netbios worker thread. But this will cancel on all + // lana. + // + +#if 0 + // Reset the corresponding adapter so all pending NCBs get cancelled + + RtlZeroMemory(&Ncb, sizeof(NCB)); + Ncb.ncb_command = NCBRESET; + Ncb.ncb_lana_num = Od2LanaEnum.lana[LanaIndex]; + + Net16bios(&Ncb); + + if (Ncb.ncb_retcode != NRC_GOODRET) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosClose: Unable to reset adapter %lu, retcode = %x\n", (ULONG)Ncb.ncb_lana_num, (ULONG)Ncb.ncb_retcode)); + } +#endif + } +#endif + + RtlLeaveCriticalSection(&Od2NbSyncCrit); + return(NERR_Success); +} + + +APIRET +Net16BiosEnum( + PCHAR pszServer, + LONG sLevel, + PCHAR pbBuffer, + ULONG cbBuffer, + PUSHORT pcEntriesRead, + PUSHORT pcTotalAvail + ) +{ + NTSTATUS Status; + ULONG strucsiz; + UCHAR i; + struct netbios_info_0 nb0; + struct netbios_info_1 nb1; + + try { + if ((pszServer != NULL) && (*pszServer != '\0')) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosEnum() for a remote server is not implemented yet\n")); + } +#endif + return(ERROR_NOT_SUPPORTED); + } + + Od2ProbeForWrite(pbBuffer, cbBuffer, 1); + Od2ProbeForWrite(pcEntriesRead, sizeof(USHORT), 1); + Od2ProbeForWrite(pcTotalAvail, sizeof(USHORT), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 0 && sLevel != 1) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosEnum() Level %d not legal\n", sLevel)); + } +#endif + return(ERROR_INVALID_LEVEL); + } + + Status = Od2ActivateLana( + (ULONG) -1, + NULL); + + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosEnum() Od2ActivateLana failed, Status = %lx\n", Status)); + } +#endif + return(NERR_NetNotStarted); + } + + *pcTotalAvail = (USHORT) Od2LanaEnum.length; + *pcEntriesRead = 0; + + strucsiz = sLevel == 0 ? sizeof(nb0) : sizeof(nb1); + + for (i = 0; i < Od2LanaEnum.length && cbBuffer >= strucsiz; i++) { + if (sLevel == 0) { + RtlZeroMemory(&nb0, strucsiz); + strcpy(nb0.nb0_net_name, "NET"); + _itoa((int)i+1, &nb0.nb0_net_name[3], 10); + RtlMoveMemory(pbBuffer, &nb0, strucsiz); + } else { // sLevel == 1 + RtlZeroMemory(&nb1, strucsiz); + strcpy(nb1.nb1_net_name, "NET"); + _itoa((int)i+1, &nb1.nb1_net_name[3], 10); + strcpy(nb1.nb1_driver_name, "VrtWnNB$"); + nb1.nb1_lana_num = Od2LanaEnum.lana[i]; + + // put some fictive information in it... + + nb1.nb1_driver_type = NB_TYPE_NCB; + nb1.nb1_net_status = NB_OPEN_REGULAR|NB_LAN_MANAGED; + nb1.nb1_net_bandwidth = 10000000L; + nb1.nb1_max_sess = 255; + nb1.nb1_max_ncbs = 255; + nb1.nb1_max_names = 255; + + RtlMoveMemory(pbBuffer, &nb1, strucsiz); + } + pbBuffer += strucsiz; + cbBuffer -= strucsiz; + (*pcEntriesRead)++; + } + + if (*pcEntriesRead < (USHORT)Od2LanaEnum.length) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosEnum: returning ERROR_MORE_DATA\n")); + } +#endif + return(ERROR_MORE_DATA); + } + return(NERR_Success); +} + + +APIRET +Net16BiosGetInfo( + PCHAR pszServer, + PCHAR pszNetBiosName, + LONG sLevel, + PCHAR pbBuffer, + ULONG cbBuffer, + PUSHORT pcbTotalAvail + ) +{ + NTSTATUS Status; + ULONG strucsiz; + ULONG NetNumber; + ULONG LanaIndex; + struct netbios_info_0 nb0; + struct netbios_info_1 nb1; + + try { + if ((pszServer != NULL) && (*pszServer != '\0')) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosGetInfo() for a remote server is not implemented yet\n")); + } +#endif + return(ERROR_NOT_SUPPORTED); + } + + PROBE_STRING(pszNetBiosName); + Od2ProbeForWrite(pbBuffer, cbBuffer, 1); + Od2ProbeForWrite(pcbTotalAvail, sizeof(USHORT), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (sLevel != 0 && sLevel != 1) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosGetInfo() Level %d not legal\n", sLevel)); + } +#endif + return(ERROR_INVALID_LEVEL); + } + + strucsiz = sLevel == 0 ? sizeof(nb0) : sizeof(nb1); + + if (cbBuffer < strucsiz) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosGetInfo: user buffer too small\n")); + } +#endif + return(NERR_BufTooSmall); + } + + if (pszNetBiosName == NULL || *pszNetBiosName == '\0') { + NetNumber = 0; + } else { + if (_strnicmp(pszNetBiosName, "NET", 3)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosGetInfo: Bad network name: %s\n", pszNetBiosName)); + } +#endif + return(ERROR_BAD_NETPATH); + } + + NetNumber = atol(pszNetBiosName+3); + } + + Status = Od2ActivateLana( + (ULONG) -1, + NULL); + + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosGetInfo() Od2ActivateLana failed, Status = %lx\n", Status)); + } +#endif + return(NERR_NetNotStarted); + } + + LanaIndex = Od2NetNumberToLanaIndex(NetNumber); + + if (LanaIndex == (ULONG) -1) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosGetInfo: Bad network name: %s\n", pszNetBiosName)); + } +#endif + return(ERROR_BAD_NETPATH); + } + + *pcbTotalAvail = (USHORT) strucsiz; + + if (sLevel == 0) { + RtlZeroMemory(&nb0, strucsiz); + strcpy(nb0.nb0_net_name, pszNetBiosName); + RtlMoveMemory(pbBuffer, &nb0, strucsiz); + } else { // sLevel == 1 + RtlZeroMemory(&nb1, strucsiz); + strcpy(nb1.nb1_net_name, pszNetBiosName); + strcpy(nb1.nb1_driver_name, "VrtWnNB$"); + nb1.nb1_lana_num = Od2LanaEnum.lana[LanaIndex]; + + // put some fictive information in it... + + nb1.nb1_driver_type = NB_TYPE_NCB; + nb1.nb1_net_status = NB_OPEN_REGULAR|NB_LAN_MANAGED; + nb1.nb1_net_bandwidth = 10000000L; + nb1.nb1_max_sess = 255; + nb1.nb1_max_ncbs = 255; + nb1.nb1_max_names = 255; + + RtlMoveMemory(pbBuffer, &nb1, strucsiz); + } + + return(NERR_Success); +} + + +APIRET +Net16BiosOpen( + PCHAR pszDevName, + PCHAR pszReserved, + ULONG usOpenOpt, + PUSHORT phDevName + ) +{ + NTSTATUS Status; + ULONG NetNumber; + ULONG LanaIndex; + + UNREFERENCED_PARAMETER(pszReserved); + +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen() called\n")); + } +#endif + + try { + PROBE_STRING(pszDevName); + Od2ProbeForWrite(phDevName, sizeof(USHORT), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (usOpenOpt < NB_REGULAR || + usOpenOpt > NB_EXCLUSIVE) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen() illegal usOpenOpt = %lx\n", usOpenOpt)); + } +#endif + return(ERROR_INVALID_PARAMETER); + } + + if (usOpenOpt != NB_REGULAR) { // we only support NB_REGULAR for now +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen() unsupported usOpenOpt = %lx\n", usOpenOpt)); + } +#endif + return(ERROR_ACCESS_DENIED); + } + + if (pszDevName == NULL || *pszDevName == '\0') { + NetNumber = 0L; + } else { + if (_strnicmp(pszDevName, "NET", 3)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen: Bad network name: %s\n", pszDevName)); + } +#endif + return(ERROR_BAD_NETPATH); + } + + NetNumber = atol(pszDevName+3); + } + + if (NetNumber > 0xffL) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen: Bad network name: %s\n", pszDevName)); + } +#endif + return(ERROR_BAD_NETPATH); + } + + Status = Od2ActivateLana( + NetNumber, + &LanaIndex); + + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen() Od2ActivateLana failed, Status = %lx\n", Status)); + } +#endif + return(NERR_NetNotStarted); + } + + if (LanaIndex == (ULONG) -1) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosOpen: Bad network name: %s\n", pszDevName)); + } +#endif + return(ERROR_BAD_NETPATH); + } + + if (NetNumber != 0) { + *phDevName = (USHORT) NetNumber; + } else { + if (Od2LanaEnum.length >= DEFAULT_NET) { + *phDevName = (USHORT) DEFAULT_NET; + } else { + *phDevName = (USHORT) 1; + } + } + + return(NERR_Success); +} + + +// Old lanman NetBiosSubmit. Generally depends on the newer Netbios 3.0 (Net16bios) +// however, this implements the following differences: +// +// - on async requests, a semaphore is cleared instead of calling a post routine +// - implements the possiblity of NCB chaining which is unavailable with Net16bios +// - does an automatic open of the default lana if necessary +// + +APIRET +Net16BiosSubmit( + IN ULONG hDevName, + IN ULONG NcbOpt, + IN OUT PVOID pNCB + ) +{ + PNCB pNcb; + PCHAR OrigSegBase; + NTSTATUS Status; + ULONG LanaIndex; + BOOLEAN FirstRound; + BOOLEAN CancelChain; + USHORT Link; + UCHAR OrigLanaNum; + UCHAR SynchCommand; + UCHAR Asynch; + UCHAR rc; + +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit() called\n")); + } +#endif + + if (NcbOpt > 3) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit called with an invalid NcbOpt = %lu\n", NcbOpt)); + } +#endif + return(ERROR_INVALID_PARAMETER); + } + + if (hDevName > 0xffL) { + + LanaIndex = (ULONG)-1; + + } else if (hDevName == 0L) { // use default net? + + // + // do a default open of device handle 0 + // + + Status = Od2ActivateLana( + hDevName, + &LanaIndex); + + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit: Od2ActivateLana failed, Status= %lx\n", Status)); + } +#endif + return(NERR_NetNotStarted); + } + + } else { + + // + // Initialize, and check if the handle is open + // + + Status = Od2ActivateLana( + (ULONG) -1, + NULL); + + if (!NT_SUCCESS(Status)) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit: Od2ActivateLana failed, Status= %lx\n", Status)); + } +#endif + return(NERR_NetNotStarted); + } + + LanaIndex = Od2NetNumberToLanaIndex(hDevName); + + if (LanaIndex != (ULONG) -1) { + + if (!(Od2LanaState[LanaIndex] & 0x1)) { // lana closed? + LanaIndex = (ULONG) -1; + } + } + + } + + if (LanaIndex == (ULONG) -1) { +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit: Bad handle, hDevName = %lu\n", hDevName)); + } +#endif + return(ERROR_INVALID_HANDLE); + } + + // + // NcbOpt == 1 implies that we should retry the NCB on some types of errors. + // Since the LanMan programmer's reference does not document which errors cause a + // retry, we shall not retry anything for the present + // + + for (FirstRound = TRUE, CancelChain = FALSE; ; FirstRound = FALSE) { + + if (NcbOpt > 1) { + + if (FirstRound) { + OrigSegBase = SELTOFLAT(FLATTOSEL(pNCB)); + } + + try { + Link = *(PUSHORT)pNCB; + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (Link == 0xffff) { + if (FirstRound) { + return(NERR_Success); + } else { + break; + } + } + + pNcb = (PNCB)((PCHAR)pNCB+sizeof(USHORT)); + pNCB = (PVOID)(OrigSegBase + Link); + + try { + Od2ProbeForWrite(pNcb, sizeof(NCB), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + + if (CancelChain) { + pNcb->ncb_retcode = NRC_CMDCAN; + pNcb->ncb_cmd_cplt = NRC_CMDCAN; + continue; + } + } else { + if (FirstRound) { + pNcb = (PNCB) pNCB; + + try { + Od2ProbeForWrite(pNcb, sizeof(NCB), 1); + } except( EXCEPTION_EXECUTE_HANDLER ) { + Od2ExitGP(); + } + } + } + + pNcb->ncb_retcode = NRC_PENDING; + pNcb->ncb_cmd_cplt = NRC_PENDING; + + SynchCommand = pNcb->ncb_command & ~ASYNCH; + Asynch = pNcb->ncb_command & ASYNCH; + + // + // If it is a netbios 2 reset - disallow, since we only allow open for NB_REGULAR. + // + + if (SynchCommand == NCBRESET) { + pNcb->ncb_retcode = NRC_ILLCMD; + pNcb->ncb_cmd_cplt = NRC_ILLCMD; + rc = NRC_ILLCMD; + goto ErrorHandling; + } + + if (Asynch) { + + LONG Count; + + Count = InterlockedDecrement(&Od2MaxAsynchNcbs); + + if (Count < 0) { + + (VOID) InterlockedIncrement(&Od2MaxAsynchNcbs); +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit: max asynch ncb count exceeded\n")); + } +#endif + pNcb->ncb_retcode = NRC_NORES; + pNcb->ncb_cmd_cplt = NRC_NORES; + rc = NRC_NORES; + goto ErrorHandling; + + } + } + + // + // switch lananum to represent the "device driver" + // originally this was done only if the lananum is 0, + // but it is now done always + // + + OrigLanaNum = pNcb->ncb_lana_num; + pNcb->ncb_lana_num = Od2LanaEnum.lana[LanaIndex]; + + // + // mark this as a netbios 2 ncb for special processing + // + + *(PULONG)&pNcb->ncb_reserve[4] = NETBIOS2_SEMANTICS_SIGNATURE; + + Net16bios(pNcb); + + rc = pNcb->ncb_retcode; + pNcb->ncb_lana_num = OrigLanaNum; + +ErrorHandling: + + if (NcbOpt == 0) { + break; + } else if (NcbOpt == 1) { + + // for implementing error-retry on a single NCB, check the error code here + // and if it should be retried simply "continue" instead of "break" + break; + + } else if (NcbOpt == 3) { // stop on error + CancelChain = TRUE; + } + + // if proceed-on-error, continue the loop + } + + switch (rc) { + case NRC_GOODRET: + case NRC_PENDING: + return(NERR_Success); + + default: +#if DBG + IF_OD2_DEBUG( NET ) { + KdPrint(("NetBiosSubmit: Final return code = %x\n", (ULONG)rc)); + } +#endif + return((APIRET)rc | 0x100); + } +} + +APIRET +DosINetTransaction( + IN LPSTR ServerName, + IN LPBYTE SendParmBuffer, + IN DWORD SendParmBufLen, + IN LPBYTE SendDataBuffer, + IN DWORD SendDataBufLen, + OUT LPBYTE ReceiveParmBuffer, + IN DWORD ReceiveParmBufLen, + IN LPBYTE ReceiveDataBuffer, + IN OUT LPDWORD ReceiveDataBufLen, + IN BOOL NullSessionFlag + ) + +/*++ + +Routine Description: + + Sends a transaction request to a server and receives a response + +Arguments: + + ServerName - to send request to + SendParmBuffer - send parameters + SendParmBufLen - length of send parameters + SendDataBuffer - send data + SendDataBufLen - length of send data + ReceiveParmBuffer - receive parameter buffer + ReceiveParmBufLen - length of receive parameter buffer + ReceiveDataBuffer - where to receive data + ReceiveDataBufLen - length of data buffer + NullSessionFlag - set if we are to use a null session + +Return Value: + + APIRET + Success - NERR_Success + Failure - + +--*/ + +{ + APIRET status; + + status = RxpTransactSmb((USHORT *)ServerName, + + // + // BUGBUG - transport name? + // + + (LPTSTR)NULL, + SendParmBuffer, + SendParmBufLen, + SendDataBuffer, + SendDataBufLen, + ReceiveParmBuffer, + ReceiveParmBufLen, + ReceiveDataBuffer, + ReceiveDataBufLen, + NullSessionFlag + ); + + return status; +} + + +APIRET +DosIRemoteApi( + IN DWORD ApiNumber, + IN LPSTR ServerNamePointer, + IN LPSTR ParameterDescriptor, + IN LPSTR DataDescriptor, + IN LPSTR AuxDescriptor, + IN ULONG NullSessionFlag + ) +{ + APIRET rc; + +#if DBG + USHORT tid, pid; + + IF_OD2_DEBUG ( APIS ) { + pid = (USHORT)(Od2Process->Pib.ProcessId); + tid = (USHORT)(Od2CurrentThreadId()); + + if ((Os2DebugTID == 0) || (Os2DebugTID == tid)) + { + KdPrint(("[PID %d: TID %d] %s\n", + pid, tid, Os2NetAPIName[ApiNumber])); + } + } +#endif + + rc = VrRemoteApi( + ApiNumber, + ServerNamePointer, + ParameterDescriptor, + DataDescriptor, + AuxDescriptor, + (UCHAR)NullSessionFlag + ); + return rc; +} + +APIRET + VrEncryptSES( + IN LPSTR ServerNamePointer, + IN LPSTR passwordPointer, // Input password (Not encripted) + IN LPSTR encryptedLmOwfPassword // output password (encripted) + ); + +APIRET +DosIEncryptSES( + IN LPSTR ServerNamePointer, + IN LPSTR passwordPointer, // Input password (Not encripted) + IN LPSTR encryptedLmOwfPassword // output password (encripted) + ) +{ + APIRET rc; + + rc = VrEncryptSES(ServerNamePointer, passwordPointer, + encryptedLmOwfPassword); + return(rc); +} + +APIRET +NetIWkstaGetUserInfo (LPBYTE UserName, LPBYTE LogonServer, + LPBYTE LogonDomain, LPBYTE OtherDomains, LPBYTE WsName) +{ + //TCHAR Server[UNCLEN]; + LPBYTE BufPtr; + NET_API_STATUS rc; + PWKSTA_USER_INFO_1 pInfo1; + PWKSTA_INFO_100 pInfo2; + + rc = NetWkstaUserGetInfo(NULL, 1L, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + pInfo1 = (PWKSTA_USER_INFO_1) BufPtr; + + UT2ANSIstrcpy(UserName, pInfo1->wkui1_username); + + strcpy(LogonServer, "\\\\"); + UT2ANSIstrcpy(LogonServer + 2, pInfo1->wkui1_logon_server); + + UT2ANSIstrcpy(LogonDomain, pInfo1->wkui1_logon_domain); + + UT2ANSIstrcpy(OtherDomains, pInfo1->wkui1_oth_domains); + + NetApiBufferFree(BufPtr); + + rc = NetWkstaGetInfo(0L, 100L, &BufPtr); + + if (rc != NO_ERROR) { + return(rc); + } + + pInfo2 = (PWKSTA_INFO_100) BufPtr; + + UT2ANSIstrcpy(WsName, pInfo2->wki100_computername); + + NetApiBufferFree(BufPtr); + + return NO_ERROR; + +} |