summaryrefslogtreecommitdiffstats
path: root/private/nw/svcdlls/nwwks/lib
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/nw/svcdlls/nwwks/lib
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/nw/svcdlls/nwwks/lib')
-rw-r--r--private/nw/svcdlls/nwwks/lib/lsa.c537
-rw-r--r--private/nw/svcdlls/nwwks/lib/makefile6
-rw-r--r--private/nw/svcdlls/nwwks/lib/misc.c785
-rw-r--r--private/nw/svcdlls/nwwks/lib/reg.c1010
-rw-r--r--private/nw/svcdlls/nwwks/lib/sources47
-rw-r--r--private/nw/svcdlls/nwwks/lib/splutil.c351
6 files changed, 2736 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/lib/lsa.c b/private/nw/svcdlls/nwwks/lib/lsa.c
new file mode 100644
index 000000000..1dc664aa4
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/lib/lsa.c
@@ -0,0 +1,537 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ lsa.c
+
+Abstract:
+
+ This module provides helpers to call LSA, particularly for
+ manipulating secret objects.
+
+Author:
+
+ Rita Wong (ritaw) 22-Apr-1993
+
+--*/
+
+#include <stdlib.h>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windef.h>
+#include <winerror.h>
+#include <winbase.h>
+
+#include <nwlsa.h>
+
+//-------------------------------------------------------------------//
+// //
+// Constants and Macros //
+// //
+//-------------------------------------------------------------------//
+
+#define NW_SECRET_PREFIX L"_MS_NWCS_"
+
+
+DWORD
+NwOpenPolicy(
+ IN ACCESS_MASK DesiredAccess,
+ OUT LSA_HANDLE *PolicyHandle
+ )
+/*++
+
+Routine Description:
+
+ This function gets a handle to the local security policy by calling
+ LsaOpenPolicy.
+
+Arguments:
+
+ DesiredAccess - Supplies the desired access to the local security
+ policy.
+
+ PolicyHandle - Receives a handle to the opened policy.
+
+Return Value:
+
+ NO_ERROR - Policy handle is returned.
+
+ Error from LSA.
+
+--*/
+{
+ NTSTATUS ntstatus;
+ OBJECT_ATTRIBUTES ObjAttributes;
+
+
+ //
+ // Open a handle to the local security policy. Initialize the
+ // objects attributes structure first.
+ //
+ InitializeObjectAttributes(
+ &ObjAttributes,
+ NULL,
+ 0L,
+ NULL,
+ NULL
+ );
+
+ ntstatus = LsaOpenPolicy(
+ NULL,
+ &ObjAttributes,
+ DesiredAccess,
+ PolicyHandle
+ );
+
+ if (! NT_SUCCESS(ntstatus)) {
+ KdPrint(("NWWORKSTATION: LsaOpenPolicy returns %08lx\n",
+ ntstatus));
+
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+ return NO_ERROR;
+}
+
+
+DWORD
+NwOpenSecret(
+ IN ACCESS_MASK DesiredAccess,
+ IN LSA_HANDLE PolicyHandle,
+ IN LPWSTR LsaSecretName,
+ OUT PLSA_HANDLE SecretHandle
+ )
+/*++
+
+Routine Description:
+
+ This function opens a handle to the specified secret object.
+
+Arguments:
+
+ DesiredAccess - Supplies the desired access to the secret object.
+
+ PolicyHandle - Supplies a handle to an already opened LSA policy.
+
+ LsaSecretName - Supplies the name of the secret to open.
+
+ SecretHandle - Receives the handle of the opened secret.
+
+Return Value:
+
+ NO_ERROR - Secret handle is returned.
+
+ Error from LSA.
+
+--*/
+{
+ NTSTATUS ntstatus;
+ UNICODE_STRING SecretNameString;
+
+
+ RtlInitUnicodeString(&SecretNameString, LsaSecretName);
+
+ ntstatus = LsaOpenSecret(
+ PolicyHandle,
+ &SecretNameString,
+ DesiredAccess,
+ SecretHandle
+ );
+
+
+ if (! NT_SUCCESS(ntstatus)) {
+ KdPrint(("NWWORKSTATION: LsaOpenSecret %ws returns %08lx\n",
+ LsaSecretName, ntstatus));
+
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+ return NO_ERROR;
+}
+
+
+DWORD
+NwFormSecretName(
+ IN LPWSTR Qualifier,
+ OUT LPWSTR *LsaSecretName
+ )
+/*++
+
+Routine Description:
+
+ This function creates a secret name from the user name.
+ It also allocates the buffer to return the created secret name which
+ must be freed by the caller using LocalFree when done with it.
+
+Arguments:
+
+ Qualifier - Supplies the qualifier which forms part of part of the secret
+ object name we are creating.
+
+ LsaSecretName - Receives a pointer to the buffer which contains the
+ secret object name.
+
+Return Value:
+
+ NO_ERROR - Successfully returned secret name.
+
+ ERROR_NOT_ENOUGH_MEMORY - Failed to allocate buffer to hold the secret
+ name.
+
+--*/
+{
+ if ((*LsaSecretName = (LPWSTR)LocalAlloc(
+ 0,
+ (wcslen(NW_SECRET_PREFIX) +
+ wcslen(Qualifier) +
+ 1) * sizeof(WCHAR)
+ )) == NULL) {
+
+ KdPrint(("NWWORKSTATION: NwFormSecretName: LocalAlloc failed %lu\n",
+ GetLastError()));
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ wcscpy(*LsaSecretName, NW_SECRET_PREFIX);
+ wcscat(*LsaSecretName, Qualifier);
+
+ return NO_ERROR;
+}
+
+
+
+DWORD
+NwSetPassword(
+ IN LPWSTR Qualifier,
+ IN LPWSTR Password
+ )
+/*++
+
+Routine Description:
+
+ This function opens ( creates one if needed ) the LSA secret object,
+ and sets it with the specified password.
+
+Arguments:
+
+ Qualifier - Supplies the qualifier which forms part of part of the secret
+ object name to be created.
+
+ Password - Supplies the user specified password for an account.
+
+Return Value:
+
+ NO_ERROR - Secret object for the password is created and set with new value.
+
+ Error from LSA.
+
+--*/
+{
+ DWORD status;
+ NTSTATUS ntstatus;
+ LSA_HANDLE PolicyHandle;
+
+ LSA_HANDLE SecretHandle;
+ UNICODE_STRING SecretNameString;
+ LPWSTR LsaSecretName;
+
+ UNICODE_STRING NewPasswordString;
+ UNICODE_STRING OldPasswordString;
+
+
+ //
+ // Open a handle to the local security policy.
+ //
+ if ((status = NwOpenPolicy(
+ POLICY_CREATE_SECRET,
+ &PolicyHandle
+ )) != NO_ERROR) {
+ KdPrint(("NWWORKSTATION: NwCreatePassword: NwOpenPolicy failed\n"));
+ return status;
+ }
+
+ //
+ // Create the LSA secret object. But first, form a secret name.
+ //
+ if ((status = NwFormSecretName(
+ Qualifier,
+ &LsaSecretName
+ )) != NO_ERROR) {
+ (void) LsaClose(PolicyHandle);
+ return status;
+ }
+
+ RtlInitUnicodeString(&SecretNameString, LsaSecretName);
+
+ ntstatus = LsaCreateSecret(
+ PolicyHandle,
+ &SecretNameString,
+ SECRET_SET_VALUE | DELETE,
+ &SecretHandle
+ );
+
+
+ //
+ // note: ignore object already exists error. just use the existing
+ // object. this could be because the user didnt completely cleanup
+ // during deinstall. the unique names makes it unlikely to be a real
+ // collision.
+ //
+ if ( ntstatus == STATUS_OBJECT_NAME_COLLISION ) {
+ ntstatus = NwOpenSecret(
+ SECRET_SET_VALUE,
+ PolicyHandle,
+ LsaSecretName,
+ &SecretHandle
+ );
+ }
+
+ //
+ // Don't need the name or policy handle anymore.
+ //
+ (void) LocalFree((HLOCAL) LsaSecretName);
+ (void) LsaClose(PolicyHandle);
+
+ if (! NT_SUCCESS(ntstatus)) {
+
+ KdPrint(("NWWORKSTATION: NwCreatePassword: LsaCreateSecret or LsaOpenSecret returned %08lx for %ws\n", ntstatus, LsaSecretName));
+
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+
+ RtlInitUnicodeString(&OldPasswordString, NULL);
+ RtlInitUnicodeString(&NewPasswordString, Password);
+
+ ntstatus = LsaSetSecret(
+ SecretHandle,
+ &NewPasswordString,
+ &OldPasswordString
+ );
+
+ if (! NT_SUCCESS(ntstatus)) {
+ KdPrint(("NWWORKSTATION NwCreatePassword: LsaSetSecret returned %08lx\n",
+ ntstatus));
+
+ status = RtlNtStatusToDosError(ntstatus);
+
+ //
+ // Delete the secret object
+ //
+ ntstatus = LsaDelete(SecretHandle);
+
+ if (! NT_SUCCESS(ntstatus)) {
+ KdPrint(("NWWORKSTATION: NwCreatePassword: LsaDelete to restore back to original returned %08lx\n",
+ ntstatus));
+ (void) LsaClose(SecretHandle);
+ }
+
+ //
+ // Secret handle is closed by LsaDelete if successfully deleted.
+ //
+ return status;
+ }
+
+ (void) LsaClose(SecretHandle);
+
+ return NO_ERROR;
+}
+
+
+
+DWORD
+NwDeletePassword(
+ IN LPWSTR Qualifier
+ )
+/*++
+
+Routine Description:
+
+ This function deletes the LSA secret object whose name is derived
+ from the specified Qualifier.
+
+Arguments:
+
+ Qualifier - Supplies the qualifier which forms part of part of the secret
+ object name to be deleted.
+
+Return Value:
+
+ NO_ERROR - Secret object for password is deleted.
+
+ Error from LSA.
+
+--*/
+{
+ DWORD status;
+ NTSTATUS ntstatus;
+
+ LSA_HANDLE PolicyHandle;
+
+ LSA_HANDLE SecretHandle;
+ LPWSTR LsaSecretName;
+
+
+ //
+ // Open a handle to the local security policy.
+ //
+ if ((status = NwOpenPolicy(
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ )) != NO_ERROR) {
+ KdPrint(("NWWORKSTATION: NwDeletePassword: NwOpenPolicy failed\n"));
+ return status;
+ }
+
+ //
+ // Get the secret object name from the specified user name.
+ //
+ if ((status = NwFormSecretName(
+ Qualifier,
+ &LsaSecretName
+ )) != NO_ERROR) {
+ (void) LsaClose(PolicyHandle);
+ return status;
+ }
+
+ status = NwOpenSecret(
+ DELETE,
+ PolicyHandle,
+ LsaSecretName,
+ &SecretHandle
+ );
+
+ //
+ // Don't need the name or policy handle anymore.
+ //
+ (void) LocalFree((HLOCAL) LsaSecretName);
+ (void) LsaClose(PolicyHandle);
+
+ if (status != NO_ERROR) {
+ KdPrint(("NWWORKSTATION: NwDeletePassword: NwOpenSecret failed\n"));
+ return status;
+ }
+
+ ntstatus = LsaDelete(SecretHandle);
+
+ if (! NT_SUCCESS(ntstatus)) {
+ KdPrint(("NWWORKSTATION: NwDeletePassword: LsaDelete returned %08lx\n",
+ ntstatus));
+ (void) LsaClose(SecretHandle);
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+ return NO_ERROR;
+}
+
+
+
+DWORD
+NwGetPassword(
+ IN LPWSTR Qualifier,
+ OUT PUNICODE_STRING *Password,
+ OUT PUNICODE_STRING *OldPassword
+ )
+/*++
+
+Routine Description:
+
+ This function retrieves the current password and old password
+ values from the service secret object given the user name.
+
+Arguments:
+
+ Qualifier - Supplies the qualifier which forms part of the key to the
+ secret object name.
+
+ Password - Receives a pointer to the string structure that contains
+ the password.
+
+ OldPassword - Receives a pointer to the string structure that
+ contains the old password.
+
+Return Value:
+
+ NO_ERROR - Secret object for password is changed to new value.
+
+ Error from LSA.
+
+--*/
+{
+ DWORD status;
+ NTSTATUS ntstatus;
+
+ LSA_HANDLE PolicyHandle;
+ LSA_HANDLE SecretHandle;
+
+ LPWSTR LsaSecretName;
+
+
+ //
+ // Open a handle to the local security policy to read the
+ // value of the secret.
+ //
+ if ((status = NwOpenPolicy(
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ )) != NO_ERROR) {
+ return status;
+ }
+
+ //
+ // Get the secret object name from the specified user name.
+ //
+ if ((status = NwFormSecretName(
+ Qualifier,
+ &LsaSecretName
+ )) != NO_ERROR) {
+ (void) LsaClose(PolicyHandle);
+ return status;
+ }
+
+ status = NwOpenSecret(
+ SECRET_QUERY_VALUE,
+ PolicyHandle,
+ LsaSecretName,
+ &SecretHandle
+ );
+
+ //
+ // Don't need the name or policy handle anymore.
+ //
+ (void) LocalFree((HLOCAL) LsaSecretName);
+ (void) LsaClose(PolicyHandle);
+
+ if (status != NO_ERROR) {
+ KdPrint(("NWWORKSTATION: ScGetSecret: ScOpenSecret failed\n"));
+ return status;
+ }
+
+ //
+ // Query the old value of the secret object so that we can
+ // we can restore it if we fail to change the password later.
+ //
+ ntstatus = LsaQuerySecret(
+ SecretHandle,
+ Password,
+ NULL, // don't need set time
+ OldPassword,
+ NULL // don't need set time
+ );
+
+ (void) LsaClose(SecretHandle);
+
+ if (! NT_SUCCESS(ntstatus)) {
+ KdPrint(("NWWORKSTATION: NwGetPassword: LsaQuerySecret for previous values returned %08lx\n",
+ ntstatus));
+
+ return RtlNtStatusToDosError(ntstatus);
+ }
+
+ return NO_ERROR;
+}
diff --git a/private/nw/svcdlls/nwwks/lib/makefile b/private/nw/svcdlls/nwwks/lib/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/lib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/nw/svcdlls/nwwks/lib/misc.c b/private/nw/svcdlls/nwwks/lib/misc.c
new file mode 100644
index 000000000..e28db0a84
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/lib/misc.c
@@ -0,0 +1,785 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ api.c
+
+Abstract:
+
+ This module contains misc APIs that are used by the
+ NWC wksta.
+
+Author:
+
+ ChuckC 2-Mar-94 Created
+
+
+Revision History:
+
+--*/
+
+
+#include <stdlib.h>
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <nwcons.h>
+#include <nwmisc.h>
+#include <nwapi32.h>
+#include "nwstatus.h"
+#include "nwevent.h"
+
+DWORD
+NwMapStatus(
+ IN NTSTATUS NtStatus
+ );
+
+DWORD
+NwOpenPreferredServer(
+ PHANDLE ServerHandle
+ );
+
+NTSTATUS
+NwOpenHandle(
+ IN PUNICODE_STRING ObjectName,
+ IN BOOL ValidateFlag,
+ OUT PHANDLE ObjectHandle
+ );
+
+NTSTATUS
+NwCallNtOpenFile(
+ OUT PHANDLE ObjectHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN PUNICODE_STRING ObjectName,
+ IN ULONG OpenOptions
+ );
+
+
+//
+// list of error mappings known for E3H calls. we do not have a single list
+// because Netware reuses the numbers depending on call.
+//
+
+typedef struct _ERROR_MAP_ENTRY
+{
+ UCHAR NetError;
+ NTSTATUS ResultingStatus;
+} ERROR_MAP_ENTRY ;
+
+ERROR_MAP_ENTRY Error_Map_Bindery[] =
+{
+
+ //
+ // NetWare specific error mappings. Specific to E3H.
+ //
+ { 1, STATUS_DISK_FULL },
+ {128, STATUS_SHARING_VIOLATION },
+ {129, STATUS_INSUFF_SERVER_RESOURCES },
+ {130, STATUS_ACCESS_DENIED },
+ {131, STATUS_DATA_ERROR },
+ {132, STATUS_ACCESS_DENIED },
+ {133, STATUS_ACCESS_DENIED },
+ {134, STATUS_ACCESS_DENIED },
+ {135, STATUS_OBJECT_NAME_INVALID },
+ {136, STATUS_INVALID_HANDLE },
+ {137, STATUS_ACCESS_DENIED },
+ {138, STATUS_ACCESS_DENIED },
+ {139, STATUS_ACCESS_DENIED },
+ {140, STATUS_ACCESS_DENIED },
+ {141, STATUS_SHARING_VIOLATION },
+ {142, STATUS_SHARING_VIOLATION },
+ {143, STATUS_ACCESS_DENIED },
+ {144, STATUS_ACCESS_DENIED },
+ {145, STATUS_OBJECT_NAME_COLLISION },
+ {146, STATUS_OBJECT_NAME_COLLISION },
+ {147, STATUS_ACCESS_DENIED },
+ {148, STATUS_ACCESS_DENIED },
+ {150, STATUS_INSUFF_SERVER_RESOURCES },
+ {151, STATUS_NO_SPOOL_SPACE },
+ {152, STATUS_NO_SUCH_DEVICE },
+ {153, STATUS_DISK_FULL },
+ {154, STATUS_NOT_SAME_DEVICE },
+ {155, STATUS_INVALID_HANDLE },
+ {156, STATUS_OBJECT_PATH_NOT_FOUND },
+ {157, STATUS_INSUFF_SERVER_RESOURCES },
+ {158, STATUS_OBJECT_PATH_INVALID },
+ {159, STATUS_SHARING_VIOLATION },
+ {160, STATUS_DIRECTORY_NOT_EMPTY },
+ {161, STATUS_DATA_ERROR },
+ {162, STATUS_SHARING_VIOLATION },
+ {192, STATUS_ACCESS_DENIED },
+ {198, STATUS_ACCESS_DENIED },
+ {211, STATUS_ACCESS_DENIED },
+ {212, STATUS_PRINT_QUEUE_FULL },
+ {213, STATUS_PRINT_CANCELLED },
+ {214, STATUS_ACCESS_DENIED },
+ {215, STATUS_PASSWORD_RESTRICTION },
+ {216, STATUS_PASSWORD_RESTRICTION },
+ {220, STATUS_ACCOUNT_DISABLED },
+ {222, STATUS_PASSWORD_EXPIRED },
+ {223, STATUS_PASSWORD_EXPIRED },
+ {239, STATUS_OBJECT_NAME_INVALID },
+ {240, STATUS_OBJECT_NAME_INVALID },
+ {251, STATUS_INVALID_PARAMETER },
+ {252, STATUS_NO_MORE_ENTRIES },
+ {253, STATUS_FILE_LOCK_CONFLICT },
+ {254, STATUS_FILE_LOCK_CONFLICT },
+ {255, STATUS_UNSUCCESSFUL}
+};
+
+
+ERROR_MAP_ENTRY Error_Map_General[] =
+{
+ { 1, STATUS_DISK_FULL },
+ {128, STATUS_SHARING_VIOLATION },
+ {129, STATUS_INSUFF_SERVER_RESOURCES },
+ {130, STATUS_ACCESS_DENIED },
+ {131, STATUS_DATA_ERROR },
+ {132, STATUS_ACCESS_DENIED },
+ {133, STATUS_ACCESS_DENIED },
+ {134, STATUS_ACCESS_DENIED },
+ {135, STATUS_OBJECT_NAME_INVALID },
+ {136, STATUS_INVALID_HANDLE },
+ {137, STATUS_ACCESS_DENIED },
+ {138, STATUS_ACCESS_DENIED },
+ {139, STATUS_ACCESS_DENIED },
+ {140, STATUS_ACCESS_DENIED },
+ {141, STATUS_SHARING_VIOLATION },
+ {142, STATUS_SHARING_VIOLATION },
+ {143, STATUS_ACCESS_DENIED },
+ {144, STATUS_ACCESS_DENIED },
+ {145, STATUS_OBJECT_NAME_COLLISION },
+ {146, STATUS_OBJECT_NAME_COLLISION },
+ {147, STATUS_ACCESS_DENIED },
+ {148, STATUS_ACCESS_DENIED },
+ {150, STATUS_INSUFF_SERVER_RESOURCES },
+ {151, STATUS_NO_SPOOL_SPACE },
+ {152, STATUS_NO_SUCH_DEVICE },
+ {153, STATUS_DISK_FULL },
+ {154, STATUS_NOT_SAME_DEVICE },
+ {155, STATUS_INVALID_HANDLE },
+ {156, STATUS_OBJECT_PATH_NOT_FOUND },
+ {157, STATUS_INSUFF_SERVER_RESOURCES },
+ {158, STATUS_OBJECT_PATH_INVALID },
+ {159, STATUS_SHARING_VIOLATION },
+ {160, STATUS_DIRECTORY_NOT_EMPTY },
+ {161, STATUS_DATA_ERROR },
+ {162, STATUS_SHARING_VIOLATION },
+ {192, STATUS_ACCESS_DENIED },
+ {198, STATUS_ACCESS_DENIED },
+ {211, STATUS_ACCESS_DENIED },
+ {212, STATUS_PRINT_QUEUE_FULL },
+ {213, STATUS_PRINT_CANCELLED },
+ {214, STATUS_ACCESS_DENIED },
+ {215, STATUS_DEVICE_BUSY },
+ {216, STATUS_DEVICE_DOES_NOT_EXIST },
+ {220, STATUS_ACCOUNT_DISABLED },
+ {222, STATUS_PASSWORD_EXPIRED },
+ {223, STATUS_PASSWORD_EXPIRED },
+ {239, STATUS_OBJECT_NAME_INVALID },
+ {240, STATUS_OBJECT_NAME_INVALID },
+ {251, STATUS_INVALID_PARAMETER },
+ {252, STATUS_NO_MORE_ENTRIES },
+ {253, STATUS_FILE_LOCK_CONFLICT },
+ {254, STATUS_FILE_LOCK_CONFLICT },
+ {255, STATUS_UNSUCCESSFUL}
+};
+
+#define NUM_ERRORS(x) (sizeof(x)/sizeof(x[0]))
+
+DWORD
+NwMapBinderyCompletionCode(
+ IN NTSTATUS NtStatus
+ )
+/*++
+
+Routine Description:
+
+ This function takes a bindery completion code embedded in an NT status
+ code and maps it to the appropriate Win32 error code. Used specifically
+ for E3H operations.
+
+Arguments:
+
+ NtStatus - Supplies the NT status (that contains the code in low 16 bits)
+
+Return Value:
+
+ Returns the appropriate Win32 error.
+
+--*/
+{
+ DWORD i; UCHAR code ;
+
+ //
+ // A small optimization for the most common case.
+ //
+ if (NtStatus == STATUS_SUCCESS)
+ return NO_ERROR;
+
+ //
+ // Map connection errors specially.
+ //
+
+ if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) &&
+ ( (NtStatus & 0xFF00) != 0 ) )
+ {
+ return ERROR_UNEXP_NET_ERR;
+ }
+
+ //
+ // if facility code not set, assume it is NT Status
+ //
+ if ( (NtStatus & 0xFFFF0000) != 0xC0010000)
+ return RtlNtStatusToDosError(NtStatus);
+
+ code = NtStatus & 0x000000FF ;
+ for (i = 0; i < NUM_ERRORS(Error_Map_Bindery); i++)
+ {
+ if (Error_Map_Bindery[i].NetError == code)
+ return( NwMapStatus(Error_Map_Bindery[i].ResultingStatus));
+ }
+
+ //
+ // if cannot find let NwMapStatus do its best
+ //
+ return NwMapStatus(NtStatus);
+}
+
+
+
+DWORD
+NwMapStatus(
+ IN NTSTATUS NtStatus
+ )
+/*++
+
+Routine Description:
+
+ This function takes an NT status code and maps it to the appropriate
+ Win32 error code. If facility code is set, assume it is NW specific
+
+Arguments:
+
+ NtStatus - Supplies the NT status.
+
+Return Value:
+
+ Returns the appropriate Win32 error.
+
+--*/
+{
+ DWORD i; UCHAR code ;
+
+ //
+ // A small optimization for the most common case.
+ //
+ if (NtStatus == STATUS_SUCCESS)
+ return NO_ERROR;
+
+ //
+ // Map connection errors specially.
+ //
+
+ if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) &&
+ ( (NtStatus & 0xFF00) != 0 ) )
+ {
+ return ERROR_UNEXP_NET_ERR;
+ }
+
+ //
+ // if facility code set, assume it is NW Completion code
+ //
+ if ( (NtStatus & 0xFFFF0000) == 0xC0010000)
+ {
+ code = NtStatus & 0x000000FF ;
+ for (i = 0; i < NUM_ERRORS(Error_Map_General); i++)
+ {
+ if (Error_Map_General[i].NetError == code)
+ {
+ //
+ // map it to NTSTATUS and then drop thru to map to Win32
+ //
+ NtStatus = Error_Map_General[i].ResultingStatus ;
+ break ;
+ }
+ }
+ }
+
+ switch (NtStatus) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ return ERROR_ALREADY_ASSIGNED;
+
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ return ERROR_NOT_CONNECTED;
+
+ case STATUS_IMAGE_ALREADY_LOADED:
+ case STATUS_REDIRECTOR_STARTED:
+ return ERROR_SERVICE_ALREADY_RUNNING;
+
+ case STATUS_REDIRECTOR_HAS_OPEN_HANDLES:
+ return ERROR_REDIRECTOR_HAS_OPEN_HANDLES;
+
+ case STATUS_NO_MORE_FILES:
+ case STATUS_NO_MORE_ENTRIES:
+ return WN_NO_MORE_ENTRIES;
+
+ case STATUS_MORE_ENTRIES:
+ return WN_MORE_DATA;
+
+ case STATUS_CONNECTION_IN_USE:
+ return ERROR_DEVICE_IN_USE;
+
+ case NWRDR_PASSWORD_HAS_EXPIRED:
+ return NW_PASSWORD_HAS_EXPIRED;
+
+ case STATUS_INVALID_DEVICE_REQUEST:
+ return ERROR_CONNECTION_INVALID;
+
+ default:
+ return RtlNtStatusToDosError(NtStatus);
+ }
+}
+
+DWORD
+NwGetGraceLoginCount(
+ LPWSTR Server,
+ LPWSTR UserName,
+ LPDWORD lpResult
+ )
+/*++
+
+Routine Description:
+
+ Get the number grace logins for a user.
+
+Arguments:
+
+ Server - the server to authenticate against
+
+ UserName - the user account
+
+Return Value:
+
+ Returns the appropriate Win32 error.
+
+--*/
+{
+ DWORD status ;
+ HANDLE hConn ;
+ CHAR UserNameO[NW_MAX_USERNAME_LEN+1] ;
+ BYTE LoginControl[128] ;
+ BYTE MoreFlags, PropFlags ;
+
+ //
+ // skip the backslashes if present
+ //
+ if (*Server == L'\\')
+ Server += 2 ;
+
+ //
+ // attach to the NW server
+ //
+ if (status = NWAttachToFileServerW(Server,
+ 0,
+ &hConn))
+ {
+ return status ;
+ }
+
+ //
+ // convert unicode UserName to OEM, and then call the NCP
+ //
+ if ( !WideCharToMultiByte(CP_OEMCP,
+ 0,
+ UserName,
+ -1,
+ UserNameO,
+ sizeof(UserNameO),
+ NULL,
+ NULL))
+ {
+ status = GetLastError() ;
+ }
+ else
+ {
+ status = NWReadPropertyValue( hConn,
+ UserNameO,
+ OT_USER,
+ "LOGIN_CONTROL",
+ 1,
+ LoginControl,
+ &MoreFlags,
+ &PropFlags) ;
+ }
+
+ //
+ // dont need these anymore. if any error, bag out
+ //
+ (void) NWDetachFromFileServer(hConn) ;
+
+
+ if (status == NO_ERROR)
+ *lpResult = (DWORD) LoginControl[7] ;
+
+ return status ;
+}
+
+
+WORD
+NwParseNdsUncPath(
+ IN OUT LPWSTR * Result,
+ IN LPWSTR ContainerName,
+ IN ULONG flag
+)
+/*++
+
+Routine Description:
+
+ This function is used to extract either the tree name, fully distinguished
+ name path to an object, or object name, out of a complete NDS UNC path.
+
+Arguments:
+
+ Result - parsed result buffer.
+ ContainerName - Complete NDS UNC path that is to be parsed.
+ flag - Flag indicating operation to be performed:
+
+ PARSE_NDS_GET_TREE_NAME
+ PARSE_NDS_GET_PATH_NAME
+ PARSE_NDS_GET_OBJECT_NAME
+
+
+Return Value:
+
+ Length of string in result buffer. If error occured, 0 is returned.
+
+--*/ // NwParseNdsUncPath
+{
+ unsigned short length = 2;
+ unsigned short totalLength = wcslen( ContainerName );
+
+ if ( totalLength < 2 )
+ return 0;
+
+ //
+ // First get length to indicate the character in the string that indicates the
+ // "\" in between the tree name and the rest of the UNC path.
+ //
+ // Example: \\<tree name>\<path to object>[\|.]<object>
+ // ^
+ // |
+ //
+ while ( length < totalLength && ContainerName[length] != L'\\' )
+ {
+ length++;
+ }
+
+ if ( flag == PARSE_NDS_GET_TREE_NAME )
+ {
+ *Result = (LPWSTR) ( ContainerName + 2 );
+
+ return ( length - 2 ) * sizeof( WCHAR ); // Take off 2 for the two \\'s
+ }
+
+ if ( flag == PARSE_NDS_GET_PATH_NAME && length == totalLength )
+ {
+ *Result = ContainerName;
+
+ return 0;
+ }
+
+ if ( flag == PARSE_NDS_GET_PATH_NAME )
+ {
+ *Result = ContainerName + length + 1;
+
+ return ( totalLength - length - 1 ) * sizeof( WCHAR );
+ }
+
+ *Result = ContainerName + totalLength - 1;
+ length = 1;
+
+ while ( **Result != L'\\' )
+ {
+ *Result--;
+ length++;
+ }
+
+ *Result++;
+ length--;
+
+ return length * sizeof( WCHAR );
+}
+
+
+DWORD
+NwOpenAServer(
+ PWCHAR pwszServName,
+ PHANDLE ServerHandle,
+ BOOL fVerify
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a handle to a server.
+
+Arguments:
+
+ ServerHandle - Receives an opened handle to the preferred or
+ nearest server.
+
+Return Value:
+
+ NO_ERROR or reason for failure.
+
+--*/
+{
+ UNICODE_STRING AServer;
+ WCHAR wszName[sizeof(NW_RDR_NAME) + (48 * sizeof(WCHAR))];
+ DWORD wLen;
+
+
+ if(!pwszServName)
+ {
+ pwszServName = NW_RDR_PREFERRED_SERVER;
+ RtlInitUnicodeString(&AServer, wszName);
+ }
+ else
+ {
+ wLen = wcslen(pwszServName);
+ if(wLen > 47)
+ {
+ return(WSAEFAULT);
+ }
+ wcscpy(wszName, NW_RDR_NAME);
+ wcscat(wszName, pwszServName);
+ RtlInitUnicodeString(&AServer, wszName);
+ }
+
+ return RtlNtStatusToDosError(
+ NwOpenHandle(&AServer, fVerify, ServerHandle)
+ );
+
+}
+
+
+DWORD
+NwOpenPreferredServer(
+ PHANDLE ServerHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a handle to the preferred server. If the
+ preferred server has not been specified, a handle to the
+ nearest server is opened instead.
+
+Arguments:
+
+ ServerHandle - Receives an opened handle to the preferred or
+ nearest server.
+
+Return Value:
+
+ NO_ERROR or reason for failure.
+
+--*/
+{
+ UNICODE_STRING PreferredServer;
+
+
+ //
+ // The NetWare redirector recognizes "*" to mean the preferred
+ // or nearest server.
+ //
+ RtlInitUnicodeString(&PreferredServer, NW_RDR_PREFERRED_SERVER);
+
+ return RtlNtStatusToDosError(
+ NwOpenHandle(&PreferredServer, FALSE, ServerHandle)
+ );
+
+}
+
+
+NTSTATUS
+NwOpenHandle(
+ IN PUNICODE_STRING ObjectName,
+ IN BOOL ValidateFlag,
+ OUT PHANDLE ObjectHandle
+ )
+/*++
+
+Routine Description:
+
+ This function opens a handle to \Device\Nwrdr\<ObjectName>.
+
+Arguments:
+
+ ObjectName - Supplies the name of the redirector object to open.
+
+ ValidateFlag - Supplies a flag which if TRUE, opens the handle to
+ the object by validating the default user account.
+
+ ObjectHandle - Receives a pointer to the opened object handle.
+
+Return Value:
+
+ STATUS_SUCCESS or reason for failure.
+
+--*/
+{
+ ACCESS_MASK DesiredAccess = SYNCHRONIZE;
+
+
+ if (ValidateFlag) {
+
+ //
+ // The redirector only authenticates the default user credential
+ // if the remote resource is opened with write access.
+ //
+ DesiredAccess |= FILE_WRITE_DATA;
+ }
+
+
+ *ObjectHandle = NULL;
+
+ return NwCallNtOpenFile(
+ ObjectHandle,
+ DesiredAccess,
+ ObjectName,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+}
+
+
+NTSTATUS
+NwCallNtOpenFile(
+ OUT PHANDLE ObjectHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN PUNICODE_STRING ObjectName,
+ IN ULONG OpenOptions
+ )
+{
+
+ NTSTATUS ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ ObjectName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ ntstatus = NtOpenFile(
+ ObjectHandle,
+ DesiredAccess,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_VALID_FLAGS,
+ OpenOptions
+ );
+
+ if (!NT_ERROR(ntstatus) &&
+ !NT_INFORMATION(ntstatus) &&
+ !NT_WARNING(ntstatus)) {
+
+ ntstatus = IoStatusBlock.Status;
+
+ }
+
+ return ntstatus;
+}
+
+
+BOOL
+NwConvertToUnicode(
+ OUT LPWSTR *UnicodeOut,
+ IN LPSTR OemIn
+ )
+/*++
+
+Routine Description:
+
+ This function converts the given OEM string to a Unicode string.
+ The Unicode string is returned in a buffer allocated by this
+ function and must be freed with LocalFree.
+
+Arguments:
+
+ UnicodeOut - Receives a pointer to the Unicode string.
+
+ OemIn - This is a pointer to an ansi string that is to be converted.
+
+Return Value:
+
+ TRUE - The conversion was successful.
+
+ FALSE - The conversion was unsuccessful. In this case a buffer for
+ the unicode string was not allocated.
+
+--*/
+{
+ NTSTATUS ntstatus;
+ DWORD BufSize;
+ UNICODE_STRING UnicodeString;
+ OEM_STRING OemString;
+
+
+ //
+ // Allocate a buffer for the unicode string.
+ //
+
+ BufSize = (strlen(OemIn) + 1) * sizeof(WCHAR);
+
+ *UnicodeOut = LocalAlloc(LMEM_ZEROINIT, BufSize);
+
+ if (*UnicodeOut == NULL) {
+ KdPrint(("NWWORKSTATION: NwConvertToUnicode:LocalAlloc failed %lu\n",
+ GetLastError()));
+ return FALSE;
+ }
+
+ //
+ // Initialize the string structures
+ //
+ RtlInitAnsiString((PANSI_STRING) &OemString, OemIn);
+
+ UnicodeString.Buffer = *UnicodeOut;
+ UnicodeString.MaximumLength = (USHORT) BufSize;
+ UnicodeString.Length = 0;
+
+ //
+ // Call the conversion function.
+ //
+ ntstatus = RtlOemStringToUnicodeString(
+ &UnicodeString, // Destination
+ &OemString, // Source
+ FALSE // Allocate the destination
+ );
+
+ if (ntstatus != STATUS_SUCCESS) {
+
+ KdPrint(("NWWORKSTATION: NwConvertToUnicode: RtlOemStringToUnicodeString failure x%08lx\n",
+ ntstatus));
+
+ (void) LocalFree((HLOCAL) *UnicodeOut);
+ *UnicodeOut = NULL;
+ return FALSE;
+ }
+
+ *UnicodeOut = UnicodeString.Buffer;
+
+ return TRUE;
+
+}
diff --git a/private/nw/svcdlls/nwwks/lib/reg.c b/private/nw/svcdlls/nwwks/lib/reg.c
new file mode 100644
index 000000000..2259d0f90
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/lib/reg.c
@@ -0,0 +1,1010 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ reg.c
+
+Abstract:
+
+ This module provides helpers to call the registry used by both
+ the client and server sides of the workstation.
+
+Author:
+
+ Rita Wong (ritaw) 22-Apr-1993
+
+--*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windef.h>
+#include <winerror.h>
+#include <winbase.h>
+#include <winreg.h>
+
+#include <nwsnames.h>
+#include <nwreg.h>
+#include <nwapi.h>
+#include <lmcons.h>
+#include <lmerr.h>
+
+#define LMSERVER_LINKAGE_REGKEY L"System\\CurrentControlSet\\Services\\LanmanServer\\Linkage"
+#define OTHERDEPS_VALUENAME L"OtherDependencies"
+
+//
+// Forward Declare
+//
+
+static
+DWORD
+NwRegQueryValueExW(
+ IN HKEY hKey,
+ IN LPWSTR lpValueName,
+ OUT LPDWORD lpReserved,
+ OUT LPDWORD lpType,
+ OUT LPBYTE lpData,
+ IN OUT LPDWORD lpcbData
+ );
+
+static
+DWORD
+EnumAndDeleteShares(
+ VOID
+ ) ;
+
+DWORD
+CalcNullNullSize(
+ WCHAR *pszNullNull
+ ) ;
+
+WCHAR *
+FindStringInNullNull(
+ WCHAR *pszNullNull,
+ WCHAR *pszString
+ ) ;
+
+VOID
+RemoveNWCFromNullNullList(
+ WCHAR *OtherDeps
+ ) ;
+
+
+
+
+DWORD
+NwReadRegValue(
+ IN HKEY Key,
+ IN LPWSTR ValueName,
+ OUT LPWSTR *Value
+ )
+/*++
+
+Routine Description:
+
+ This function allocates the output buffer and reads the requested
+ value from the registry into it.
+
+Arguments:
+
+ Key - Supplies opened handle to the key to read from.
+
+ ValueName - Supplies name of the value to retrieve data.
+
+ Value - Returns a pointer to the output buffer which points to
+ the memory allocated and contains the data read in from the
+ registry. This pointer must be freed with LocalFree when done.
+
+Return Value:
+
+ ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into.
+
+ Error from registry call.
+
+--*/
+{
+ LONG RegError;
+ DWORD NumRequired = 0;
+ DWORD ValueType;
+
+
+ //
+ // Set returned buffer pointer to NULL.
+ //
+ *Value = NULL;
+
+ RegError = NwRegQueryValueExW(
+ Key,
+ ValueName,
+ NULL,
+ &ValueType,
+ (LPBYTE) NULL,
+ &NumRequired
+ );
+
+ if (RegError != ERROR_SUCCESS && NumRequired > 0) {
+
+ if ((*Value = (LPWSTR) LocalAlloc(
+ LMEM_ZEROINIT,
+ (UINT) NumRequired
+ )) == NULL) {
+
+ KdPrint(("NWWORKSTATION: NwReadRegValue: LocalAlloc of size %lu failed %lu\n",
+ NumRequired, GetLastError()));
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RegError = NwRegQueryValueExW(
+ Key,
+ ValueName,
+ NULL,
+ &ValueType,
+ (LPBYTE) *Value,
+ &NumRequired
+ );
+ }
+ else if (RegError == ERROR_SUCCESS) {
+ KdPrint(("NWWORKSTATION: NwReadRegValue got SUCCESS with NULL buffer."));
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+ if (RegError != ERROR_SUCCESS) {
+
+ if (*Value != NULL) {
+ (void) LocalFree((HLOCAL) *Value);
+ *Value = NULL;
+ }
+
+ return (DWORD) RegError;
+ }
+
+ return NO_ERROR;
+}
+
+
+static
+DWORD
+NwRegQueryValueExW(
+ IN HKEY hKey,
+ IN LPWSTR lpValueName,
+ OUT LPDWORD lpReserved,
+ OUT LPDWORD lpType,
+ OUT LPBYTE lpData,
+ IN OUT LPDWORD lpcbData
+ )
+/*++
+
+Routine Description:
+
+ This routine supports the same functionality as Win32 RegQueryValueEx
+ API, except that it works. It returns the correct lpcbData value when
+ a NULL output buffer is specified.
+
+ This code is stolen from the service controller.
+
+Arguments:
+
+ same as RegQueryValueEx
+
+Return Value:
+
+ NO_ERROR or reason for failure.
+
+--*/
+{
+ NTSTATUS ntstatus;
+ UNICODE_STRING ValueName;
+ PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
+ DWORD BufSize;
+
+
+ UNREFERENCED_PARAMETER(lpReserved);
+
+ //
+ // Make sure we have a buffer size if the buffer is present.
+ //
+ if ((ARGUMENT_PRESENT(lpData)) && (! ARGUMENT_PRESENT(lpcbData))) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RtlInitUnicodeString(&ValueName, lpValueName);
+
+ //
+ // Allocate memory for the ValueKeyInfo
+ //
+ BufSize = *lpcbData + sizeof(KEY_VALUE_FULL_INFORMATION) +
+ ValueName.Length
+ - sizeof(WCHAR); // subtract memory for 1 char because it's included
+ // in the sizeof(KEY_VALUE_FULL_INFORMATION).
+
+ KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) LocalAlloc(
+ LMEM_ZEROINIT,
+ (UINT) BufSize
+ );
+
+ if (KeyValueInfo == NULL) {
+ KdPrint(("NWWORKSTATION: NwRegQueryValueExW: LocalAlloc failed %lu\n",
+ GetLastError()));
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ ntstatus = NtQueryValueKey(
+ hKey,
+ &ValueName,
+ KeyValueFullInformation,
+ (PVOID) KeyValueInfo,
+ (ULONG) BufSize,
+ (PULONG) &BufSize
+ );
+
+ if ((NT_SUCCESS(ntstatus) || (ntstatus == STATUS_BUFFER_OVERFLOW))
+ && ARGUMENT_PRESENT(lpcbData)) {
+
+ *lpcbData = KeyValueInfo->DataLength;
+ }
+
+ if (NT_SUCCESS(ntstatus)) {
+
+ if (ARGUMENT_PRESENT(lpType)) {
+ *lpType = KeyValueInfo->Type;
+ }
+
+
+ if (ARGUMENT_PRESENT(lpData)) {
+ memcpy(
+ lpData,
+ (LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset,
+ KeyValueInfo->DataLength
+ );
+ }
+ }
+
+ (void) LocalFree((HLOCAL) KeyValueInfo);
+
+ return RtlNtStatusToDosError(ntstatus);
+
+}
+
+VOID
+NwLuidToWStr(
+ IN PLUID LogonId,
+ OUT LPWSTR LogonIdStr
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a LUID into a string in hex value format so
+ that it can be used as a registry key.
+
+Arguments:
+
+ LogonId - Supplies the LUID.
+
+ LogonIdStr - Receives the string. This routine assumes that this
+ buffer is large enough to fit 17 characters.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ swprintf(LogonIdStr, L"%08lx%08lx", LogonId->HighPart, LogonId->LowPart);
+}
+
+VOID
+NwWStrToLuid(
+ IN LPWSTR LogonIdStr,
+ OUT PLUID LogonId
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a string in hex value format into a LUID.
+
+Arguments:
+
+ LogonIdStr - Supplies the string.
+
+ LogonId - Receives the LUID.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ swscanf(LogonIdStr, L"%08lx%08lx", &LogonId->HighPart, &LogonId->LowPart);
+}
+
+VOID
+NwDeleteCurrentUser(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes the current user value under the parameters key.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LONG RegError;
+ HKEY WkstaKey;
+
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Parameters
+ //
+ RegError = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_REGKEY,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE | DELETE,
+ &WkstaKey
+ );
+
+ if (RegError != NO_ERROR) {
+ KdPrint(("NWPROVAU: NwpInitializeRegistry open NWCWorkstation\\Parameters key unexpected error %lu!\n",
+ RegError));
+ return;
+ }
+
+ //
+ // Delete CurrentUser value first so that the workstation won't be
+ // reading this stale value. Ignore error since it may not exist.
+ //
+ (void) RegDeleteValueW(
+ WkstaKey,
+ NW_CURRENTUSER_VALUENAME
+ );
+
+ (void) RegCloseKey(WkstaKey);
+}
+
+DWORD
+NwDeleteServiceLogon(
+ IN PLUID Id OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes a specific service logon ID key in the registry
+ if a logon ID is specified, otherwise it deletes all service logon
+ ID keys.
+
+Arguments:
+
+ Id - Supplies the logon ID to delete. NULL means delete all.
+
+Return Status:
+
+ None.
+
+--*/
+{
+ LONG RegError;
+ LONG DelError;
+ HKEY ServiceLogonKey;
+
+ WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
+
+
+ RegError = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_SERVICE_LOGON_REGKEY,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE | DELETE,
+ &ServiceLogonKey
+ );
+
+ if (RegError != ERROR_SUCCESS) {
+ return RegError;
+ }
+
+ if (ARGUMENT_PRESENT(Id)) {
+
+ //
+ // Delete the key specified.
+ //
+ NwLuidToWStr(Id, LogonIdKey);
+
+ DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
+
+ }
+ else {
+
+ //
+ // Delete all service logon ID keys.
+ //
+
+ do {
+
+ RegError = RegEnumKeyW(
+ ServiceLogonKey,
+ 0,
+ LogonIdKey,
+ sizeof(LogonIdKey) / sizeof(WCHAR)
+ );
+
+ if (RegError == ERROR_SUCCESS) {
+
+ //
+ // Got a logon id key, delete it.
+ //
+
+ DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
+ }
+ else if (RegError != ERROR_NO_MORE_ITEMS) {
+ KdPrint((" NwDeleteServiceLogon: failed to enum logon IDs %lu\n", RegError));
+ }
+
+ } while (RegError == ERROR_SUCCESS);
+ }
+
+ (void) RegCloseKey(ServiceLogonKey);
+
+ return ((DWORD) DelError);
+}
+
+
+
+DWORD
+NwpRegisterGatewayShare(
+ IN LPWSTR ShareName,
+ IN LPWSTR DriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine remembers that a gateway share has been created so
+ that it can be cleanup up when NWCS is uninstalled.
+
+Arguments:
+
+ ShareName - name of share
+ DriveName - name of drive that is shared
+
+Return Status:
+
+ Win32 error of any failure.
+
+--*/
+{
+ DWORD status ;
+
+
+ //
+ // make sure we have valid parameters
+ //
+ if (ShareName && DriveName)
+ {
+ HKEY hKey ;
+ DWORD dwDisposition ;
+
+ //
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Shares (create it if not there)
+ //
+ status = RegCreateKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_GATEWAY_SHARES,
+ 0,
+ L"",
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE, // desired access
+ NULL, // default security
+ &hKey,
+ &dwDisposition // ignored
+ );
+
+ if ( status )
+ return status ;
+
+ //
+ // wtite out value with valuename=sharename, valuedata=drive
+ //
+ status = RegSetValueExW(
+ hKey,
+ ShareName,
+ 0,
+ REG_SZ,
+ (LPBYTE) DriveName,
+ (wcslen(DriveName)+1) * sizeof(WCHAR)) ;
+
+ (void) RegCloseKey( hKey );
+ }
+ else
+ status = ERROR_INVALID_PARAMETER ;
+
+ return status ;
+
+}
+
+DWORD
+NwpCleanupGatewayShares(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up all persistent share info and also tidies
+ up the registry for NWCS. Later is not needed in uninstall, but is
+ there so we have a single routine that completely disables the
+ gateway.
+
+Arguments:
+
+ None.
+
+Return Status:
+
+ Win32 error for failed APIs.
+
+--*/
+{
+ DWORD status, FinalStatus = NO_ERROR ;
+ HKEY WkstaKey = NULL,
+ ServerLinkageKey = NULL ;
+ LPWSTR OtherDeps = NULL ;
+
+ //
+ // Enumeratre and delete all shares
+ //
+ FinalStatus = status = EnumAndDeleteShares() ;
+
+ //
+ // if update registry by cleaning out both Drive and Shares keys.
+ // ignore return values here. the keys may not be present.
+ //
+ (void) RegDeleteKeyW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_GATEWAY_DRIVES
+ ) ;
+
+ (void) RegDeleteKeyW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_GATEWAY_SHARES
+ ) ;
+
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Parameters
+ //
+ status = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_REGKEY,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_WRITE, // desired access
+ &WkstaKey
+ );
+
+ if (status == ERROR_SUCCESS)
+ {
+ //
+ // delete the gateway account and gateway enabled flag.
+ // ignore failures here (the values may not be present)
+ //
+ (void) RegDeleteValueW(
+ WkstaKey,
+ NW_GATEWAYACCOUNT_VALUENAME
+ ) ;
+ (void) RegDeleteValueW(
+ WkstaKey,
+ NW_GATEWAY_ENABLE
+ ) ;
+
+ (void) RegCloseKey( WkstaKey );
+ }
+
+ //
+ // store new status if necessary
+ //
+ if (FinalStatus == NO_ERROR)
+ FinalStatus = status ;
+
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \LanmanServer\Linkage
+ //
+ status = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ LMSERVER_LINKAGE_REGKEY,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_WRITE | KEY_READ, // desired access
+ &ServerLinkageKey
+ );
+
+ if (status == ERROR_SUCCESS)
+ {
+ //
+ // remove us from the OtherDependencies.
+ // ignore read failures here (it may not be present)
+ //
+ status = NwReadRegValue(
+ ServerLinkageKey,
+ OTHERDEPS_VALUENAME,
+ &OtherDeps
+ );
+
+ if (status == NO_ERROR)
+ {
+ //
+ // this call munges the list to remove NWC if there.
+ //
+ RemoveNWCFromNullNullList(OtherDeps) ;
+
+ status = RegSetValueExW(
+ ServerLinkageKey,
+ OTHERDEPS_VALUENAME,
+ 0,
+ REG_MULTI_SZ,
+ (BYTE *)OtherDeps,
+ CalcNullNullSize(OtherDeps) * sizeof(WCHAR)) ;
+
+ (void) LocalFree(OtherDeps) ;
+ }
+ else
+ {
+ status = NO_ERROR ;
+ }
+
+ (void) RegCloseKey( ServerLinkageKey );
+ }
+
+ //
+ // store new status if necessary
+ //
+ if (FinalStatus == NO_ERROR)
+ FinalStatus = status ;
+
+
+ return (FinalStatus) ;
+}
+
+DWORD
+NwpClearGatewayShare(
+ IN LPWSTR ShareName
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes a specific share from the remembered gateway
+ shares in the registry.
+
+Arguments:
+
+ ShareName - share value to delete
+
+Return Status:
+
+ Win32 status code.
+
+--*/
+{
+ DWORD status = NO_ERROR ;
+
+ //
+ // check that paramter is non null
+ //
+ if (ShareName)
+ {
+ HKEY hKey ;
+
+ //
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Drives
+ //
+ status = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_GATEWAY_SHARES,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_WRITE, // desired access
+ &hKey
+ );
+
+ if ( status )
+ return status ;
+
+ status = RegDeleteValueW(
+ hKey,
+ ShareName
+ ) ;
+
+ (void) RegCloseKey( hKey );
+ }
+ else
+ status = ERROR_INVALID_PARAMETER ;
+
+ return status ;
+}
+
+typedef NET_API_STATUS (*PF_NETSHAREDEL) (
+ LPWSTR server,
+ LPWSTR name,
+ DWORD reserved) ;
+
+#define NETSHAREDELSTICKY_API "NetShareDelSticky"
+#define NETSHAREDEL_API "NetShareDel"
+#define NETAPI_DLL L"NETAPI32"
+
+DWORD
+EnumAndDeleteShares(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine removes all persister share info in the server for
+ all gateway shares.
+
+Arguments:
+
+ None.
+
+Return Status:
+
+ Win32 error code.
+
+--*/
+{
+ DWORD err, i, type ;
+ HKEY hKey = NULL ;
+ FILETIME FileTime ;
+ HANDLE hNetapi = NULL ;
+ PF_NETSHAREDEL pfNetShareDel, pfNetShareDelSticky ;
+ WCHAR Class[256], Share[NNLEN+1], Device[MAX_PATH+1] ;
+ DWORD dwClass, dwSubKeys, dwMaxSubKey, dwMaxClass,
+ dwValues, dwMaxValueName, dwMaxValueData, dwSDLength,
+ dwShareLength, dwDeviceLength ;
+
+ //
+ // load the library so that not everyone needs link to netapi32
+ //
+ if (!(hNetapi = LoadLibraryW(NETAPI_DLL)))
+ return (GetLastError()) ;
+
+ //
+ // get addresses of the 2 functions we are interested in
+ //
+ if (!(pfNetShareDel = (PF_NETSHAREDEL) GetProcAddress(hNetapi,
+ NETSHAREDEL_API)))
+ {
+ err = GetLastError() ;
+ goto ExitPoint ;
+ }
+
+ if (!(pfNetShareDelSticky = (PF_NETSHAREDEL) GetProcAddress(hNetapi,
+ NETSHAREDELSTICKY_API)))
+ {
+ err = GetLastError() ;
+ goto ExitPoint ;
+ }
+
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCGateway\Shares
+ //
+ err = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_GATEWAY_SHARES,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_READ, // desired access
+ &hKey
+ );
+
+ if ( err )
+ goto ExitPoint ;
+
+ //
+ // read the info about that key
+ //
+ dwClass = sizeof(Class)/sizeof(Class[0]) ;
+ err = RegQueryInfoKeyW(hKey,
+ Class,
+ &dwClass,
+ NULL,
+ &dwSubKeys,
+ &dwMaxSubKey,
+ &dwMaxClass,
+ &dwValues,
+ &dwMaxValueName,
+ &dwMaxValueData,
+ &dwSDLength,
+ &FileTime) ;
+ if ( err )
+ {
+ goto ExitPoint ;
+ }
+
+ //
+ // for each value found, we have a share to delete
+ //
+ for (i = 0; i < dwValues; i++)
+ {
+ dwShareLength = sizeof(Share)/sizeof(Share[0]) ;
+ dwDeviceLength = sizeof(Device) ;
+ type = REG_SZ ;
+ err = RegEnumValueW(hKey,
+ i,
+ Share,
+ &dwShareLength,
+ NULL,
+ &type,
+ (LPBYTE)Device,
+ &dwDeviceLength) ;
+
+ //
+ // cleanup the share. try delete the share proper. if not
+ // there, remove the sticky info instead.
+ //
+ if (!err)
+ {
+ err = (*pfNetShareDel)(NULL, Share, 0) ;
+
+ if (err == NERR_NetNameNotFound)
+ {
+ (void) (*pfNetShareDelSticky)(NULL, Share, 0) ;
+ }
+ }
+
+ //
+ // ignore errors within the loop. we can to carry on to
+ // cleanup as much as possible.
+ //
+ err = NO_ERROR ;
+ }
+
+
+
+ExitPoint:
+
+ if (hKey)
+ (void) RegCloseKey( hKey );
+
+ if (hNetapi)
+ (void) FreeLibrary(hNetapi) ;
+
+ return err ;
+}
+
+
+DWORD
+CalcNullNullSize(
+ WCHAR *pszNullNull
+ )
+/*++
+
+Routine Description:
+
+ Walk thru a NULL NULL string, counting the number of
+ characters, including the 2 nulls at the end.
+
+Arguments:
+
+ Pointer to a NULL NULL string
+
+Return Status:
+
+ Count of number of *characters*. See description.
+
+--*/
+{
+
+ DWORD dwSize = 0 ;
+ WCHAR *pszTmp = pszNullNull ;
+
+ if (!pszNullNull)
+ return 0 ;
+
+ while (*pszTmp)
+ {
+ DWORD dwLen = wcslen(pszTmp) + 1 ;
+
+ dwSize += dwLen ;
+ pszTmp += dwLen ;
+ }
+
+ return (dwSize+1) ;
+}
+
+WCHAR *
+FindStringInNullNull(
+ WCHAR *pszNullNull,
+ WCHAR *pszString
+)
+/*++
+
+Routine Description:
+
+ Walk thru a NULL NULL string, looking for the search string
+
+Arguments:
+
+ pszNullNull: the string list we will search.
+ pszString: what we are searching for.
+
+Return Status:
+
+ The start of the string if found. Null, otherwise.
+
+--*/
+{
+ WCHAR *pszTmp = pszNullNull ;
+
+ if (!pszNullNull || !*pszNullNull)
+ return NULL ;
+
+ do {
+
+ if (_wcsicmp(pszTmp,pszString)==0)
+ return pszTmp ;
+
+ pszTmp += wcslen(pszTmp) + 1 ;
+
+ } while (*pszTmp) ;
+
+ return NULL ;
+}
+
+VOID
+RemoveNWCFromNullNullList(
+ WCHAR *OtherDeps
+ )
+/*++
+
+Routine Description:
+
+ Remove the NWCWorkstation string from a null null string.
+
+Arguments:
+
+ OtherDeps: the string list we will munge.
+
+Return Status:
+
+ None.
+
+--*/
+{
+ LPWSTR pszTmp0, pszTmp1 ;
+
+ //
+ // find the NWCWorkstation string
+ //
+ pszTmp0 = FindStringInNullNull(OtherDeps, NW_WORKSTATION_SERVICE) ;
+
+ if (!pszTmp0)
+ return ;
+
+ pszTmp1 = pszTmp0 + wcslen(pszTmp0) + 1 ; // skip past it
+
+ //
+ // shift the rest up
+ //
+ memmove(pszTmp0, pszTmp1, CalcNullNullSize(pszTmp1)*sizeof(WCHAR)) ;
+}
diff --git a/private/nw/svcdlls/nwwks/lib/sources b/private/nw/svcdlls/nwwks/lib/sources
new file mode 100644
index 000000000..5911ce45b
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/lib/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=nw
+MINORCOMP=nwwlib
+
+TARGETNAME=nwwlib
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc;..\..\..\inc;$(_NTROOT)\private\inc
+
+SOURCES= \
+ lsa.c \
+ reg.c \
+ misc.c \
+ splutil.c
+
+UNICODE=1
+
+NET_C_DEFINES=-DRPC_NO_WINDOWS_H -DNOT_USED
+
+UMTYPE=console
+
+UMLIBS= \
+ obj\*\nwwlib.lib
+
+OPTIONAL_UMTEST=
diff --git a/private/nw/svcdlls/nwwks/lib/splutil.c b/private/nw/svcdlls/nwwks/lib/splutil.c
new file mode 100644
index 000000000..4f0c6fd9b
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/lib/splutil.c
@@ -0,0 +1,351 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ splutil.c
+
+Abstract:
+
+ This module provides all the utility functions for the netware print
+ provider.
+
+Author:
+
+ Yi-Hsin Sung (yihsins) 15-Apr-1993
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+#include <winspool.h>
+#include <splutil.h>
+
+DWORD PrinterInfo1Offsets[]={offsetof(LPPRINTER_INFO_1W, pDescription),
+ offsetof(LPPRINTER_INFO_1W, pName),
+ offsetof(LPPRINTER_INFO_1W, pComment),
+ 0xFFFFFFFF};
+
+DWORD PrinterInfo2Offsets[]={offsetof(LPPRINTER_INFO_2W, pServerName),
+ offsetof(LPPRINTER_INFO_2W, pPrinterName),
+ offsetof(LPPRINTER_INFO_2W, pShareName),
+ offsetof(LPPRINTER_INFO_2W, pPortName),
+ offsetof(LPPRINTER_INFO_2W, pDriverName),
+ offsetof(LPPRINTER_INFO_2W, pComment),
+ offsetof(LPPRINTER_INFO_2W, pLocation),
+ offsetof(LPPRINTER_INFO_2W, pDevMode),
+ offsetof(LPPRINTER_INFO_2W, pSepFile),
+ offsetof(LPPRINTER_INFO_2W, pPrintProcessor),
+ offsetof(LPPRINTER_INFO_2W, pDatatype),
+ offsetof(LPPRINTER_INFO_2W, pParameters),
+ offsetof(LPPRINTER_INFO_2W, pSecurityDescriptor),
+ 0xFFFFFFFF};
+
+DWORD PrinterInfo3Offsets[]={offsetof(LPPRINTER_INFO_3, pSecurityDescriptor),
+ 0xFFFFFFFF};
+
+DWORD JobInfo1Offsets[]={offsetof(LPJOB_INFO_1W, pPrinterName),
+ offsetof(LPJOB_INFO_1W, pMachineName),
+ offsetof(LPJOB_INFO_1W, pUserName),
+ offsetof(LPJOB_INFO_1W, pDocument),
+ offsetof(LPJOB_INFO_1W, pDatatype),
+ offsetof(LPJOB_INFO_1W, pStatus),
+ 0xFFFFFFFF};
+
+DWORD JobInfo2Offsets[]={offsetof(LPJOB_INFO_2W, pPrinterName),
+ offsetof(LPJOB_INFO_2W, pMachineName),
+ offsetof(LPJOB_INFO_2W, pUserName),
+ offsetof(LPJOB_INFO_2W, pDocument),
+ offsetof(LPJOB_INFO_2W, pNotifyName),
+ offsetof(LPJOB_INFO_2W, pDatatype),
+ offsetof(LPJOB_INFO_2W, pPrintProcessor),
+ offsetof(LPJOB_INFO_2W, pParameters),
+ offsetof(LPJOB_INFO_2W, pDriverName),
+ offsetof(LPJOB_INFO_2W, pDevMode),
+ offsetof(LPJOB_INFO_2W, pStatus),
+ offsetof(LPJOB_INFO_2W, pSecurityDescriptor),
+ 0xFFFFFFFF};
+
+DWORD AddJobInfo1Offsets[]={offsetof(LPADDJOB_INFO_1W, Path),
+ 0xFFFFFFFF};
+
+
+VOID
+MarshallUpStructure(
+ LPBYTE lpStructure,
+ LPDWORD lpOffsets,
+ LPBYTE lpBufferStart
+)
+{
+ register DWORD i=0;
+
+ while (lpOffsets[i] != -1) {
+
+ if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
+ (*(LPBYTE *)(lpStructure+lpOffsets[i]))+=(DWORD)lpBufferStart;
+ }
+
+ i++;
+ }
+}
+
+
+
+VOID
+MarshallDownStructure(
+ LPBYTE lpStructure,
+ LPDWORD lpOffsets,
+ LPBYTE lpBufferStart
+)
+{
+ register DWORD i=0;
+
+ if (!lpStructure)
+ return;
+
+ while (lpOffsets[i] != -1) {
+
+ if ((*(LPBYTE*)(lpStructure+lpOffsets[i]))) {
+ (*(LPBYTE*)(lpStructure+lpOffsets[i]))-=(DWORD)lpBufferStart;
+ }
+
+ i++;
+ }
+}
+
+
+
+LPVOID
+AllocNwSplMem(
+ DWORD flags,
+ DWORD cb
+)
+/*++
+
+Routine Description:
+
+ This function will allocate local memory. It will possibly allocate extra
+ memory and fill this with debugging information for the debugging version.
+
+Arguments:
+
+ flags - Flags to be passed to LocalAlloc
+
+ cb - The amount of memory to allocate in bytes
+
+Return Value:
+
+ NON-NULL - A pointer to the allocated memory
+
+--*/
+{
+ LPDWORD pMem;
+ DWORD cbNew;
+
+#if DBG
+ cbNew = cb + 2*sizeof(DWORD);
+ if (cbNew & 3)
+ cbNew += sizeof(DWORD) - (cbNew & 3);
+#else
+ cbNew = cb;
+#endif
+
+ pMem = (LPDWORD) LocalAlloc( flags, cbNew );
+
+ if ( !pMem )
+ {
+ KdPrint(("Memory Allocation in AllocNwSplMem failed for %d bytes\n", cbNew));
+ return NULL;
+ }
+
+#if DBG
+ *pMem = cb;
+ *(LPDWORD)((LPBYTE)pMem+cbNew-sizeof(DWORD)) = 0xdeadbeef;
+ return (LPVOID) (pMem + 1);
+#else
+ return (LPVOID) pMem;
+#endif
+
+}
+
+
+
+VOID
+FreeNwSplMem(
+ LPVOID pMem,
+ DWORD cb
+)
+/*++
+
+Routine Description:
+
+ This function will frees the local memory allocated by AllocSplMem.
+ Extra checking will be performed in the debug version to ensure that
+ the size to be freed is indeed the size we allocated through AllocSplMem.
+
+Arguments:
+
+ pMem - A pointer to the allocated memory
+ cb - The amount of memory to free
+
+Return Value:
+
+--*/
+{
+ DWORD cbNew;
+ LPDWORD pNewMem;
+
+ if ( !pMem )
+ return;
+
+ pNewMem = pMem;
+#if DBG
+ pNewMem--;
+ cbNew = cb + 2*sizeof(DWORD);
+ if ( cbNew & 3 )
+ cbNew += sizeof(DWORD) - (cbNew & 3);
+
+ if ( ( *pNewMem != cb )
+ || (*(LPDWORD)((LPBYTE)pNewMem + cbNew - sizeof(DWORD)) != 0xdeadbeef)
+ )
+ {
+ KdPrint(("Corrupt Memory in FreeNwSplMem : %0lx\n", pNewMem ));
+ return;
+ }
+#else
+ cbNew = cb;
+#endif
+
+ LocalFree( (LPVOID) pNewMem );
+}
+
+
+
+LPWSTR
+AllocNwSplStr(
+ LPWSTR pStr
+)
+/*++
+
+Routine Description:
+
+ This function will allocate enough local memory to store the specified
+ string, and copy that string to the allocated memory
+
+Arguments:
+
+ pStr - Pointer to the string that needs to be allocated and stored
+
+Return Value:
+
+ NON-NULL - A pointer to the allocated memory containing the string
+
+--*/
+{
+ LPWSTR pMem;
+
+ if ( !pStr )
+ return NULL;
+
+ if ( pMem = AllocNwSplMem(0, (wcslen(pStr) + 1) * sizeof(WCHAR)))
+ wcscpy(pMem, pStr);
+
+ return pMem;
+}
+
+
+
+VOID
+FreeNwSplStr(
+ LPWSTR pStr
+)
+/*++
+
+Routine Description:
+
+ This function will frees the string allocated by AllocSplStr.
+ Extra checking will be performed in the debug version to ensure that
+ the size to be freed is indeed the size we allocated through AllocSplStr.
+
+Arguments:
+
+ pStr - A pointer to the allocated string
+
+Return Value:
+
+--*/
+{
+ if ( pStr )
+ FreeNwSplMem(pStr, (wcslen(pStr) + 1) * sizeof(WCHAR));
+}
+
+
+
+BOOL
+ValidateUNCName(
+ LPWSTR pName
+)
+/*++
+
+Routine Description:
+
+ This function will checks whether the given name is a valid UNC
+ name ( in the form \\server\name) or not.
+
+Arguments:
+
+ pName - The supplied name
+
+Return Value:
+
+ TRUE - The name given is a valid UNC name
+ FALSE - Otherwise
+
+--*/
+{
+ if ( pName
+ && (*pName++ == L'\\')
+ && (*pName++ == L'\\')
+ && (wcschr(pName, L'\\'))
+ )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#ifndef NOT_USED
+
+LPWSTR
+GetNextElement(LPWSTR *pPtr, WCHAR token)
+{
+ LPWSTR pszRestOfString = *pPtr;
+ LPWSTR pszRetval = NULL;
+ LPWSTR pszStr = NULL;
+
+ if ( *pszRestOfString == L'\0')
+ return NULL;
+
+ if ((pszStr = wcschr (pszRestOfString, token))== NULL )
+ {
+ pszRetval = *pPtr;
+ *pPtr += wcslen(*pPtr);
+ return pszRetval;
+ }
+ else
+ {
+ *pszStr = L'\0';
+ pszRetval = *pPtr ;
+ *pPtr = ++pszStr ;
+ return pszRetval ;
+ }
+}
+
+#endif