summaryrefslogtreecommitdiffstats
path: root/private/net/portuas
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/net/portuas
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/net/portuas')
-rw-r--r--private/net/portuas/alias.c582
-rw-r--r--private/net/portuas/argvw.c267
-rw-r--r--private/net/portuas/dumpuser.c245
-rw-r--r--private/net/portuas/groups.c120
-rw-r--r--private/net/portuas/hashtst.c84
-rw-r--r--private/net/portuas/logfile.c257
-rw-r--r--private/net/portuas/makefile6
-rw-r--r--private/net/portuas/makefile.inc7
-rw-r--r--private/net/portuas/members.c116
-rw-r--r--private/net/portuas/modals.c86
-rw-r--r--private/net/portuas/owfcrypt.c152
-rw-r--r--private/net/portuas/passwds.c140
-rw-r--r--private/net/portuas/port.c340
-rw-r--r--private/net/portuas/portlib.c1366
-rw-r--r--private/net/portuas/portmac.c171
-rw-r--r--private/net/portuas/portmap.c489
-rw-r--r--private/net/portuas/portpars.c255
-rw-r--r--private/net/portuas/portuas.c74
-rw-r--r--private/net/portuas/portuas.rc13
-rw-r--r--private/net/portuas/portuasp.h466
-rw-r--r--private/net/portuas/prompt.c771
-rw-r--r--private/net/portuas/puasmsg.h334
-rw-r--r--private/net/portuas/sources52
-rw-r--r--private/net/portuas/uasread.c1307
-rw-r--r--private/net/portuas/users.c118
25 files changed, 7818 insertions, 0 deletions
diff --git a/private/net/portuas/alias.c b/private/net/portuas/alias.c
new file mode 100644
index 000000000..12ebf38d0
--- /dev/null
+++ b/private/net/portuas/alias.c
@@ -0,0 +1,582 @@
+/*++
+
+Copyright (c) 1992-1993 Microsoft Corporation
+
+Module Name:
+
+ Alias.c
+
+Abstract:
+
+ NT alias functions:
+ PortUasAliasSetup() -- one-time init of static data
+ PortUasAddUserToAliases()
+ PortUasAliasCleanup()
+
+Author:
+
+ John Rogers (JohnRo) 24-Apr-1992
+
+Revision History:
+
+ 24-Apr-1992 JohnRo
+ Created.
+ 05-May-1992 JohnRo
+ Fixed desired _access parm to SamConnect() and SamOpenAlias().
+ Fixed misleading msg when SamOpenDomain() fails.
+ Call NetpGetLocalDomainId() instead of NetpGetDomainId() so we can get
+ the kind that SamOpenDomain() wants.
+ Only _open aliases for this product type.
+ 09-Jun-1992 JohnRo
+ RAID 10139: PortUAS should add to admin group/alias.
+ Fixed PortUasAliasSetup's error handling.
+ 27-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ Use NetLib's get product type function.
+ 01-Jun-1993 JohnRo
+ Made changes suggested by PC-LINT 5.0
+
+--*/
+
+
+// Uncomment this to enable comm ops alias:
+//#define USE_COMM_OPS
+
+
+#include <nt.h> // NTSTATUS, NT_SUCCESS(), etc.
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h> // LocalFree(), etc.
+#include <lmcons.h>
+
+#include <lmaccess.h> // UF_ equates, LPUSER_INFO_2, etc.
+#include <lmerr.h> // NO_ERROR, NERR_ equates.
+#include <netdebug.h> // DBGSTATIC, NetpAssert(), etc.
+#include <netlib.h> // NetpGetProductType(), NetpMemoryFree().
+#include <netlibnt.h> // NetpNtStatusToApiStatus().
+#include <ntsam.h> // SAM_HANDLE, SamConnect(), etc.
+#include <secobj.h> // NetpDomainIdToSid().
+#include <portuasp.h> // My prototypes, UNEXPECTED_MSG(), PortUasSam*, etc.
+
+#include "nlstxt.h" // Nls message ID codes.
+
+
+//#define OUR_ALIAS_DESIRED_ACCESS (ALIAS_ADD_MEMBER | STANDARD_RIGHTS_REQUIRED)
+#define OUR_ALIAS_DESIRED_ACCESS ALIAS_ADD_MEMBER
+
+//#define OUR_GROUP_DESIRED_ACCESS (GROUP_ADD_MEMBER | STANDARD_RIGHTS_REQUIRED)
+#define OUR_GROUP_DESIRED_ACCESS GROUP_ADD_MEMBER
+
+
+//int _wcsicmp(const wchar_t *string1, const wchar_t *string2);
+
+//
+// State data (misc):
+//
+DBGSTATIC BOOL PortUasTargetIsLanmanNt;
+
+//
+// State data (alias handles and group handles):
+//
+DBGSTATIC SAM_HANDLE PortUasSamAccountOpsAliasHandle = NULL;
+DBGSTATIC SAM_HANDLE PortUasSamAdminsAliasHandle = NULL;
+DBGSTATIC SAM_HANDLE PortUasSamAdminsGroupHandle = NULL;
+#ifdef USE_COMM_OPS
+DBGSTATIC SAM_HANDLE PortUasSamCommOpsAliasHandle = NULL;
+#endif
+DBGSTATIC SAM_HANDLE PortUasSamPowerUsersAliasHandle = NULL;
+DBGSTATIC SAM_HANDLE PortUasSamPrintOpsAliasHandle = NULL;
+DBGSTATIC SAM_HANDLE PortUasSamServerOpsAliasHandle = NULL;
+
+
+NET_API_STATUS
+PortUasAliasSetup(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ PortUas ports account information in a LanMan 2.0 UAS database into
+ the SAM database.
+
+Arguments:
+
+ UasPathName - supplies the path name to the UAS database file.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+--*/
+
+{
+ NET_API_STATUS ApiStatus;
+ NTSTATUS NtStatus;
+ NT_PRODUCT_TYPE ProductType;
+
+ //
+ // Caller should have already set global domain IDs and SAM domain handles.
+ //
+
+ NetpAssert( PortUasAccountsDomainId != NULL );
+ NetpAssert( PortUasBuiltinDomainId != NULL );
+
+ NetpAssert( PortUasSamAccountsDomainHandle != NULL );
+ NetpAssert( PortUasSamBuiltinDomainHandle != NULL );
+
+ //
+ // Decide on policy: should we combine operator accounts into the
+ // "power user" alias (on WindowsNT) or leave them in seperate
+ // aliases (on LanManNT)?
+ //
+
+ ApiStatus = NetpGetProductType(
+ NULL, // local (no server name)
+ &ProductType ); // get result here.
+ if (ApiStatus != NO_ERROR) {
+
+ UNEXPECTED_MSG( "NetpGetProductType", ApiStatus );
+ goto SetupError;
+ }
+ if (ProductType == NtProductLanManNt) {
+ PortUasTargetIsLanmanNt = TRUE;
+ } else {
+ PortUasTargetIsLanmanNt = FALSE;
+ }
+ if (Verbose) {
+ DEBUG_MSG( (PREFIX_PORTUAS "Product type is " FORMAT_DWORD
+ ", IsLanmanNt is " FORMAT_DWORD ".\n", ProductType,
+ (DWORD) PortUasTargetIsLanmanNt) );
+ }
+
+ //
+ // Open the well-known aliases and/or groups for this product type.
+ //
+ if (PortUasTargetIsLanmanNt) {
+
+ NtStatus = SamOpenAlias(
+ PortUasSamBuiltinDomainHandle, // aliases live in builtin dom.
+ OUR_ALIAS_DESIRED_ACCESS,
+ DOMAIN_ALIAS_RID_ACCOUNT_OPS, // alias ID
+ & PortUasSamAccountOpsAliasHandle ); // alias handle
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamOpenAlias(account)", ApiStatus );
+ goto SetupError;
+ }
+ NetpAssert( PortUasSamAccountOpsAliasHandle != NULL );
+
+ NtStatus = SamOpenGroup(
+ PortUasSamAccountsDomainHandle, // groups live in accts domain
+ OUR_GROUP_DESIRED_ACCESS,
+ DOMAIN_GROUP_RID_ADMINS, // alias ID
+ & PortUasSamAdminsGroupHandle ); // alias handle
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamOpenGroup(admins global group)", ApiStatus );
+ goto SetupError;
+ }
+ NetpAssert( PortUasSamAdminsGroupHandle != NULL );
+
+ NtStatus = SamOpenAlias(
+ PortUasSamBuiltinDomainHandle,
+ OUR_ALIAS_DESIRED_ACCESS,
+ DOMAIN_ALIAS_RID_PRINT_OPS, // alias ID
+ & PortUasSamPrintOpsAliasHandle ); // alias handle
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamOpenAlias(print)", ApiStatus );
+ goto SetupError;
+
+ }
+ NetpAssert( PortUasSamPrintOpsAliasHandle != NULL );
+
+ NtStatus = SamOpenAlias(
+ PortUasSamBuiltinDomainHandle,
+ OUR_ALIAS_DESIRED_ACCESS,
+ DOMAIN_ALIAS_RID_SYSTEM_OPS, // alias ID
+ & PortUasSamServerOpsAliasHandle ); // alias handle
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamOpenAlias(server)", ApiStatus );
+ goto SetupError;
+ }
+ NetpAssert( PortUasSamServerOpsAliasHandle != NULL );
+
+ } else {
+
+ // Target must be Windows/NT (not Lanman/NT), which changes policy.
+
+ NtStatus = SamOpenAlias(
+ PortUasSamBuiltinDomainHandle,
+ OUR_ALIAS_DESIRED_ACCESS,
+ DOMAIN_ALIAS_RID_ADMINS , // alias ID
+ & PortUasSamAdminsAliasHandle ); // alias handle
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamOpenAlias(admins local group)", ApiStatus );
+ goto SetupError;
+ }
+ NetpAssert( PortUasSamAdminsAliasHandle != NULL );
+
+ NtStatus = SamOpenAlias(
+ PortUasSamBuiltinDomainHandle,
+ OUR_ALIAS_DESIRED_ACCESS,
+ DOMAIN_ALIAS_RID_POWER_USERS, // alias ID
+ & PortUasSamPowerUsersAliasHandle ); // alias handle
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamOpenAlias(power users)", ApiStatus );
+ goto SetupError;
+ }
+ NetpAssert( PortUasSamPowerUsersAliasHandle != NULL );
+
+ }
+
+ return (NO_ERROR);
+
+SetupError:
+
+ //
+ // Come here to process errors. ApiStatus has already been set.
+ //
+
+ NetpAssert( ApiStatus != NO_ERROR );
+
+ (VOID) PortUasAliasCleanup();
+
+ return (ApiStatus);
+
+} // PortUasAliasSetup
+
+
+DBGSTATIC NET_API_STATUS
+PortUasAddUserToAlias(
+ IN PSID UserSid,
+ IN SAM_HANDLE AliasHandle
+ )
+{
+ NET_API_STATUS ApiStatus;
+ NTSTATUS NtStatus;
+
+ NetpAssert( UserSid != NULL );
+ NetpAssert( AliasHandle != NULL );
+
+ NtStatus = SamAddMemberToAlias(
+ AliasHandle,
+ UserSid );
+
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+
+ // Allow repeated runs of PortUAS...
+ if (ApiStatus == ERROR_MEMBER_IN_ALIAS) {
+ return (NO_ERROR);
+ }
+
+ UNEXPECTED_MSG( "SamAddMemberToAlias", ApiStatus );
+ return (ApiStatus);
+ }
+
+ return (NO_ERROR);
+}
+
+
+NET_API_STATUS
+PortUasNameToRid(
+ IN LPCTSTR Name, // may be user or group name.
+ IN SID_NAME_USE ExpectedType,
+ OUT PULONG UserRid
+ )
+{
+ NET_API_STATUS ApiStatus;
+ PSID_NAME_USE NameUse;
+ NTSTATUS NtStatus;
+ UNICODE_STRING UnicodeName;
+ PULONG TempRid;
+
+ NetpAssert( Name != NULL );
+ NetpAssert( (*Name) != NULLC );
+ NetpAssert( UserRid != NULL );
+
+ NetpAssert( PortUasSamAccountsDomainHandle != NULL );
+
+ //
+ // Get a RID for this user name.
+ //
+ RtlInitUnicodeString(
+ & UnicodeName, // dest (NT struct)
+ Name ); // src (null-terminated)
+
+ NtStatus = SamLookupNamesInDomain(
+ PortUasSamAccountsDomainHandle, // users live in accounts domain
+ (ULONG) 1, // only want one name.
+ &UnicodeName, // name (in NT struct)
+ &TempRid, // alloc and set RIDs.
+ &NameUse ); // alloc and set name types.
+
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamLookupNamesInDomain(accounts)", ApiStatus );
+ DEBUG_MSG( (PREFIX_PORTUAS "SAM lookup(accounts) of "
+ FORMAT_LPWSTR " failed.\n", Name) );
+ return (ApiStatus);
+ }
+
+ NetpAssert( NameUse != NULL );
+ NetpAssert( TempRid != NULL );
+
+ *UserRid = *TempRid;
+
+ //
+ // Did type user wanted match the actual one?
+ //
+ if (ExpectedType != *NameUse) {
+ NetpAssert( FALSE ); // BUGBUG: Is this possible?
+ ApiStatus = ERROR_INVALID_PARAMETER; // BUGBUG: A better error code?
+ goto Cleanup;
+ }
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+ //
+ // Free memory which SAM allocated for us.
+ //
+ NtStatus = SamFreeMemory( NameUse );
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamFreeMemory(use)", ApiStatus );
+ return (ApiStatus);
+ }
+
+ NtStatus = SamFreeMemory( TempRid );
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+ UNEXPECTED_MSG( "SamFreeMemory(rid)", ApiStatus );
+ return (ApiStatus);
+ }
+
+ return (ApiStatus);
+
+} // PortUasNameToRid
+
+
+DBGSTATIC NET_API_STATUS
+PortUasUserNameToRidAndSid(
+ IN LPCWSTR UserName,
+ OUT PULONG UserRid,
+ OUT PSID * UserSid
+ )
+{
+ NET_API_STATUS ApiStatus;
+
+ NetpAssert( UserName != NULL );
+ NetpAssert( (*UserName) != NULLC );
+ NetpAssert( UserRid != NULL );
+ NetpAssert( UserSid != NULL );
+
+ NetpAssert( PortUasSamAccountsDomainHandle != NULL );
+
+ //
+ // Get a RID for this user name.
+ //
+ ApiStatus = PortUasNameToRid(
+ (LPCTSTR) UserName,
+ SidTypeUser, // expected type
+ UserRid ); // set RID for caller.
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasNameToRid", ApiStatus );
+ return (ApiStatus);
+ }
+
+ //
+ // Convert the RID to a SID.
+ //
+
+ ApiStatus = NetpDomainIdToSid(
+ PortUasAccountsDomainId, // user IDs live in accounts domain
+ *UserRid,
+ UserSid );
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetpDomainIdToSid", ApiStatus );
+ return (ApiStatus);
+ }
+ NetpAssert( (*UserSid) != NULL );
+
+ return (NO_ERROR);
+
+} // PortUasUserNameToRidAndSid
+
+
+NET_API_STATUS
+PortUasAddUserToAliases(
+ IN LPCWSTR UserName,
+ IN DWORD Priv, // USER_PRIV_ values from lmaccess.h
+ IN DWORD AuthFlags // AF_ values from lmaccess.h
+ )
+{
+ NET_API_STATUS ApiStatus;
+ NTSTATUS NtStatus;
+ ULONG UserRid;
+ PSID UserSid;
+
+ NetpAssert( UserName != NULL );
+ NetpAssert( (*UserName) != NULLC );
+
+ //
+ // If it's an ordinary user (or guest), ignore it.
+ //
+ if ( (AuthFlags == 0) && (Priv != USER_PRIV_ADMIN) ) {
+ return (NO_ERROR);
+ }
+
+ //
+ // Convert UserName to UserSid.
+ //
+ ApiStatus = PortUasUserNameToRidAndSid(
+ UserName,
+ &UserRid, // set RID for this user.
+ &UserSid ); // alloc and set ptr for SID.
+ if (ApiStatus != NO_ERROR) {
+ return (ApiStatus);
+ }
+ NetpAssert( UserSid != NULL );
+
+ if (Priv == USER_PRIV_ADMIN) {
+ //
+ // Depending on product type, add to admins local group or admins
+ // global group.
+ //
+ if (PortUasTargetIsLanmanNt) {
+ //PROGRESS_MSG( ("Adding user " FORMAT_LPWSTR
+ // " to admins global group...\n", UserName) );
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_USER_TO_ADMINS_GLOBAL_GROUP, UserName );
+ NtStatus = SamAddMemberToGroup(
+ PortUasSamAdminsGroupHandle,
+ UserRid,
+ SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT |
+ SE_GROUP_ENABLED );
+
+ if ( !NT_SUCCESS( NtStatus ) ) {
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus );
+
+ // Allow repeated runs of PortUAS...
+ if (ApiStatus == NERR_UserInGroup) {
+ return (NO_ERROR);
+ }
+
+ UNEXPECTED_MSG( "SamAddMemberToGroup", ApiStatus );
+ return (ApiStatus);
+ }
+ } else {
+ //PROGRESS_MSG( ("Adding user " FORMAT_LPWSTR
+ // " to admins local group...\n", UserName) );
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_USER_TO_ADMINS_LOCAL_GROUP, UserName );
+ ApiStatus = PortUasAddUserToAlias( UserSid,
+ PortUasSamAdminsAliasHandle );
+ if (ApiStatus != NO_ERROR) {
+ // Msg already logged.
+ return (ApiStatus);
+ }
+ }
+ }
+
+ //
+ // Add user (operator) to applicable alias(es).
+ //
+ if (PortUasTargetIsLanmanNt) {
+
+ if (AuthFlags & AF_OP_ACCOUNTS) {
+ //PROGRESS_MSG( ("Adding user " FORMAT_LPWSTR " to acct ops alias.\n",
+ // UserName) );
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_USER_TO_ACCT_OPS_ALIAS, UserName );
+ ApiStatus = PortUasAddUserToAlias( UserSid,
+ PortUasSamAccountOpsAliasHandle );
+ if (ApiStatus != NO_ERROR) {
+ // Msg already logged.
+ return (ApiStatus);
+ }
+ }
+
+ if (AuthFlags & AF_OP_COMM) {
+
+#ifdef USE_COMM_OPS
+ //PROGRESS_MSG( ("Adding user " FORMAT_LPWSTR " to comm ops alias.\n",
+ // UserName) );
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_USER_TO_COMM_OPS_ALIAS, UserName );
+ ApiStatus = PortUasAddUserToAlias( UserSid,
+ PortUasSamCommOpsAliasHandle );
+ if (ApiStatus != NO_ERROR) {
+ // Msg already logged.
+ return (ApiStatus);
+ }
+#else
+ //WARNING_MSG( ("Ignoring comm operator flag for " FORMAT_LPWSTR
+ // ".\n", UserName) );
+ (void)NlsPutMsg(STDOUT,PUAS_IGNORING_COMM_OPERATOR_FLAG, UserName);
+#endif
+ }
+
+ if (AuthFlags & AF_OP_PRINT) {
+ //PROGRESS_MSG( ("Adding user " FORMAT_LPWSTR " to print alias.\n",
+ // UserName) );
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_USER_TO_PRINT_ALIAS, UserName );
+ ApiStatus = PortUasAddUserToAlias( UserSid,
+ PortUasSamPrintOpsAliasHandle );
+ if (ApiStatus != NO_ERROR) {
+ // Msg already logged.
+ return (ApiStatus);
+ }
+ }
+
+ if (AuthFlags & AF_OP_SERVER) {
+ //PROGRESS_MSG( ("Adding user " FORMAT_LPWSTR " to srv ops alias.\n",
+ // UserName) );
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_USER_TO_SRV_OPS_ALIAS, UserName );
+ ApiStatus = PortUasAddUserToAlias( UserSid,
+ PortUasSamServerOpsAliasHandle );
+ if (ApiStatus != NO_ERROR) {
+ // Msg already logged.
+ return (ApiStatus);
+ }
+ }
+
+ } else {
+
+ ApiStatus = PortUasAddUserToAlias( UserSid,
+ PortUasSamPowerUsersAliasHandle );
+ if (ApiStatus != NO_ERROR) {
+ // Msg already logged.
+ return (ApiStatus);
+ }
+ }
+
+ NetpMemoryFree( UserSid ); // Free mem alloc'ed by PortUasUserNameToSid().
+
+ NetpAssert( ApiStatus == NO_ERROR );
+ return (NO_ERROR);
+}
+
+
+NET_API_STATUS
+PortUasAliasCleanup(
+ VOID
+ )
+{
+
+ CLOSE_SAM_HANDLE( PortUasSamAdminsAliasHandle );
+ CLOSE_SAM_HANDLE( PortUasSamAdminsGroupHandle );
+ CLOSE_SAM_HANDLE( PortUasSamAccountOpsAliasHandle );
+#ifdef USE_COMM_OPS
+ CLOSE_SAM_HANDLE( PortUasSamCommOpsAliasHandle );
+#endif
+ CLOSE_SAM_HANDLE( PortUasSamPowerUsersAliasHandle );
+ CLOSE_SAM_HANDLE( PortUasSamPrintOpsAliasHandle );
+ CLOSE_SAM_HANDLE( PortUasSamServerOpsAliasHandle );
+
+ return (NO_ERROR);
+
+} // PortUasAliasCleanup
diff --git a/private/net/portuas/argvw.c b/private/net/portuas/argvw.c
new file mode 100644
index 000000000..6dc13737f
--- /dev/null
+++ b/private/net/portuas/argvw.c
@@ -0,0 +1,267 @@
+/***
+*argvw.c - create Unicode version of argv arguments
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* processes program command line
+*
+*Revision History:
+*
+*******************************************************************************/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <stdlib.h>
+#include <tchar.h>
+#include <wchar.h>
+
+
+/***
+*void Parse_Cmdline(cmdstart, argv, lpstr, numargs, numbytes)
+*
+*Purpose:
+* Parses the command line and sets up the Unicode argv[] array.
+* On entry, cmdstart should point to the command line,
+* argv should point to memory for the argv array, lpstr
+* points to memory to place the text of the arguments.
+* If these are NULL, then no storing (only counting)
+* is done. On exit, *numargs has the number of
+* arguments (plus one for a final NULL argument),
+* and *numbytes has the number of bytes used in the buffer
+* pointed to by args.
+*
+*Entry:
+* LPWSTR cmdstart - pointer to command line of the form
+* <progname><nul><args><nul>
+* TCHAR **argv - where to build argv array; NULL means don't
+* build array
+* LPWSTR lpstr - where to place argument text; NULL means don't
+* store text
+*
+*Exit:
+* no return value
+* INT *numargs - returns number of argv entries created
+* INT *numbytes - number of bytes used in args buffer
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void Parse_Cmdline (
+ LPWSTR cmdstart,
+ LPWSTR*argv,
+ LPWSTR lpstr,
+ INT *numargs,
+ INT *numbytes
+ )
+{
+ LPWSTR p;
+ WCHAR c;
+ INT inquote; /* 1 = inside quotes */
+ INT copychar; /* 1 = copy char to *args */
+ WORD numslash; /* num of backslashes seen */
+
+ *numbytes = 0;
+ *numargs = 1; /* the program name at least */
+
+ /* first scan the program name, copy it, and count the bytes */
+ p = cmdstart;
+ if (argv)
+ *argv++ = lpstr;
+
+ /* A quoted program name is handled here. The handling is much
+ simpler than for other arguments. Basically, whatever lies
+ between the leading double-quote and next one, or a terminal null
+ character is simply accepted. Fancier handling is not required
+ because the program name must be a legal NTFS/HPFS file name.
+ Note that the double-quote characters are not copied, nor do they
+ contribute to numbytes. */
+ if (*p == TEXT('\"'))
+ {
+ /* scan from just past the first double-quote through the next
+ double-quote, or up to a null, whichever comes first */
+ while ((*(++p) != TEXT('\"')) && (*p != TEXT('\0')))
+ {
+ *numbytes += sizeof(WCHAR);
+ if (lpstr)
+ *lpstr++ = *p;
+ }
+ /* append the terminating null */
+ *numbytes += sizeof(WCHAR);
+ if (lpstr)
+ *lpstr++ = TEXT('\0');
+
+ /* if we stopped on a double-quote (usual case), skip over it */
+ if (*p == TEXT('\"'))
+ p++;
+ }
+ else
+ {
+ /* Not a quoted program name */
+ do {
+ *numbytes += sizeof(WCHAR);
+ if (lpstr)
+ *lpstr++ = *p;
+
+ c = (WCHAR) *p++;
+
+ } while (c > TEXT(' '));
+
+ if (c == TEXT('\0'))
+ {
+ p--;
+ }
+ else
+ {
+ if (lpstr)
+ *(lpstr - 1) = TEXT('\0');
+ }
+ }
+
+ inquote = 0;
+
+ /* loop on each argument */
+ for ( ; ; )
+ {
+ if (*p)
+ {
+ while (*p == TEXT(' ') || *p == TEXT('\t'))
+ ++p;
+ }
+
+ if (*p == TEXT('\0'))
+ break; /* end of args */
+
+ /* scan an argument */
+ if (argv)
+ *argv++ = lpstr; /* store ptr to arg */
+ ++*numargs;
+
+ /* loop through scanning one argument */
+ for ( ; ; )
+ {
+ copychar = 1;
+ /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
+ 2N+1 backslashes + " ==> N backslashes + literal "
+ N backslashes ==> N backslashes */
+ numslash = 0;
+ while (*p == TEXT('\\'))
+ {
+ /* count number of backslashes for use below */
+ ++p;
+ ++numslash;
+ }
+ if (*p == TEXT('\"'))
+ {
+ /* if 2N backslashes before, start/end quote, otherwise
+ copy literally */
+ if (numslash % 2 == 0)
+ {
+ if (inquote)
+ if (p[1] == TEXT('\"'))
+ p++; /* Double quote inside quoted string */
+ else /* skip first quote char and copy second */
+ copychar = 0;
+ else
+ copychar = 0; /* don't copy quote */
+
+ inquote = !inquote;
+ }
+ numslash /= 2; /* divide numslash by two */
+ }
+
+ /* copy slashes */
+ while (numslash--)
+ {
+ if (lpstr)
+ *lpstr++ = TEXT('\\');
+ *numbytes += sizeof(WCHAR);
+ }
+
+ /* if at end of arg, break loop */
+ if (*p == TEXT('\0') || (!inquote && (*p == TEXT(' ') || *p == TEXT('\t'))))
+ break;
+
+ /* copy character into argument */
+ if (copychar)
+ {
+ if (lpstr)
+ *lpstr++ = *p;
+ *numbytes += sizeof(WCHAR);
+ }
+ ++p;
+ }
+
+ /* null-terminate the argument */
+
+ if (lpstr)
+ *lpstr++ = TEXT('\0'); /* terminate string */
+ *numbytes += sizeof(WCHAR);
+ }
+
+}
+
+
+/***
+*CommandLineToArgvW - set up Unicode "argv" for C programs
+*
+*Purpose:
+* Read the command line and create the argv array for C
+* programs.
+*
+*Entry:
+* Arguments are retrieved from the program command line
+*
+*Exit:
+* "argv" points to a null-terminated list of pointers to UNICODE
+* strings, each of which is an argument from the command line.
+* The list of pointers is also located on the heap or stack.
+*
+*Exceptions:
+* Terminates with out of memory error if no memory to allocate.
+*
+*******************************************************************************/
+
+LPWSTR* CommandLineToArgvW (LPCWSTR lpCmdLine, int*pNumArgs)
+{
+ LPWSTR*argv_U;
+ LPWSTR cmdstart; /* start of command line to parse */
+ INT numbytes;
+ WCHAR pgmname[MAX_PATH];
+
+ if (pNumArgs == NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ /* Get the program name pointer from Win32 Base */
+
+ GetModuleFileName (NULL, pgmname, sizeof(pgmname) / sizeof(WCHAR));
+
+ /* if there's no command line at all (won't happen from cmd.exe, but
+ possibly another program), then we use pgmname as the command line
+ to parse, so that argv[0] is initialized to the program name */
+ cmdstart = (LPWSTR)((*lpCmdLine == TEXT('\0')) ? (LPCWSTR)pgmname : lpCmdLine);
+
+ /* first find out how much space is needed to store args */
+ Parse_Cmdline (cmdstart, NULL, NULL, pNumArgs, &numbytes);
+
+ /* allocate space for argv[] vector and strings */
+ argv_U = (LPWSTR*) RtlAllocateHeap(RtlProcessHeap(),0,
+ *pNumArgs * sizeof(LPWSTR) + numbytes);
+ if (!argv_U) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return (NULL);
+ }
+
+ /* store args and argv ptrs in just allocated block */
+ Parse_Cmdline (cmdstart, argv_U,
+ (LPWSTR) (((LPBYTE)argv_U) + *pNumArgs * sizeof(LPWSTR)),
+ pNumArgs, &numbytes);
+
+ return (argv_U);
+}
+
diff --git a/private/net/portuas/dumpuser.c b/private/net/portuas/dumpuser.c
new file mode 100644
index 000000000..b16c64cfa
--- /dev/null
+++ b/private/net/portuas/dumpuser.c
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ DumpUser.C
+
+Abstract:
+
+ DumpUserInfo() is a debug-only display of an entire user info 2 struct.
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 29-Oct-1991
+
+Revision History:
+
+ 29-Oct-1991 w-shankn
+ Created.
+ 11-Mar-1992 JohnRo
+ Extracted this code into its own routine.
+ 18-Mar-1992 JohnRo
+ Added mention of user name being too long.
+ 24-Apr-1992 JohnRo
+ Use FORMAT_ equates.
+ 30-Apr-1992 JohnRo
+ Allow password to be null pointer.
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 10-May-1993 JohnRo
+ RAID 6113: PortUAS: "dangerous handling of Unicode".
+ 17-Aug-1993 JohnRo
+ RAID 3094: PortUAS displays chars incorrectly.
+ RAID 2822: PortUAS maps characters funny.
+
+--*/
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <lmcons.h> // NET_API_STATUS, ENCRYPTED_PWLEN.
+
+#include <lmaccess.h>
+#include <debugfmt.h> // FORMAT_ equates.
+#include <stdio.h> // printf().
+#include <portuasp.h> // My prototype, Verbose flag.
+#include <tstr.h> // STRSIZE().
+#include <wchar.h> // wcslen().
+
+#include "nlstxt.h" // NLS message ID's
+
+
+VOID
+DumpHex(
+ IN LPBYTE Area,
+ IN DWORD Size
+ )
+{
+ DWORD Index;
+
+ if (Area != NULL) {
+ for ( Index = 0; Index < Size; Index++ ) {
+
+ (void) WriteToCon( TEXT("%.2x "), Area[Index] );
+
+ // Split DWORDs by an extra space.
+ if ( ((Index+1) % 4) == 0 ) {
+ (void) WriteToCon( TEXT(" ") );
+ }
+
+ // BUGBUG: split lines someday?
+ }
+ (void) WriteToCon( TEXT("\n\n") );
+ } else {
+ // BUGBUG: Internationalize this!
+ (void) WriteToCon( TEXT("(NULL)\n") );
+ }
+
+} // DumpHex
+
+
+VOID
+DumpUserInfo(
+ IN LPUSER_INFO_22 user
+ )
+
+/*++
+
+Routine Description:
+
+ DumpUserInfo displays an entire user info level 22 structure,
+ mainly for debugging.
+
+Arguments:
+
+ user - points to a user info level 22 structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD i;
+
+ //(void) WriteToCon( TEXT("========================================\n") );
+ (void) NlsPutMsg(STDOUT, PUAS_BAR);
+
+ // (void) WriteToCon( TEXT(" Name(non-NLS): '") TFORMAT_LPWSTR TEXT("'\n"), user->usri22_name );
+ (void) NlsPutMsg(STDOUT, PUAS_USER_STATS_1, user->usri22_name );
+ if (wcslen(user->usri22_name) > PORTUAS_MAX_USER_LEN) {
+ //(void) WriteToCon( TEXT("*** NAME TOO LONG! ***\n") );
+ (void) NlsPutMsg (STDOUT, PUAS_NAME_TOO_LONG);
+ }
+ if (Verbose) {
+ DumpHex(
+ (LPVOID) user->usri22_name, // area
+ STRSIZE( user->usri22_name ) ); // byte count
+ }
+
+ //DumpPassword( TEXT(" Password: "), (LPVOID) user->usri22_password );
+ DumpPassword( PUAS_PASSWORD, (LPVOID) user->usri22_password );
+
+ //(void) WriteToCon( TEXT(" Password age: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_password_age );
+ //(void) WriteToCon( TEXT(" Privilege: ") FORMAT_DWORD TEXT("\n"), user->usri22_priv );
+ //(void) WriteToCon( TEXT(" Home directory: '") TFORMAT_LPWSTR TEXT("'\n"),
+ // user->usri22_home_dir );
+ //(void) WriteToCon( TEXT(" Comment: '") TFORMAT_LPWSTR TEXT("'\n"), user->usri22_comment );
+ //(void) WriteToCon( TEXT(" Flags: ") FORMAT_HEX_DWORD TEXT("\n"), user->usri22_flags );
+ //(void) WriteToCon( TEXT(" Script path: '") TFORMAT_LPWSTR TEXT("'\n"),
+ // user->usri22_script_path );
+ //(void) WriteToCon( TEXT(" Auth. Flags: ") FORMAT_HEX_DWORD TEXT("\n"),
+ // user->usri22_auth_flags );
+ //(void) WriteToCon( TEXT(" Full name: '") TFORMAT_LPWSTR TEXT("'\n"),
+ // user->usri22_full_name );
+ //(void) WriteToCon( TEXT(" User comment: '") TFORMAT_LPWSTR TEXT("'\n"),
+ // user->usri22_usr_comment );
+ //(void) WriteToCon( TEXT(" Parms: '") TFORMAT_LPWSTR TEXT("'\n"), user->usri22_parms );
+ //(void) WriteToCon( TEXT(" Workstations: '") TFORMAT_LPWSTR TEXT("'\n"),
+ // user->usri22_workstations );
+ //(void) WriteToCon( TEXT(" Last logon: ") FORMAT_DWORD TEXT("\n"), user->usri22_last_logon );
+ //(void) WriteToCon( TEXT(" Last logoff: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_last_logoff );
+ //(void) WriteToCon( TEXT(" Acct. expires: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_acct_expires );
+ //(void) WriteToCon( TEXT(" Max storage: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_max_storage );
+ //(void) WriteToCon( TEXT(" Units per week: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_units_per_week );
+
+ (void) NlsPutMsg (STDOUT, PUAS_USER_STATS_2,
+ user->usri22_password_age,
+ user->usri22_priv,
+ user->usri22_home_dir,
+ user->usri22_comment,
+ user->usri22_flags,
+ user->usri22_script_path,
+ user->usri22_auth_flags,
+ user->usri22_full_name,
+ user->usri22_usr_comment,
+ user->usri22_parms,
+ user->usri22_workstations,
+ user->usri22_last_logon,
+ user->usri22_last_logoff,
+ user->usri22_acct_expires,
+ user->usri22_max_storage,
+ user->usri22_units_per_week );
+
+ //(void) WriteToCon( TEXT(" Logon hours:") );
+ (void)NlsPutMsg(STDOUT, PUAS_USER_STATS_3);
+ for( i = 0; i < 168; i++ ) {
+ if ( UAS_ISBITON( user->usri22_logon_hours, i )) (void) WriteToCon( TEXT("1") );
+ else (void) WriteToCon( TEXT("0") );
+ }
+ (void) WriteToCon( TEXT("\n") );
+ //(void) WriteToCon( TEXT(" Bad password count: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_bad_pw_count );
+ //(void) WriteToCon( TEXT(" Num logons: ") FORMAT_DWORD TEXT("\n"), user->usri22_num_logons );
+ //(void) WriteToCon( TEXT(" Logon server: '") TFORMAT_LPWSTR TEXT("'\n"),
+ // user->usri22_logon_server );
+ //(void) WriteToCon( TEXT(" Country code: ") FORMAT_DWORD TEXT("\n"),
+ // user->usri22_country_code );
+ //(void) WriteToCon( TEXT(" Code page: ") FORMAT_DWORD TEXT("\n"), user->usri22_code_page );
+
+ (void) NlsPutMsg (STDOUT, PUAS_USER_STATS_4,
+ user->usri22_bad_pw_count,
+ user->usri22_num_logons,
+ user->usri22_logon_server,
+ user->usri22_country_code,
+ user->usri22_code_page );
+ //(void) WriteToCon( TEXT("========================================\n") );
+ (void)NlsPutMsg(STDOUT, PUAS_BAR);
+
+} // DumpUserInfo
+
+
+VOID
+DumpPassword(
+ //IN LPTSTR Tag,
+ IN USHORT Tag,
+ IN LPBYTE Password OPTIONAL
+ )
+{
+
+ //(void) WriteToCon( FORMAT_LPSTR TEXT("\n"), Tag );
+ (VOID) NlsPutMsg(STDOUT, Tag);
+
+ DumpHex(
+ Password, // area
+ ENCRYPTED_PWLEN ); // byte count
+
+} // DumpPassword
+
+#if DBG
+/*** PortDeb - print debugging messages
+ *
+ * PortDeb(msg, arg0, arg1, arg2, arg3, arg4)
+ *
+ * Args:
+ * msg - A printf style message string.
+ * arg0-4 - The other args to be printed.
+ *
+ */
+void
+PortDeb(CHAR *msg, ...)
+{
+ CHAR Buffer[ 512 ];
+ va_list args;
+ CHAR *pch = Buffer;
+ int cb;
+
+
+ va_start( args, msg );
+ cb = _vsnprintf( Buffer, 512, msg, args );
+ va_end( args );
+ if (cb > 512)
+ fprintf(stderr, "Debug output buffer length exceeded - crash imminent\n");
+ OutputDebugStringA(Buffer);
+}
+
+#endif
diff --git a/private/net/portuas/groups.c b/private/net/portuas/groups.c
new file mode 100644
index 000000000..29aec03fe
--- /dev/null
+++ b/private/net/portuas/groups.c
@@ -0,0 +1,120 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Revision History:
+
+ 28-Feb-1992 JohnRo
+ Fixed MIPS build errors.
+ 03-Mar-1992 JohnRo
+ Do special handling for privs and auth flags.
+ Report long user names.
+ 24-Apr-1992 JohnRo
+ Made immune to UNICODE being defined.
+ 27-May-1992 JohnRo
+ RAID 9829: winsvc.h and related file cleanup.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 27-Apr-1993 JohnRo
+ Corrected wide-vs-narrow chars bug.
+ Changed to use common parse code.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h>
+
+// These may be included in any order:
+
+#include <assert.h> // assert().
+#include <lmaccess.h> // LPGROUP_INFO_1, etc.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <netdebug.h> // FORMAT_API_STATUS and other FORMAT_ equates.
+#include "portuasp.h"
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+//#include <string.h> // strlen().
+//#include <tstring.h>
+#include <wchar.h> // wcslen().
+
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ NET_API_STATUS rc;
+ LPSTR file_name = NULL;
+ LPGROUP_INFO_1 groups;
+ LPDWORD gids;
+ CHAR msg[120];
+ DWORD count;
+ DWORD i;
+
+ file_name = PortUasParseCommandLine( argc, argv );
+ assert( file_name != NULL );
+
+ if (( rc = PortUasOpen( file_name )) != NO_ERROR ) {
+
+ (VOID) sprintf(
+ msg,
+ "Problem opening database - " FORMAT_API_STATUS "\n",
+ rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ rc = PortUasGetGroups(
+ (LPBYTE *) (LPVOID) &groups,
+ (LPBYTE *) (LPVOID) &gids,
+ &count );
+ if (rc != NO_ERROR ) {
+
+ (VOID) sprintf(
+ msg,
+ "Problem getting groups - " FORMAT_API_STATUS "\n",
+ rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ PortUasClose();
+ return (EXIT_FAILURE);
+ }
+
+ for ( i = 0; i < count; i++ ) {
+
+ LPCWSTR name = groups[i].grpi1_name;
+ LPCWSTR comment = groups[i].grpi1_comment;
+
+ assert( name != NULL );
+ assert( comment != NULL );
+
+ printf( "Group - " FORMAT_DWORD "\n", gids[i] );
+ printf( "Name - '" FORMAT_LPWSTR "'\n", name );
+ if ( wcslen( name ) > PORTUAS_MAX_GROUP_LEN ) {
+ (void) printf( "***NAME TOO LONG***\n" );
+ }
+ if ( PortUasIsGroupRedundant( (LPWSTR) name ) ) {
+ (void) printf( "***REDUNDANT***\n" );
+ } else {
+ printf( "Comment - '" FORMAT_LPWSTR "'\n\n", comment );
+ }
+ }
+
+ printf( "\n" );
+
+ NetApiBufferFree( (LPBYTE)gids );
+ NetApiBufferFree( (LPBYTE)groups );
+ PortUasClose();
+
+ return (EXIT_SUCCESS);
+}
diff --git a/private/net/portuas/hashtst.c b/private/net/portuas/hashtst.c
new file mode 100644
index 000000000..8ce9c7b3a
--- /dev/null
+++ b/private/net/portuas/hashtst.c
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Revision History:
+
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+--*/
+
+
+//#include <os2.h>
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <string.h>
+//#include <netlib.h>
+/* #include <doscalls.h> */
+
+#define far
+#define nprintf printf
+#define strlenf strlen
+
+
+typedef unsigned short HASH_T; // Was "int" with 16-bit compiler. --JohnRo
+typedef unsigned char CHAR_T; // was "char" with 16-bit...
+
+
+HASH_T hash (CHAR_T far *);
+
+int _CRTAPI1
+main(
+ int argc,
+ char *argv[]
+ )
+{
+ CHAR_T buf[80]; // was "char" -- JohnRo
+ int hashtbl[2048];
+ HASH_T hashval;
+ int i;
+ int len;
+
+ argv;
+ if (argc != 1)
+ {
+ nprintf ("Usage: hashtst < file\n");
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = 0; i < 2048; i++)
+ hashtbl[i] = 0;
+
+ buf[0] = '\0';
+ while (buf[0] != '$')
+ {
+ gets ( (char *) buf);
+ if ((len = strlenf (buf)) > 1)
+ {
+/* buf[len-1] = '\0'; */
+ hashval = hash(buf);
+ nprintf ("%s hashes to %d\n", buf, (int) hashval);
+ hashtbl[hashval]++;
+ }
+ }
+
+ for (i = 0; i < 2048; i++)
+ nprintf ("%4d %4d\n", i, hashtbl[i]);
+ return (EXIT_SUCCESS);
+}
+
+HASH_T
+hash (CHAR_T far *string)
+{
+ HASH_T acc = 0;
+
+ while (*string != '\0' && *string != '\n')
+ {
+ acc = (acc << 3) | ((acc >> 8) & 7);
+ acc ^= *string++;
+ }
+
+ return (acc & 0x7FF);
+}
+
+
diff --git a/private/net/portuas/logfile.c b/private/net/portuas/logfile.c
new file mode 100644
index 000000000..b259e7db7
--- /dev/null
+++ b/private/net/portuas/logfile.c
@@ -0,0 +1,257 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ LogFile.c
+
+Abstract:
+
+ Port UAS log file routines:
+
+ PortUasOpenLogFile
+ PortUasWriteToLogFile
+ PortUasCloseLogFile
+
+Author:
+
+ JR (John Rogers, JohnRo@Microsoft) 02-Sep-1993
+
+Environment:
+
+ Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
+ Requires ANSI C extensions: slash-slash comments, long external names.
+
+Revision History:
+
+ 02-Sep-1993 JohnRo
+ Created to add PortUAS /log:filename switch for Cheetah.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h> // IN, LPWSTR, BOOL, etc.
+#include <lmcons.h> // NET_API_STATUS.
+
+// These may be included in any order:
+
+#include <lmapibuf.h> // NetApiBufferFree().
+#include <netdebug.h> // NetpKdPrint(), FORMAT_ equates.
+#include <portuasp.h> // My prototypes.
+#include <prefix.h> // PREFIX_ equates.
+#include <tstring.h> // NetpAlloc{type}From{type}, TCHAR_EOS.
+#include <winerror.h> // ERROR_ equates, NO_ERROR.
+
+
+NET_API_STATUS
+PortUasOpenLogFile(
+ IN LPCTSTR FileName,
+ OUT LPHANDLE ResultHandle
+ )
+/*++
+
+Routine Description:
+
+ PortUasOpenLogFile opens a PortUAS log file for a given file
+ name and passes back a handle for use in writing to the file.
+ This handle is expected to only be passed to PortUasWriteToLogFile
+ and PortUasCloseLogFile.
+
+Arguments:
+
+ FileName - The name of the file to be created as a log file. This
+ might be of the form "d:\mystuff\first.log", ".\junk.txt", or even
+ a UNC name like "\\myserver\share\x\y\z". This file must not already
+ exist, or an error will be returned.
+
+ CODEWORK: If the file already exists, we might want to consider
+ having this routine do one or more of the following:
+ - prompt for a new file name
+ - prompt for permission to delete the existing file
+ - prompt for permission to append to the existing file
+
+ ResultHandle - Points to a HANDLE variable which will be filled-in with
+ a handle to be used to process the log file. This handle is only
+ intended to be passed to PortUasWriteToLogFile and PortUasCloseLogFile.
+
+Return Value:
+
+ NET_API_STATUS.
+
+--*/
+{
+ NET_API_STATUS ApiStatus;
+ HANDLE TheHandle = INVALID_HANDLE_VALUE;
+
+ if ( (FileName==NULL) || ((*FileName)==TCHAR_EOS) ) {
+ ApiStatus = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+ if (ResultHandle == NULL) {
+ ApiStatus = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ TheHandle = CreateFile(
+ FileName,
+ GENERIC_WRITE, // desired access
+ 0, // share mode (none)
+ NULL, // no security attr
+ CREATE_NEW, // disposition create new (fail exist)
+ 0, // flags and attributes: normal
+ (HANDLE) NULL ); // no template
+ if (TheHandle == INVALID_HANDLE_VALUE) {
+ ApiStatus = (NET_API_STATUS) GetLastError();
+ NetpAssert( ApiStatus != NO_ERROR );
+ goto Cleanup; // Don't forget to release lock(s)...
+ }
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+
+ if (ApiStatus == NO_ERROR) {
+ NetpAssert( ResultHandle != NULL );
+ NetpAssert( TheHandle != INVALID_HANDLE_VALUE );
+ *ResultHandle = TheHandle;
+ } else {
+ if (ResultHandle != NULL) {
+ *ResultHandle = INVALID_HANDLE_VALUE;
+ }
+ NetpKdPrint(( PREFIX_PORTUAS
+ "PortUasOpenLogFile FAILED: status=" FORMAT_API_STATUS ".\n",
+ ApiStatus ));
+ }
+
+ return (ApiStatus);
+
+} // PortUasOpenLogFile
+
+
+NET_API_STATUS
+PortUasWriteToLogFile(
+ IN HANDLE LogFileHandle,
+ IN LPCTSTR TextToLog
+ )
+/*++
+
+Routine Description:
+
+ PortUasWriteToLogFile appends the given text to the given log file.
+
+Arguments:
+
+ LogFileHandle - Must refer to an open log file, from PortUasOpenLogFile.
+
+ TextToLog - Contains text to be appended to the log file. This text
+ may contain newline characters to break the output into multiple
+ lines. PortUasWriteToLogFile does not automatically do any line
+ breaks.
+
+Return Value:
+
+ NET_API_STATUS.
+
+--*/
+{
+ NET_API_STATUS ApiStatus;
+ DWORD BytesWritten = 0;
+ BOOL OK;
+ DWORD SizeToWrite; // str buffer size (in bytes, w/o '\0' char).
+ LPSTR StrBuffer = NULL;
+
+ NetpAssert( LogFileHandle != INVALID_HANDLE_VALUE );
+ NetpAssert( TextToLog != NULL );
+
+ //FARBUGBUG You should consider writing the file in the input codepage,
+ //FARBUGBUG rather than in the default. An alternative would be to
+ //FARBUGBUG write a Unicode log file, which can be displayed by the
+ //FARBUGBUG TYPE command, or in unipad.
+ StrBuffer = NetpAllocStrFromTStr( (LPVOID) TextToLog );
+ if (StrBuffer == NULL) {
+ ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ SizeToWrite = strlen( StrBuffer ); // buff size, not including '\0' char.
+
+ OK = WriteFile(
+ LogFileHandle,
+ StrBuffer,
+ SizeToWrite, // number of bytes to write
+ &BytesWritten, // bytes actually written
+ NULL ); // no overlapped structure
+ if ( !OK ) {
+ ApiStatus = (NET_API_STATUS) GetLastError();
+ NetpAssert( ApiStatus != NO_ERROR );
+ goto Cleanup;
+ }
+ NetpAssert( SizeToWrite == BytesWritten );
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+
+ if (ApiStatus != NO_ERROR) {
+ NetpKdPrint(( PREFIX_PORTUAS
+ "PortUasWriteToLogFile FAILED: status=" FORMAT_API_STATUS ".\n",
+ ApiStatus ));
+ }
+
+ if (StrBuffer != NULL) {
+ (VOID) NetApiBufferFree( StrBuffer );
+ }
+
+ return (ApiStatus);
+
+} // PortUasWriteToLogFile
+
+
+NET_API_STATUS
+PortUasCloseLogFile(
+ IN HANDLE LogFileHandle
+ )
+/*++
+
+Routine Description:
+
+ PortUasCloseLogFile closes an open log file.
+
+Arguments:
+
+ LogFileHandle - Must refer to an open log file, from PortUasOpenLogFile.
+
+Return Value:
+
+ NET_API_STATUS.
+
+--*/
+{
+ NET_API_STATUS ApiStatus;
+
+ NetpAssert( LogFileHandle != INVALID_HANDLE_VALUE );
+
+ if ( !CloseHandle( LogFileHandle ) ) {
+ ApiStatus = (NET_API_STATUS) GetLastError();
+ NetpAssert( ApiStatus != NO_ERROR );
+ goto Cleanup;
+ }
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+
+ if (ApiStatus != NO_ERROR) {
+ NetpKdPrint(( PREFIX_PORTUAS
+ "PortUasCloseLogFile FAILED: status=" FORMAT_API_STATUS ".\n",
+ ApiStatus ));
+ }
+ return (ApiStatus);
+
+} // PortUasCloseLogFile
diff --git a/private/net/portuas/makefile b/private/net/portuas/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/net/portuas/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/net/portuas/makefile.inc b/private/net/portuas/makefile.inc
new file mode 100644
index 000000000..9ebb9a655
--- /dev/null
+++ b/private/net/portuas/makefile.inc
@@ -0,0 +1,7 @@
+nlstxt.mc: puasmsg.h
+ mapmsg -p PUAS PUAS_BASE puasmsg.h > nlstxt.mc
+
+portuas.rc: nlstxt.rc msg00001.bin
+
+nlstxt.h nlstxt.rc msg00001.bin: nlstxt.mc
+ mc -v nlstxt.mc
diff --git a/private/net/portuas/members.c b/private/net/portuas/members.c
new file mode 100644
index 000000000..934d84106
--- /dev/null
+++ b/private/net/portuas/members.c
@@ -0,0 +1,116 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Revision History:
+
+ 28-Feb-1992 JohnRo
+ Fixed MIPS build errors.
+ 18-Mar-1992 JohnRo
+ Use iterator to allow hash-table collision handling.
+ 24-Apr-1992 JohnRo
+ Made immune to UNICODE being defined.
+ 27-May-1992 JohnRo
+ RAID 9829: winsvc.h and related file cleanup.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+
+--*/
+
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h>
+
+#include <lmaccess.h> // LPGROUP_INFO_0, etc.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <lmerr.h> // NERR_ equates.
+#include "portuasp.h"
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <tstring.h>
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ NET_API_STATUS rc;
+ LPGROUP_INFO_0 groups;
+ LPDWORD gids;
+ BYTE msg[120];
+ BYTE name[GNLEN+1];
+ DWORD count;
+ DWORD j;
+ USER_ITERATOR userIterator;
+
+ if ( argc < 2 ) {
+
+ sprintf( msg, "Usage : members {uas database name}\n" );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ if (( rc = PortUasOpen( argv[1] )) != NERR_Success ) {
+
+ sprintf( msg, "Problem opening database - %ld\n", rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ PortUasInitUserIterator( userIterator );
+ while (TRUE) {
+
+ rc = PortUasGetUserGroups(
+ &userIterator,
+ (LPBYTE *) (LPVOID) &groups,
+ (LPBYTE *) (LPVOID) &gids,
+ &count );
+ if ( rc == NERR_UserNotFound ) {
+ break;
+ } else if ( rc != NERR_Success ) {
+
+ sprintf( msg, "Problem reading user - %ld\n", rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ PortUasClose();
+ return (EXIT_FAILURE);
+
+ }
+
+ if ( rc == NERR_Success ) {
+
+ printf( "User index - %ld\n", userIterator.Index );
+
+ if ( count == 0 ) {
+
+ printf( "No groups\n" );
+ }
+
+ for ( j = 0; j < count; j++ ) {
+
+#if defined(DBCS) // main()
+ NetpCopyWStrToStrDBCSN( name, groups[j].grpi0_name, sizeof(name));
+#else
+ NetpCopyWStrToStr( name, groups[j].grpi0_name );
+#endif // defined(DBCS)
+ printf( "Group - %ld - %s\n", gids[j], name );
+ }
+
+ printf( "\n" );
+
+ NetApiBufferFree( (LPBYTE)gids );
+ NetApiBufferFree( (LPBYTE)groups );
+ }
+ }
+
+ PortUasClose();
+ return (EXIT_SUCCESS);
+}
diff --git a/private/net/portuas/modals.c b/private/net/portuas/modals.c
new file mode 100644
index 000000000..dc498f3ef
--- /dev/null
+++ b/private/net/portuas/modals.c
@@ -0,0 +1,86 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+ 27-Apr-1992 JohnRo
+ Made immune to UNICODE being defined.
+ Use FORMAT_ equates.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h>
+
+// These may be included in any order:
+
+#include <lmaccess.h> // LPUSER_MODALS_INFO_0, etc.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <netdebug.h> // FORMAT_ equates.
+#include "portuasp.h"
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <tstring.h>
+
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ NET_API_STATUS rc;
+ BYTE msg[120];
+ LPUSER_MODALS_INFO_0 modals0;
+
+ if ( argc < 2 ) {
+
+ (VOID) sprintf( msg, "Usage : modals {uas database name}\n" );
+ (VOID) MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ if (( rc = PortUasOpen( argv[1] )) != NO_ERROR ) {
+
+ (VOID) sprintf( msg, "Problem opening database - " FORMAT_API_STATUS
+ "\n", rc );
+ (VOID) MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ if (( rc = PortUasGetModals( &modals0 )) != NO_ERROR ) {
+
+ (VOID) sprintf( msg, "Problem getting modals - " FORMAT_API_STATUS "\n",
+ rc );
+ (VOID) MessageBoxA( NULL, msg, NULL, MB_OK );
+ PortUasClose();
+ return (EXIT_FAILURE);
+ }
+
+ (VOID) printf( "Minimum password length - " FORMAT_DWORD "\n",
+ modals0->usrmod0_min_passwd_len );
+ (VOID) printf( "Maximum password age - " FORMAT_DWORD "\n",
+ modals0->usrmod0_max_passwd_age );
+ (VOID) printf( "Minimum password age - " FORMAT_DWORD "\n",
+ modals0->usrmod0_min_passwd_age );
+ (VOID) printf( "Force logoff time - " FORMAT_DWORD "\n",
+ modals0->usrmod0_force_logoff );
+ (VOID) printf( "Password history length - " FORMAT_DWORD "\n",
+ modals0->usrmod0_password_hist_len );
+
+ (VOID) NetApiBufferFree( modals0 );
+ PortUasClose();
+ return (EXIT_SUCCESS);
+}
diff --git a/private/net/portuas/owfcrypt.c b/private/net/portuas/owfcrypt.c
new file mode 100644
index 000000000..11627185f
--- /dev/null
+++ b/private/net/portuas/owfcrypt.c
@@ -0,0 +1,152 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ OwfCrypt.c
+
+Abstract:
+
+ Only contains PortUasDecryptNtOwfPwdWithIndex().
+
+Author:
+
+ David Chalmers (Davidc) 10-21-91
+
+Revision History:
+
+ 21-Oct-1991 DavidC
+ [DavidC created the general-purpose version of this code.]
+ 18-Mar-1992 JohnRo
+ Swiped DavidC's code and made it part of PortUAS (at DavidC's
+ request).
+ 22-Jul-1993 JohnRo
+ Made changes suggested by PC-LINT 5.0
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h>
+// Don't complain about "unneeded" includes of this file:
+/*lint -efile(764,ntrtl.h) */
+#include <ntrtl.h>
+#include <windef.h> // DWORD, etc.
+#include <lmcons.h> // NET_API_STATUS.
+
+// These may be included in any order:
+
+#include <crypt.h> // PENCRYPTED_LM_OWF_PASSWORD, etc.
+#include <netdebug.h> // DBGSTATIC.
+#include <netlibnt.h> // NetpNtStatusToApiStatus().
+#include <portuasp.h> // My prototype.
+
+
+
+DBGSTATIC VOID
+KeysFromIndex(
+ IN LPDWORD Index,
+ OUT BLOCK_KEY Key[2])
+
+/*++
+
+Routine Description:
+
+ Helper function - generates 2 keys from an index value
+
+--*/
+
+{
+ PCHAR pKey, pIndex;
+ PCHAR IndexStart = (PCHAR)&(Index[0]);
+ PCHAR IndexEnd = (PCHAR)&(Index[1]);
+ PCHAR KeyStart = (PCHAR)&(Key[0]);
+ PCHAR KeyEnd = (PCHAR)&(Key[1]);
+
+ IndexEnd -= 2; // Temp LM hack
+
+ // Calculate the keys by concatenating the index with itself
+
+ //
+ // To be compatible with Lanman we do this concatenation in the first
+ // key only, then copy the first key to the second.
+ //
+
+ pKey = KeyStart;
+ pIndex = IndexStart;
+
+ while (pKey < KeyEnd) {
+
+ *pKey++ = *pIndex++;
+
+ if (pIndex == IndexEnd) {
+
+ // Start at beginning of index again
+ pIndex = IndexStart;
+ }
+ }
+
+ Key[1] = Key[0];
+}
+
+
+NET_API_STATUS
+//RtlDecryptLmOwfPwdWithIndex(
+PortUasDecryptLmOwfPwdWithIndex(
+ IN LPVOID lpEncryptedLmOwfPassword,
+ IN LPDWORD lpIndex,
+ OUT LPVOID lpLmOwfPassword
+ )
+/*++
+
+Routine Description:
+
+ Decrypts an OwfPassword with an index
+
+Arguments:
+
+ EncryptedLmOwfPassword - The encrypted OwfPassword to be decrypted
+
+ INDEX - value to be used as decryption key
+
+ LmOwfPassword - Decrypted OwfPassword is returned here
+
+
+Return Values:
+
+ NO_ERROR - The function completed successfully. The decrypted
+ OwfPassword is in LmOwfPassword
+
+ Other values - Something failed. The LmOwfPassword is undefined.
+
+--*/
+{
+ PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword = lpEncryptedLmOwfPassword;
+ LPDWORD Index = lpIndex;
+ PLM_OWF_PASSWORD LmOwfPassword = lpLmOwfPassword;
+ NTSTATUS Status;
+ BLOCK_KEY Key[2];
+
+ NetpAssert( sizeof( CRYPT_INDEX ) == sizeof( DWORD ) );
+
+ // Calculate the keys
+
+ KeysFromIndex(Index, &(Key[0]));
+
+ // Use the keys
+
+ Status = RtlDecryptBlock(&(EncryptedLmOwfPassword->data[0]),
+ &(Key[0]),
+ (PCLEAR_BLOCK) (LPVOID) &(LmOwfPassword->data[0]));
+ if (!NT_SUCCESS(Status)) {
+ return(NetpNtStatusToApiStatus(Status));
+ }
+
+ Status = RtlDecryptBlock(&(EncryptedLmOwfPassword->data[1]),
+ &(Key[1]),
+ (PCLEAR_BLOCK) (LPVOID) &(LmOwfPassword->data[1]));
+
+ return(NetpNtStatusToApiStatus(Status));
+}
diff --git a/private/net/portuas/passwds.c b/private/net/portuas/passwds.c
new file mode 100644
index 000000000..3cddd6895
--- /dev/null
+++ b/private/net/portuas/passwds.c
@@ -0,0 +1,140 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ PassWds.C
+
+Abstract:
+
+ BUGBUG
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 24-Oct-1991
+
+Revision History:
+
+ 24-Oct-1991 w-shankn
+ Created.
+ 07-Feb-1992 JohnRo
+ Added this block of comments.
+ Avoid compiler warnings.
+ 19-Mar-1992 JohnRo
+ Use iterator to allow hash-table collision handling.
+ Added command-line parsing stuff.
+ Display user name too.
+ 24-Apr-1992 JohnRo
+ Made immune to UNICODE being defined.
+ Use FORMAT_ equates.
+ 27-May-1992 JohnRo
+ RAID 9829: winsvc.h and related file cleanup.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 21-Apr-1993 JohnRo
+ Made changes to be compatible with RonaldM's NLS changes.
+
+--*/
+
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h>
+
+#include <assert.h> // assert().
+#include <hashfunc.h> // HASH_VALUE, HashUserName().
+#include <lmaccess.h> // LPUSER_INFO_22, etc.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <lmerr.h> // NERR_ equates.
+#include <netdebug.h> // FORMAT_ equates.
+#include "nlstxt.h" // NLS message ID's
+#include <portuasp.h> // PortUasParseCommandLine(), etc.
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <tstring.h>
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ LPSTR fileName;
+ HASH_VALUE hashValue;
+ USER_ITERATOR iterator;
+ NET_API_STATUS rc;
+ LPBYTE password;
+ BYTE msg[120];
+ LPUSER_INFO_22 user;
+
+ fileName = PortUasParseCommandLine( argc, argv );
+ assert( fileName != NULL );
+
+ if (( rc = PortUasOpen( fileName )) != NERR_Success ) {
+
+ (void) sprintf( msg, "Problem opening database - "
+ FORMAT_API_STATUS "\n", rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ PortUasInitUserIterator( iterator );
+ while (TRUE) {
+
+ //
+ // Start by getting user info for next user.
+ //
+ rc = PortUasGetUser( &iterator, (LPBYTE *) (LPVOID) &user );
+ if ( rc == NERR_UserNotFound ) {
+ break; // Done.
+ }
+ assert( rc == NERR_Success );
+ assert( user != NULL );
+ hashValue = HashUserName( user->usri22_name );
+
+ //
+ // Now let's get the password.
+ //
+ rc = PortUasGetUserOWFPassword( &iterator, &password );
+ if ( rc != NERR_Success ) {
+
+ (void) sprintf( msg, "Problem reading user password - "
+ FORMAT_API_STATUS "\n", rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ PortUasClose();
+ return (EXIT_FAILURE);
+
+ }
+
+ //
+ // Print out what we've got.
+ //
+
+ (void) printf( "User - " FORMAT_LPWSTR "\n", user->usri22_name );
+ (void) printf( "Index - " FORMAT_DWORD "\n", iterator.Index );
+ (void) printf( "Hash value - " FORMAT_HASH_VALUE "\n", hashValue );
+
+ //DumpPassword( "Password -", password );
+ DumpPassword( PUAS_PASSWORD, password );
+
+
+ // BUGBUG: Hash value doesn't match yet.
+ // NetpAssert( iterator.Index == hashValue );
+ if (iterator.Index != hashValue) {
+ (void) printf( "****** HASH != INDEX ******\n");
+ }
+
+ (void) NetApiBufferFree( password );
+ (void) NetApiBufferFree( user );
+ }
+
+ PortUasClose();
+ return (EXIT_SUCCESS);
+}
diff --git a/private/net/portuas/port.c b/private/net/portuas/port.c
new file mode 100644
index 000000000..732cfa447
--- /dev/null
+++ b/private/net/portuas/port.c
@@ -0,0 +1,340 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ Port.C
+
+Abstract:
+
+ BUGBUG
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 24-Oct-1991
+
+Revision History:
+
+ 24-Oct-1991 w-shankn
+ Created.
+ 07-Feb-1992 JohnRo
+ Avoid compiler warnings.
+ Use NetApiBufferAllocate() instead of private version.
+ Added this block of comments.
+ Avoid unused header files.
+ 27-Feb-1992 JohnRo
+ Changed user info level from 98 to 21 (avoid LAN/Server conflicts).
+ 28-Feb-1992 JohnRo
+ User info must include units_per_week field.
+ 11-Mar-1992 JohnRo
+ Added command-line parsing stuff.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ Also added support for NetUserModalsGet level 1 (with role).
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h> // NET_API_STATUS, etc.
+
+// These may be included in any order:
+
+#include <lmaccess.h>
+#include <lmapibuf.h> // NetApiBufferAllocate().
+#include <lmerr.h>
+#include <netdebug.h> // NetpAssert().
+#include <portuas.h>
+#include <portuasp.h> // PortUasParseCommandLine(), etc.
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <tstring.h>
+
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ LPSTR FileName;
+ NET_API_STATUS rc;
+
+ FileName = PortUasParseCommandLine( argc, argv );
+ NetpAssert( FileName != NULL );
+
+ rc = PortUas( FileName );
+
+ printf( "PortUas returned - %ld\n", rc );
+ return (EXIT_SUCCESS);
+
+}
+
+//
+// Hacks of Net APIs.
+//
+
+NET_API_STATUS NET_API_FUNCTION
+NetUserModalsGet(
+ IN LPWSTR servername OPTIONAL,
+ IN DWORD level,
+ IN LPBYTE * buf
+ )
+
+{
+ UNREFERENCED_PARAMETER(servername);
+
+ if (level == 0) {
+
+ LPUSER_MODALS_INFO_0 modals;
+
+ if ( NetApiBufferAllocate( sizeof(USER_MODALS_INFO_0), (LPVOID *) buf )) {
+
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ modals = (LPUSER_MODALS_INFO_0)*buf;
+
+ modals->usrmod0_min_passwd_len = 10;
+ modals->usrmod0_max_passwd_age = (DWORD)-1;
+ modals->usrmod0_min_passwd_age = (DWORD)-1;
+ modals->usrmod0_force_logoff = (DWORD)-1;
+ modals->usrmod0_password_hist_len = (DWORD)-1;
+ } else if (level == 1) {
+ LPUSER_MODALS_INFO_1 modals;
+ DWORD size = sizeof(USER_MODALS_INFO_1); // BUGBUG: add string space?
+
+ if ( NetApiBufferAllocate( size, (LPVOID *) buf )) {
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ modals = (LPUSER_MODALS_INFO_1) *buf;
+ modals->usrmod1_role = UAS_ROLE_PRIMARY;
+ modals->usrmod1_primary = NULL; // BUGBUG: copy a string here?
+ } else {
+ NetpAssert( FALSE );
+ return (ERROR_INVALID_LEVEL);
+ }
+
+ return NERR_Success;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetUserModalsSet(
+ IN LPWSTR servername OPTIONAL,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err OPTIONAL
+ )
+
+{
+
+ LPUSER_MODALS_INFO_0 modals = (LPUSER_MODALS_INFO_0)buf;
+
+ UNREFERENCED_PARAMETER(parm_err);
+ UNREFERENCED_PARAMETER(servername);
+
+ printf( "========================================\n" );
+ printf( "Setting modals level %ld\n", level );
+ printf( "Min. password length %ld\n", modals->usrmod0_min_passwd_len );
+ printf( "Max. password age %ld\n", modals->usrmod0_max_passwd_age );
+ printf( "Min. password age %ld\n", modals->usrmod0_min_passwd_age );
+ printf( "Force logoff %ld\n", modals->usrmod0_force_logoff );
+ printf( "Password history %ld\n", modals->usrmod0_password_hist_len );
+ printf( "========================================\n" );
+
+ return NERR_Success;
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetGroupAdd(
+ IN LPWSTR servername OPTIONAL,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err OPTIONAL
+ )
+
+{
+
+ LPGROUP_INFO_1 group = (LPGROUP_INFO_1)buf;
+
+ UNREFERENCED_PARAMETER(parm_err);
+ UNREFERENCED_PARAMETER(servername);
+
+ printf( "========================================\n" );
+ printf( "Adding group level %ld\n", level );
+ printf( "Name %ws\n", group->grpi1_name );
+ printf( "Comment %ws\n", group->grpi1_comment );
+ printf( "========================================\n" );
+
+ if (!wcscmp( group->grpi1_name, L"USERS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( group->grpi1_name, L"ADMINS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( group->grpi1_name, L"GUESTS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( group->grpi1_name, L"LOCAL" )) return NERR_SpeGroupOp;
+ if (!wcscmp( group->grpi1_name, L"NEWGROUP" )) return NERR_GroupExists;
+ if (!wcscmp( group->grpi1_name, L"ADMIN" )) return NERR_UserExists;
+ if (!wcscmp( group->grpi1_name, L"W-SHANKN" )) return NERR_UserExists;
+ if (!wcscmp( group->grpi1_name, L"W-SHANKN2" )) return NERR_UserExists;
+
+ return NERR_Success;
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetGroupAddUser(
+ IN LPWSTR servername OPTIONAL,
+ IN LPWSTR GroupName,
+ IN LPWSTR username
+ )
+{
+
+ UNREFERENCED_PARAMETER(servername);
+
+ printf( "========================================\n" );
+ printf( "Adding user to group\n" );
+ printf( "Group %ws\n", GroupName );
+ printf( "User %ws\n", username );
+ printf( "========================================\n" );
+
+ if (!wcscmp( GroupName, L"USERS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( GroupName, L"ADMINS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( GroupName, L"GUESTS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( GroupName, L"LOCAL" )) return NERR_SpeGroupOp;
+ if (!wcscmp( GroupName, L"ADMIN" )) return NERR_UserExists;
+ if (!wcscmp( GroupName, L"W-SHANKN" )) return NERR_UserExists;
+ if (!wcscmp( GroupName, L"W-SHANKN2" )) return NERR_UserExists;
+ if (!wcscmp( GroupName, L"NEWGROUP" ) && !wcscmp( username, L"W-SHANKN" )) return NERR_UserInGroup;
+
+ return NERR_Success;
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetGroupSetInfo(
+ IN LPWSTR servername OPTIONAL,
+ IN LPWSTR groupname,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err OPTIONAL
+ )
+{
+
+ LPWSTR groupComment = (LPWSTR)buf;
+
+ UNREFERENCED_PARAMETER(parm_err);
+ UNREFERENCED_PARAMETER(servername);
+
+ printf( "========================================\n" );
+ printf( "Changing group level %ld\n", level );
+ printf( "Comment %ws\n", groupComment );
+ printf( "========================================\n" );
+
+ if (!wcscmp( groupname, L"USERS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( groupname, L"ADMINS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( groupname, L"GUESTS" )) return NERR_SpeGroupOp;
+ if (!wcscmp( groupname, L"LOCAL" )) return NERR_SpeGroupOp;
+
+ return NERR_Success;
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetUserAdd(
+ IN LPWSTR servername OPTIONAL,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err OPTIONAL
+ )
+{
+
+ LPUSER_INFO_22 user = (LPUSER_INFO_22)buf;
+
+ UNREFERENCED_PARAMETER(parm_err);
+ UNREFERENCED_PARAMETER(servername);
+
+ NetpAssert( level == 22 );
+ NetpAssert( user != NULL );
+
+ printf( "Adding user level %ld\n", level );
+ DumpUserInfo( user );
+
+ if (!wcscmp( user->usri22_name, L"USERS" )) return NERR_GroupExists;
+ if (!wcscmp( user->usri22_name, L"ADMINS" )) return NERR_GroupExists;
+ if (!wcscmp( user->usri22_name, L"GUESTS" )) return NERR_GroupExists;
+ if (!wcscmp( user->usri22_name, L"LOCAL" )) return NERR_GroupExists;
+ if (!wcscmp( user->usri22_name, L"NEWGROUP" )) return NERR_GroupExists;
+ if (!wcscmp( user->usri22_name, L"W-SHANKN" )) return NERR_UserExists;
+
+ return NERR_Success;
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetUserSetInfo(
+ IN LPWSTR servername OPTIONAL,
+ IN LPWSTR username,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err OPTIONAL
+ )
+{
+
+ LPUSER_INFO_22 user = (LPUSER_INFO_22)buf;
+ DWORD i;
+
+ UNREFERENCED_PARAMETER(parm_err);
+ UNREFERENCED_PARAMETER(servername);
+
+ NetpAssert( level == 22 );
+
+ printf( "========================================\n" );
+ printf( "Changing user level %ld\n", level );
+ printf( "Name %ws\n", username );
+
+ printf( "Password " );
+ for ( i = 0; i < 16; i++ ) {
+ printf( "%.2x ", user->usri22_password[i] );
+ }
+
+ printf( "Privilege %ld\n", user->usri22_priv );
+ printf( "Home directory %ws\n", user->usri22_home_dir );
+ printf( "Comment %ws\n", user->usri22_comment );
+ printf( "Flags %ld\n", user->usri22_flags );
+ printf( "Script path %ws\n", user->usri22_script_path );
+ printf( "Auth. Flags %ld\n", user->usri22_auth_flags );
+ printf( "Full name %ws\n", user->usri22_full_name );
+ printf( "User comment %ws\n", user->usri22_usr_comment );
+ printf( "Parms %ws\n", user->usri22_parms );
+ printf( "Workstations %ws\n", user->usri22_workstations );
+ printf( "Acct. expires %ld\n", user->usri22_acct_expires );
+ printf( "Max storage %ld\n", user->usri22_max_storage );
+ printf( "Units per week %ld\n", user->usri22_units_per_week );
+ printf( "Logon hours" );
+ for( i = 0; i < 168; i++ ) {
+ if ( UAS_ISBITON( user->usri22_logon_hours, i )) printf( "1" );
+ else printf( "0" );
+ }
+ printf( "\nLogon server %ws\n", user->usri22_logon_server );
+ printf( "Country code %ld\n", user->usri22_country_code );
+ printf( "Code page %ld\n", user->usri22_code_page );
+ printf( "========================================\n" );
+
+ if (!wcscmp( username, L"USERS" )) return NERR_GroupExists;
+ if (!wcscmp( username, L"ADMINS" )) return NERR_GroupExists;
+ if (!wcscmp( username, L"GUESTS" )) return NERR_GroupExists;
+ if (!wcscmp( username, L"LOCAL" )) return NERR_GroupExists;
+ if (!wcscmp( username, L"NEWGROUP" )) return NERR_GroupExists;
+
+ return NERR_Success;
+
+}
diff --git a/private/net/portuas/portlib.c b/private/net/portuas/portlib.c
new file mode 100644
index 000000000..13d39b1db
--- /dev/null
+++ b/private/net/portuas/portlib.c
@@ -0,0 +1,1366 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ PortLib.C
+
+Abstract:
+
+ Main entry code for the PortUas runtime library function.
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 29-Oct-1991
+
+Revision History:
+
+ 29-Oct-1991 w-shankn
+ Created.
+ 06-Feb-1992 JohnRo
+ Fixed memory leak with uPassword.
+ Made changes suggested by PC-LINT.
+ 27-Feb-1992 JohnRo
+ Changed user info level from 98 to 21 (avoid LAN/Server conflicts).
+ Added message about updating existing user.
+ 28-Feb-1992 JohnRo
+ Fixed MIPS build errors.
+ 03-Mar-1992 JohnRo
+ Fixed bug in handling group memberships.
+ Do special handling for privs and auth flags.
+ Avoid creating redundant groups.
+ 11-Mar-1992 JohnRo
+ Fixed bug handling priv/auth difference on existing user.
+ Use WARNING_MSG(), ERROR_MSG(), PROGRESS_MSG() macros.
+ 18-Mar-1992 JohnRo
+ Use iterator to allow hash-table collision handling.
+ 23-Apr-1992 JohnRo
+ Handle probable LanMan bug: password required but password is null.
+ 07-May-1992 JohnRo
+ Avoid dummy passwords altogether.
+ Added alias support for operators.
+ Added WORKAROUND_SAM_BUG support (NetUserAdd fails, try again).
+ Fixed a possible memory leak in PortUas().
+ Use FORMAT_ equates.
+ 10-Jun-1992 JohnRo
+ RAID 10139: PortUAS should add to admin group/alias.
+ PortUAS was also leaving temporary modals set on exit.
+ Fixed bad (temp) value of max_passwd_age.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ (Moved portuas.c to portlib.c and port2.c to portuas.c)
+ 06-Oct-1992 JohnRo
+ RAID 9020: Setup: PortUAS fails (group name same as a domain name).
+ 29-Oct-1992 JohnRo
+ RAID 9020 ("prompt on conflicts" version).
+ RAID 9613: PortUAS should prevent run on BDC.
+ 20-Nov-1992 JohnRo
+ RAID 3875: PortUAS don't really ignore "redundant" groups.
+ 27-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 26-Apr-1993 JohnRo
+ SAM bug seems to be obsolete, so avoid workaround for it.
+ 11-Jun-1993 JohnRo
+ RAID 13257: PortUAS does not handle operator privileges.
+ 11-Aug-1993 JohnRo
+ RAID NTBUG 16822: PortUAS should have ^C handler to restore user modals.
+ RAID NTISSUE 2260: PortUAS returns a NetUserAdd error=1379 with local
+ group.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // NTSTATUS, NT_SUCCESS().
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h> // LocalFree(), SetConsoleCtrlHandler(), etc.
+#include <lmcons.h>
+
+// These may be included in any order:
+
+#include <crypt.h> // LM_OWF_PASSWORD, Rtl encrypt/decrypt/equal routines.
+#include <lmaccess.h> // AF_ and UF_ equates, LPUSER_INFO_22, etc.
+#include <lmapibuf.h>
+#include <lmerr.h>
+#include <names.h> // NetpIsMacPrimaryGroupFieldValid().
+#include <netdebug.h> // DBGSTATIC, NetpAssert(), etc.
+#include <netlib.h> // LOCAL_DOMAIN_TYPE_ equates.
+#include <netlibnt.h> // NetpNtStatusToApiStatus().
+#include <portuas.h>
+#include <portuasp.h> // WARNING_MSG(), PortUasSam*, Verbose, etc.
+#include <wchar.h> // _wcsicmp().
+#include <tchar.h>
+
+#include "nlstxt.h" // NLS message ID's
+
+// Don't need DOMAIN_GET_ALIAS_MEMBERSHIP or group equivalent...
+#define OUR_DOMAIN_DESIRED_ACCESS DOMAIN_LOOKUP
+
+
+// Enable real functionality.
+#define PORTUAS_ENABLE
+
+
+// Enable retry NetUserAdd (once) if it fails with ERROR_ACCESS_DENIED.
+//#define WORKAROUND_SAM_BUG
+
+
+#define REASON_NO_ERROR ((DWORD) -1)
+
+
+#define SET_MAP_REASON( someValue ) \
+ { \
+ mapNeeded = TRUE; \
+ if (originalMapReason == REASON_NO_ERROR) { \
+ originalMapReason = someValue; \
+ } \
+ mapReason = someValue; \
+ }
+
+#define RESET_MAP_REASON( ) \
+ { \
+ mapNeeded = FALSE; \
+ originalMapReason = REASON_NO_ERROR; \
+ untriedMapEntry = NULL; /* Null pointer so we don't kill it. */ \
+ }
+
+
+// Global domain IDs. These are set here, used here and in alias code, and
+// cleaned-up here.
+PSID PortUasAccountsDomainId = NULL;
+PSID PortUasBuiltinDomainId = NULL;
+
+// Global SAM handles. These are set here, used here and in alias code, and
+// cleaned-up here.
+SAM_HANDLE PortUasSamConnectHandle = NULL;
+SAM_HANDLE PortUasSamAccountsDomainHandle = NULL;
+SAM_HANDLE PortUasSamBuiltinDomainHandle = NULL;
+
+// Global variables which are used by PortUasModalsCleanup() in the
+// event of a control-C...
+DBGSTATIC LPUSER_MODALS_INFO_0 finalModals0 = NULL;
+DBGSTATIC BOOL modalsTemporarilyChanged = FALSE;
+
+
+
+DBGSTATIC BOOL WINAPI
+PortUasModalsCleanup(
+ DWORD CtrlType
+ )
+/*++
+
+Routine Description:
+
+ BUGBUG
+
+ This routine is registered with the Windows SetConsoleCtrlHandler() API.
+
+Arguments:
+
+ CtrlType - indicates which reason for calling this routine.
+
+Return Value:
+
+ BOOL - TRUE iff we want to be last handler. We don't care...
+
+--*/
+
+{
+ NET_API_STATUS rc;
+
+ UNREFERENCED_PARAMETER( CtrlType );
+
+ if (modalsTemporarilyChanged) {
+
+#ifdef PORTUAS_ENABLE
+ NetpAssert( finalModals0 != NULL );
+ if ( rc = NetUserModalsSet( NULL, 0, (LPVOID)finalModals0, NULL )) {
+
+ UNEXPECTED_MSG( "NetUserModalsSet(final)", rc );
+ rc = PortUasError( rc );
+ }
+ // BUGBUG: We lose the "rc" value here...
+#endif
+ }
+ modalsTemporarilyChanged = FALSE;
+
+ if (finalModals0 != NULL) {
+ (void) NetApiBufferFree( finalModals0 );
+ finalModals0 = NULL;
+ }
+
+ if (Verbose) {
+ DEBUG_MSG(( "Done setting modals to their final values.\n" ));
+ }
+
+ return (FALSE); // we don't want to be only routine to process this...
+
+} // PortUasModalsCleanup
+
+
+NET_API_STATUS
+PortUas(
+ IN LPTSTR UasPathName
+ )
+
+/*++
+
+Routine Description:
+
+ PortUas ports account information in a LanMan 2.0 UAS database into
+ the SAM database.
+
+Arguments:
+
+ UasPathName - supplies the path name to the UAS database file.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+
+--*/
+
+{
+
+ NET_API_STATUS rc;
+ BOOL groupAdded[UAS_MAXGROUP];
+
+ USER_MODALS_INFO_0 tempModals0;
+
+ LPGROUP_INFO_1 groups;
+ LPDWORD gIds;
+ DWORD gCount;
+
+ LPMAP_ENTRY untriedMapEntry = NULL; // NULL once map entry is good.
+ BOOL mapNeeded;
+ DWORD mapReason; // REASON_ equates from PortUAS.h
+ DWORD originalMapReason; // REASON_ equates from PortUAS.h
+ BOOL mapSetup = FALSE;
+
+ USER_ITERATOR UserIterator;
+ LPUSER_INFO_22 user = NULL;
+ LPBYTE userEncryptedPassword = NULL;
+ LPGROUP_INFO_0 userGroups;
+ LPDWORD ugIds;
+ DWORD ugCount;
+
+ BOOL aliasesSetup = FALSE;
+ BOOL databaseOpen = FALSE;
+ DWORD i;
+ NTSTATUS ntStatus;
+ LM_OWF_PASSWORD nullEncryptedPassword;
+
+ //
+ // Are we running on a machine which allows updates to security info?
+ // (Can't update a Backup Domain Controller directly, for instance.)
+ //
+ rc = PortUasMachineAllowsUpdates();
+ if (rc == NERR_NotPrimary) {
+ //ERROR_MSG((
+ // "PortUAS must be run on a Primary Domain Controller (PDC) or\n"
+ // "Windows/NT system, not a Backup Domain Controller (BDC).\n" ));
+ (void)NlsPutMsg(STDOUT, PUAS_PDC_GOOD_BDC_BAD);
+ goto Cleanup;
+ } else if (rc == ERROR_ACCESS_DENIED) {
+ //ERROR_MSG((
+ // "Your account does not have privilege for this.\n" ));
+ (void)NlsPutMsg(STDOUT, PUAS_NO_PRIVILEGE);
+ goto Cleanup;
+ } else if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasMachineAllowsUpdates", rc );
+ goto Cleanup;
+ }
+
+ //
+ // Start off by setting-up a null (encrypted) password.
+ //
+ ntStatus = RtlCalculateLmOwfPassword( "", &nullEncryptedPassword );
+ NetpAssert( NT_SUCCESS( ntStatus ) );
+
+ //
+ // Open (at least, try to) the UAS database.
+ //
+
+ if ( UasPathName == NULL ) {
+
+ rc = NERR_ACFNotFound;
+ goto Cleanup;
+ }
+
+ if ( rc = PortUasOpen( UasPathName )) {
+
+ goto Cleanup;
+ }
+ databaseOpen = TRUE;
+
+ //
+ // Initialize name mapping table.
+ //
+ RESET_MAP_REASON( );
+
+ rc = PortUasMapTableInit( );
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasTableMapInit", rc );
+ goto Cleanup;
+ }
+ mapSetup = TRUE;
+
+ NetpAssert( PortUasSamConnectHandle == NULL );
+ NetpAssert( PortUasSamAccountsDomainHandle == NULL );
+ NetpAssert( PortUasSamBuiltinDomainHandle == NULL );
+
+ //
+ // Get a connection to SAM.
+ //
+ ntStatus = SamConnect(
+ NULL, // no server name (local)
+ &PortUasSamConnectHandle, // resulting SAM handle
+ // SAM_SERVER_READ | // desired access
+ // SAM_SERVER_CONNECT |
+ SAM_SERVER_LOOKUP_DOMAIN,
+ NULL ); // no object attributes
+ if ( !NT_SUCCESS( ntStatus ) ) {
+ rc = NetpNtStatusToApiStatus( ntStatus );
+ UNEXPECTED_MSG( "SamConnect", rc );
+ goto Cleanup;
+ }
+ NetpAssert( PortUasSamConnectHandle != NULL );
+
+ //
+ // To open the accounts and builtin domains (below), we'll need the
+ // domain IDs.
+ //
+ rc = NetpGetLocalDomainId (
+ LOCAL_DOMAIN_TYPE_ACCOUNTS, // type we want.
+ & PortUasAccountsDomainId );
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "NetpGetDomainId(accounts)", rc );
+ goto Cleanup;
+ }
+ NetpAssert( PortUasAccountsDomainId != NULL );
+
+ rc = NetpGetLocalDomainId (
+ LOCAL_DOMAIN_TYPE_BUILTIN, // type we want.
+ & PortUasBuiltinDomainId );
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "NetpGetDomainId(builtin)", rc );
+ goto Cleanup;
+ }
+ NetpAssert( PortUasBuiltinDomainId != NULL );
+ NetpAssert( PortUasBuiltinDomainId != PortUasAccountsDomainId );
+
+ //
+ // We also need to open the accounts and builtin domains.
+ //
+ ntStatus = SamOpenDomain(
+ PortUasSamConnectHandle,
+ OUR_DOMAIN_DESIRED_ACCESS,
+ PortUasAccountsDomainId,
+ &PortUasSamAccountsDomainHandle );
+ if ( !NT_SUCCESS( ntStatus ) ) {
+ rc = NetpNtStatusToApiStatus( ntStatus );
+ UNEXPECTED_MSG( "SamOpenDomain(accounts)", rc );
+ goto Cleanup;
+ }
+ NetpAssert( PortUasSamAccountsDomainHandle != NULL );
+
+ ntStatus = SamOpenDomain(
+ PortUasSamConnectHandle,
+ OUR_DOMAIN_DESIRED_ACCESS,
+ PortUasBuiltinDomainId,
+ &PortUasSamBuiltinDomainHandle );
+ if ( !NT_SUCCESS( ntStatus ) ) {
+ rc = NetpNtStatusToApiStatus( ntStatus );
+ UNEXPECTED_MSG( "SamOpenDomain(builtin)", rc );
+ goto Cleanup;
+ }
+ NetpAssert( PortUasSamBuiltinDomainHandle != NULL );
+
+ //
+ // Initialize alias stuff.
+ //
+ rc = PortUasAliasSetup();
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+ aliasesSetup = TRUE;
+
+ //
+ // Everything we've done so far is transient. (If someone hits control-C
+ // or whatever, then the system would close alias handles, free memory, etc,
+ // as part of the usual process cleanup.) However, we're about to set the
+ // user modals (to some temporary values), which are NOT transient. So
+ // we need to make arragements to restore the user modals if we die from
+ // control-C or whatever...
+ //
+ // Register our cleanup routine with the Win32 runtime.
+ //
+ if ( !SetConsoleCtrlHandler( PortUasModalsCleanup, TRUE /* add */ ) ) {
+ rc = GetLastError();
+ UNEXPECTED_MSG( "SetConsoleCtrlHandler", rc ); // report the error.
+ NetpAssert( rc != NO_ERROR );
+ goto Cleanup;
+ }
+
+ //
+ //
+ // Get final version of modals.
+ //
+
+ if ( rc = PortUasGetModals( &finalModals0 )) {
+
+ goto Cleanup;
+ }
+
+ //
+ // We want to (1) be able to set NULL passwords in the process of
+ // creating an account, and (2) want to avoid repetitive password
+ // errors if PortUAS is run twice in a row. So CliffV suggests
+ // temporarily changing the modals to allow this. So, let's set
+ // the temporary version now.
+ //
+ tempModals0.usrmod0_min_passwd_len = 0;
+ tempModals0.usrmod0_max_passwd_age = ONE_DAY;
+ tempModals0.usrmod0_min_passwd_age = 0;
+ tempModals0.usrmod0_force_logoff = 0;
+ tempModals0.usrmod0_password_hist_len = 0;
+
+#ifdef PORTUAS_ENABLE
+ if ( rc = NetUserModalsSet( NULL, 0, (LPBYTE)&tempModals0, NULL )) {
+
+ UNEXPECTED_MSG( "NetUserModalsSet(temp)", rc );
+ rc = PortUasError( rc );
+ goto Cleanup;
+ }
+#endif
+ modalsTemporarilyChanged = TRUE;
+
+ //
+ // Initialize added group table.
+ //
+
+ for ( i = 0; i < UAS_MAXGROUP; i++ ) {
+
+ groupAdded[i] = FALSE;
+
+ }
+
+ //
+ // Get a list of groups (including the redundant ones).
+ //
+
+ rc = PortUasGetGroups(
+ (LPBYTE *) (LPVOID) &groups,
+ (LPBYTE *) (LPVOID) &gIds,
+ &gCount );
+ if (rc != NO_ERROR) {
+
+ goto Cleanup;
+ }
+
+ //
+ // Add the groups one by one.
+ //
+
+ for ( i = 0; i < gCount; i++ ) {
+
+ BOOL ignoreThisGroup = FALSE;
+ LPWSTR originalGroupName = groups[i].grpi1_name;
+ LPWSTR groupName = originalGroupName;
+ NetpAssert( groupName[0] != NULLC );
+ RESET_MAP_REASON( );
+
+ if (Verbose) {
+ DEBUG_MSG( ("UAS database has group '" FORMAT_LPWSTR "'...\n",
+ originalGroupName ));
+ }
+
+ //
+ // Repeat adding under different names until...
+ //
+ do {
+
+#ifdef FAT8
+ //
+ // BUGBUG: Temporary!!! Current reg stuff uses FAT (8.3) for
+ // registry, so avoid long names!
+ //
+ if ( wcslen( groupName ) > PORTUAS_MAX_GROUP_LEN ) {
+
+ SET_MAP_REASON( REASON_NAME_LONG_FOR_TEMP_REG );
+ continue; // Loop again checking this name.
+ }
+#endif // FAT8
+
+ if ( PortUasIsGroupRedundant( groupName ) ) {
+ //WARNING_MSG((
+ // "Ignoring redundant group '" FORMAT_LPWSTR "'...\n",
+ // groupName ));
+ (void)NlsPutMsg(STDOUT, PUAS_IGNORING_REDUNDANT_GROUP,
+ groupName );
+ break; // Stop trying to add this group under any name.
+ }
+
+#ifdef PORTUAS_ENABLE
+ //
+ // Actually create the group.
+ //
+ groups[i].grpi1_name = groupName;
+ rc = NetGroupAdd( NULL, 1, (LPBYTE)( &groups[i] ), NULL );
+#else
+ rc = NERR_Success;
+#endif
+
+ if ( !rc ) {
+
+ groupAdded[gIds[i]] = TRUE;
+ //PROGRESS_MSG(( "Group '" FORMAT_LPWSTR "' added.\n",
+ // groupName ));
+ (void)NlsPutMsg(STDOUT, PUAS_GROUP_ADDED, groupName);
+ RESET_MAP_REASON( );
+ break; // Done trying to add this group under any name.
+
+ //
+ // If the group already exists in NT, update it.
+ //
+
+ } else if ( rc == NERR_GroupExists ) {
+ //PROGRESS_MSG(( "Changing group '" FORMAT_LPWSTR "'.\n",
+ // groupName ));
+ (void)NlsPutMsg(STDOUT, PUAS_CHANGING_GROUP,
+ groupName );
+
+#ifdef PORTUAS_ENABLE
+ if (( rc = NetGroupSetInfo(
+ NULL,
+ groupName,
+ GROUP_COMMENT_INFOLEVEL,
+ (LPBYTE)( &(groups[i].grpi1_comment) ),
+ NULL )) && rc != NERR_SpeGroupOp ) {
+
+ UNEXPECTED_MSG( "NetGroupSetInfo", rc );
+ (void) NetApiBufferFree( groups );
+ (void) NetApiBufferFree( gIds );
+ rc = PortUasError( rc );
+ goto Cleanup;
+ }
+#endif
+ groupAdded[gIds[i]] = TRUE;
+ RESET_MAP_REASON( );
+ break; // Done trying to add this group under any name.
+
+ //
+ // If the group exists as a username, map another name for it.
+ //
+
+ } else if ( rc == NERR_UserExists ) {
+
+ SET_MAP_REASON( REASON_CONFLICT_WITH_USERNAME );
+
+ } else if ( rc == NERR_BadUsername ) {
+
+ SET_MAP_REASON( REASON_BAD_NAME_SYNTAX );
+
+ } else if ( rc == ERROR_ALIAS_EXISTS ) {
+
+ SET_MAP_REASON( REASON_CONFLICT_WITH_LOCALGROUP );
+
+ } else if ( rc == ERROR_DOMAIN_EXISTS ) {
+
+ SET_MAP_REASON( REASON_CONFLICT_WITH_DOMAIN );
+
+ //
+ // Special group: ignore and continue.
+ //
+
+ } else if ( rc == NERR_SpeGroupOp ) {
+
+ RESET_MAP_REASON( );
+
+ //
+ // Return any other error.
+ //
+
+ } else {
+
+ UNEXPECTED_MSG( "NetGroupAdd", rc );
+ (void) NetApiBufferFree( groups );
+ (void) NetApiBufferFree( gIds );
+ rc = PortUasError( rc );
+ goto Cleanup;
+ }
+
+ //
+ // If old map entry was a failure, then tell admin and delete entry.
+ //
+ if (untriedMapEntry != NULL) {
+ // BUGBUG: can new name be NULL here?
+ rc = PortUasComplainAboutBadName(
+ untriedMapEntry->NewName,
+ FALSE, // no, this isn't a user name
+ mapReason ); // reason for latest failue.
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasComplainAboutBadName(redo group)",
+ rc );
+ goto Cleanup;
+ }
+
+ rc = PortUasDeleteBadMapEntry( untriedMapEntry );
+ untriedMapEntry = NULL; // Null pointer so we don't kill it.
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasDeleteBadMapEntry(group)", rc );
+ goto Cleanup;
+ }
+ }
+
+ //
+ // If this name needs to be mapped, then try to create a map table
+ // entry for the original bad name and the original reason.
+ //
+ if (mapNeeded) {
+ rc = PortUasFindOrCreateMapEntry(
+ originalGroupName, // old name
+ FALSE, // no, this isn't a user name
+ originalMapReason,
+ & ignoreThisGroup,
+ & untriedMapEntry ); // Do NOT free this!
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasFindOrCreateMapEntry(group)", rc );
+ goto Cleanup;
+ }
+
+ if (ignoreThisGroup) {
+ break; // Stop trying to add this group under any name.
+ }
+ NetpAssert( untriedMapEntry != NULL );
+ groupName = untriedMapEntry->NewName;
+ NetpAssert( groupName != NULL );
+ continue; // Loop again checking this name.
+ }
+
+ } while ( mapNeeded );
+
+ } // for each group
+
+
+ (void) NetApiBufferFree( groups );
+ (void) NetApiBufferFree( gIds );
+
+ //
+ // Now add users.
+ //
+
+ PortUasInitUserIterator( UserIterator );
+
+ for ( ; ; ) {
+
+ BOOL ignoreThisUser = FALSE;
+ DWORD originalAuthFlags; // AF_OP_ value for this user.
+ LPWSTR originalUserName;
+ DWORD originalUserPriv; // UAS USER_PRIV_ value for this user.
+ LPWSTR userName;
+ BOOL userUpdated = FALSE;
+ RESET_MAP_REASON( );
+
+ //
+ // Get user data from database. Note that this will return a null
+ // pointer for a password.
+ //
+
+ rc = PortUasGetUser( &UserIterator, (LPBYTE *) (LPVOID) &user );
+
+ //
+ // No more users to port?
+ //
+
+ if ( rc == NERR_UserNotFound ) {
+
+ break;
+ }
+
+
+ if ( rc ) {
+
+ rc = PortUasError( rc );
+ goto Cleanup;
+ }
+
+ NetpAssert( user != NULL );
+ originalUserName = user->usri22_name;
+ userName = originalUserName;
+ NetpAssert( userName[0] != NULLC );
+
+ //
+ // Repeat adding user under different names until...
+ //
+ do {
+
+#ifdef FAT8
+ //
+ // BUGBUG: Temporary!!! Current reg stuff uses FAT (8.3) for
+ // registry, so avoid long names!
+ //
+ if ( wcslen( userName ) > PORTUAS_MAX_USER_LEN ) {
+ SET_MAP_REASON( REASON_NAME_LONG_FOR_TEMP_REG );
+ continue;
+ }
+#endif // FAT8
+
+ //
+ // Read the (one-way-encrypted) password.
+ //
+ rc = PortUasGetUserOWFPassword(
+ &UserIterator,
+ &userEncryptedPassword );
+
+ if (rc != NO_ERROR ) {
+ rc = PortUasError( rc );
+ goto Cleanup;
+ }
+
+ //
+ // Update priviledges and authorization to be compatible with NT as
+ // we're adding/changing the user. Then we'll use the original info
+ // to update NT via aliases.
+ //
+ originalAuthFlags = user->usri22_auth_flags;
+ originalUserPriv = user->usri22_priv;
+ if ( user->usri22_priv == USER_PRIV_ADMIN ) {
+ //WARNING_MSG(( "Adding admin '" FORMAT_LPWSTR
+ // "' as regular user...\n",
+ // userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_ADMIN_AS_REGULAR_USER,
+ userName );
+ user->usri22_priv = USER_PRIV_USER;
+ } else if ( user->usri22_priv == USER_PRIV_GUEST ) {
+ //WARNING_MSG(( "Adding guest '" FORMAT_LPWSTR
+ // "' as regular user...\n",
+ // userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_GUEST_AS_REGULAR_USER,
+ userName );
+ user->usri22_priv = USER_PRIV_USER;
+ } else if ( user->usri22_priv != USER_PRIV_USER ) {
+ //WARNING_MSG((
+ // "Changing unknown priv for '" FORMAT_LPWSTR "' from "
+ // FORMAT_DWORD " to regular user.\n",
+ // userName, user->usri22_priv ));
+ (void)NlsPutMsg(STDOUT, PUAS_CHANGING_UNK_PRIV_TO_REGULAR_USER,
+ userName, user->usri22_priv );
+ user->usri22_priv = USER_PRIV_USER;
+ }
+ if ( user->usri22_auth_flags != 0 ) {
+ //WARNING_MSG(( "Adding operator '" FORMAT_LPWSTR
+ // "' as regular user...\n",
+ // userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_ADDING_OPERATOR_AS_REGULAR_USER,
+ userName );
+ user->usri22_auth_flags = 0;
+ }
+
+ //
+ // copy encrypted password.
+ //
+
+ *(PLM_OWF_PASSWORD)(&(user->usri22_password[0])) =
+ *(PLM_OWF_PASSWORD) userEncryptedPassword;
+
+ //
+ // Handle probable Lanman bug where password is null but password
+ // is "required". CliffV has seen this in actual LM 2.x UAS
+ // databases.
+ //
+
+ if (RtlEqualLmOwfPassword(
+ &nullEncryptedPassword,
+ (PLM_OWF_PASSWORD) userEncryptedPassword )) {
+
+ if ( ! (user->usri22_flags & UF_PASSWD_NOTREQD) ) {
+ //WARNING_MSG(( "Working around probable LanMan bug for user "
+ // "'" FORMAT_LPWSTR "'.\n", userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_WORKING_AROUND_LANMAN_BUG, userName );
+ user->usri22_flags |= UF_PASSWD_NOTREQD;
+ }
+ }
+
+ //
+ // Try to add the user, possibly under another name.
+ //
+ user->usri22_name = userName;
+
+#ifdef PORTUAS_ENABLE
+ rc = NetUserAdd( NULL, 22, (LPBYTE)user, NULL );
+
+#ifdef WORKAROUND_SAM_BUG
+ if (rc == ERROR_ACCESS_DENIED) {
+ //WARNING_MSG((
+ // "Access denied on NetUserAdd, "
+ // "possible SAM bug, retrying...\n" ));
+ (void)NlsPutMsg(STDOUT, PUAS_ACCESS_DENIED_POSSIBLE_SAM_BUG);
+ rc = NetUserAdd( NULL, 22, (LPBYTE)user, NULL );
+ }
+#endif // WORKAROUND_SAM_BUG
+
+
+
+#else // ndef PORTUAS_ENABLE
+ rc = NERR_Success;
+
+#endif // ndef PORTUAS_ENABLE
+
+ if (rc == NO_ERROR) {
+ (void)NlsPutMsg(STDOUT, PUAS_ADDED_USER_OK,
+ userName );
+
+ userUpdated = TRUE;
+ RESET_MAP_REASON( );
+
+ } else if ( rc == NERR_BadUsername ) {
+
+ SET_MAP_REASON( REASON_BAD_NAME_SYNTAX );
+
+ } else if ( rc == ERROR_INVALID_PARAMETER ) {
+
+ //WARNING_MSG(( "Error 87 adding user '" FORMAT_LPWSTR
+ // "', user info:\n", userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_ERROR_87_ADDING_USER, userName );
+
+ DumpUserInfo( user ); // Log this info so we can track bogus...
+
+ //
+ // If the user exists as a (global) group name, map the name.
+ //
+
+ } else if ( rc == NERR_GroupExists ) {
+
+ SET_MAP_REASON( REASON_CONFLICT_WITH_GROUP );
+
+ //
+ // If the user exists as a local group name, map the name.
+ //
+
+ } else if ( rc == ERROR_ALIAS_EXISTS ) {
+
+ SET_MAP_REASON( REASON_CONFLICT_WITH_LOCALGROUP );
+
+ //
+ // Update data for existing user.
+ //
+
+ } else if ( rc == NERR_UserExists ) {
+
+ LPUSER_INFO_2 CurrentInfo;
+
+ //PROGRESS_MSG(( "User " FORMAT_LPWSTR
+ // " already exists; updating...\n", userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_USER_ALREADY_EXISTS_UPDATING, userName );
+
+ //
+ // We must preserve what SAM thinks the priv and auth flags are.
+ //
+ rc = NetUserGetInfo(
+ NULL,
+ userName,
+ 2,
+ (LPBYTE *) (LPVOID) & CurrentInfo );
+ if ( rc != NO_ERROR) {
+
+ //
+ // continue to process next user.
+ //
+
+ break;
+
+ }
+ RESET_MAP_REASON( );
+
+ user->usri22_auth_flags = CurrentInfo->usri2_auth_flags;
+ user->usri22_priv = CurrentInfo->usri2_priv;
+ (void) NetApiBufferFree( CurrentInfo );
+
+ //
+ // Update everything except priv and auth flags.
+ //
+ if ( rc = NetUserSetInfo( NULL, userName, 22,
+ (LPBYTE)user, NULL )) {
+
+ if ( rc == ERROR_INVALID_PARAMETER ) {
+
+ //WARNING_MSG(( "Error 87 changing user '" FORMAT_LPWSTR
+ // "', user info:\n", userName ));
+ (void)NlsPutMsg(STDOUT, PUAS_ERROR_87_CHANGING_USER,
+ userName );
+ DumpUserInfo( user ); // Log this info.
+ } else {
+ UNEXPECTED_MSG( "NetUserSetInfo(normal)", rc );
+ }
+
+ //
+ // continue to process next user.
+ //
+
+ break;
+
+ } else {
+ userUpdated = TRUE;
+ }
+
+ //
+ // Report any other error.
+ //
+
+ } else {
+
+ UNEXPECTED_MSG( "NetUserAdd", rc );
+
+ //
+ // continue to process next user.
+ //
+
+ break;
+
+ }
+
+ //
+ // If the user was updated, assign this user to groups and aliases.
+ //
+
+ if ( userUpdated ) {
+
+ NetpAssert( !mapNeeded );
+
+ //
+ // Get a list of groups for the user.
+ //
+
+ rc = PortUasGetUserGroups(
+ &UserIterator,
+ (LPBYTE *) (LPVOID) &userGroups,
+ (LPBYTE *) (LPVOID) &ugIds,
+ &ugCount );
+ if (rc != NERR_Success) {
+
+ rc = PortUasError( rc );
+ goto Cleanup;
+ }
+
+ //
+ // Add the groups one by one.
+ //
+
+ for ( i = 0; i < ugCount; i++ ) {
+
+ if ( groupAdded[ugIds[i]] ) {
+
+ LPMAP_ENTRY goodMapEntry;
+ LPWSTR groupName = userGroups[i].grpi0_name;
+ BOOL ignoreThisGroup = FALSE;
+ NetpAssert( groupName != NULL );
+ NetpAssert( !PortUasIsGroupRedundant( groupName ) );
+
+ //
+ // Find existing map for group name (if any).
+ // Note: PortUasFindMapEntry returns NO_ERROR
+ // and sets *goodMapEntry=NULL if not found.
+ //
+ rc = PortUasFindMapEntry(
+ groupName, // Name to find.
+ & ignoreThisGroup,
+ & goodMapEntry ); // Do NOT free this!
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasFindMapEntry", rc );
+ (VOID) NetApiBufferFree( ugIds );
+ goto Cleanup;
+ }
+ if (ignoreThisGroup) {
+ continue; // ignore this group
+ }
+ if (goodMapEntry != NULL) {
+ NetpAssert( goodMapEntry->NewName != NULL);
+ groupName = goodMapEntry->NewName;
+ }
+
+
+#ifdef PORTUAS_ENABLE
+ rc = NetGroupAddUser( NULL,
+ groupName, // mapped group name
+ userName );
+
+ if ( rc && rc != NERR_SpeGroupOp
+ && rc != NERR_UserInGroup ) {
+
+ UNEXPECTED_MSG( "NetGroupAddUser", rc );
+ (void) NetApiBufferFree( ugIds );
+
+ //
+ // continue to process next user.
+ //
+
+ break;
+
+ }
+
+ //PROGRESS_MSG((
+ // "User '" FORMAT_LPWSTR "' added to group '"
+ // FORMAT_LPWSTR "'.\n", userName, groupName ));
+ (void)NlsPutMsg(STDOUT, PUAS_USER_ADDED_TO_GROUP,
+ userName, groupName );
+#endif
+ }
+ }
+
+ (void) NetApiBufferFree( userGroups );
+ (void) NetApiBufferFree( ugIds );
+
+ if ( rc && rc != NERR_SpeGroupOp
+ && rc != NERR_UserInGroup ) {
+
+ //
+ // continue to process next user.
+ //
+
+ break;
+
+ }
+
+ //
+ // If user was an operator of some kind, add him/her to one or
+ // more aliases. Ditto if this is an admin.
+ //
+ rc = PortUasAddUserToAliases(
+ userName,
+ originalUserPriv,
+ originalAuthFlags & AF_SETTABLE_BITS );
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasAddUserToAliases", rc );
+
+ //
+ // continue to process next user.
+ //
+
+ break;
+
+ }
+
+ //
+ // Finally, if there was a Macintosh primary group field for
+ // this user, then set the primary group for him/her.
+ //
+ if ( NetpIsMacPrimaryGroupFieldValid(
+ (LPCTSTR) (user->usri22_parms) ) ) {
+
+ rc = PortUasSetMacPrimaryGroup(
+ (LPCTSTR) userName,
+ (LPCTSTR) (user->usri22_parms) );
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasSetMacPrimaryGroup", rc );
+ // Continue with next user.
+ }
+ }
+
+ }
+
+ //
+ // If old map entry was a failure, then tell admin and delete entry.
+ //
+ if (untriedMapEntry != NULL) {
+ // BUGBUG: can new name be NULL here?
+ rc = PortUasComplainAboutBadName(
+ untriedMapEntry->NewName,
+ TRUE, // yes, this is user name.
+ mapReason ); // reason for latest failue.
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasComplainAboutBadName(redo user)",
+ rc );
+ goto Cleanup;
+ }
+
+ rc = PortUasDeleteBadMapEntry( untriedMapEntry );
+ untriedMapEntry = NULL; // Null pointer so we don't kill it.
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasDeleteBadMapEntry(user)", rc );
+ goto Cleanup;
+ }
+ }
+
+ //
+ // If this name needs to be mapped, then try to create a map table
+ // entry for the original bad name and the original reason.
+ //
+ if (mapNeeded) {
+ NetpAssert( !userUpdated );
+ rc = PortUasFindOrCreateMapEntry(
+ originalUserName, // old name
+ TRUE, // yes, this is user name.
+ originalMapReason,
+ & ignoreThisUser,
+ & untriedMapEntry ); // Do NOT free this!
+ if (rc != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasFindOrCreateMapEntry(user)", rc );
+ goto Cleanup;
+ }
+
+ if (ignoreThisUser) {
+ break; // Stop trying to add this user under any name.
+ }
+ userName = untriedMapEntry->NewName;
+ NetpAssert( userName != NULL );
+ continue; // Loop again checking this name.
+ }
+
+ } while (mapNeeded);
+
+ //
+ // Now that we're done with this user, we can free data for him/her.
+ //
+ (void) NetApiBufferFree( user );
+ user = NULL; // avoid confusing cleanup code.
+
+ } // for each user
+
+ //
+ // Everything has been ported, we can actually return successfully.
+ //
+ rc = NERR_Success;
+
+ //
+ // Handle error or normal cleanup. (rc must be set before we get here.)
+ //
+Cleanup:
+
+ (VOID) PortUasModalsCleanup( CTRL_CLOSE_EVENT );
+
+ if (aliasesSetup) {
+ (VOID) PortUasAliasCleanup();
+ }
+
+ if (databaseOpen) {
+ PortUasClose();
+ }
+ if (mapSetup) {
+ (VOID) PortUasFreeMapTable( );
+ }
+
+ //
+ // Free the domain ID memory.
+ //
+ if (PortUasAccountsDomainId != NULL) {
+ (VOID) LocalFree( PortUasAccountsDomainId );
+ }
+ if (PortUasBuiltinDomainId != NULL) {
+ (VOID) LocalFree( PortUasBuiltinDomainId );
+ }
+
+ CLOSE_SAM_HANDLE( PortUasSamConnectHandle );
+ CLOSE_SAM_HANDLE( PortUasSamAccountsDomainHandle );
+ CLOSE_SAM_HANDLE( PortUasSamBuiltinDomainHandle );
+
+ if (user != NULL) {
+ (void) NetApiBufferFree( user );
+ }
+ if (userEncryptedPassword != NULL) {
+ (void) NetApiBufferFree( userEncryptedPassword );
+ }
+ return (rc);
+
+} // PortUas()
+
+
+// Expected returns: NERR_NotPrimary, ERROR_ACCESS_DENIED, or NO_ERROR.
+NET_API_STATUS
+PortUasMachineAllowsUpdates(
+ VOID
+ )
+{
+ NET_API_STATUS ApiStatus;
+ LPUSER_MODALS_INFO_1 Modals = NULL;
+
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasMachineAllowsUpdates: "
+ "getting role...\n" ));
+ }
+ ApiStatus = NetUserModalsGet(
+ NULL, // no server name (local)
+ 1, // info level
+ (LPBYTE *) (LPVOID) &Modals ); // alloc and set ptr
+ if (ApiStatus == ERROR_ACCESS_DENIED) {
+ goto Cleanup;
+ } else if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetUserModalsGet", ApiStatus );
+ goto Cleanup;
+ }
+ NetpAssert( Modals != NULL );
+
+ switch ( Modals->usrmod1_role ) {
+ case UAS_ROLE_PRIMARY:
+ break;
+
+ case UAS_ROLE_BACKUP:
+
+ ApiStatus = NERR_NotPrimary;
+ goto Cleanup;
+
+ case UAS_ROLE_MEMBER: /*FALLTHROUGH*/
+ case UAS_ROLE_STANDALONE: /*FALLTHROUGH*/
+ default:
+ // CliffV says we won't ever see member or standalone for NT.
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasMachineAllowsUpdates: "
+ "unexpected value " FORMAT_DWORD " for role.\n",
+ Modals->usrmod1_role ));
+ NetpAssert( FALSE );
+ ApiStatus = NERR_InternalError;
+ goto Cleanup;
+ }
+
+ //
+ // Now find out if we're really an admin.
+ //
+
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasMachineAllowsUpdates: "
+ "seeing if we're an admin.\n" ));
+ }
+
+ ApiStatus = NetUserModalsSet (
+ NULL, // no server name
+ 1, // level
+ (LPVOID) Modals, // buffer
+ NULL ); // don't care about parm err
+ if (ApiStatus == ERROR_ACCESS_DENIED) {
+ // caller will tell user.
+ goto Cleanup;
+ } else if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetUserModalsSet(test)", ApiStatus );
+ goto Cleanup;
+ }
+
+Cleanup:
+ if (Modals != NULL) {
+ (VOID) NetApiBufferFree( Modals );
+ }
+ return (ApiStatus);
+}
+
+
+
+BOOL
+PortUasIsGroupRedundant(
+ IN LPWSTR GroupName
+ )
+{
+ NetpAssert( GroupName != NULL );
+ NetpAssert( (*GroupName) != NULLC );
+
+ if ( _wcsicmp( GroupName, (LPCTSTR) GROUP_SPECIALGRP_ADMINS ) == 0) {
+ return (TRUE); // Match, must be redundant.
+ } else if ( _wcsicmp( GroupName, (LPCTSTR) GROUP_SPECIALGRP_GUESTS ) == 0) {
+ return (TRUE); // Match, must be redundant.
+ } else if ( _wcsicmp( GroupName, (LPCTSTR) GROUP_SPECIALGRP_LOCAL ) == 0) {
+ return (TRUE); // Match, must be redundant.
+ } else if ( _wcsicmp( GroupName, (LPCTSTR) GROUP_SPECIALGRP_USERS ) == 0) {
+ return (TRUE); // Match, must be redundant.
+ } else {
+ return (FALSE); // No match, must not be redundant.
+ }
+ /*NOTREACHED*/
+
+} // PortUasIsGroupRedundant
+
+
+
+NET_API_STATUS
+PortUasError(
+ IN NET_API_STATUS Error
+ )
+
+/*++
+
+Routine Description:
+
+ Maps certain errors onto ones that PortUas can return.
+
+Arguments:
+
+ Error - the error code to map.
+
+Return Value:
+
+ NET_API_STATUS - the mapped error code.
+
+
+--*/
+
+{
+
+ switch ( Error ) {
+
+ case NERR_NoRoom:
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ case ERROR_INVALID_PARAMETER:
+ case ERROR_INVALID_PASSWORD:
+ case NERR_UserNotFound:
+
+ return NERR_InternalError;
+
+ default:
+
+ return Error;
+ }
+
+} // PortUasError
+
+int FileIsConsole(HANDLE fh)
+{
+ unsigned htype ;
+
+ return GetConsoleMode( fh, &htype );
+// htype = GetFileType(fh);
+// htype &= ~FILE_TYPE_REMOTE;
+// return htype == FILE_TYPE_CHAR;
+}
+
+
+#define MAX_BUF_SIZE 1024
+ TCHAR ConBuf[MAX_BUF_SIZE];
+static CHAR AnsiBuf[MAX_BUF_SIZE*2]; /* 2 because of DBCS */
+
+int
+MyWriteConsole(int fOutOrErr, int cch)
+{
+ HANDLE hOut;
+
+ if (fOutOrErr == STDOUT)
+ hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ else
+ hOut = GetStdHandle(STD_ERROR_HANDLE);
+
+ if (FileIsConsole(hOut))
+ WriteConsole(hOut, ConBuf, cch, &cch, NULL);
+ else {
+ cch = WideCharToMultiByte(CP_OEMCP, 0,
+ ConBuf, cch,
+ AnsiBuf, MAX_BUF_SIZE*3,
+ NULL, NULL);
+ WriteFile(hOut, AnsiBuf, cch, &cch, NULL);
+ }
+
+ return cch;
+}
+
+int
+WriteToCon(TCHAR*fmt, ...)
+{
+ va_list args;
+ int cch;
+
+ va_start( args, fmt );
+ cch = _vsntprintf( ConBuf, MAX_BUF_SIZE, fmt, args );
+ va_end( args );
+ return MyWriteConsole(STDOUT, cch);
+}
+
diff --git a/private/net/portuas/portmac.c b/private/net/portuas/portmac.c
new file mode 100644
index 000000000..ae318ba5d
--- /dev/null
+++ b/private/net/portuas/portmac.c
@@ -0,0 +1,171 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ PortMac.c
+
+Abstract:
+
+ PortMac contains routines to handle the Macintosh primary group
+ field in the UAS database.
+
+Author:
+
+ JR (John Rogers, JohnRo@Microsoft) 26-Jan-1993
+
+Revision History:
+
+ 29-Oct-1992 JohnRo
+ Created for RAID 9020 ("prompt on conflicts" version).
+ 27-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 29-Jan-1993 JohnRo
+ Made changes suggested by PC-LINT 5.0.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h> // IN, OUT, OPTIONAL, LPTSTR, etc.
+#include <lmcons.h> // NET_API_STATUS, PARMNUM_BASE_INFOLEVEL, etc.
+
+// These may be included in any order:
+
+#include <lmaccess.h> // NetUserSetInfo(), NetGroupUserAdd(), etc.
+#include <lmerr.h> // NO_ERROR, ERROR_, and NERR_ equates.
+#include <names.h> // NetpGetPrimaryGroupFromMac().
+#include <netdebug.h> // NetpAssert(), etc.
+#include <netlib.h> // NetpMemoryFree().
+#include <portuasp.h> // LPMAP_ENTRY, UNEXPECTED_MSG(), my prototypes, etc.
+
+#include "nlstxt.h" // NLS message ID's
+
+NET_API_STATUS
+PortUasSetMacPrimaryGroup(
+ IN LPCTSTR UserName,
+ IN LPCTSTR MacPrimaryField // field in "mGroup:junk" format.
+ )
+{
+ NET_API_STATUS ApiStatus;
+ LPTSTR GroupName = NULL;
+ LPTSTR GroupNameToUse = NULL;
+ ULONG GroupRid;
+ BOOL IgnoreThis;
+ LPMAP_ENTRY MapEntry = NULL;
+ USER_INFO_1051 UserInfo;
+
+ //
+ // Extract the primary group name from the Mac field.
+ //
+
+ ApiStatus = NetpGetPrimaryGroupFromMacField(
+ MacPrimaryField, // name in "mGroup:" format.
+ & GroupName ); // alloc and set ptr.
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetpGetPrimaryGroupFromMacField", ApiStatus );
+ goto Cleanup;
+ }
+ NetpAssert( GroupName != NULL );
+ NetpAssert( NetpIsGroupNameValid( GroupName ) );
+
+
+ //
+ // Tell admin what we're planning.
+ //
+ //PROGRESS_MSG(( "Setting primary group for user '" FORMAT_LPTSTR
+ // "' to '" FORMAT_LPTSTR "' (before mapping)...\n",
+ // UserName, GroupName ));
+ (void)NlsPutMsg(STDOUT, PUAS_SETTING_PRIM_GROUP_BEFORE_MAPPING,
+ UserName, GroupName );
+ //
+ // Map this group name if necessary.
+ //
+
+ ApiStatus = PortUasFindMapEntry(
+ GroupName, // name to find
+ &IgnoreThis, // did user say ignore this one?
+ &MapEntry ); // set ptr to existing map entry
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasFindMapEntry", ApiStatus );
+ goto Cleanup;
+ }
+ if (IgnoreThis) {
+ // User said ignore this entry.
+ ApiStatus = NO_ERROR;
+ goto Cleanup;
+ }
+ if (MapEntry == NULL) {
+ GroupNameToUse = GroupName; // no mapping
+ } else {
+ GroupNameToUse = MapEntry->NewName;
+ }
+ NetpAssert( GroupNameToUse != NULL );
+ NetpAssert( NetpIsGroupNameValid( GroupNameToUse ) );
+
+ //
+ // Make sure this user is a member of the group (add to group if needed).
+ // This will also check if the group and user exist.
+ //
+
+ //PROGRESS_MSG(( "Setting primary group for user '" FORMAT_LPTSTR
+ // "' to '" FORMAT_LPTSTR "' (after mapping)...\n",
+ // UserName, GroupNameToUse ));
+
+ (void)NlsPutMsg(STDOUT, PUAS_SETTING_PRIM_GROUP_AFTER_MAPPING,
+ UserName, GroupNameToUse );
+
+ ApiStatus = NetGroupAddUser(
+ NULL, // local (no server name)
+ GroupNameToUse, // group to update
+ (LPTSTR) UserName ); // user name to add to group
+ if ( (ApiStatus != NO_ERROR) && (ApiStatus != NERR_UserInGroup) ) {
+ UNEXPECTED_MSG( "NetGroupAddUser", ApiStatus );
+ goto Cleanup;
+ }
+
+ //
+ // Convert the group name to a RID.
+ //
+ ApiStatus = PortUasNameToRid(
+ (LPCWSTR) GroupNameToUse,
+ SidTypeGroup, // expected type
+ &GroupRid );
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasNameToRid", ApiStatus );
+ goto Cleanup;
+ }
+
+ //
+ // Call NetUserSetInfo to set the primary group ID using the RID.
+ //
+ UserInfo.usri1051_primary_group_id = (DWORD) GroupRid;
+
+ ApiStatus = NetUserSetInfo (
+ NULL, // local (no server name)
+ (LPTSTR) UserName,
+ PARMNUM_BASE_INFOLEVEL + USER_PRIMARY_GROUP_PARMNUM,
+ (LPVOID) &UserInfo,
+ NULL ); // don't care about parmnum
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetUserSetInfo", ApiStatus );
+ goto Cleanup;
+ }
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+
+ if (GroupName != NULL) {
+ NetpMemoryFree( GroupName );
+ }
+
+ // No need to do anything with MapEntry or GroupNameToUse.
+
+ return (ApiStatus);
+}
diff --git a/private/net/portuas/portmap.c b/private/net/portuas/portmap.c
new file mode 100644
index 000000000..577fb8fa5
--- /dev/null
+++ b/private/net/portuas/portmap.c
@@ -0,0 +1,489 @@
+/*++
+
+Copyright (c) 1992-1993 Microsoft Corporation
+
+Module Name:
+
+ PortMap.C
+
+Abstract:
+
+ PortUAS name mapping layer.
+
+Author:
+
+ John Rogers (JohnRo) 29-Oct-1992
+
+Revision History:
+
+ 29-Oct-1992 JohnRo
+ Created for RAID 9020 ("prompt on conflicts" version).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <windef.h>
+#include <lmcons.h>
+
+// These may be included in any order:
+
+#include <lmapibuf.h>
+#include <netdebug.h> // DBGSTATIC, NetpAssert(), etc.
+#include <netlib.h> // NetpSetOptionalArg().
+#include <portuasp.h> // WARNING_MSG(), Verbose, my prototypes, etc.
+#include <string.h> // memcpy().
+#include <tstring.h> // NetpAllocWStrFromWStr(), WCSSIZE().
+#include <wchar.h> // _wcsicmp().
+#include <winerror.h> // NO_ERROR, ERROR_ equates.
+
+#include "nlstxt.h" // NLS message ID's
+
+DBGSTATIC BOOL IgnoreAllNamesInError = FALSE;
+
+// Array of map table entries.
+DBGSTATIC LPMAP_ENTRY MapTableStart = NULL;
+
+DBGSTATIC DWORD MapTableEntryCount = 0;
+
+
+NET_API_STATUS
+PortUasMapTableInit(
+ VOID
+ )
+{
+ MapTableStart = NULL;
+ MapTableEntryCount = 0;
+ IgnoreAllNamesInError = FALSE;
+
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "Initial map table:\n" ));
+ PortUasDbgDisplayMapTable( );
+ }
+ return (NO_ERROR);
+
+} // PortUasMapTableInit
+
+
+// Return NO_ERROR and *MapEntry=NULL if not found.
+NET_API_STATUS
+PortUasFindMapEntry(
+ IN LPWSTR NameToFind,
+ OUT BOOL * IgnoreThis OPTIONAL,
+ OUT LPMAP_ENTRY * MapEntry // Do NOT free this!
+ )
+{
+ DWORD EntriesLeft;
+ LPMAP_ENTRY TableEntry;
+
+ NetpAssert( NameToFind != NULL );
+ NetpAssert( (*NameToFind) != NULLC );
+ NetpAssert( MapEntry != NULL );
+
+ if (MapTableEntryCount == 0) {
+ NetpAssert( MapTableStart == NULL );
+
+ // Not found (table empty).
+ NetpSetOptionalArg( IgnoreThis, FALSE );
+ *MapEntry = NULL;
+ return (NO_ERROR);
+ }
+
+ TableEntry = MapTableStart;
+ for (EntriesLeft=MapTableEntryCount; EntriesLeft > 0; --EntriesLeft) {
+ if (_wcsicmp( NameToFind, TableEntry->OldName ) == 0 ) {
+
+ // Found.
+ if ( (TableEntry->NewName) == NULL ) {
+ NetpSetOptionalArg( IgnoreThis, TRUE );
+ } else {
+ NetpSetOptionalArg( IgnoreThis, FALSE );
+ }
+ *MapEntry = TableEntry;
+ return (NO_ERROR);
+ }
+ ++TableEntry;
+ }
+
+ // Not found (in non-empty table).
+ NetpSetOptionalArg( IgnoreThis, FALSE );
+ *MapEntry = NULL;
+ return (NO_ERROR);
+
+} // PortUasFindMapEntry
+
+
+// This sets globals MapTableStart and MapTableEntryCount.
+DBGSTATIC NET_API_STATUS
+PortUasReallocateMapTable(
+ IN DWORD NewEntryCount
+ )
+{
+ NET_API_STATUS ApiStatus;
+
+ if (NewEntryCount==0) {
+
+ //
+ // Handle worst case: no entries left.
+ //
+
+ if (MapTableStart != NULL) {
+ (VOID) NetApiBufferFree( MapTableStart );
+ MapTableStart = NULL;
+ MapTableEntryCount = 0;
+ } else {
+ NetpAssert( MapTableEntryCount == 0 );
+ }
+
+ } else if (MapTableStart == NULL) {
+
+ //
+ // Another strange case: just allocate it the first time around.
+ //
+
+ NetpAssert( NewEntryCount == 1 );
+ ApiStatus = NetApiBufferAllocate(
+ sizeof( MAP_ENTRY ) * NewEntryCount,
+ (LPVOID *) (LPVOID) & MapTableStart ); // alloc and set ptr
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetApiBufferAllocate(map tbl)", ApiStatus );
+ goto Cleanup;
+ }
+ NetpAssert( MapTableStart != NULL );
+
+ } else {
+
+ //
+ // Reallocate the map table to make room for one more structure.
+ //
+
+ ApiStatus = NetApiBufferReallocate(
+ MapTableStart, // old buffer
+ sizeof( MAP_ENTRY ) * NewEntryCount,
+ (LPVOID *) (LPVOID) & MapTableStart ); // alloc and set ptr
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "NetApiBufferReallocate(map table)", ApiStatus );
+ goto Cleanup;
+ }
+ NetpAssert( MapTableStart != NULL );
+ }
+
+ //
+ // Update was OK.
+ //
+ MapTableEntryCount = NewEntryCount;
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+ if (ApiStatus != NO_ERROR) {
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasReallocateMapTable: "
+ " returning " FORMAT_API_STATUS ".\n", ApiStatus ));
+ }
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasReallocateMapTable: "
+ " exiting with table at " FORMAT_LPVOID ", " FORMAT_DWORD
+ " entries.\n", (LPVOID) MapTableStart, MapTableEntryCount ));
+ }
+ return (ApiStatus);
+
+} // PortUasReallocateMapTable
+
+
+NET_API_STATUS
+PortUasFindOrCreateMapEntry(
+ IN LPWSTR OldName,
+ IN BOOL ThisIsUserName, // TRUE for user name, FALSE for group name.
+ IN DWORD Reason, // REASON_ equates from PortUAS.h
+ OUT BOOL * IgnoreThis,
+ OUT LPMAP_ENTRY * MapEntryOut // Do NOT free this!
+ )
+{
+ NET_API_STATUS ApiStatus;
+ LPWSTR NewName = NULL;
+ LPWSTR OldNameCopy = NULL;
+ LPMAP_ENTRY TableEntry = NULL;
+
+ NetpAssert( OldName != NULL );
+ NetpAssert( (*OldName) != NULLC );
+ NetpAssert( MapEntryOut != NULL );
+
+ if (IgnoreAllNamesInError) {
+ *IgnoreThis = TRUE;
+ *MapEntryOut = NULL;
+ return (NO_ERROR);
+ }
+
+ //
+ // Find existing entry (if any).
+ // Note that PortUasFindMapEntry returns NO_ERROR and sets *MapEntry=NULL
+ // if not found.
+ //
+ ApiStatus = PortUasFindMapEntry(
+ OldName, // name to find
+ IgnoreThis,
+ MapEntryOut ); // Set map entry ptr - do NOT free this!
+ if (ApiStatus != NO_ERROR) {
+ return (ApiStatus);
+ }
+ if (*MapEntryOut != NULL) {
+ if ( (*MapEntryOut)->NewName != NULL ) {
+ *IgnoreThis = FALSE;
+ } else {
+ *IgnoreThis = TRUE;
+ }
+ return (NO_ERROR);
+ }
+
+ //
+ // Prompt for new name.
+ //
+ ApiStatus = PortUasDefaultPromptForNewName(
+ OldName,
+ ThisIsUserName, // TRUE for user name, FALSE for group name
+ Reason, // REASON_ equates.
+ & NewName, // alloc w/ NetApiBufferAllocate().
+ IgnoreThis,
+ & IgnoreAllNamesInError );
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasDefaultPromptForNewName", ApiStatus );
+ goto Cleanup;
+ }
+
+ //
+ // Allocate copy of old name.
+ //
+ OldNameCopy = NetpAllocWStrFromWStr( OldName );
+ if (OldNameCopy == NULL) {
+ ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
+ UNEXPECTED_MSG( "NetpAllocWStrFromWStr", ApiStatus );
+ goto Cleanup;
+ }
+
+ //
+ // Reallocate the map table to make room for one more structure.
+ // (Or, just allocate it the first time around.)
+ // This sets globals MapTableStart and MapTableEntryCount.
+ //
+ ApiStatus = PortUasReallocateMapTable( MapTableEntryCount+1 );
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasReallocateMapTable(create)", ApiStatus );
+ goto Cleanup;
+ }
+ NetpAssert( MapTableStart != NULL );
+ NetpAssert( MapTableEntryCount != 0 );
+
+ //
+ // Create the new entry.
+ //
+
+ TableEntry = & MapTableStart[MapTableEntryCount-1];
+
+ if (*IgnoreThis) {
+ TableEntry->NewName = NULL;
+ } else {
+ TableEntry->NewName = NewName;
+ }
+ TableEntry->OldName = OldNameCopy;
+
+ //
+ // If we made it this far, then everything is valid.
+ //
+ *MapEntryOut = TableEntry;
+
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "Updated map table:\n" ));
+ PortUasDbgDisplayMapTable( );
+ }
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+
+ if (ApiStatus != NO_ERROR) {
+ *MapEntryOut = NULL;
+ if ( (ApiStatus != NO_ERROR) && (NewName !=NULL ) ) {
+ (VOID) NetApiBufferFree( NewName );
+ }
+ if ( (ApiStatus != NO_ERROR) && (OldNameCopy !=NULL ) ) {
+ (VOID) NetApiBufferFree( OldNameCopy );
+ }
+ }
+ return (ApiStatus);
+
+} // PortUasFindOrCreateMapEntry
+
+
+DBGSTATIC VOID
+PortUasFreeStringsForMapEntry(
+ IN LPMAP_ENTRY TableEntry
+ )
+{
+ NetpAssert( TableEntry != NULL );
+ NetpAssert( TableEntry->OldName != NULL );
+ (VOID) NetApiBufferFree( TableEntry->OldName );
+
+ if (TableEntry->NewName != NULL) {
+ (VOID) NetApiBufferFree( TableEntry->NewName );
+ }
+} // PortUasFreeStringsForMapEntry
+
+
+NET_API_STATUS
+PortUasDeleteBadMapEntry(
+ IN LPMAP_ENTRY EntryToDelete
+ )
+{
+ NET_API_STATUS ApiStatus;
+ DWORD EntriesLeft;
+ LPMAP_ENTRY TableEntry;
+
+ if (EntryToDelete == NULL ) {
+ ApiStatus = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (MapTableEntryCount == 0) {
+ NetpAssert( MapTableStart == NULL );
+
+ // Not found (table empty).
+ ApiStatus = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ TableEntry = MapTableStart;
+ NetpAssert( MapTableStart != NULL );
+ for (EntriesLeft=MapTableEntryCount; EntriesLeft > 0; --EntriesLeft) {
+ if (EntryToDelete == TableEntry) {
+
+ // Found it!
+
+ // Free string(s) pointed-to by this entry.
+ PortUasFreeStringsForMapEntry( EntryToDelete );
+
+ // Compress this entry out of table.
+ if (EntriesLeft > 1) { // Any entries after this?
+ (VOID) memcpy(
+ EntryToDelete, // dest: entry to be wiped-out
+ EntryToDelete + (EntriesLeft-1), // src: last entry
+ sizeof(MAP_ENTRY) ); // byte count
+ }
+
+ // Realloc area for structures and set globals.
+ ApiStatus = PortUasReallocateMapTable(
+ MapTableEntryCount-1 ); // new entry count
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasReallocateMapTable(del)", ApiStatus );
+ goto Cleanup;
+ }
+
+ ApiStatus = NO_ERROR;
+ goto Cleanup;
+ }
+ ++TableEntry;
+ }
+
+ // Not found (in non-empty table).
+ ApiStatus = ERROR_INVALID_PARAMETER;
+
+Cleanup:
+ if (ApiStatus != NO_ERROR) {
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasDeleteBadMapTableEntry: "
+ " returning " FORMAT_API_STATUS ".\n", ApiStatus ));
+ }
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "Map table (after entry delete):\n" ));
+ PortUasDbgDisplayMapTable( );
+ }
+ return (ApiStatus);
+
+} // PortUasDeleteBadMapEntry
+
+
+NET_API_STATUS
+PortUasFreeMapTable(
+ VOID
+ )
+{
+ DWORD EntriesLeft;
+ LPMAP_ENTRY TableEntry;
+
+ if (MapTableStart != NULL) {
+ NetpAssert( MapTableEntryCount != 0 );
+
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "Final map table (before free):\n" ));
+ PortUasDbgDisplayMapTable( );
+ }
+
+ //
+ // Free name strings in each table entry.
+ //
+ TableEntry = MapTableStart;
+ for (EntriesLeft=MapTableEntryCount; EntriesLeft > 0; --EntriesLeft) {
+
+ PortUasFreeStringsForMapEntry( TableEntry );
+
+ ++TableEntry;
+ }
+
+ //
+ // Free array of structures.
+ //
+
+ (VOID) NetApiBufferFree( MapTableStart );
+ MapTableStart = NULL;
+ MapTableEntryCount = 0;
+ } else {
+ NetpAssert( MapTableEntryCount == 0 );
+ }
+
+ if (Verbose) {
+ NetpKdPrint(( PREFIX_PORTUAS "Final map table (after free):\n" ));
+ PortUasDbgDisplayMapTable( );
+ }
+
+ return (NO_ERROR);
+
+} // PortUasFreeMapTable
+
+
+VOID
+PortUasDbgDisplayMapTable(
+ VOID
+ )
+{
+ DWORD EntriesLeft;
+ LPMAP_ENTRY TableEntry;
+ NetpKdPrint(( PREFIX_PORTUAS "Map table: (" FORMAT_DWORD " entries)...\n",
+ MapTableEntryCount ));
+ if (MapTableEntryCount == 0) {
+ NetpAssert( MapTableStart == NULL );
+ return;
+ }
+
+ TableEntry = MapTableStart;
+ for (EntriesLeft=MapTableEntryCount; EntriesLeft > 0; --EntriesLeft) {
+ PortUasDbgDisplayMapEntry( TableEntry );
+ ++TableEntry;
+ }
+}
+
+
+VOID
+PortUasDbgDisplayMapEntry(
+ IN LPMAP_ENTRY Entry
+ )
+{
+ NetpAssert( Entry != NULL );
+ NetpAssert( (Entry->OldName) != NULL );
+
+ NetpKdPrint(( " map entry at " FORMAT_LPVOID ":\n", (LPVOID) Entry ));
+ NetpKdPrint(( " old name : " FORMAT_LPWSTR "\n", Entry->OldName ));
+ NetpKdPrint(( " new name : " FORMAT_LPWSTR "\n",
+ (Entry->NewName) ? (Entry->NewName) : L"(**IGNORE**)" ));
+
+}
diff --git a/private/net/portuas/portpars.c b/private/net/portuas/portpars.c
new file mode 100644
index 000000000..f18c9210f
--- /dev/null
+++ b/private/net/portuas/portpars.c
@@ -0,0 +1,255 @@
+/*++
+
+Copyright (c) 1992-1993 Microsoft Corporation
+
+Module Name:
+
+ PortPars.c
+
+Abstract:
+
+ BUGBUG
+
+Author:
+
+ John Rogers (JohnRo) 11-Mar-1992
+
+Environment:
+
+ Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
+ Requires ANSI C extensions: slash-slash comments, long external names,
+ _stricmp(), _strnicmp().
+
+Revision History:
+
+ 18-Mar-1992 JohnRo
+ Added flag for verbose output at run time.
+ 11-Mar-1992 JohnRo
+ Cut and pasted this code from examples/netcnfg.c and netlib/conffake.c.
+ 29-Oct-1992 JohnRo
+ RAID 8383: PortUAS: check for redundant cmd line args.
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 1-Mar-1993 RonaldM
+ NLS-conversion
+ 29-Jul-1993 JohnRo
+ Made changes suggested by PC-LINT 5.0
+ 02-Sep-1993 JohnRo
+ Add PortUAS /log:filename switch for Cheetah.
+ Also use NetpNameCompare() to compare user names.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h> // LPSTR, etc.
+#include <winnls.h>
+#include <shellapi.h> // CommandLineToArgvW
+#include <lmcons.h> // NET_API_STATUS.
+
+// These may be included in any order:
+
+#include <ctype.h> // tolower(), etc.
+#include <wchar.h>
+#include <tchar.h>
+#include <lmapibuf.h> // NetApiBufferFree().
+#include <netdebug.h> // DBGSTATIC, FORMAT_ eqautes, NetpKdPrint().
+#include <portuasp.h> // My prototype, PortUasGlobal vars, etc.
+#include <prefix.h> // PREFIX_ equates.
+#include <stdio.h> // fprintf().
+#include <stdlib.h> // exit(), EXIT_SUCCESS, etc.
+#include <string.h> // _stricmp(), strnicmp().
+#include <tstring.h> // NetpAllocTStrFromStr().
+
+#include "nlstxt.h" // NLS text ID codes
+
+// Global codepage info
+extern int CurrentCP = CP_OEMCP;
+
+DBGSTATIC void
+PortUasUsage(
+ TCHAR * pszProgram
+ );
+
+LPTSTR // Returns file name or NULL on error.
+PortUasParseCommandLine(
+ int argc,
+ char *argv[]
+ )
+{
+ NET_API_STATUS ApiStatus;
+ LPTSTR File = NULL; // File name
+ LPTSTR LogFileName = NULL;
+ LPTSTR TempArg;
+ int iCount; // Index counter
+ LPTSTR *argvW;
+
+ argvW = CommandLineToArgvW(GetCommandLine(), &argc);
+
+ for (iCount = 1; iCount < argc; iCount++) {
+
+ if ((*argvW[iCount] == MINUS) || (*argvW[iCount] == SLASH)) {
+
+ TempArg = NULL;
+ switch (_totlower(*(argvW[iCount]+1))) { // Process switches
+
+ case TEXT('f'): // -f filename
+ if ( ++iCount < argc )
+ TempArg = argvW[iCount];
+ if ( (TempArg == NULL) || (File != NULL) ) {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+ File = TempArg;
+ break;
+
+ case TEXT('c'): // "-codepage codepage"
+ {
+ CHAR szAnsi[10];
+
+ if ( _tcsicmp( argvW[iCount]+1, TEXT("codepage") ) == 0 ) {
+ if ( ++iCount < argc )
+ TempArg = argvW[iCount];
+ } else if ( _tcsnicmp( argvW[iCount]+1, TEXT("codepage:"), 9 ) == 0 ) {
+ TempArg = argvW[iCount] + 10;
+ } else {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+
+ if ( TempArg == NULL || *TempArg == TEXT('\0') )
+ {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+
+ // FARBUGBUG - when wtoi is available, replace next 4 lines
+ WideCharToMultiByte (CP_ACP, 0,
+ TempArg, 10,
+ szAnsi, 10, NULL, NULL);
+ CurrentCP = atoi(szAnsi);
+ if ( !IsValidCodePage( CurrentCP ) )
+ {
+ ApiStatus = PUAS_INVALID_CODEPAGE;
+ (void)NlsPutMsg(STDERR, PUAS_INVALID_CODEPAGE);
+ goto Cleanup;
+ }
+ break;
+ }
+ case TEXT('l'): // "-log filename"
+ {
+
+ //
+ // Parse arg and find the log filename.
+ //
+
+ if ( _tcsicmp( argvW[iCount]+1, TEXT("log") ) == 0 ) {
+ if ( ++iCount < argc )
+ TempArg = argvW[iCount]; // "-log filename" form.
+ } else if ( _tcsnicmp( argvW[iCount]+1, TEXT("log:"), 4 ) == 0 ) {
+ TempArg = argvW[iCount] + 5; // "-log:filename" form.
+ } else {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+
+
+ if (TempArg == NULL || *TempArg == TEXT('\0') ) {
+ PortUasUsage(argvW[0]); // "-log" without name.
+ /*NOTREACHED*/
+ }
+ if (LogFileName != NULL) {
+ PortUasUsage(argvW[0]); // can't give name twice!
+ /*NOTREACHED*/
+ }
+
+ //
+ // Open log file and store handle in global.
+ //
+
+ ApiStatus = PortUasOpenLogFile(
+ (LPCTSTR) TempArg,
+ & PortUasGlobalLogFileHandle );
+ if (ApiStatus != NO_ERROR) {
+
+ (void)NlsPutMsg(STDERR, PUAS_LOG_FILE_NOT_OPEN, argvW[0]);
+
+ UNEXPECTED_MSG(
+ "PortUasOpenLogFile",
+ ApiStatus );
+ goto Cleanup;
+
+ }
+
+ NetpAssert(
+ PortUasGlobalLogFileHandle != INVALID_HANDLE_VALUE );
+
+
+
+ break;
+
+ }
+
+ case TEXT('u'): // -u user
+ if ( ++iCount < argc )
+ TempArg = argvW[iCount];
+ if ( (TempArg == NULL) || (PortUasGlobalUserToSkipTo!=NULL) ) {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+ PortUasGlobalUserToSkipTo = TempArg;
+ break;
+
+ case TEXT('v'): // -v (verbose)
+ Verbose = TRUE;
+ break;
+
+ default:
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+ } else {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+
+ }
+
+ if (File == NULL) {
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+
+ return (File);
+
+Cleanup:
+
+ if (ApiStatus != NO_ERROR) {
+ File = NULL;
+ NetpKdPrint(( PREFIX_PORTUAS
+ "PortUasParseCommandLine FAILED: status "
+ FORMAT_API_STATUS ".\n", ApiStatus ));
+
+ PortUasUsage(argvW[0]);
+ /*NOTREACHED*/
+ }
+
+ return (File); // May be NULL on error.
+
+} // PortUasParseCommandLine
+
+
+DBGSTATIC void
+PortUasUsage(
+ TCHAR * pszProgram
+ )
+{
+ (void)NlsPutMsg(STDERR, PUAS_USAGE, pszProgram);
+ exit(EXIT_FAILURE);
+ /*NOTREACHED*/
+
+} // PortUasUsage
diff --git a/private/net/portuas/portuas.c b/private/net/portuas/portuas.c
new file mode 100644
index 000000000..a417902c7
--- /dev/null
+++ b/private/net/portuas/portuas.c
@@ -0,0 +1,74 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ PortUas.c (main program for UAS-to-SAM database conversion)
+
+Revision history:
+
+ 27-Feb-1992 JohnRo
+ Changed user info level from 98 to 21 (avoid LAN/Server conflicts).
+ 28-Feb-1992 JohnRo
+ User info must include units_per_week field.
+ 11-Mar-1992 JohnRo
+ Added command-line parsing stuff.
+ 27-May-1992 JohnRo
+ RAID 9829: winsvc.h and related file cleanup.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ (Moved portuas.c to portlib.c and port2.c to portuas.c)
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 18-Feb-1993 RonaldM
+ NLS support added.
+ 17-Jun-1993 RonaldM
+ PortUAS buglet: invalid database w/o -v (verbose) gets no message.
+ Made changes suggested by PC-LINT 5.0
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h>
+
+// These may be included in any order:
+
+#include <netdebug.h> // NetpAssert(), etc.
+#include <wchar.h>
+#include <io.h> // write
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <portuas.h>
+#include <portuasp.h> // PortUasParseCommandLine(), Verbose, etc.
+
+#include "nlstxt.h" // NLS message definitions
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ LPTSTR FileName;
+ NET_API_STATUS rc;
+
+ FileName = PortUasParseCommandLine( argc, argv );
+
+ NetpAssert( FileName != NULL );
+
+ rc = PortUas( FileName );
+
+ if ( Verbose || (rc != NO_ERROR) ) {
+ //(VOID) WriteToCon( TEXT("PortUas returned - %lu\n"), rc );
+ (VOID) NlsPutMsg( STDOUT, PUAS_PORTUAS_RETURNED, rc, rc );
+ }
+ return ( (int) rc);
+}
diff --git a/private/net/portuas/portuas.rc b/private/net/portuas/portuas.rc
new file mode 100644
index 000000000..34112143f
--- /dev/null
+++ b/private/net/portuas/portuas.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "PORTUAS Utility"
+#define VER_INTERNALNAME_STR "portuas.exe"
+#define VER_ORIGINALFILENAME_STR "portuas.exe"
+
+#include "common.ver"
+
+1 11 MSG00001.bin
diff --git a/private/net/portuas/portuasp.h b/private/net/portuas/portuasp.h
new file mode 100644
index 000000000..dd2184b15
--- /dev/null
+++ b/private/net/portuas/portuasp.h
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ PortUASP.H
+
+Abstract:
+
+ Private header file for UAS->SAM porting code.
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 24-Oct-1991
+
+Environment:
+
+ Uses NT APIs and lots of Win32 things.
+ Requires ANSI C extensions: slash-slash comments, long external names.
+
+Revision History:
+
+ 24-Oct-1991 w-shankn
+ Created.
+ 02-Mar-1992 JohnRo
+ Avoid creating redundant groups.
+ 10-Mar-1992 JohnRo
+ Don't need 8.3 length restriction anymore.
+ 13-Mar-1992 JohnRo
+ Added command-line parsing stuff.
+ Added WARNING_MSG(), ERROR_MSG(), PROGRESS_MSG() macros.
+ 18-Mar-1992 JohnRo
+ Use iterator to allow hash-table collision handling.
+ Added flag for verbose output at run time.
+ 19-Mar-1992 JohnRo
+ Moved decrypt function here from NT RTL code (per DavidC).
+ 30-Apr-1992 JohnRo
+ Added alias support for operators.
+ Undo temporary length restrictions.
+ Allow password to be null pointer to DumpPassword().
+ 08-Jun-1992 JohnRo
+ RAID 10139: PortUAS should add to admin group/alias.
+ Use PREFIX_ equates.
+ 27-Oct-1992 JohnRo
+ RAID 9020: setup: PortUas fails ("prompt on conflicts" version).
+ RAID 9613: PortUAS should prevent run on BDC.
+ 27-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ Made changes suggested by PC-LINT 5.0
+ 18-Feb-1993 RonaldM
+ Added NlsPutMsg() prototype plus STDOUT and STDERR defs.
+ 28-Jul-1993 JohnRo
+ RAID 16822: PortUAS should have ^C handler to restore user modals.
+ Made changes suggested by PC-LINT 5.0
+ 02-Sep-1993 JohnRo
+ Add PortUAS /log:filename switch for Cheetah.
+ Also use NetpNameCompare() to compare user names.
+ Added Environment comment section.
+
+--*/
+
+
+#ifndef _PORTUASP_
+#define _PORTUASP_
+
+
+// These must be included first:
+
+#include <lmcons.h> // LM20_UNLEN, LM20_GNLEN.
+
+
+// These may be included in any order:
+
+#include <debugfmt.h> // FORMAT_API_STATUS, etc.
+#include <ntsam.h> // SAM_HANDLE.
+
+// Don't complain about "unneeded" includes of this file:
+/*lint -efile(764,stdio.h) */
+/*lint -efile(766,stdio.h) */
+#include <stdio.h> // printf().
+
+// Don't complain about "unneeded" includes of this file:
+/*lint -efile(764,permit.h) */
+/*lint -efile(766,permit.h) */
+#include <permit.h> // UAS_MAXGROUP.
+
+// Don't complain about "unneeded" includes of this file:
+/*lint -efile(764,prefix.h) */
+/*lint -efile(766,prefix.h) */
+#include <prefix.h> // PREFIX_ equates.
+
+#define BANG TEXT('!')
+#define MINUS TEXT('-')
+#define SLASH TEXT('/')
+#define NULLC TEXT('\0')
+#define NEWLINE TEXT('\n')
+#define RETURN TEXT('\r')
+
+//FARBUGBUG This is really hacky.
+#define TFORMAT_LPWSTR TEXT(FORMAT_LPWSTR)
+
+//
+// Maximum lengths of user and group names.
+// Lengths are in characters, and don't include trailing nulls.
+//
+#define PORTUAS_MAX_USER_LEN LM20_UNLEN
+//#define PORTUAS_MAX_USER_LEN 8
+
+#define PORTUAS_MAX_GROUP_LEN LM20_GNLEN
+//#define PORTUAS_MAX_GROUP_LEN 8
+
+
+#if DBG
+void PortDeb(CHAR *, ...);
+#define DEBUG_MSG( arglist ) PortDeb arglist
+#else
+#define DEBUG_MSG( arglist )
+#endif
+
+//#define ERROR_MSG( arglist ) (void) WriteToCon arglist
+//#define PROGRESS_MSG( arglist ) (void) WriteToCon arglist
+//#define WARNING_MSG( arglist ) (void) WriteToCon arglist
+
+#if 0
+#define UNEXPECTED_MSG( apiName, retCode ) \
+ ERROR_MSG( (PREFIX_PORTUAS "unexpected return code " FORMAT_API_STATUS \
+ " from API " apiName ".\n", retCode ))
+#endif
+
+#define UNEXPECTED_MSG( apiName, retCode ) \
+ (void) NlsPutMsg(STDOUT, PUAS_UNEXPECTED_RETURN_CODE, retCode, apiName)
+
+ //
+ // Close the various SAM handles (aliases, domain, and connect).
+ //
+#define CLOSE_SAM_HANDLE(globalVar) \
+ { \
+ NET_API_STATUS ApiStatus; \
+ NTSTATUS NtStatus; \
+ if (globalVar != NULL) { \
+ NtStatus = SamCloseHandle( globalVar ); \
+ globalVar = NULL; \
+ if ( !NT_SUCCESS( NtStatus ) ) { \
+ ApiStatus = NetpNtStatusToApiStatus( NtStatus ); \
+ UNEXPECTED_MSG( "SamCloseHandle" #globalVar ")", ApiStatus ); \
+ /* continue closing stuff */ \
+ } \
+ } \
+ }
+
+//
+// Global variables.
+//
+
+extern PSID PortUasAccountsDomainId;
+extern PSID PortUasBuiltinDomainId;
+
+extern SAM_HANDLE PortUasSamConnectHandle;
+extern SAM_HANDLE PortUasSamAccountsDomainHandle;
+extern SAM_HANDLE PortUasSamBuiltinDomainHandle;
+
+extern HANDLE PortUasGlobalLogFileHandle; // Set by PortUasParseCommandLine().
+
+extern LPTSTR PortUasGlobalUserToSkipTo; // Set by PortUasParseCommandLine().
+
+extern BOOL Verbose;
+
+// NLS stuff
+
+#define STDERR 2
+#define STDOUT 1
+
+/*lint -save -e579 */ // Don't complain about unwidened before ...
+USHORT NlsPutMsg(USHORT, USHORT, ... );
+/*lint -restore */
+
+//
+// Error coding.
+//
+
+NET_API_STATUS
+PortUasError(
+ IN NET_API_STATUS Error
+ );
+
+//
+// UAS Read routines.
+//
+
+NET_API_STATUS
+PortUasOpen(
+ IN LPTSTR File
+ );
+
+VOID
+PortUasClose(
+ VOID
+ );
+
+// User modals information.
+
+NET_API_STATUS
+PortUasGetModals(
+ OUT LPUSER_MODALS_INFO_0 * Modals0
+ );
+
+// Group information.
+
+NET_API_STATUS
+PortUasGetGroups(
+ OUT LPBYTE * Buffer,
+ OUT LPBYTE * Gids,
+ OUT LPDWORD Entries
+ );
+
+BOOL
+PortUasIsGroupRedundant(
+ IN LPWSTR GroupName
+ );
+
+
+//
+// User iterator stuff.
+// This stuff is required to hide details of the hash collision buckets from
+// as much code as possible.
+//
+
+typedef struct {
+ DWORD Index; // 0..UAS_USER_HASH_ENTRIES-1: normal.
+ // UAS_USER_HASH_ENTRIES: done.
+ // NULL_INDEX: initial value.
+ DWORD DiskOffset;
+} USER_ITERATOR, *LPUSER_ITERATOR;
+
+#define NULL_DISK_OFFSET 0x00000000
+#define NULL_INDEX 0xFFFFFFFF
+
+// VOID
+// PortUasCopyUserIterator(
+// OUT LPUSER_ITERATOR Dest,
+// IN LPUSER_ITERATOR Src
+// );
+//
+#define PortUasCopyUserIterator( Dest, Src ) \
+ { \
+ (Dest)->Index = (Src)->Index; \
+ (Dest)->DiskOffset = (Src)->DiskOffset; \
+ }
+
+#define PortUasInitUserIterator( It ) \
+ { \
+ It.Index = NULL_INDEX; \
+ It.DiskOffset = NULL_DISK_OFFSET; \
+ }
+
+// BOOL
+// PortUasUserIteratorEqual(
+// IN LPUSER_ITERATOR One,
+// IN LPUSER_ITERATOR TheOther
+// );
+//
+#define PortUasUserIteratorEqual( One, TheOther ) \
+ ( ( ((One)->Index) == ((TheOther)->Index) ) \
+ && ( ((One)->DiskOffset) == ((TheOther)->DiskOffset) ) )
+
+
+//
+// User information.
+//
+
+NET_API_STATUS
+PortUasDecryptLmOwfPwdWithIndex(
+ IN LPVOID EncryptedLmOwfPassword,
+ IN LPDWORD Index,
+ OUT LPVOID LmOwfPassword
+ );
+
+NET_API_STATUS
+PortUasGetUser(
+ IN OUT LPUSER_ITERATOR UserIterator,
+ OUT LPBYTE * Buffer
+ );
+
+NET_API_STATUS
+PortUasGetUserOWFPassword(
+ IN LPUSER_ITERATOR UserIterator,
+ OUT LPBYTE * Password
+ );
+
+NET_API_STATUS
+PortUasGetUserGroups(
+ IN LPUSER_ITERATOR UserIterator,
+ OUT LPBYTE * Buffer,
+ OUT LPBYTE * Gids,
+ OUT LPDWORD Entries
+ );
+
+NET_API_STATUS
+PortUasNameToRid(
+ IN LPCTSTR Name, // may be group or user name
+ IN SID_NAME_USE ExpectedType,
+ OUT PULONG UserRid
+ );
+
+NET_API_STATUS
+PortUasSetMacPrimaryGroup(
+ IN LPCTSTR UserName,
+ IN LPCTSTR MacPrimaryField // field in "mGroup:junk" format.
+ );
+
+VOID
+DumpPassword(
+ // LPTSTR Tag,
+ IN USHORT Tag,
+ IN LPBYTE Password OPTIONAL
+ );
+
+VOID
+DumpUserInfo(
+ IN LPUSER_INFO_22 user
+ );
+
+//
+// PortUAS name mapping layer.
+//
+
+typedef struct {
+ LPWSTR OldName;
+ LPWSTR NewName; // May be NULL (if this is to be ignored).
+} MAP_ENTRY, *PMAP_ENTRY, *LPMAP_ENTRY;
+
+NET_API_STATUS
+PortUasMapTableInit(
+ VOID
+ );
+
+// Return NO_ERROR and *MapEntry=NULL if not found.
+NET_API_STATUS
+PortUasFindMapEntry(
+ IN LPWSTR NameToFind,
+ OUT BOOL * IgnoreThis OPTIONAL,
+ OUT LPMAP_ENTRY * MapEntry // Do NOT free this!
+ );
+
+NET_API_STATUS
+PortUasFindOrCreateMapEntry(
+ IN LPWSTR OldName,
+ IN BOOL ThisIsUserName, // TRUE for user name, FALSE for group name.
+ IN DWORD Reason, // REASON_ equates from PortUAS.h
+ OUT BOOL * IgnoreThis,
+ OUT LPMAP_ENTRY * MapEntry // Do NOT free this!
+ );
+
+NET_API_STATUS
+PortUasDeleteBadMapEntry(
+ IN LPMAP_ENTRY Entry
+ );
+
+NET_API_STATUS
+PortUasFreeMapTable(
+ VOID
+ );
+
+VOID
+PortUasDbgDisplayMapTable(
+ VOID
+ );
+
+VOID
+PortUasDbgDisplayMapEntry(
+ IN LPMAP_ENTRY Entry
+ );
+
+//
+// Complain to admin about a bad user or group name.
+//
+NET_API_STATUS
+PortUasComplainAboutBadName(
+ IN LPWSTR OldName,
+ IN BOOL ThisIsUserName, // TRUE for user name, FALSE for group name
+ IN DWORD Reason // REASON_ equates from PortUAS.h
+ );
+
+//
+// Prompt for new (user or group) name routine.
+//
+
+NET_API_STATUS
+PortUasDefaultPromptForNewName(
+ IN LPWSTR OldName,
+ IN BOOL ThisIsUserName, // TRUE for user name, FALSE for group name
+ IN DWORD Reason, // REASON_ equates from PortUAS.h
+ OUT LPWSTR * NewName, // alloc w/ NetApiBufferAllocate().
+ OUT BOOL * IgnoreThis,
+ OUT BOOL * ForceIgnoreFromNowOn
+ );
+
+//
+// Are updates to security allowed on this machine?
+// (We can't update a Backup Domain Controller directly.)
+// Expected returns: NERR_NotPrimary, ERROR_ACCESS_DENIED, or NO_ERROR.
+//
+NET_API_STATUS
+PortUasMachineAllowsUpdates(
+ VOID
+ );
+
+//
+// Command-line parsing routine (optional use).
+//
+
+LPTSTR // Returns file name. Does not return on error.
+PortUasParseCommandLine(
+ IN int argc,
+ IN char *argv[]
+ );
+
+//
+// Alias-handling routines.
+//
+
+NET_API_STATUS
+PortUasAliasSetup(
+ VOID
+ );
+
+NET_API_STATUS
+PortUasAddUserToAliases(
+ IN LPCWSTR UserName,
+ IN DWORD Priv, // USER_PRIV_ values from lmaccess.h
+ IN DWORD AuthFlags // AF_ values from lmaccess.h
+ );
+
+NET_API_STATUS
+PortUasAliasCleanup(
+ VOID
+ );
+
+//
+// Log file routines (see LogFile.c)...
+//
+
+NET_API_STATUS
+PortUasOpenLogFile(
+ IN LPCTSTR FileName,
+ OUT LPHANDLE ResultHandle
+ );
+
+NET_API_STATUS
+PortUasWriteToLogFile(
+ IN HANDLE LogFileHandle,
+ IN LPCTSTR TextToLog
+ );
+
+NET_API_STATUS
+PortUasCloseLogFile(
+ IN HANDLE LogFileHandle
+ );
+
+
+INT
+WriteToCon(
+ TCHAR*fmt, ...
+ );
+#endif // _PORTUASP_
diff --git a/private/net/portuas/prompt.c b/private/net/portuas/prompt.c
new file mode 100644
index 000000000..6a0371605
--- /dev/null
+++ b/private/net/portuas/prompt.c
@@ -0,0 +1,771 @@
+/*++
+
+Copyright (c) 1992-1993 Microsoft Corporation
+
+Module Name:
+
+ Prompt.c
+
+Abstract:
+
+ PortUasDefaultPromptForNewName.
+
+Author:
+
+ John Rogers (JohnRo) 29-Oct-1992
+
+Environment:
+
+ Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
+ Requires that sizeof(DWORD) >= sizeof(pointer) (for FormatMessageW).
+ Requires ANSI C extensions: slash-slash comments, long external names.
+
+Revision History:
+
+ 29-Oct-1992 JohnRo
+ Created for RAID 9020: setup: PortUas fails ("prompt on conflicts"
+ version).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+ 30-Jul-1993 JohnRo
+ RAID NTISSUE 2260: PortUAS returns a NetUserAdd error=1379 with local
+ group.
+ Do a little checking on values set by FormatMessageA().
+ Made changes suggested by PC-LINT 5.0
+ 24-Aug-1993 JohnRo
+ RAID 2822: PortUAS maps chars funny. (Work around FormatMessageA bug.)
+ 01-Sep-1993 JohnRo
+ Add PortUAS /log:filename switch for Cheetah.
+ PC-LINT found a bug: PUAS_GROUP_EXISTS_AS_A_LOCALGROUP wasn't used yet.
+ Fix output intended to stderr.
+ Made more changes suggested by PC-LINT 5.0
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h> // IN, LPWSTR, BOOL, etc.
+#include <lmcons.h> // NET_API_STATUS, UNLEN, GNLEN.
+
+// These may be included in any order:
+
+#include <lmapibuf.h>
+#include <names.h> // NetpIsUserNameValid(), etc.
+#include <netdebug.h> // NetpAssert(), FORMAT_ equates, etc.
+#include <netlib.h> // NetpErrNoToApiStatus(), MAX_NETLIB_MESSAGE_ARG, etc.
+//#include <io.h> // write
+#include <stdarg.h> // va_list, va_start(), va_end(), va_arg().
+#include <stdio.h> // feof(), ferror(), printf(), stdin, etc.
+#include <portuas.h> // REASON_ equates.
+#include <portuasp.h> // My prototype, Verbose.
+#include <tstring.h> // NetpAllocWStrFromWStr().
+#include <tchar.h> // iswdigit(), wcsncmp(), etc.
+#include <winerror.h> // ERROR_ equates, NO_ERROR.
+
+#include "nlstxt.h" // NLS message ID's.
+
+extern TCHAR ConBuf[];
+extern int MyWriteConsole(int fOutOrErr, int cch);
+extern int FileIsConsole(HANDLE fh);
+
+//
+// Globals (may also be set by PortUasParseCommandLine):
+//
+
+HANDLE PortUasGlobalLogFileHandle = INVALID_HANDLE_VALUE;
+
+
+/*** NlsPutMsg - Print a message to a handle
+ *
+ * Purpose:
+ * PutMsg takes the given message number from the
+ * message table resource, and displays it on the requested
+ * handle with the given parameters (optional)
+ *
+ * unsigned PutMsg(unsigned Handle, unsigned MsgNum, ... )
+ *
+ * Args:
+ * Handle - the handle to print to (must be STDOUT or STDERR)
+ * MsgNum - the number of the message to print
+ * Arg1 [Arg2...] - additonal arguments for the message as necessary
+ *
+ * Returns:
+ * The number of characters printed.
+ *
+ */
+
+/*lint -save -e579 */ // Don't complain about unwidened before ...
+USHORT NlsPutMsg(USHORT Handle, USHORT usMsgNum, ... )
+{
+ LPTSTR AllocatedStrings[ MAX_NETLIB_MESSAGE_ARG+1 ]; // 0 unused.
+ NET_API_STATUS ApiStatus;
+ va_list arglist;
+ BOOL ArgListInUse = FALSE;
+ LPWSTR FormattedOutput = NULL;
+ DWORD Index;
+ DWORD ModifiedArgs[ MAX_NETLIB_MESSAGE_ARG+1 ]; // 0 ignored.
+ DWORD msglen;
+ LPSTR NarrowFormat = NULL;
+ LPWSTR UnicodeFormat = NULL; // Unicode format, modified as we go.
+
+ NetpAssert( (Handle == STDOUT) || (Handle == STDERR) );
+
+ va_start(arglist, usMsgNum);
+ ArgListInUse = TRUE;
+
+ for (Index=0; Index <= MAX_NETLIB_MESSAGE_ARG; ++Index) {
+ AllocatedStrings[Index] = NULL;
+ }
+
+ //
+ // As of this writing (19-Aug-1993), there is a bug below FormatMessageA(),
+ // where the "Unicode-to-ANSI translation" just truncates Unicode chars to
+ // 8 bits. So, we need to avoid that by using FormatMessageA to get the
+ // message, convert it to Unicode, and use FormatMessageW to do the actual
+ // formatting.
+ //
+ // Get the format string (as NarrowFormat).
+ //
+
+ msglen = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_HMODULE,
+ NULL, // source
+ usMsgNum,
+ (DWORD) 0, // Default country ID.
+ (LPVOID) &NarrowFormat, // Alloc and set pointer.
+ 0,
+ &arglist );
+
+ if (msglen == 0) {
+ ApiStatus = GetLastError();
+ (VOID) WriteToCon(
+ TEXT("PortUAS.exe: FormatMessageA failed: ") TEXT(FORMAT_API_STATUS) TEXT("\n"),
+ ApiStatus );
+ NetpAssert( ApiStatus != NO_ERROR );
+ goto Cleanup;
+ }
+
+ NetpAssert( NarrowFormat != NULL );
+ if (NarrowFormat == NULL) {
+ msglen = 0;
+ goto Cleanup;
+ }
+
+ //
+ // OK, Now convert the format string to Unicode.
+ // We'll modify the Unicode format string (in place) below...
+ //
+
+ UnicodeFormat = NetpAllocWStrFromStr( NarrowFormat );
+ if (UnicodeFormat == NULL) {
+ // Rats, probably ran out of memory. Well, we tried.
+ msglen = 0;
+ goto Cleanup;
+ }
+
+ //
+ // FormatMessageA() just walked the va_list. We're going to walk it
+ // again, looking for args to convert. So, tell C runtime...
+ //
+
+ NetpAssert( ArgListInUse );
+ va_end(arglist);
+ va_start(arglist, usMsgNum);
+
+ //
+ // For each numbered arg (1..MAX_NETLIB_MESSAGE_ARG), perhaps modify UnicodeFormat in
+ // place and come up with a narrow string for its arg. For other args,
+ // just copy from va_list format to an array we can pass to
+ // FormatMessageW().
+ //
+ // Things we handle:
+ // %1!lu!
+ // %2
+ // %5!08lX!
+ // %16!ws!
+ //
+
+ for (Index=1; Index <= MAX_NETLIB_MESSAGE_ARG; ++Index) {
+ LPWSTR ThisFormat;
+
+ ThisFormat = (LPWSTR) NetpFindNumberedFormatInWStr(
+ UnicodeFormat,
+ Index ); // Arg number (1=first).
+ if (ThisFormat == NULL) {
+ break; // Just last numbered arg (if any).
+ }
+
+ NetpAssert( ThisFormat[0] == L'%' );
+ NetpAssert( ThisFormat[1] != L'0' ); // Leading zero would confuse.
+ NetpAssert( iswdigit( ThisFormat[1] ) );
+ NetpAssert( wcslen( ThisFormat ) >= 2 ); // At least "%1".
+
+ // Skip "%1" or "%16"...
+ ++ThisFormat; // Skip percent sign.
+ NetpSkipWDigits( ThisFormat );
+
+ // Parse format itself.
+ if (ThisFormat[0] == L'!') {
+ ++ThisFormat; // Skip leading BANG.
+
+ // Skip possible leading digits in "08lX"...
+ NetpSkipWDigits( ThisFormat );
+
+ if ( wcsncmp( ThisFormat, (LPWSTR) L"ws", 2 ) == 0 ) {
+
+ LPWSTR OriginalArg;
+ OriginalArg = va_arg( arglist, LPWSTR );
+ AllocatedStrings[ Index ] = OriginalArg;
+
+ // Modify format AND arg for this one.
+ ThisFormat[0] = TEXT('h');
+ ModifiedArgs[ Index ] = (DWORD) AllocatedStrings[ Index ];
+ ThisFormat += 2; // Skip "hs".
+
+ } else if ( ThisFormat[0] == TEXT('l') ) {
+
+ DWORD TempDword;
+ if ( wcsncmp( ThisFormat, (LPWSTR) L"lu", 2 ) == 0 ) {
+ TempDword = va_arg( arglist, DWORD );
+ ModifiedArgs[ Index ] = TempDword;
+ } else if ( wcsncmp( ThisFormat, (LPWSTR) L"lX", 2 ) == 0 ) {
+ TempDword = va_arg( arglist, DWORD );
+ ModifiedArgs[ Index ] = TempDword;
+ } else if ( wcsncmp( ThisFormat, (LPWSTR) L"lx", 2 ) == 0 ) {
+ TempDword = va_arg( arglist, DWORD );
+ ModifiedArgs[ Index ] = TempDword;
+ } else {
+ NetpAssert( FALSE );
+ msglen = 0;
+ goto Cleanup;
+ }
+ ThisFormat += 2; // Skip "lu", etc.
+ } else if ( wcsncmp( ThisFormat, (LPWSTR) L"s", 1 ) == 0 ) {
+ LPTSTR OriginalArg = va_arg( arglist, LPTSTR );
+ //FARBUGBUG '%s' is Unicode to FormatMessageW.
+ ModifiedArgs[ Index ] = (DWORD) OriginalArg;
+ ThisFormat += 1; // Skip "s", etc.
+ } else if ( wcsncmp( ThisFormat, (LPWSTR) L"hs", 2 ) == 0 ) {
+ LPTSTR OriginalArg = va_arg( arglist, LPTSTR );
+ ModifiedArgs[ Index ] = (DWORD) OriginalArg;
+ ThisFormat += 2; // Skip "hs", etc.
+ } else {
+ NetpAssert( FALSE );
+ msglen = 0;
+ goto Cleanup;
+ }
+
+ // Must be to trailing BANG here.
+ NetpAssert( L'!' == *ThisFormat );
+ if (*ThisFormat != BANG) {
+ msglen = 0;
+ goto Cleanup;
+ }
+ ++ThisFormat; // Skip trailing BANG
+ } else {
+ //FARBUGBUG '%s' is Unicode to FormatMessageW.
+ LPTSTR OriginalArg = va_arg( arglist, LPTSTR );
+ ModifiedArgs[ Index ] = (DWORD) OriginalArg;
+ ThisFormat += 1; // Skip "s", etc.
+ }
+ }
+
+ //
+ // Use modified Unicode format string and modified args, to format the
+ // message.
+ //
+
+ msglen = FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ UnicodeFormat, // source of format string
+ usMsgNum,
+ (DWORD) 0, // Default country ID.
+ (LPVOID) &FormattedOutput, // Alloc and set pointer.
+ 0,
+ (LPVOID) &ModifiedArgs[1] ); // Array of 32-bit args.
+ if (msglen == 0) {
+ ApiStatus = GetLastError();
+ (VOID) WriteToCon(
+ TEXT("PortUAS.exe: FormatMessageW failed: ") TEXT(FORMAT_API_STATUS) TEXT("\n"),
+ ApiStatus );
+ NetpAssert( ApiStatus != NO_ERROR );
+ // BUGBUG: Event log this?
+ goto Cleanup;
+ }
+
+ NetpAssert( FormattedOutput != NULL );
+ if (FormattedOutput == NULL) {
+ msglen = 0;
+ goto Cleanup;
+ }
+
+ //
+ // Print the message.
+ //
+
+ {
+ if (Handle == STDOUT) {
+ msglen = WriteToCon(TFORMAT_LPWSTR, FormattedOutput);
+ } else {
+ msglen = _stprintf( ConBuf, TFORMAT_LPWSTR, FormattedOutput);
+ if (msglen >= 0)
+ msglen = MyWriteConsole(STDERR, msglen);
+ else
+ msglen = 0;
+ }
+ }
+ if ( msglen == ((USHORT)-1) ) {
+ msglen = 0;
+ }
+
+ //
+ // If we're logging stuff, then log a copy of this message too.
+ //
+
+ if (PortUasGlobalLogFileHandle != INVALID_HANDLE_VALUE) {
+ ApiStatus = PortUasWriteToLogFile(
+ PortUasGlobalLogFileHandle,
+ (LPCTSTR) FormattedOutput );
+ if (ApiStatus != NO_ERROR) {
+ msglen = 0;
+ }
+ }
+
+Cleanup:
+
+ if (msglen == 0) {
+ // BUGBUG: event log this?
+ (VOID) WriteToCon( TEXT("PortUAS.exe: UNEXPECTED ERROR.\n") );
+ }
+
+ for (Index=0; Index<=MAX_NETLIB_MESSAGE_ARG; ++Index) {
+ if (AllocatedStrings[Index] != NULL) {
+ (VOID) NetApiBufferFree( AllocatedStrings[Index] );
+ }
+ }
+
+ if (FormattedOutput != NULL) {
+ (VOID) LocalFree( FormattedOutput );
+ }
+ if (NarrowFormat != NULL) {
+ (VOID) LocalFree( NarrowFormat );
+ }
+ if (UnicodeFormat != NULL) {
+ (VOID) LocalFree( UnicodeFormat );
+ }
+ if (ArgListInUse) {
+ va_end(arglist);
+ }
+ return( (USHORT) msglen);
+}
+/*lint -restore */
+
+
+DBGSTATIC NET_API_STATUS
+PortUasGetString(
+ OUT LPWSTR BufferW,
+ IN DWORD BufLenW // number of chars for string and NULLC.
+ )
+{
+ NET_API_STATUS ApiStatus;
+ char * BufferA = NULL;
+ DWORD BufLenA = BufLenW + 1; // room for str, \n, \0
+ char * NewLine;
+ char * Result;
+
+ NetpAssert( BufferW != NULL );
+ NetpAssert( BufLenW > 0 );
+
+ if (FileIsConsole(GetStdHandle(STD_INPUT_HANDLE))) {
+ ApiStatus = ReadConsole(GetStdHandle(STD_INPUT_HANDLE),
+ BufferW, BufLenW, &BufLenA, 0);
+ if (ApiStatus) {
+ //
+ // Get rid of cr/lf
+ //
+ if (wcschr(BufferW, RETURN) == NULL) {
+ if (wcschr(BufferW, NEWLINE))
+ *wcschr(BufferW, NEWLINE) = NULLC;
+ }
+ else
+ *wcschr(BufferW, RETURN) = NULLC;
+ ApiStatus = NO_ERROR;
+ goto Cleanup;
+ }
+ else {
+ ApiStatus = GetLastError();
+ }
+ }
+
+ //
+ // Allocate an 8-bit version.
+ //
+ ApiStatus = NetApiBufferAllocate(
+ BufLenA, // byte count
+ (LPVOID *) (LPVOID) & BufferA);
+ if (ApiStatus != NO_ERROR) {
+ NetpAssert( BufferA == NULL );
+ goto Cleanup;
+ } else {
+ NetpAssert( BufferA != NULL );
+ }
+
+ //
+ // Read user's input (from stdin).
+ // fgets will return a buffer of the form "flarp\n\0".
+ //
+ Result = fgets(
+ BufferA,
+ (int) BufLenA,
+ stdin);
+
+ //
+ // Check for end of file or error.
+ //
+ if (Result == NULL) {
+ if (ferror(stdin)) {
+ ApiStatus = NetpErrNoToApiStatus( errno );
+ NetpAssert( ApiStatus != NO_ERROR );
+ goto Cleanup;
+ } else {
+ NetpAssert( feof(stdin) );
+ ApiStatus = ERROR_HANDLE_EOF;
+ goto Cleanup;
+ }
+ }
+
+ //
+ // Make sure string isn't too long, and get rid of newline.
+ //
+ NewLine = strchr( BufferA, '\n');
+ if (NewLine == NULL) {
+ ApiStatus = ERROR_INVALID_DATA; // string was too long.
+ goto Cleanup;
+ }
+
+ NetpAssert( *(NewLine+1) == '\0' );
+ *NewLine = '\0';
+
+ //
+ // copy and convert to UNICODE.
+ //
+ NetpCopyStrToWStr(
+ BufferW, // dest: unicode
+ (LPVOID) BufferA ); // src: string in default LAN codepage
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+ if (BufferA != NULL) {
+ (VOID) NetApiBufferFree( BufferA );
+ }
+ if (Verbose) {
+ if (ApiStatus==NO_ERROR) {
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasGetString: "
+ " output string is '" FORMAT_LPWSTR "'.\n", BufferW ));
+ }
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasGetString: "
+ " returning status " FORMAT_API_STATUS ".\n", ApiStatus ));
+ }
+ return (ApiStatus);
+
+} // PortUasGetString
+
+
+NET_API_STATUS
+PortUasComplainAboutBadName(
+ IN LPWSTR OldName,
+ IN BOOL ThisIsUserName, // TRUE for user name, FALSE for group name
+ IN DWORD Reason // REASON_ equates from PortUAS.h
+ )
+{
+ NET_API_STATUS ApiStatus;
+ //LPTSTR ReasonText = NULL;
+ USHORT ReasonText = 0;
+
+ //
+ // Come up with reason text (WriteToCon format string).
+ //
+ switch (Reason) {
+ case REASON_BAD_NAME_SYNTAX:
+ //ReasonText = "bad name syntax '" FORMAT_LPWSTR "'";
+ ReasonText = PUAS_BAD_NAME_SYNTAX;
+ break;
+
+ case REASON_CONFLICT_WITH_DOMAIN:
+ //ReasonText = "name '" FORMAT_LPWSTR "' conflicts with a domain name";
+ ReasonText = PUAS_NAME_CONFLICTS_WITH_A_DOMAIN_NAME;
+ break;
+
+ case REASON_CONFLICT_WITH_GROUP:
+ //ReasonText = "User '" FORMAT_LPWSTR "' exists as a group";
+ ReasonText = PUAS_USER_EXISTS_AS_A_GROUP;
+ break;
+
+ case REASON_CONFLICT_WITH_USERNAME:
+ //ReasonText = "group '" FORMAT_LPWSTR "' exists as a user";
+ ReasonText = PUAS_GROUP_EXISTS_AS_A_USER;
+ break;
+
+#ifdef FAT8
+ case REASON_NAME_LONG_FOR_TEMP_REG:
+ //ReasonText = "group '" FORMAT_LPWSTR "' name too long.";
+ ReasonText = PUAS_GROUP_NAME_TOO_LONG;
+ break;
+#endif
+
+ case REASON_CONFLICT_WITH_LOCALGROUP:
+ if (ThisIsUserName) {
+ //ReasonText = "User '" FORMAT_LPWSTR "' exists as a local group";
+ ReasonText = PUAS_USER_EXISTS_AS_A_LOCALGROUP;
+ } else {
+ ReasonText = PUAS_GROUP_EXISTS_AS_A_LOCALGROUP;
+ }
+ break;
+
+ default:
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasComplainAboutBadName: "
+ "got invalid value " FORMAT_DWORD " for reason.\n",
+ Reason ));
+ ApiStatus = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+ //NetpAssert( ReasonText != NULL );
+ NetpAssert( ReasonText != 0 );
+
+ //(VOID) WriteToCon( TEXT("\n\n*** Bad %s name *** "),
+ // ( ThisIsUserName ? TEXT("user") : TEXT("group") ) );
+ if (ThisIsUserName) {
+ (VOID) NlsPutMsg(STDOUT, PUAS_BAD_USER_NAME);
+ }
+ else {
+ (VOID) NlsPutMsg(STDOUT, PUAS_BAD_GROUP_NAME);
+ }
+ //(VOID) WriteToCon( ReasonText, OldName );
+ (VOID)NlsPutMsg(STDOUT, ReasonText, OldName);
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+ return (ApiStatus);
+}
+
+DBGSTATIC BOOL
+IsCharInString (
+ IN WCHAR wch,
+ IN WCHAR * wszString
+ )
+{
+ WCHAR * wszTemp = wszString;
+
+ while (*wszTemp != (WCHAR)NULLC) {
+ if (*wszTemp == wch) {
+ return(TRUE);
+ }
+ ++wszTemp;
+ }
+ return(FALSE);
+}
+
+NET_API_STATUS
+PortUasDefaultPromptForNewName(
+ IN LPWSTR OldName,
+ IN BOOL ThisIsUserName, // TRUE for user name, FALSE for group name
+ IN DWORD Reason, // REASON_ equates from PortUAS.h
+ OUT LPWSTR * NewName, // alloc w/ NetApiBufferAllocate().
+ OUT BOOL * IgnoreThis,
+ OUT BOOL * ForceIgnoreFromNowOn
+ )
+{
+ NET_API_STATUS ApiStatus;
+ WCHAR Flag[3];
+ LPWSTR NameToComplainAbout = OldName; // OldName first time, but...
+ WCHAR TempName[UNLEN+2]; // space for user name or group name
+
+ static WCHAR * szYesNoForceChars[3] = {NULL, NULL, NULL}; // 0(Yes), 1(No), 2(Force)
+ UINT i;
+ BOOL Valid;
+
+ // Get the localised yes, no and force characters.
+
+ // IMPORTANT!!! Yes, No, and Force characters must be
+ // stored in sequentially-numbered messages in
+ // the MSGTABLE resource!
+
+ for (i=0; i<=2; ++i) {
+ if (szYesNoForceChars[i] == NULL) {
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_HMODULE,
+ NULL,
+ (PUAS_YES_CHARS + i),
+ 0L, // Default country ID.
+ (LPTSTR)&(szYesNoForceChars[i]),
+ 0,
+ NULL ) == 0) {
+
+ UNEXPECTED_MSG( "FormatMessage", GetLastError() );
+ }
+ }
+ }
+
+ NetpAssert( OldName != NULL );
+ NetpAssert( (ThisIsUserName==TRUE) || (ThisIsUserName==FALSE) );
+ NetpAssert( NewName != NULL );
+ NetpAssert( IgnoreThis != NULL );
+ NetpAssert( ForceIgnoreFromNowOn != NULL );
+ NetpAssert( UNLEN >= GNLEN ); // Make TempName larger if this fails.
+
+ *NewName = NULL; // don't confuse caller on error.
+
+ Valid = FALSE;
+ while ( !Valid ) {
+
+ //
+ // Explain what's wrong...
+ //
+ ApiStatus = PortUasComplainAboutBadName(
+ OldName,
+ ThisIsUserName,
+ Reason );
+ if (ApiStatus != NO_ERROR) {
+ UNEXPECTED_MSG( "PortUasComplainAboutBadName", ApiStatus );
+ goto Cleanup;
+ }
+
+ //
+ // Prompt explaining what's wrong and what they can do...
+ //
+ //(VOID) WriteToCon(
+ // TEXT("\n")
+ // TEXT("Do you want to enter a new name?\n")
+ // TEXT("Enter Y for yes, N to ignore this name, or F to force ")
+ // TEXT("ignore from now on.\n") );
+ (VOID)NlsPutMsg(STDOUT, PUAS_DO_YOU_WANT_A_NEW_NAME);
+
+ ApiStatus = PortUasGetString( Flag, 3 ); // get str (max 1 char & nul)
+ switch (ApiStatus) {
+ case NO_ERROR:
+ break;
+
+ case ERROR_INVALID_DATA: // Name too long gets this.
+ Valid = FALSE;
+ continue; // loop again.
+
+ case ERROR_HANDLE_EOF:
+ *IgnoreThis = TRUE;
+ *ForceIgnoreFromNowOn = TRUE;
+ ApiStatus = NO_ERROR;
+ goto Cleanup;
+
+ default:
+ UNEXPECTED_MSG( "PortUasGetString(flag)", ApiStatus );
+ goto Cleanup;
+ }
+
+ NetpAssert( ApiStatus == NO_ERROR );
+
+ //switch (Flag[0]) {
+ //
+ //case TEXT('Y'): /*FALLTHROUGH*/
+ //case TEXT('y'):
+ if (IsCharInString(Flag[0],szYesNoForceChars[0]))
+ {
+ //(VOID) WriteToCon( TEXT("Enter a new name:\n") );
+ (VOID)NlsPutMsg(STDOUT, PUAS_ENTER_A_NEW_NAME);
+
+ ApiStatus = PortUasGetString( TempName, UNLEN+2 );
+
+ switch (ApiStatus) {
+ case NO_ERROR:
+ break;
+
+ case ERROR_INVALID_DATA: // Name too long gets this.
+ NameToComplainAbout = TempName;
+ Reason = REASON_BAD_NAME_SYNTAX;
+ Valid = FALSE;
+ continue; // Loop again.
+
+ case ERROR_HANDLE_EOF:
+ *IgnoreThis = TRUE;
+ *ForceIgnoreFromNowOn = TRUE;
+ ApiStatus = NO_ERROR;
+ goto Cleanup;
+
+ default:
+ UNEXPECTED_MSG( "PortUasGetString(name)", ApiStatus );
+ goto Cleanup;
+ }
+
+ if (TempName[0] == NULLC) {
+ NameToComplainAbout = TempName;
+ Reason = REASON_BAD_NAME_SYNTAX;
+ Valid = FALSE;
+ continue; // Loop again.
+ }
+
+ if (ThisIsUserName) {
+ if ( !NetpIsUserNameValid( TempName ) ) {
+ NameToComplainAbout = TempName;
+ Reason = REASON_BAD_NAME_SYNTAX;
+ Valid = FALSE;
+ continue; // Loop again.
+ }
+ } else {
+ if ( !NetpIsGroupNameValid( TempName ) ) {
+ NameToComplainAbout = TempName;
+ Reason = REASON_BAD_NAME_SYNTAX;
+ Valid = FALSE;
+ continue; // Loop again.
+ }
+ }
+
+ Valid = TRUE;
+ *IgnoreThis = FALSE;
+ *ForceIgnoreFromNowOn = FALSE;
+
+ *NewName = NetpAllocWStrFromWStr( TempName );
+ if (*NewName == NULL) {
+ ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ break;
+ }
+ //case TEXT('N'): /*FALLTHROUGH*/
+ //case TEXT('n'):
+ else if (IsCharInString(Flag[0],szYesNoForceChars[1]))
+ {
+ Valid = TRUE;
+ *IgnoreThis = TRUE;
+ *ForceIgnoreFromNowOn = FALSE;
+ break;
+ }
+ //case TEXT('F'): /*FALLTHROUGH*/
+ //case TEXT('f'):
+ else if (IsCharInString(Flag[0],szYesNoForceChars[2]))
+ {
+ Valid = TRUE;
+ *IgnoreThis = TRUE;
+ *ForceIgnoreFromNowOn = TRUE;
+ break;
+ }
+ //default: // Handle empty string here.
+ else
+ {
+ Valid = FALSE; // Repeat prompt for flag and ask again.
+ }
+
+ } // while !Valid
+
+Cleanup:
+
+ return (ApiStatus);
+
+} // PortUasDefaultPromptForNewName
diff --git a/private/net/portuas/puasmsg.h b/private/net/portuas/puasmsg.h
new file mode 100644
index 000000000..0d6025f88
--- /dev/null
+++ b/private/net/portuas/puasmsg.h
@@ -0,0 +1,334 @@
+#define PUAS_BASE 10000 /* PUAS Messages start here */
+
+#define PUAS_UNEXPECTED_RETURN_CODE (PUAS_BASE + 0)
+ /*
+ *Unexpected return code %1!lu! from API %2!hs!.
+ */
+
+#define PUAS_PORTUAS_RETURNED (PUAS_BASE + 1)
+ /*
+ *PortUAS returned - %1!lu!. More information about this and other
+ *error codes greater than 2100 may be available by typing
+ *NET HELPMSG %2!lu! at the command prompt. A zero indicates that
+ *no errors were detected when the database was converted.
+ */
+
+#define PUAS_UNEXPECTED_PRODUCT_TYPE (PUAS_BASE + 2)
+ /*
+ *Unexpected product type %1!lu!.
+ */
+
+#define PUAS_ADDING_USER_TO_ADMINS_GLOBAL_GROUP (PUAS_BASE + 3)
+ /*
+ *Adding user %1!s! to Domain Admins global group...
+ */
+
+#define PUAS_ADDING_USER_TO_ADMINS_LOCAL_GROUP (PUAS_BASE + 4)
+ /*
+ *Adding user %1!s! to Administrators local group...
+ */
+
+#define PUAS_ADDING_USER_TO_ACCT_OPS_ALIAS (PUAS_BASE + 5)
+ /*
+ *Adding user %1!s! to Account Operators local group...
+ */
+
+#define PUAS_ADDING_USER_TO_COMM_OPS_ALIAS (PUAS_BASE + 6)
+ /*
+ *Adding user %1!s! to Communication Operators local group...
+ */
+
+#define PUAS_IGNORING_COMM_OPERATOR_FLAG (PUAS_BASE + 7)
+ /*
+ *Ignoring the commumication operator flag for user %1!s!...
+ */
+
+#define PUAS_ADDING_USER_TO_PRINT_ALIAS (PUAS_BASE + 8)
+ /*
+ *Adding user %1!s! to Print Operators local group...
+ */
+
+#define PUAS_ADDING_USER_TO_SRV_OPS_ALIAS (PUAS_BASE + 9)
+ /*
+ *Adding user %1!s! to Server Operators local group...
+ */
+
+#define PUAS_PROCESSED_OR_SKIPPED_USERS_OF_TOTAL (PUAS_BASE + 10)
+ /*
+ *Processed or skipped %1!lu! users out of %2!lu! total users.
+ */
+
+#define PUAS_READING_USER_OF_TOTAL (PUAS_BASE + 11)
+ /*
+ *Reading user %1!lu! of %2!lu!...
+ */
+
+#define PUAS_SKIPPING_USER (PUAS_BASE + 12)
+ /*
+ *Skipping user %1!hs!...
+ */
+
+#define PUAS_BAD_NAME_SYNTAX (PUAS_BASE + 13)
+ /*
+ *invalid name syntax '%1!s!'%0
+ */
+
+#define PUAS_NAME_CONFLICTS_WITH_A_DOMAIN_NAME (PUAS_BASE + 14)
+ /*
+ *name '%1!s!' conflicts with a domain name%0
+ */
+
+#define PUAS_USER_EXISTS_AS_A_GROUP (PUAS_BASE + 15)
+ /*
+ *user '%1!s!' already exists as a global group name in the Windows NT
+ *security database%0
+ */
+
+#define PUAS_GROUP_EXISTS_AS_A_USER (PUAS_BASE + 16)
+ /*
+ *group '%1!s!' is already used as a user name in the Windows NT
+ *security database%0
+ */
+
+#define PUAS_GROUP_NAME_TOO_LONG (PUAS_BASE + 17)
+ /*
+ *group name '%1!s!' is too long%0
+ */
+
+#define PUAS_BAD_USER_NAME (PUAS_BASE + 18)
+ /*
+ *
+ *
+ **** Bad user name *** %0
+ */
+
+#define PUAS_BAD_GROUP_NAME (PUAS_BASE + 19)
+ /*
+ *
+ *
+ **** Bad group name *** %0
+ */
+
+#define PUAS_DO_YOU_WANT_A_NEW_NAME (PUAS_BASE + 20)
+ /*
+ *
+ *Do you want to enter a new name?
+ *Enter Y for yes, N to ignore this name,
+ *or F to force ignore all invalid names from now on.
+ */
+
+#define PUAS_YES_CHARS (PUAS_BASE + 21)
+ /*
+ *Yy%0
+ */
+
+#define PUAS_NO_CHARS (PUAS_BASE + 22)
+ /*
+ *Nn%0
+ */
+
+#define PUAS_FORCE_CHARS (PUAS_BASE + 23)
+ /*
+ *Ff%0
+ */
+
+#define PUAS_ENTER_A_NEW_NAME (PUAS_BASE + 24)
+ /*
+ *Enter a new name:
+ */
+
+#define PUAS_USAGE (PUAS_BASE + 25)
+ /*
+ *Usage: %1!s! [/v] [/codepage codepage] /f filename
+ * [/log filename] [/u username]
+ *where
+ * /v indicates verbose mode.
+ * /codepage codepage is the OEM codepage the UAS is in.
+ * /f filename is the name of the UAS.
+ * /log filename specifies a file to log results.
+ * /u username specifies the user to port.
+ *
+ *Options may begin with either '-' or '/'.
+ */
+
+#define PUAS_BAR (PUAS_BASE + 26)
+ /*
+ *========================================
+ */
+
+#define PUAS_USER_STATS_1 (PUAS_BASE + 27)
+ /*
+ * Name: '%1!s!'
+ */
+
+#define PUAS_NAME_TOO_LONG (PUAS_BASE + 28)
+ /*
+ **** NAME TOO LONG! ***
+ */
+
+#define PUAS_PASSWORD (PUAS_BASE + 29)
+ /*
+ * Password:
+ */
+
+#define PUAS_USER_STATS_2 (PUAS_BASE + 30)
+ /*
+ * Password age: %1!lu!
+ * Privilege: %2!lu!
+ * Home directory: '%3!s!'
+ * Comment: '%4!s!'
+ * Flags: %5!08lX!
+ * Script path: '%6!s!'
+ * Authorization flags: %7!08lX!
+ * Full name: '%8!s!'
+ * User comment: '%9!s!'
+ * Parameters: '%10!s!'
+ * Workstations: '%11!s!'
+ * Last logon: %12!lu!
+ * Last logoff: %13!lu!
+ * Account expires: %14!lu!
+ * Maximum storage: %15!lu!
+ * Units per week: %16!lu!
+ */
+
+#define PUAS_USER_STATS_3 (PUAS_BASE + 31)
+ /*
+ * Logon hours:%0
+ */
+
+#define PUAS_USER_STATS_4 (PUAS_BASE + 32)
+ /*
+ * Bad password count: %1!lu!
+ * Number of logons: %2!lu!
+ * Logon server: '%3!s!'
+ * Country code: %4!lu!
+ * Code page: %5!lu!
+ */
+
+#define PUAS_PDC_GOOD_BDC_BAD (PUAS_BASE + 33)
+ /*
+ *PORTUAS can not be run on a Backup Domain Controller.
+ */
+
+#define PUAS_NO_PRIVILEGE (PUAS_BASE + 34)
+ /*
+ *Your account does not have permission to do this.
+ */
+
+#define PUAS_IGNORING_REDUNDANT_GROUP (PUAS_BASE + 35)
+ /*
+ *Ignoring redundant group '%1!s!'...
+ */
+
+#define PUAS_GROUP_ADDED (PUAS_BASE + 36)
+ /*
+ *Group '%1!s!' added.
+ */
+
+#define PUAS_CHANGING_GROUP (PUAS_BASE + 37)
+ /*
+ *Changing group '%1!s!'...
+ */
+
+#define PUAS_ADDING_ADMIN_AS_REGULAR_USER (PUAS_BASE + 38)
+ /*
+ *Adding administrator '%1!s!' as regular user...
+ */
+
+#define PUAS_ADDING_GUEST_AS_REGULAR_USER (PUAS_BASE + 39)
+ /*
+ *Adding guest '%1!s!' as regular user...
+ */
+
+#define PUAS_CHANGING_UNK_PRIV_TO_REGULAR_USER (PUAS_BASE + 40)
+ /*
+ *Changing unknown permissions for '%1!s!' from %2!lu! to regular
+ *user...
+ */
+
+#define PUAS_ADDING_OPERATOR_AS_REGULAR_USER (PUAS_BASE + 41)
+ /*
+ *Adding operator '%1!s!' as regular user...
+ */
+
+#define PUAS_WORKING_AROUND_LANMAN_BUG (PUAS_BASE + 42)
+ /*
+ *Changing account permissions to allow null password
+ *for user '%1!s!...
+ */
+
+#define PUAS_ADDED_USER_OK (PUAS_BASE + 44)
+ /*
+ *Added user '%1!s!' successfully.
+ */
+
+#define PUAS_ERROR_87_ADDING_USER (PUAS_BASE + 45)
+ /*
+ *Error 87 occurred adding user '%1!s!'. User information:
+ */
+
+#define PUAS_USER_ALREADY_EXISTS_UPDATING (PUAS_BASE + 46)
+ /*
+ *User %1!s! already exists. The security database is being updated...
+ */
+
+#define PUAS_ERROR_87_CHANGING_USER (PUAS_BASE + 47)
+ /*
+ *Error 87 occurred changing user '%1!s!'. User information:
+ */
+
+#define PUAS_USER_ADDED_TO_GROUP (PUAS_BASE + 48)
+ /*
+ *User '%1!s!' added to group '%2!s!'.
+ */
+
+#define PUAS_SETTING_PRIM_GROUP_BEFORE_MAPPING (PUAS_BASE + 49)
+ /*
+ *Setting primary group for user '%1!s!' to '%2!s!' (before mapping)...
+ */
+
+#define PUAS_SETTING_PRIM_GROUP_AFTER_MAPPING (PUAS_BASE + 50)
+ /*
+ *Setting primary group for user '%1!s!' to '%2!s!' (after mapping)...
+ */
+
+#define PUAS_UAS_DATABASE_HAS_USERS (PUAS_BASE + 51)
+ /*
+ *The user accounts database has %1!lu! users.
+ */
+
+#define PUAS_ERROR_PROCESSING_LOGON_HOURS (PUAS_BASE + 52)
+ /*
+ *An error occurred while processing the logon hours for user %1!hs!.
+ */
+
+#define PUAS_ERROR_PROCESSING_WORKSTATIONS (PUAS_BASE + 53)
+ /*
+ *An error occurred while processing the workstation list for user %1!hs!.
+ */
+
+#define PUAS_USER_EXISTS_AS_A_LOCALGROUP (PUAS_BASE + 54)
+ /*
+ *user '%1!s!' already exists
+ *as a local group name in the Windows NT security database%0
+ */
+
+#define PUAS_GROUP_EXISTS_AS_A_LOCALGROUP (PUAS_BASE + 55)
+ /*
+ *group '%1!s!' already exists
+ *as a local group name in the Windows NT security database%0
+ */
+
+#define PUAS_INVALID_CODEPAGE (PUAS_BASE + 56)
+ /*
+ *The specified codepage is invalid.
+ */
+
+#define PUAS_LOG_FILE_NOT_OPEN (PUAS_BASE + 57)
+ /*
+ *The log file could not be created, possibly because it already
+ *exists. If this is the case, either delete or rename the log file,
+ *or change the log file name used on the command line when running
+ *%1 again.
+ *
+ */
diff --git a/private/net/portuas/sources b/private/net/portuas/sources
new file mode 100644
index 000000000..fd08955e6
--- /dev/null
+++ b/private/net/portuas/sources
@@ -0,0 +1,52 @@
+MAJORCOMP=net
+MINORCOMP=portuas
+
+TARGETNAME=portuas
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc;..\..\inc
+
+!IFNDEF DISABLE_NET_UNICODE
+UNICODE=1 _UNICODE=1
+NET_C_DEFINES=-DUNICODE -D_UNICODE
+!ENDIF
+
+USE_CRTDLL=1
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ Portuas.rc \
+ Alias.c \
+ Argvw.c \
+ DumpUser.c \
+ LogFile.c \
+ OwfCrypt.c \
+ PortLib.c \
+ PortMac.c \
+ PortMap.c \
+ PortPars.c \
+ Prompt.c \
+ UasRead.c
+
+UMAPPL=PortUas
+UMTEST=groups*hashtst*modals*users*members*passwds*port
+UMTYPE=console
+UMLIBS= \
+ obj\*\portuas.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\netlib.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\samlib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMRES=obj\*\Portuas.res
+
+NTTARGETFILE0=nlstxt.h nlstxt.mc nlstxt.rc
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
diff --git a/private/net/portuas/uasread.c b/private/net/portuas/uasread.c
new file mode 100644
index 000000000..b5c8d221b
--- /dev/null
+++ b/private/net/portuas/uasread.c
@@ -0,0 +1,1307 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ UASREAD.C
+
+Abstract:
+
+ Routines to _read UAS database entries.
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 24-Oct-1991
+
+Revision History:
+
+ 24-Oct-1991 w-shankn
+ Created.
+ 07-Feb-1992 JohnRo
+ Fixed compile errors!
+ Fixed memory free bug (hAlloc was both local and global variable).
+ Made changes suggested by PC-LINT.
+ 28-Feb-1992 JohnRo
+ User info must include units_per_week field.
+ 28-Feb-1992 JohnRo
+ Fixed bugs getting some numbers (e.g. codepage).
+ 03-Mar-1992 JohnRo
+ Added some checking for non-null group name.
+ 11-Mar-1992 JohnRo
+ Added command-line parsing stuff.
+ Use WARNING_MSG(), ERROR_MSG(), PROGRESS_MSG() macros.
+ 18-Mar-1992 JohnRo
+ Use iterator to allow hash-table collision handling.
+ Added flag for verbose output at run time.
+ 19-Mar-1992 JohnRo
+ Use our own version of decrypt code.
+ Fixed bug in user iterator bump code.
+ Added display of number of users in database and returned.
+ 05-May-1992 JohnRo
+ Avoid dummy passwords altogether.
+ Minor changes to verbose level vs. messages printed.
+ Made changes suggested by PC-LINT.
+ 23-Mar-1993 JohnRo
+ RAID 1187: logon hours are inappropriately set.
+ Got rid of new warnings from the new compiler.
+ Use <prefix.h> equates.
+ 10-May-1993 JohnRo
+ RAID 6113: PortUAS: "dangerous handling of Unicode". Actually, PortUAS
+ was handling Unicode better than other parts of the system, so PortUAS
+ has to go down to the lowest common denominator. Hopefully after
+ NT product 1, we can correct this. See BRAIN_DAMAGE_UNICODE below.
+ 30-Jul-1993 JohnRo
+ Use NetpKdPrint() where possible.
+ Made changes suggested by PC-LINT 5.0
+ 02-Sep-1993 JohnRo
+ Use NetpNameCompare() to compare user names.
+ Use NetApiBufferAllocate() instead of private version.
+
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <crypt.h>
+#include <ntrtl.h> // Needed by <windows.h>
+#include <nturtl.h> // Needed by <windows.h>
+#include <windows.h> // _lread(), etc.
+#include <lmcons.h> // NET_API_STATUS, etc.
+
+// These may be included in any order:
+
+#include <crypt.h>
+#include <icanon.h> // I_NetNameCompare
+#include <lmaccess.h>
+#include <lmapibuf.h> // NetApiBufferAllocate(), NetApiBufferFree().
+#include <lmerr.h>
+#include <loghours.h> // NetpRotateLogonHours().
+#include <memory.h>
+#include <netdebug.h> // DBGSTATIC, NetpAssert().
+#include <netlibnt.h> // NetpNtStatusToApiStatus().
+#include <portuasp.h> // WARNING_MSG(), etc.
+#include <prefix.h> // PREFIX_ equates.
+#include <smbgtpt.h>
+#include <string.h> // strcmp(), strlen() etc.
+#include <tstring.h> // NetpCopy{type}To{type}, NetpSubsetStr(), etc.
+#include <wchar.h>
+#include <tchar.h>
+
+#include "nlstxt.h" // NLS messages
+
+//
+// Global variables (set by PortUasParseCommandLine()).
+//
+ LPTSTR PortUasGlobalUserToSkipTo = NULL;
+ BOOL Verbose = FALSE;
+extern int CurrentCP;
+
+//
+// Static pointers to memory where data will be read in from UAS database.
+//
+
+DBGSTATIC HANDLE hAlloc;
+DBGSTATIC HANDLE database = INVALID_HANDLE_VALUE;
+DBGSTATIC LPUAS_AHDR UasHeader;
+DBGSTATIC LPUAS_GROUPREC groups;
+DBGSTATIC LPUAS_DISKUSERHASH userHashes;
+DBGSTATIC LPUAS_USER_OBJECT user;
+DBGSTATIC BOOL uasInMemory = FALSE;
+DBGSTATIC USER_ITERATOR currentUser;
+
+//
+// Static counters for user-interface.
+//
+DBGSTATIC DWORD usersDoneSoFar = 0; // Users processed or skipped.
+DBGSTATIC DWORD usersTotal;
+
+//
+// Private functions.
+//
+
+DBGSTATIC
+NET_API_STATUS
+PortUaspGetUserData(
+ IN LPUSER_ITERATOR Iterator
+ );
+
+//FARBUGBUG This is a pretty big macro, now; probably should be a function.
+#define PortUaspPutString( Record, Field, String, Var ) \
+ { \
+ int cch; \
+ cch = strlen(String) + 1; \
+ ( Record ).Field = Var; \
+ cch = MultiByteToWideChar(CurrentCP, MB_PRECOMPOSED, String, cch, Var, cch); \
+ NetpAssert(cch != 0); \
+ Var += cch; \
+ }
+
+#define MAKE_PTR( User, Field ) \
+ ((LPSTR)( &(User)->uo_record ) \
+ + ( SmbGetUshort( &(User)->uo_record.Field )))
+
+#define UAS_GROUP_ENTRY_IS_VALID( EntryPtr ) \
+ ( ( ((BYTE) (EntryPtr)->name[0]) != UAS_REC_EMPTY ) \
+ && ( ((BYTE) (EntryPtr)->name[0]) != UAS_REC_DELETE ) )
+
+
+
+NET_API_STATUS
+PortUasOpen(
+ IN LPTSTR File
+ )
+
+/*++
+
+Routine Description:
+
+ Open LM2.0 UAS database and read contents into memory.
+
+Arguments:
+
+ File - pathname of UAS database file. Usually C:\LANMAN\ACCOUNTS\NET.ACC.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ ERROR_NOT_ENOUGH_MEMORY - self-explanatory
+ NERR_InvalidDatabase - file is corrupt or invalid
+ NERR_ACFNotFound - can't find the file
+ NERR_ACFFileIOFail - problem reading file
+
+--*/
+
+{
+#ifdef BRAIN_DAMAGE_UNICODE
+ DWORD i;
+#endif
+ DWORD size;
+ INT cb;
+ LPBYTE alloc;
+
+ //
+ // Allocate memory. Memory required is for: UasHeader
+ // group data
+ // user hash table
+ // single user entry
+
+ size = UAS_HASH_TBL_OFFSET + UAS_HASH_TBL_SIZE + UAS_MAX_USER_SIZE;
+ if (( hAlloc =
+ LocalAlloc( LMEM_MOVEABLE | LMEM_ZEROINIT, size )) == NULL ) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (( alloc = LocalLock( hAlloc )) == NULL ) {
+
+ (void) LocalFree( hAlloc );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Assign portions of allocated memory to data sections.
+ //
+
+ UasHeader = (LPUAS_AHDR)alloc;
+ groups = (LPUAS_GROUPREC)( alloc + UAS_GROUP_HASH_START );
+ userHashes = (LPUAS_DISKUSERHASH)( alloc + UAS_HASH_TBL_OFFSET );
+ user = (LPUAS_USER_OBJECT)( alloc + UAS_HASH_TBL_OFFSET
+ + UAS_HASH_TBL_SIZE );
+
+ //
+ // Open UAS database.
+ //
+
+ database = CreateFile(File, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (database == INVALID_HANDLE_VALUE) {
+
+ return NERR_ACFNotFound;
+ }
+
+ //
+ // Read UasHeader.
+ //
+
+ if (!ReadFile(database, UasHeader, UAS_GROUP_HASH_START, &cb, NULL) ||
+ cb != UAS_GROUP_HASH_START ) {
+
+ PortUasClose();
+ return NERR_ACFFileIOFail;
+ }
+
+ //
+ // Check if the file is an actual UAS database.
+ //
+
+ if ( strcmp( UasHeader->signature, UAS_LMSIG ) ||
+ strcmp( UasHeader->DBIdInfo, UAS_DBIDINFO_TEXT ) ||
+ SmbGetUshort( &UasHeader->integrity_flag ) == FALSE ) {
+
+ PortUasClose();
+ return NERR_InvalidDatabase;
+ }
+
+ //
+ // Check size of database.
+ //
+
+ if (( size = GetFileSize( database, NULL )) == (DWORD)-1L ) {
+
+ PortUasClose();
+ return NERR_ACFFileIOFail;
+
+ }
+
+ if (( size < ( SmbGetUlong( &UasHeader->free_list )
+ + UAS_DISK_BLOCK_SIZE ))
+ || ( size < ( SmbGetUlong( &UasHeader->access_list )
+ + UAS_DISK_BLOCK_SIZE ))
+ || (( size - UAS_HASH_TBL_OFFSET - 2 * UAS_HASH_TBL_SIZE )
+ % UAS_DISK_BLOCK_SIZE )) {
+
+ PortUasClose();
+ return NERR_InvalidDatabase;
+ }
+
+ usersTotal = (DWORD) SmbGetUshort( &(UasHeader->num_users) );
+ if (Verbose) {
+ //PROGRESS_MSG( ("UAS database has " FORMAT_DWORD " users.\n",
+ // usersTotal ) );
+ (void)NlsPutMsg(STDOUT, PUAS_UAS_DATABASE_HAS_USERS, usersTotal );
+ }
+ usersDoneSoFar = 0;
+
+
+ //
+ // Get group information.
+ //
+
+ if (!ReadFile(database, groups, UAS_GRECSIZE * UAS_MAXGROUP, &cb, NULL) ||
+ cb != UAS_GRECSIZE * UAS_MAXGROUP ) {
+
+ PortUasClose();
+ return NERR_ACFFileIOFail;
+ }
+
+ //
+ // Get user hash table.
+ //
+
+ if (SetFilePointer(database, UAS_HASH_TBL_OFFSET, NULL, FILE_BEGIN) == -1) {
+
+ PortUasClose();
+ return NERR_ACFFileIOFail;
+ }
+
+ if (!ReadFile(database, userHashes, UAS_HASH_TBL_SIZE, &cb, NULL) ||
+ cb != UAS_HASH_TBL_SIZE ) {
+
+ PortUasClose();
+ return NERR_ACFFileIOFail;
+ }
+
+ uasInMemory = TRUE;
+ PortUasInitUserIterator( currentUser );
+ return NERR_Success;
+
+}
+
+
+
+VOID
+PortUasClose(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Close the currently open UAS database.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if ( database != INVALID_HANDLE_VALUE ) {
+
+ uasInMemory = FALSE;
+ PortUasInitUserIterator( currentUser );
+ CloseHandle( database );
+ (VOID) LocalUnlock( hAlloc );
+ (VOID) LocalFree( hAlloc );
+ database = INVALID_HANDLE_VALUE;
+
+ if (Verbose) {
+ //PROGRESS_MSG( ("Processed or skipped " FORMAT_DWORD
+ // " users of an expected " FORMAT_DWORD ".\n",
+ // usersDoneSoFar, usersTotal) );
+ (void)NlsPutMsg(STDOUT, PUAS_PROCESSED_OR_SKIPPED_USERS_OF_TOTAL,
+ usersDoneSoFar, usersTotal );
+ }
+ NetpAssert( usersDoneSoFar == usersTotal );
+ }
+
+ return;
+
+}
+
+
+
+NET_API_STATUS
+PortUasGetModals(
+ OUT LPUSER_MODALS_INFO_0 * Modals0
+ )
+
+/*++
+
+Routine Description:
+
+ Get user modals settings from current database.
+
+Arguments:
+
+ Modals0 - A pointer to an LPUSER_MODALS_INFO_0 which will get a pointer
+ to the returned level 0 user modals structure. This buffer
+ must be freed with NetApiBufferFree.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ NERR_ACFNotLoaded - database not open
+ ERROR_NOT_ENOUGH_MEMORY - self-explanatory
+
+--*/
+
+{
+
+ //
+ // Check if the database is in memory.
+ //
+
+ if ( !uasInMemory ) {
+
+ return NERR_ACFNotLoaded;
+ }
+
+ //
+ // Try to allocate two buffers for all the user modals data.
+ //
+
+ if ( NetApiBufferAllocate( sizeof(USER_MODALS_INFO_0), (PVOID *)Modals0 )){
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Fill buffer with data.
+ //
+
+ (*Modals0)->usrmod0_min_passwd_len
+ = (DWORD)SmbGetUshort( &UasHeader->min_passwd_len );
+ (*Modals0)->usrmod0_max_passwd_age
+ = SmbGetUlong( &UasHeader->max_passwd_age );
+ (*Modals0)->usrmod0_min_passwd_age
+ = SmbGetUlong( &UasHeader->min_passwd_age );
+ (*Modals0)->usrmod0_force_logoff
+ = SmbGetUlong( &UasHeader->force_logoff );
+ (*Modals0)->usrmod0_password_hist_len
+ = (DWORD)SmbGetUshort( &UasHeader->passwd_hist_len );
+
+ return NERR_Success;
+
+}
+
+
+
+NET_API_STATUS
+PortUasGetGroups(
+ OUT LPBYTE * Buffer,
+ OUT LPBYTE * Gids,
+ OUT LPDWORD Entries
+ )
+
+/*++
+
+Routine Description:
+
+ Get groups from the current database.
+
+Arguments:
+
+ Buffer - A pointer to an LPBYTE which will get a pointer to the returned
+ buffer. The buffer will contain a number of GROUP_INFO_1
+ structures, similar to that returned from NetGroupEnum. This
+ buffer must be freed with NetApiBufferFree.
+
+ Gids - A pointer to an LPBYTE which will get a pointer to an array
+ of group IDs, corresponding to the entries in the returned
+ buffer. This array must be freed with NetApiBufferFree.
+
+ Entries - A pointer to a DWORD which will receive the number of
+ entries in the buffer. There are no more entries in the
+ database.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ NERR_ACFNotLoaded - database not open
+ ERROR_NOT_ENOUGH_MEMORY - self-explanatory
+
+--*/
+
+{
+
+ DWORD i;
+ DWORD count;
+ DWORD size; // byte count.
+ LPDWORD groupIds;
+ LPGROUP_INFO_1 groupInfo;
+ LPWSTR varData;
+
+ *Entries = 0;
+
+ //
+ // Check if the database is in memory.
+ //
+
+ if ( !uasInMemory ) {
+
+ return NERR_ACFNotLoaded;
+ }
+
+ //
+ // Go through the group entries, calculating required buffer size.
+ //
+
+ size = 16;
+ count = 0;
+ for ( i = 0; i < UAS_MAXGROUP; i++ ) {
+
+ //
+ // Only enumerate valid entries.
+ //
+
+ if ( UAS_GROUP_ENTRY_IS_VALID( &groups[i] ) ) {
+
+ count++;
+ size += sizeof(GROUP_INFO_1);
+ size += sizeof(WCHAR) * ( strlen( (char *) groups[i].name ) + 1);
+ size += sizeof(WCHAR) * ( strlen( (char *) groups[i].comment ) + 1);
+ }
+ }
+
+ //
+ // Try to get buffers big enough.
+ //
+
+ if ( NetApiBufferAllocate( 16 + count * sizeof(DWORD), (PVOID *)Gids )) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if ( NetApiBufferAllocate( size, (PVOID *)Buffer )) {
+
+ (void) NetApiBufferFree( *Gids );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Fill buffer with data.
+ //
+
+ groupInfo = (LPGROUP_INFO_1)*Buffer;
+ groupIds = (LPDWORD)*Gids;
+ varData = (LPVOID)( &groupInfo[count] );
+ count = 0;
+ for ( i = 0; i < UAS_MAXGROUP; i++ ) {
+
+ //
+ // Only enumerate valid entries.
+ //
+
+ if ( UAS_GROUP_ENTRY_IS_VALID( &groups[i] ) ) {
+
+ NetpAssert( groups[i].name[0] != NULLC );
+
+ groupIds[count] = (DWORD)i;
+ PortUaspPutString( groupInfo[count], grpi1_name,
+ groups[i].name, varData );
+ PortUaspPutString( groupInfo[count], grpi1_comment,
+ groups[i].comment, varData );
+ count++;
+ }
+ }
+
+ *Entries = count;
+
+ return NERR_Success;
+
+}
+
+
+DBGSTATIC BOOL
+PortUasIsUserIteratorValid(
+ IN LPUSER_ITERATOR Iterator
+ )
+{
+
+#define M(text) \
+ { \
+ NetpKdPrint(( PREFIX_PORTUAS "PortUasIsUserIteratorValid: " \
+ text ".\n" )); \
+ }
+
+
+ if (Iterator == NULL) {
+ M("null ptr");
+ return (FALSE);
+ } else if ( (Iterator->Index == NULL_INDEX)
+ && (Iterator->DiskOffset==NULL_DISK_OFFSET) ) {
+
+ return (TRUE); // initial value
+ } else if (Iterator->Index == UAS_USER_HASH_ENTRIES) {
+ return (TRUE); // done
+ } else if (Iterator->Index > UAS_USER_HASH_ENTRIES) {
+ M("index too large");
+ return (FALSE);
+ } else if (Iterator->Index == NULL_INDEX) {
+ M("null index w/o null disk offset");
+ return (FALSE);
+ } else if (Iterator->DiskOffset == NULL_DISK_OFFSET) {
+ M("null disk offset w/o null index");
+ return (FALSE);
+ } else {
+ return (TRUE); // normal (in between initial and done) value.
+ }
+
+ /*NOTREACHED*/
+}
+
+
+DBGSTATIC VOID
+PortUasFindNextNonemptyUserChain(
+ IN OUT LPUSER_ITERATOR Iterator
+ )
+{
+ DWORD CurrentChain;
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+ CurrentChain = Iterator->Index;
+ if (CurrentChain == NULL_INDEX) {
+ CurrentChain = 0;
+ } else if (CurrentChain == UAS_USER_HASH_ENTRIES) {
+ return; // Already done.
+ } else {
+ ++CurrentChain;
+ }
+ while (CurrentChain < UAS_USER_HASH_ENTRIES) {
+ if ( (userHashes[CurrentChain].dh_disk) != NULL_DISK_OFFSET ) {
+ Iterator->DiskOffset = userHashes[CurrentChain].dh_disk;
+ break; // found a nonempty chain
+ }
+ ++CurrentChain;
+ }
+
+ Iterator->Index = CurrentChain; // may be UAS_USER_HASH_ENTRIES (done)
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+}
+
+
+DBGSTATIC VOID
+PortUasBumpUserIterator(
+ IN OUT LPUSER_ITERATOR Iterator
+ )
+{
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+ if (Iterator->Index == NULL_INDEX) {
+
+ // Just starting out.
+
+ PortUasFindNextNonemptyUserChain( Iterator );
+
+ } else if (Iterator->Index == UAS_USER_HASH_ENTRIES) {
+
+ // Already done. Nothing else to do.
+
+ } else {
+ DWORD NextDiskOffset;
+
+ // We're in a chain...
+
+ // We should only be here if we've got the one pointing to the
+ // next one.
+ NetpAssert( PortUasUserIteratorEqual( Iterator, &currentUser ) );
+
+ //
+ // Set disk offset to point to the next entry (if any) in chain.
+ //
+ NextDiskOffset = user->uo_header.do_next;
+
+ if (NextDiskOffset != NULL_DISK_OFFSET) {
+
+ //
+ // We've got at least one more entry in this chain.
+ //
+ Iterator->DiskOffset = NextDiskOffset;
+
+ } else {
+
+ //
+ // Handle end of chain by finding next nonempty chain.
+ //
+ PortUasFindNextNonemptyUserChain( Iterator );
+ }
+
+ }
+
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+} // PortUasBumpUserIterator
+
+
+DBGSTATIC BOOL
+PortUasIsUserIteratorDone(
+ IN LPUSER_ITERATOR Iterator
+ )
+{
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+ if (Iterator->Index == UAS_USER_HASH_ENTRIES) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+
+
+NET_API_STATUS
+PortUasGetUser(
+ IN OUT LPUSER_ITERATOR Iterator,
+ OUT LPBYTE * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Get a user from the current database.
+
+Arguments:
+
+ BUGBUG: Index (DWORD) is now Iterator (structure). Update doc!
+ Index - A pointer to a DWORD indicating which user entry to get. When
+ the index is NULL_INDEX, the first entry is read. Otherwise,
+ the index is incremented, and the next entry is read. On return,
+ this index contains the index of the entry just read.
+
+ Buffer - A pointer to an LPBYTE which will get a pointer to the returned
+ buffer. The buffer will contain a single USER_INFO_22
+ structure, similar to that returned from NetUserGetInfo,
+ except that the password will be a null array( filled with
+ zeros). This buffer must be freed with NetApiBufferFree.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ NERR_UserNotFound - no more users left
+ NERR_ACFNotLoaded - database not open
+ ERROR_INVALID_PARAMETER - iterator is bad
+ ERROR_NOT_ENOUGH_MEMORY - self-explanatory
+ NERR_ACFFileIOFail - error reading file
+
+--*/
+
+{
+ NET_API_STATUS rc;
+ DWORD size;
+ LPUSER_INFO_22 userInfo;
+ LPWSTR varData;
+
+ //
+ // Check if the database is in memory.
+ //
+
+ if ( !uasInMemory ) {
+
+ return NERR_ACFNotLoaded;
+ }
+
+
+ //
+ // (loop if we're skipping to a particular user)
+ //
+ /*lint -save -e716 */ // disable warnings for while(TRUE)
+ while (TRUE) { // (loop if we're skipping to a particular user)
+
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+ PortUasBumpUserIterator( Iterator );
+
+ if (PortUasIsUserIteratorDone( Iterator ) ) {
+
+ return NERR_UserNotFound;
+ }
+
+ ++usersDoneSoFar;
+ if (Verbose) {
+ //PROGRESS_MSG( ("Reading user " FORMAT_DWORD " of " FORMAT_DWORD
+ // ".\n", usersDoneSoFar, usersTotal) );
+ (VOID) NlsPutMsg(
+ STDOUT,
+ PUAS_READING_USER_OF_TOTAL,
+ usersDoneSoFar,
+ usersTotal );
+ }
+
+ //
+ // Get the user data in a global variable.
+ //
+
+ rc = PortUaspGetUserData( Iterator );
+ if (rc != NO_ERROR) {
+ NetpAssert( rc != NERR_UserNotFound ); // Already handled!
+ return rc;
+ }
+
+ //
+ // Decide whether or not this is the one we're looking for or
+ // if we're processing all users. If neither, then loop back
+ // and get the next user.
+ //
+
+ if (PortUasGlobalUserToSkipTo == NULL) {
+ break; // Not skipping users, so use this one by definition.
+ } else {
+ LONG Result;
+ TCHAR TempUserName[UNLEN+1];
+
+ if ( strlen( user->uo_record.name ) > UNLEN ) {
+ // Don't use this one, we would trash the stack below.
+ return (NERR_ACFFileIOFail); // corrupt database!
+ }
+ NetpCopyStrToTStr(
+ TempUserName, // dest (TCHARs)
+ (LPSTR) (user->uo_record.name) ); // src
+
+ Result = I_NetNameCompare(
+ NULL, // local (no server name)
+ PortUasGlobalUserToSkipTo,
+ TempUserName,
+ NAMETYPE_USER, // type is user name
+ 0 ); // flags: nothing special
+ if (Result != 0) {
+ //PROGRESS_MSG( ("Skipping user " FORMAT_LPSTR "...\n",
+ // user->uo_record.name) );
+ (void)NlsPutMsg(STDOUT, PUAS_SKIPPING_USER,
+ user->uo_record.name);
+
+ } else {
+ // Found the one we're looking for.
+ break;
+ }
+ }
+ }
+ /*lint -restore */ // re-enable warnings for while(TRUE)
+
+ //
+ // Find required return buffer size
+ //
+
+ size = strlen( user->uo_record.name )
+ // no password at all, so don't add chars for it here.
+ + strlen( MAKE_PTR( user, directory_o ))
+ + strlen( MAKE_PTR( user, comment_o ))
+ + strlen( MAKE_PTR( user, script_o ))
+ + strlen( MAKE_PTR( user, full_name_o ))
+ + strlen( MAKE_PTR( user, usr_comment_o ))
+ + strlen( MAKE_PTR( user, parms_o ))
+ + strlen( MAKE_PTR( user, workstation_o ))
+ + strlen( MAKE_PTR( user, logon_server_o ))
+ + 10;
+ size = size * sizeof(WCHAR)
+ + sizeof(USER_INFO_22)
+ + UNITS_PER_WEEK / 8 + 1;
+
+ //
+ // Try to get a buffer big enough.
+ //
+
+ rc = NetApiBufferAllocate( size, (PVOID *)Buffer );
+ if (rc != NO_ERROR) {
+
+ NetpAssert( rc == ERROR_NOT_ENOUGH_MEMORY );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ NetpAssert( Buffer != NULL );
+
+ //
+ // Fill buffer with data.
+ //
+
+ userInfo = (LPUSER_INFO_22)*Buffer;
+ varData = (LPVOID)( &userInfo[1] );
+
+ PortUaspPutString( *userInfo, usri22_name,
+ user->uo_record.name, varData );
+
+ RtlFillMemory( userInfo->usri22_password,
+ sizeof(userInfo->usri22_password), 0);
+
+ userInfo->usri22_priv
+ = (DWORD)SmbGetUshort( &user->uo_record.user.uc0_priv );
+ PortUaspPutString( *userInfo, usri22_home_dir,
+ MAKE_PTR( user, directory_o ), varData );
+ PortUaspPutString( *userInfo, usri22_comment,
+ MAKE_PTR( user, comment_o ), varData );
+ userInfo->usri22_flags = (DWORD)SmbGetUshort( &user->uo_record.flags );
+ PortUaspPutString( *userInfo, usri22_script_path,
+ MAKE_PTR( user, script_o ), varData );
+ userInfo->usri22_auth_flags
+ = SmbGetUlong( &user->uo_record.user.uc0_auth_flags );
+ PortUaspPutString( *userInfo, usri22_full_name,
+ MAKE_PTR( user, full_name_o ), varData );
+ PortUaspPutString( *userInfo, usri22_usr_comment,
+ MAKE_PTR( user, usr_comment_o ), varData );
+ PortUaspPutString( *userInfo, usri22_parms,
+ MAKE_PTR( user, parms_o ), varData );
+
+
+ //
+ // Convert the list of workstations from a blank separated list to
+ // comma separated list.
+ //
+ PortUaspPutString( *userInfo, usri22_workstations,
+ MAKE_PTR( user, workstation_o ), varData );
+
+ if ( wcslen( userInfo->usri22_workstations ) > 0 ) {
+ NTSTATUS NtStatus;
+ UNICODE_STRING BlankSep;
+ UNICODE_STRING CommaSep;
+
+ RtlInitUnicodeString( &BlankSep, userInfo->usri22_workstations );
+
+ NtStatus = RtlConvertUiListToApiList( &BlankSep,
+ &CommaSep,
+ TRUE ); // Blank Is Delimiter
+
+ if ( !NT_SUCCESS(NtStatus) ) {
+
+ // ERROR_MSG( ("Error processing workstation list for user " FORMAT_LPSTR,
+ // user->uo_record.name) );
+ (VOID) NlsPutMsg( STDOUT, PUAS_ERROR_PROCESSING_WORKSTATIONS,
+ user->uo_record.name );
+ return NetpNtStatusToApiStatus( NtStatus );
+ }
+
+ NetpAssert( wcslen(CommaSep.Buffer) ==
+ wcslen(userInfo->usri22_workstations) );
+ (VOID) wcscpy( userInfo->usri22_workstations, CommaSep.Buffer );
+
+ (VOID) RtlFreeHeap(RtlProcessHeap(), 0, CommaSep.Buffer );
+ }
+
+ userInfo->usri22_acct_expires
+ = SmbGetUlong( &user->uo_record.acct_expires );
+#if 0 // BUGBUG - SAM doesn't support max storage
+ userInfo->usri22_max_storage
+ = SmbGetUlong( &user->uo_record.max_storage );
+#else
+ userInfo->usri22_max_storage = USER_MAXSTORAGE_UNLIMITED;
+#endif
+ userInfo->usri22_units_per_week = UNITS_PER_WEEK;
+
+ userInfo->usri22_logon_hours = (LPBYTE)varData;
+ memcpy( (LPBYTE)varData, user->uo_record.logonhrs, UNITS_PER_WEEK / 8 );
+ if ( !NetpRotateLogonHours(
+ (LPVOID) varData, // rotate these hours (update in place)
+ UNITS_PER_WEEK,
+ TRUE /* yes, convert to GMT */ ) ) {
+
+ //ERROR_MSG( ("Error processing logon hours for user " FORMAT_LPSTR,
+ // user->uo_record.name) );
+ (VOID) NlsPutMsg(STDOUT, PUAS_ERROR_PROCESSING_LOGON_HOURS,
+ user->uo_record.name);
+
+ // Tell caller about error. This may or may not have been our
+ // fault, but NetpRotateLogonHours doesn't give any other clues.
+ return (NERR_InternalError);
+ }
+
+ varData = (LPWSTR)( (LPBYTE)varData + UNITS_PER_WEEK / 8 + 1 );
+
+ PortUaspPutString( *userInfo, usri22_logon_server,
+ MAKE_PTR( user, logon_server_o ), varData );
+ userInfo->usri22_country_code
+ = (DWORD) SmbGetUshort( &user->uo_record.country_code );
+ userInfo->usri22_code_page
+ = (DWORD) SmbGetUshort( &user->uo_record.code_page );
+
+ return NERR_Success;
+
+}
+
+
+
+NET_API_STATUS
+PortUasGetUserOWFPassword(
+ IN LPUSER_ITERATOR Iterator,
+ OUT LPBYTE * Password
+ )
+
+/*++
+
+Routine Description:
+
+ Get a user's password, in one-way-encryption form.
+
+Arguments:
+
+ BUGBUG: Index (DWORD) is now Iterator (structure). Update doc!
+ Index - A DWORD indicating which entry to get. This can, but doesn't
+ have to, be the value of the index returned from PortUasGetUser.
+
+ Password - A pointer to an LPBYTE which will get a pointer to the
+ returned password. This buffer must be freed with
+ NetApiBufferFree.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ NERR_UserNotFound - not a valid user index
+ NERR_ACFNotLoaded - database not open
+ ERROR_INVALID_PASSWORD - can't be decrypted
+ ERROR_INVALID_PARAMETER - index is bad
+ ERROR_NOT_ENOUGH_MEMORY - self-explanatory
+ NERR_ACFFileIOFail - error reading file
+
+--*/
+
+{
+
+ NET_API_STATUS rc;
+
+ //
+ // Check if the database is in memory.
+ //
+
+ if ( !uasInMemory ) {
+
+ return NERR_ACFNotLoaded;
+ }
+
+ //
+ // Check the iterator.
+ //
+
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+ //
+ // Get the user data, if necessary.
+ //
+
+ if ( rc = PortUaspGetUserData( Iterator )) {
+
+ return rc;
+ }
+
+ //
+ // Try to get a buffer.
+ //
+
+ if ( NetApiBufferAllocate( sizeof(LM_OWF_PASSWORD), (PVOID *)Password )) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Decrypt password into buffer.
+ //
+
+#if 0
+ if (Verbose) {
+ DumpPassword( "from UAS", user->uo_record.passwd );
+ }
+#endif
+ if ( PortUasDecryptLmOwfPwdWithIndex(
+ (PENCRYPTED_LM_OWF_PASSWORD)( user->uo_record.passwd ),
+ (LPDWORD) &(Iterator->Index),
+ (PLM_OWF_PASSWORD)*Password )) {
+
+ (void) NetApiBufferFree( *Password );
+ return ERROR_INVALID_PASSWORD;
+ }
+#if 0
+ if (Verbose) {
+ DumpPassword( "decrypted once", *Password );
+ }
+#endif
+
+ return NERR_Success;
+
+}
+
+
+
+NET_API_STATUS
+PortUasGetUserGroups(
+ IN LPUSER_ITERATOR UserIterator,
+ OUT LPBYTE * Buffer,
+ OUT LPBYTE * Gids,
+ OUT LPDWORD Entries
+ )
+
+/*++
+
+Routine Description:
+
+ Get groups for a user in the current database.
+
+Arguments:
+
+ BUGBUG: Index (DWORD) is now UserIterator (structure). Update doc!
+ Index - A DWORD indicating which entry to get. This can, but doesn't
+ have to, be the value of the index returned from PortUasGetUser.
+
+ Buffer - A pointer to an LPBYTE which will get a pointer to the returned
+ buffer. The buffer will contain a number of GROUP_INFO_0
+ structures, similar to that returned from NetUserGetGroups.
+
+ Gids - A pointer to an LPBYTE which will get a pointer to an array
+ of group IDs, corresponding to the entries in the returned
+ buffer. This array must be freed with NetApiBufferFree.
+
+ Entries - A pointer to a DWORD which will receive a count of the number
+ of group entries returned.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ NERR_UserNotFound - not a valid user iterator
+ NERR_ACFNotLoaded - database not open
+ ERROR_INVALID_PARAMETER - iterator is bad
+ ERROR_NOT_ENOUGH_MEMORY - self-explanatory
+ NERR_ACFFileIOFail - error reading file
+
+--*/
+
+{
+ NET_API_STATUS rc;
+ DWORD count;
+ DWORD size;
+ LPBYTE groupMask;
+ LPDWORD groupIds;
+ LPGROUP_INFO_0 groupInfo;
+ LPWSTR varData;
+ DWORD i;
+
+ //
+ // Check if the database is in memory.
+ //
+
+ if ( !uasInMemory ) {
+
+ return NERR_ACFNotLoaded;
+ }
+
+ //
+ // Check the user iterator.
+ //
+
+ NetpAssert( PortUasIsUserIteratorValid( UserIterator ) );
+
+ //
+ // Get the user data, if necessary.
+ //
+
+ if ( rc = PortUaspGetUserData( UserIterator )) {
+
+ return rc;
+ }
+
+ //
+ // Find the number of groups.
+ //
+
+ count = 0;
+ groupMask = user->uo_record.user.uc0_groups;
+
+ for ( i = 0; i < UAS_MAXGROUP; i++ ) {
+
+ if ( UAS_ISBITON( groupMask, i )) {
+
+ count++;
+ }
+ }
+
+ //
+ // Try to get a buffer of adequate size. The maximum size required is
+ // calculated using the count above and the maximum size of a group name.
+ // LANMAN 2.0 group names are smaller, we'll use that maximum.
+ //
+
+ if ( NetApiBufferAllocate( 16 + count * sizeof(DWORD), (PVOID *)Gids )) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ size = count * (( LM20_GNLEN + 1 ) * sizeof(WCHAR) + sizeof(GROUP_INFO_0))
+ + 16;
+
+ if ( NetApiBufferAllocate( size, (PVOID *)Buffer )) {
+
+ (void) NetApiBufferFree( *Gids );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // One by one, get the group names.
+ //
+
+ groupInfo = (LPGROUP_INFO_0)*Buffer;
+ groupIds = (LPDWORD)*Gids;
+ varData = (LPVOID)( &groupInfo[count] );
+ count = 0;
+ for ( i = 0; i < UAS_MAXGROUP; i++ ) {
+
+ //
+ // Only enumerate valid entries.
+ //
+
+ if ( UAS_GROUP_ENTRY_IS_VALID( &groups[i] ) ) {
+
+ if ( UAS_ISBITON( groupMask, i )) {
+
+ groupIds[count] = i;
+ PortUaspPutString( groupInfo[count], grpi0_name,
+ groups[i].name, varData );
+ count++;
+ }
+ }
+ }
+
+ *Entries = count;
+
+ return NERR_Success;
+
+}
+
+
+
+DBGSTATIC
+NET_API_STATUS
+PortUaspGetUserData(
+ IN LPUSER_ITERATOR Iterator
+ )
+
+/*++
+
+Routine Description:
+
+ Get actual data for a user indexed in the hashing table. If the
+ particular user is already loaded, it does nothing.
+
+Arguments:
+
+ Iterator - indicates user to get.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success if successful, or one of the following:
+
+ NERR_UserNotFound - not a valid user
+ NERR_ACFFileIOFail - error reading file
+--*/
+
+{
+
+ INT cb;
+ UAS_DISK_OBJ_HDR usrHeader;
+
+ NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
+
+ //
+ // Is the user already loaded?
+ //
+
+ if ( PortUasUserIteratorEqual( Iterator, &currentUser ) ) {
+
+ return NERR_Success;
+ }
+
+ //
+ // Is this a valid user?
+ //
+
+ NetpAssert( Iterator->Index != NULL_INDEX );
+ NetpAssert( Iterator->Index != UAS_USER_HASH_ENTRIES );
+ NetpAssert( Iterator->DiskOffset != NULL_DISK_OFFSET );
+ NetpAssert( userHashes[Iterator->Index].dh_disk != NULL_DISK_OFFSET );
+
+ //
+ // Flag global data as being invalid, in case we get error during read.
+ //
+ PortUasInitUserIterator( currentUser );
+
+ //
+ // Load the header for the user data.
+ //
+
+ if (SetFilePointer(database, (LONG)Iterator->DiskOffset, NULL, FILE_BEGIN)
+ == -1) {
+
+ return NERR_ACFFileIOFail;
+ }
+
+ if (!ReadFile(database, &usrHeader, sizeof(UAS_DISK_OBJ_HDR), &cb, NULL) ||
+ cb != sizeof(UAS_DISK_OBJ_HDR)) {
+
+ return NERR_ACFFileIOFail;
+ }
+
+ //
+ // Use information in the header to rewind and read the correct amount.
+ //
+
+ if (SetFilePointer(database, (LONG)Iterator->DiskOffset, NULL, FILE_BEGIN)
+ == -1) {
+
+ return NERR_ACFFileIOFail;
+ }
+
+ if (!ReadFile(database, user,
+ (DWORD)usrHeader.do_numblocks * UAS_DISK_BLOCK_SIZE,
+ &cb, NULL) ||
+ cb != usrHeader.do_numblocks * UAS_DISK_BLOCK_SIZE ) {
+
+ return NERR_ACFFileIOFail;
+ }
+
+ //
+ // Flag global data as valid again.
+ //
+ PortUasCopyUserIterator(
+ & currentUser, // dest
+ Iterator ); // src
+
+ return NERR_Success;
+
+}
diff --git a/private/net/portuas/users.c b/private/net/portuas/users.c
new file mode 100644
index 000000000..75576a94d
--- /dev/null
+++ b/private/net/portuas/users.c
@@ -0,0 +1,118 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ Users.C
+
+Abstract:
+
+ BUGBUG
+
+Author:
+
+ Shanku Niyogi (W-SHANKN) 24-Oct-1991
+
+Revision History:
+
+ 24-Oct-1991 w-shankn
+ Created.
+ 07-Feb-1992 JohnRo
+ Added this block of comments.
+ Avoid compiler warnings.
+ 28-Feb-1992 JohnRo
+ User info must include units_per_week field.
+ 28-Feb-1992 JohnRo
+ Fixed MIPS build errors.
+ 03-Mar-1992 JohnRo
+ Report long user names.
+ 11-Mar-1992 JohnRo
+ Added command-line parsing stuff.
+ 18-Mar-1992 JohnRo
+ Use iterator to allow hash-table collision handling.
+ 24-Apr-1992 JohnRo
+ Made immune to UNICODE being defined.
+ 27-May-1992 JohnRo
+ RAID 9829: winsvc.h and related file cleanup.
+ 29-Sep-1992 JohnRo
+ RAID 8001: PORTUAS.EXE not in build (work with stdcall).
+ 26-Jan-1993 JohnRo
+ RAID 8683: PortUAS should set primary group from Mac parms.
+--*/
+
+
+// These must be included first:
+
+#include <nt.h> // Needed by <portuasp.h>
+#include <ntrtl.h> // (Needed with nt.h and windows.h)
+#include <nturtl.h> // (Needed with ntrtl.h and windows.h)
+#include <windows.h>
+#include <lmcons.h>
+
+// These may be included in any order:
+
+#include <assert.h> // assert().
+#include <lmaccess.h> // LPUSER_INFO_22, etc.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <lmerr.h> // NERR_ equates.
+#include <netdebug.h> // NetpAssert(), etc.
+#include <tstring.h>
+#include <stdio.h>
+#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
+#include <string.h> // strlen().
+#include <portuasp.h> // PortUasParseCommandLine(), etc.
+
+#include "nlstxt.h" // Nls message ID codes.
+
+int _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+
+ LPSTR file_name;
+ USER_ITERATOR iterator;
+ BYTE msg[120];
+ NET_API_STATUS rc;
+ LPUSER_INFO_22 the_user = NULL;
+
+ file_name = PortUasParseCommandLine( argc, argv );
+ NetpAssert( file_name != NULL);
+
+ if (( rc = PortUasOpen( file_name )) != NERR_Success ) {
+
+ sprintf( msg, "Problem opening database - %ld\n", rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ return (EXIT_FAILURE);
+
+ }
+
+ PortUasInitUserIterator( iterator );
+ for ( ; ; ) {
+
+ rc = PortUasGetUser( &iterator, (LPBYTE *) (LPVOID) &the_user );
+ if ( rc == NERR_UserNotFound ) {
+
+ break;
+ }
+ if ( rc ) {
+
+ sprintf( msg, "Problem reading user - %ld\n", rc );
+ MessageBoxA( NULL, msg, NULL, MB_OK );
+ PortUasClose();
+ return (EXIT_FAILURE);
+
+ }
+ assert( the_user != NULL );
+
+ DumpUserInfo( the_user );
+
+ NetApiBufferFree( (LPBYTE)the_user );
+
+ }
+
+ PortUasClose();
+ return (EXIT_SUCCESS);
+}