diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/net/portuas | |
download | NT4.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')
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, ¤tUser ) ); + + // + // 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, ¤tUser ) ) { + + 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); +} |