/*--------------------------------------------------------------------------- File: ARUtil.cpp Comments: Helper functions and command-line parsing for Account Replicator (c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved Proprietary and confidential to Mission Critical Software, Inc. REVISION LOG ENTRY Revision By: Christy Boles Revised on 6/23/98 4:26:54 PM --------------------------------------------------------------------------- */ #include "StdAfx.h" #include #include #include #include #define INCL_NETUSER #define INCL_NETGROUP #define INCL_NETERRORS #include #include "Mcs.h" #include "Common.hpp" #include "TNode.hpp" #include "UString.hpp" #include "ErrDct.hpp" //#import "\bin\McsDctWorkerObjects.tlb" //#import "WorkObj.tlb" //#imported via ARUtil.hpp below #include "UserCopy.hpp" #include "ARUtil.hpp" #include "PWGen.hpp" #include "ResStr.h" #include extern TErrorDct err; bool bAllowReplicateOnSelf; extern PSID srcSid; // SID of source domain /*************************************************************************************************** CompVal: used as a compare function for TANode trees It compares a UNICODE string, with the name field in the node Return Values: 0 tn->acct_name == actname 1 tn->acct_name < actname -1 tn->acct_name > actname /***************************************************************************************************/ int CompVal( const TNode * tn, //in -tree node const void * actname //in -name to look for ) { LPWSTR str1 = ((TANode *)tn)->GetName(); LPWSTR str2 = (LPWSTR) actname; return UStrICmp(str1,str2); } /***************************************************************************************************/ /* CompNode: used as a compare function for TANode Trees It compares the name fields of TANodes Return Values: 0 t1->acct_name == t2->acct_name 1 t1->acct_name > t2->acct_name -1 t1->acct_name < t2->acct_name Error Handling: if given bad inputs, CompN displays an error message and returns 0 /***************************************************************************************************/ int CompNode( const TNode * v1, //in -first node to compare const TNode * v2 //in -second node to compare ) { TANode * t1 = (TANode *)v1; TANode * t2 = (TANode *)v2; return UStrICmp(t1->GetName(),t2->GetName()); } int CompareSid( PSID const sid1, // in - first SID to compare PSID const sid2 // in - second SID to compare ) { DWORD len1, len2; int retval = 0; len1 = GetLengthSid(sid1); len2 = GetLengthSid(sid2); if ( len1 < len2 ) { retval = -1; } if ( len1 > len2 ) { retval = 1; } if ( len1 == len2 ) { retval = memcmp(sid1,sid2,len1); } return retval; } int CompSid( const TNode * v1, // in -first node to compare const TNode * v2 // in -second node to compare ) { TANode * t1 = (TANode *)v1; TANode * t2 = (TANode *)v2; return CompareSid(t1->GetSid(),t2->GetSid()); } int CompSidVal( const TNode * tn, // in -node to compare const void * pVal // in -value to compare ) { TANode * node = (TANode *)tn; PSID pSid = (PSID)pVal; return CompareSid(node->GetSid(),pSid); } BOOL // ret-TRUE if the password is successfully generated PasswordGenerate( Options const * options, // in -includes PW Generating options WCHAR * password, // out -buffer for generated password DWORD dwPWBufferLength, // in -DIM length of password buffer BOOL isAdminAccount // in -Whether to use the Admin rules ) { DWORD rc = 0; DWORD dwMinUC; // minimum upper case chars DWORD dwMinLC; // minimum lower case chars DWORD dwMinDigit; // minimum numeric digits DWORD dwMinSpecial; // minimum special chars DWORD dwMaxConsecutiveAlpha; // maximum consecutive alpha chars DWORD dwMinLength; // minimum length WCHAR eaPassword[PWLEN+1]; // EA generated password DWORD dwEaBufferLength = DIM(eaPassword);// DIM length of newPassword // default values, if not enforcing PW strength through EA or MS DLL dwMinUC = 0; dwMinLC = 0; dwMinDigit = 1; // if no enforcement, require one digit (this is what the GUI does) dwMinSpecial = 0; dwMaxConsecutiveAlpha = 0; dwMinLength = options->minPwdLength; // Get password enforcement rules, if in effect dwMinUC = options->policyInfo.minUpper; dwMinLC = options->policyInfo.minLower; dwMinDigit = options->policyInfo.minDigits; dwMinSpecial = options->policyInfo.minSpecial; dwMaxConsecutiveAlpha = options->policyInfo.maxConsecutiveAlpha; rc = EaPasswordGenerate(dwMinUC,dwMinLC,dwMinDigit,dwMinSpecial, dwMaxConsecutiveAlpha,dwMinLength,eaPassword,dwEaBufferLength); if ( ! rc ) { UStrCpy(password,eaPassword,dwPWBufferLength); } else { if ( dwPWBufferLength ) password[0] = 0; } return rc; } PSID GetWellKnownSid( DWORD wellKnownAccount, // in - constant defined in this file, representing well-known account Options * opt, // in - migration options BOOL bTarget // in - flag, whether to use source or target domain information ) { PSID pSid = NULL; PUCHAR numsubs = NULL; DWORD * rid = NULL; BOOL error = FALSE; DWORD rc; DWORD wellKnownRid = wellKnownAccount; BOOL bNeedToBuildDomainSid = FALSE; SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY creatorIA = SECURITY_CREATOR_SID_AUTHORITY; // // Sid is the same regardless of machine, since the well-known // BUILTIN domain is referenced. // switch ( wellKnownAccount ) { case CREATOR_OWNER: if( ! AllocateAndInitializeSid( &creatorIA, 2, SECURITY_BUILTIN_DOMAIN_RID, SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, &pSid )) { err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError()); } break; case ADMINISTRATORS: if( ! AllocateAndInitializeSid( &sia, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid )) { err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError()); } break; case ACCOUNT_OPERATORS: if( ! AllocateAndInitializeSid( &sia, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS, 0, 0, 0, 0, 0, 0, &pSid )) { err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError()); } break; case BACKUP_OPERATORS: if( ! AllocateAndInitializeSid( &sia, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS, 0, 0, 0, 0, 0, 0, &pSid )) { err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError()); } break; case DOMAIN_ADMINS: wellKnownRid = DOMAIN_GROUP_RID_ADMINS; bNeedToBuildDomainSid = TRUE; break; case DOMAIN_USERS: wellKnownRid = DOMAIN_GROUP_RID_USERS; bNeedToBuildDomainSid = TRUE; break; case DOMAIN_CONTROLLERS: wellKnownRid = DOMAIN_GROUP_RID_CONTROLLERS; bNeedToBuildDomainSid = TRUE; break; case DOMAIN_COMPUTERS: wellKnownRid = DOMAIN_GROUP_RID_COMPUTERS; bNeedToBuildDomainSid = TRUE; break; default: wellKnownRid = wellKnownAccount; bNeedToBuildDomainSid = TRUE; break; } if ( bNeedToBuildDomainSid ) { // For the default case we can return a SID by using the wellKnownAccount parameter as a RID // this one is based on the sid for the domain // Get the domain SID USER_MODALS_INFO_2 * uinf = NULL; MCSASSERT(opt); srcSid = bTarget ? opt->tgtSid : opt->srcSid; if ( ! srcSid ) { rc = NetUserModalsGet(bTarget ? opt->tgtComp :opt->srcComp,2,(LPBYTE*)&uinf); if ( rc ) { err.SysMsgWrite(ErrE,rc,DCT_MSG_NO_DOMAIN_SID_SD,bTarget ? opt->tgtDomain :opt->srcDomain,rc ); error = TRUE; srcSid = NULL; } else { srcSid = uinf->usrmod2_domain_id; // make a copy of the SID to keep in the Options structure for next time PSID temp = LocalAlloc(LPTR,GetLengthSid(srcSid)); memcpy(temp,srcSid,GetLengthSid(srcSid)); if ( bTarget ) opt->tgtSid = temp; else opt->srcSid = temp; NetApiBufferFree(uinf); srcSid = temp; } } if ( srcSid ) { numsubs = GetSidSubAuthorityCount(srcSid); if (! AllocateAndInitializeSid( &sia, (*numsubs)+1, 0,0,0,0,0,0,0,0, &pSid) ) { err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError()); } if ( ! CopySid(GetLengthSid(srcSid), pSid, srcSid) ) { err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_COPY_SID_FAILED_D,GetLastError()); } // reset number of subauthorities in pSid, since we just overwrote it with information from srcSid numsubs = GetSidSubAuthorityCount(pSid); (*numsubs)++; rid = GetSidSubAuthority(pSid,(*numsubs)-1); *rid = wellKnownRid; } } if ( error ) { LocalFree(pSid); pSid = NULL; } return pSid; } //--------------------------------------------------------------------------- // GenerateSidAsString Function // // Synopsis // Generate a SID in string format from specifed domain and given RID. // // Arguments // IN pOptions - account replicator options structure // IN bTarget - specifies whether to use the target domain or source domain // IN dwRid - specified RID // // Return // The generated SID as a string if successfull or an empty string if not. //--------------------------------------------------------------------------- _bstr_t __stdcall GenerateSidAsString(Options* pOptions, BOOL bTarget, DWORD dwRid) { _bstr_t strSid; PSID pSid = GetWellKnownSid(dwRid, pOptions, bTarget); if (pSid) { WCHAR szSid[LEN_Path]; DWORD cchSid = DIM(szSid); if (GetTextualSid(pSid, szSid, &cchSid)) { strSid = szSid; } FreeSid(pSid); } return strSid; }