WindowsXP-SP1/admin/admt/workobj/arutil.cpp
2020-09-30 16:53:49 +02:00

536 lines
17 KiB
C++

/*---------------------------------------------------------------------------
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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define INCL_NETUSER
#define INCL_NETGROUP
#define INCL_NETERRORS
#include <lm.h>
#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"
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);
}
//#pragma page()
//------------------------------------------------------------------------------
// CopyServerName: Ensures that server name is in UNC form and checks its len
//------------------------------------------------------------------------------
DWORD
CopyServerName(
TCHAR * uncServ ,// out-UNC server name
TCHAR const * server // in -\\server or domain name
)
{
short l = (short) UStrLen(server);
WCHAR * uncPDC;
API_RET_TYPE rc;
DWORD retcode = 0;
if ( (server[0] == '\\' && l > UNCLEN )
|| (server[0] != '\\' && l > DNLEN) )
{
retcode = NERR_MaxLenExceeded;
}
UStrCpy(uncServ, server, CNLEN+3);
if ( server[0] != '\\' )
{
rc = NetGetDCName(NULL, uncServ, (PBYTE*)&uncPDC);
if ( ! rc )
UStrCpy(uncServ, uncPDC);
retcode = rc;
NetApiBufferFree(uncPDC);
}
return retcode;
}
BOOL // ret-FALSE is addto: is not a group account
AddToGroupResolveType(
Options * options // i/o-options
)
{
DWORD rc = 0;
DWORD lenDomain,
lenSid;
WCHAR wszDomain[DNLEN+1];
SID_NAME_USE sidNameUse; // Type of SID
BYTE sid[LEN_Sid];
WCHAR server[LEN_Computer];
// Target domain AddTo group
if ( *options->addToGroup )
{
safecopy(server,options->tgtComp);
lenSid = sizeof sid;
lenDomain = DIM(wszDomain);
wszDomain[0] = L'\0';
if ( !LookupAccountName(server,
options->addToGroup,
(PSID)sid,
&lenSid,
wszDomain,
&lenDomain,
&sidNameUse ) )
{
rc = GetLastError();
if ( rc == ERROR_NONE_MAPPED )
{
// the add-to group does not exist. Try to create it
LOCALGROUP_INFO_1 lgInfo;
WCHAR comment[LEN_Comment];
swprintf(comment,GET_STRING(IDS_AddToGroupOnTargetDescription_S),options->srcDomain);
lgInfo.lgrpi1_name = options->addToGroup;
lgInfo.lgrpi1_comment = comment;
if (! options->nochange )
{
rc = NetLocalGroupAdd(server,1,(LPBYTE)&lgInfo,NULL);
}
else
{
rc = 0;
}
if ( rc && rc != ERROR_ALIAS_EXISTS )
{
err.SysMsgWrite(ErrW,rc,DCT_MSG_CREATE_ADDTO_GROUP_FAILED_SD,options->addToGroup,rc);
}
}
else
{
err.SysMsgWrite(0, rc, DCT_MSG_RESOLVE_ADDTO_FAILED_SSD, options->addToGroup, server, rc );
}
}
else
{
rc = 0;
if ( sidNameUse == SidTypeAlias )
options->flags |= F_AddToGroupLocal;
else if ( sidNameUse != SidTypeGroup )
{
rc = 1;
err.MsgWrite(0, DCT_MSG_ADDTO_NOT_GROUP_SD, options->addToGroup, sidNameUse );
}
}
}
// Source domain addto group
if ( *options->addToGroupSource )
{
safecopy(server,options->srcComp);
lenSid = sizeof sid;
lenDomain = DIM(wszDomain);
wszDomain[0] = L'\0';
if ( !LookupAccountName(server,
options->addToGroupSource,
(PSID)sid,
&lenSid,
wszDomain,
&lenDomain,
&sidNameUse ) )
{
rc = GetLastError();
if ( rc == ERROR_NONE_MAPPED )
{
// the add-to group does not exist. Try to create it
LOCALGROUP_INFO_1 lgInfo;
WCHAR comment[LEN_Comment];
swprintf(comment,GET_STRING(IDS_AddToGroupOnSourceDescription_S),options->tgtDomain);
lgInfo.lgrpi1_name = options->addToGroupSource;
lgInfo.lgrpi1_comment = comment;
if (! options->nochange )
{
rc = NetLocalGroupAdd(server,1,(LPBYTE)&lgInfo,NULL);
}
else
{
rc = 0;
}
if ( rc && rc != ERROR_ALIAS_EXISTS )
{
err.SysMsgWrite(ErrW,rc,DCT_MSG_CREATE_ADDTO_GROUP_FAILED_SD,options->addToGroupSource,rc);
}
}
else
{
err.SysMsgWrite(0, rc, DCT_MSG_RESOLVE_ADDTO_FAILED_SSD, options->addToGroupSource, server, rc );
}
}
else
{
rc = 0;
if ( sidNameUse == SidTypeAlias )
options->flags |= F_AddToSrcGroupLocal;
else if ( sidNameUse != SidTypeGroup )
{
rc = 1;
err.MsgWrite(0, DCT_MSG_ADDTO_NOT_GROUP_SD, options->addToGroup, sidNameUse );
}
}
}
return rc == 0;
}
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;
}