2025-11-28 00:35:46 +09:00

920 lines
28 KiB
C++

#define INC_OLE2
#define UNICODE 1
#define _WIN32_DCOM
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <winldap.h>
#include <activeds.h>
#include <assert.h>
#include "CreateUserHelpers.h"
#include "UserProps.h"
//#include "AttributesList.h"
#define MAX_ATTRIBS 4096
////////////////////////////////////////////////////////////////////////////////////////////////////
// String for usage information
WCHAR * pwszUsage = L"Creates new User under the passed container.\n"
L"Usage:\n"
L"CreateUser\n"
L" <*> Simple New User Information <*>\n"
L" /LDAP <Path of container>\n"
L" ADsPath of the container for placing the new group\n"
L" /UNAME <NT 5 User Name> \n"
L" This is the name for the new group\n"
L" /SAMNAME <Downlevel NT 4 Sam Account name>\n"
L" Cannot exceed 20 characters and must be globally unique\n"
L"\n"
L" <*> Detailed New User information <*>\n"
L" /FILE < Info File >\n"
L" Filename for file to contain new user information\n"
L"\n"
L" <*> OPTIONAL Binding Information <*>\n"
L" /USER <User name used for binding to the DC>\n"
L" /PASS <Password used for binding to the DC>\n"
L" (If these are passed, binding is done with ADsOpenObject())\n"
L"\n"
L"\n";
// Sample command line:
// /LDAP "LDAP://nttest.microsoft.com/CN=UGExercise Sample Container,dc=nttest,dc=microsoft,dc=com" /UNAME BOB /SAMNAME BOB /USER Administrator /PASS ""
////////////////////////////////////////////////////////////////////////////////////////////////////
// Module level global variables
BSTR bsLDAP = NULL; // <Path of container> ADsPath of the container for placing the new group
BSTR bsUNAME = NULL; // <NT 5 User Name> This is the name for the new group
BSTR bsSAMNAME = NULL; // <Downlevel NT 4 Sam Account name> Cannot exceed 20 characters and must be globally unique
BSTR bsFILE = NULL; // < Info File > Filename for file to contain new user information
BSTR bsUSER = NULL; // <User name used for binding to the DC>
BSTR bsPASS = NULL; // <Password used for binding to the DC>
////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward Declarations
BOOL ParseCommandLine( int argc, wchar_t *argv[ ]);
HRESULT CreateUser(IDirectoryObject *pDirObject, LPWSTR pwCommonName,LPWSTR pwSamAcctName,IDirectoryObject ** ppDirObjRet);
void Trim(LPWSTR pwszData);
HRESULT CreateUserFromFile(IDirectoryObject *pDirObject, LPWSTR pwCommonName,LPWSTR pwSamAcctName,IDirectoryObject ** ppDirObjRet,LPWSTR pwszFileName);
BOOL GetNextLine(FILE* fp,LPWSTR pwszDest,int iSize);
void RemoveSpecialChars(LPWSTR pwszLine);
////////////////////////////////////////////////////////////////////////////////////////////////////
// main()
/* Note: Using the UNICODE version of main().
this removes the need for the sample to include
UNICODE-ANSI conversion routines
*/
void wmain( int argc, wchar_t *argv[ ])
{
WCHAR pwszTemp[4096];
// We have now scanned PAST whitespace- so copy the string:
wcscpy_s(pwszTemp,4096,L" A String");
Trim(pwszTemp);
HRESULT hr;
IDirectoryObject * pDirObjectContainer = NULL;
IDirectoryObject * pDirObjRet = NULL;
if (!ParseCommandLine(argc,argv))
return;
// Initialize COM
CoInitialize(0);
// Bind to the container passed
// If USER and PASS passed in, use ADsOpenObject()
if (bsUSER)
hr = ADsOpenObject(bsLDAP, bsUSER, bsPASS,
ADS_SECURE_AUTHENTICATION,IID_IDirectoryObject, (void**) &pDirObjectContainer);
else
hr = ADsGetObject( bsLDAP, IID_IDirectoryObject,(void **)&pDirObjectContainer);
if (SUCCEEDED(hr))
{
// if a file is NOT passed in- Do the simple version
if (!bsFILE)
{
// Call the helper funtion to create the User
hr = CreateUser(pDirObjectContainer, bsUNAME,bsSAMNAME,
&pDirObjRet);
}
else // file was passed in
{
// Call the helper funtion to create the User
hr = CreateUserFromFile(pDirObjectContainer, bsUNAME,bsSAMNAME,
&pDirObjRet,bsFILE);
}
if (SUCCEEDED(hr))
{
_putws(L"\n\n New User created with the following properties:\n");
IADs * pIADsNewGoup = NULL;
// User succeeded- now get an IADs interface to it
// and print some properties
hr = pDirObjRet->QueryInterface(IID_IADs,(void**)&pIADsNewGoup);
if (SUCCEEDED(hr))
{
PrintIADSObject(pIADsNewGoup);
pIADsNewGoup->Release();
pIADsNewGoup = NULL;
}
else
CheckADHRESULT(hr,L"QueryInterface() - New User for IADs");
pDirObjRet->Release();
pDirObjRet = NULL;
}
else
CheckADHRESULT(hr,L"CreateUser()");
pDirObjectContainer->Release();
pDirObjectContainer = NULL;
}
else
if (bsUSER)
CheckADHRESULT(hr,L"ADsOpenObject()");
else
CheckADHRESULT(hr,L"ADsGetObject()");
if ( bsLDAP )
::SysFreeString(bsLDAP);
if ( bsUNAME )
::SysFreeString(bsUNAME);
if ( bsSAMNAME )
::SysFreeString(bsSAMNAME);
if ( bsFILE )
::SysFreeString(bsFILE);
if ( bsUSER )
::SysFreeString(bsUSER);
if ( bsPASS )
::SysFreeString(bsPASS);
CoUninitialize();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/*
ParseCommandLine()- Parses command line and sets module level globals
Parameters:
int argc - Number of Arguments
wchar_t *argv[ ] - Array of arguments
Returns:
TRUE if Command line was successfully parsed
Affectets global variables:
BSTR bsLDAP
BSTR bsUNAME
BSTR bsSAMNAME
BSTR bsFILE
BSTR bsUSER
BSTR bsPASS
*/
BOOL ParseCommandLine( int argc, wchar_t *argv[ ])
{
/*
** PARSE the FOLLOWING ARGUMENTS:
/LDAP <Path of container>
ADsPath of the container for placing the new group
/UNAME <NT 5 User Name>
This is the name for the new group
/SAMNAME <Downlevel NT 4 Sam Account name>
Cannot exceed 20 characters and must be globally unique
<*> Detailed New User information <*>
/FILE < Info File >
Filename for file to contain new user information
<*> OPTIONAL Binding Information <*>
/USER <User name used for binding to the DC>
/PASS <Password used for binding to the DC>
(If these are passed, binding is done with ADsOpenObject())
*/
if (argc == 1)
{
_putws(pwszUsage);
return FALSE;
}
for (int x= 1; x < argc; x++)
{
if (_wcsicmp(argv[x],L"/LDAP")==0)
{
if (argc == x) // Make sure the parameter was passed
{
wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
// Go to the next argument and save it in module level variable
x++;
bsLDAP = SysAllocString(argv[x]);
}
else if (_wcsicmp(argv[x],L"/UNAME")==0)
{
if (argc == x) // Make sure the parameter was passed
{
wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
// Go to the next argument and save it in module level variable
x++;
bsUNAME = SysAllocString(argv[x]);
}
else if (_wcsicmp(argv[x],L"/SAMNAME")==0)
{
if (argc == x) // Make sure the parameter was passed
{
wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
// Go to the next argument and save it in module level variable
x++;
bsSAMNAME = SysAllocString(argv[x]);
}
else if (_wcsicmp(argv[x],L"/FILE")==0)
{
if (argc == x) // Make sure the parameter was passed
{
wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
// Go to the next argument and save it in module level variable
x++;
bsFILE = SysAllocString(argv[x]);
}
else if (_wcsicmp(argv[x],L"/USER")==0)
{
if (argc == x) // Make sure the parameter was passed
{
wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
// Go to the next argument and save it in module level variable
x++;
bsUSER = SysAllocString(argv[x]);
}
else if (_wcsicmp(argv[x],L"/PASS")==0)
{
if (argc == x) // Make sure the parameter was passed
{
wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
// Go to the next argument and save it in module level variable
x++;
bsPASS = SysAllocString(argv[x]);
}
else
{
wprintf(L"\nERROR: %s UNknown Argument\n\n",argv[x]);
_putws(pwszUsage);
return FALSE;
}
}
// Check if User is poassed, then password is required:
if (bsUSER || bsPASS)
if (!bsUSER || !bsPASS) // if either one is missing complain
{
_putws(L"\nERROR: If /USER is specified /PASS is required!");
return FALSE;
}
return TRUE;
}
HRESULT ConvertUTCFromStringToUTCTime( LPWSTR pwszTime, SYSTEMTIME *pst)
{
FILETIME ft;
TCHAR sz[3];
LPWSTR pszSrc = pwszTime;
SYSTEMTIME st;
// Year
sz[0] = pszSrc[0];
sz[1] = pszSrc[1];
sz[2] = TEXT('\0');
st.wYear = (WORD)_wtoi(sz);
if (st.wYear < 50)
{
st.wYear += 2000;
}
else
{
st.wYear += 1900;
}
// Month
sz[0] = pszSrc[2];
sz[1] = pszSrc[3];
st.wMonth = (WORD)_wtoi(sz);
// Day
sz[0] = pszSrc[4];
sz[1] = pszSrc[5];
st.wDay = (WORD)_wtoi(sz);
// Hour
sz[0] = pszSrc[6];
sz[1] = pszSrc[7];
st.wHour = (WORD)_wtoi(sz);
// Minute
sz[0] = pszSrc[8];
sz[1] = pszSrc[9];
st.wMinute = (WORD)_wtoi(sz);
// Second
sz[0] = pszSrc[10];
sz[1] = pszSrc[11];
st.wSecond = (WORD)_wtoi(sz);
st.wMilliseconds = 0;
// This gets us the day of week
SystemTimeToFileTime(&st, &ft);
FileTimeToSystemTime(&ft, &st);
*pst = st;
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* GetNextLine() - Retrives a line from the passed file pointer
Parameters
FILE* fp - File Pointer
LPWSTR pwszDest - Destination Buffer
int iSize - Size of Destination Buffer
*/
BOOL GetNextLine(FILE* fp,LPWSTR pwszDest,int iSize)
{
//BOOL bRet;
WCHAR c =0 ;
int x = 0;
do
{
if (x < iSize )
{
// Get a character
c = getwc(fp);
// Handle the end
if (x ==0 && ((char)c) == EOF )
return FALSE;
// If it is NOT a carriage return - save the character
// (note the cast to (char): as EOF is a char -1.
// with a WIDE character this becomes 65535)
// so we cast DOWN the char to test for the potential -1
if (c!= '\r' && ((char)c) != EOF && c != '\n')
pwszDest[x++] = c;
else
break;
}
} while (c != '\r' && c != EOF && c != '\n' && c !=65535);
pwszDest[x] = NULL;
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Trim() - VERY simple function for removing left and right whitespace from a unicode string
Parameters
LPWSTR pwszData - Data passed for trimming- Function will modify
*/
void Trim(LPWSTR pwszData)
{
int iscan=0;
int iput=0;
int iLenData = wcslen(pwszData);
LPWSTR pwszTemp = new WCHAR[iLenData+1];
int iLenTemp;
// Trim left:
while (pwszData[iscan] != NULL && (pwszData[iscan] == ' ' || pwszData[iscan] == '\t' ))
iscan++;
// We have now scanned PAST whitespace- so copy the string:
wcscpy_s(pwszTemp,iLenData+1,&pwszData[iscan]);
// Now we need to do the TrimRight
iLenTemp = wcslen(pwszTemp);
for (iscan = iLenTemp-1; iscan; iscan--)
{
if (!(pwszTemp[iscan] == ' ' || pwszTemp[iscan] == '\t' ) )
break;
}
pwszTemp[iscan+1] =NULL;
wcscpy_s(pwszData,iLenData,pwszTemp);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* RemoveSpecialChars() - Removes Tabs from passed string
Parameters
LPWSTR pwszLine - Target String
*/
void RemoveSpecialChars(LPWSTR pwszLine)
{
int iLen = wcslen(pwszLine);
for (int x = 0; x < iLen; x++)
{
switch (pwszLine[x])
{
case '\t':
pwszLine[x] = ' '; // convert tabs to spaces..
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* ReadDataFromLine() - Reads the Attribute and the Value from a passed line of text
Parameters
LPWSTR pwszLine - Line to read
BSTR * pbsAttrib - Attribute NAME to return
BSTR * pbsValue - Value of the attribute
*/
HRESULT ReadDataFromLine(LPWSTR pwszLine,BSTR * pbsAttrib, BSTR * pbsValue)
{
int x;
int iLen = wcslen(pwszLine);
*pbsAttrib = NULL;
*pbsValue = NULL;
// Remove any tabs still in the line:
RemoveSpecialChars(pwszLine);
// If this line is a comment or blank, bail..
if (pwszLine[0] == L'/' || iLen == 0)
return S_FALSE;
// Make a temp string to save our string
LPWSTR pwszTempAttrib = new WCHAR [iLen +1];
if ( !pwszTempAttrib )
return E_FAIL;
pwszTempAttrib[0]= NULL;
for (x = 0; x< iLen; x++)
switch(pwszLine[x])
{
case L' ':
case L'\t':
{
// NULL terminate the copy we are building
pwszTempAttrib[x] = L'\0';
x++;
goto DoneReadDataFromLine;
break;
}
case NULL: // if we hit the end of the string- there is NOT a value there
{
wprintf(L"\n!!!Attribute missing value [%s]\n",pwszLine);
delete [] pwszTempAttrib;
return E_FAIL;
}
default:
{
pwszTempAttrib[x] = pwszLine[x];
}
}
DoneReadDataFromLine:
// Trim off any preceding spaces..
Trim((LPWSTR)pwszLine +x);
// Grab the END of the passed line, and put it in the
// Value BSTR
*pbsValue = SysAllocString((LPWSTR)pwszLine +x);
// Alloc a new BSTR to return for this attribute
*pbsAttrib= SysAllocString(pwszTempAttrib);
if (iLen)
delete [] pwszTempAttrib ;
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* MakeOctetADSVALUE() - Reads the passed octet string into the passed ADSVALUE,
Sample String:
x00 x00 x00 x00 xe0 xff x03 xe0 xff x03 xe0 xff x03 xe0 xff x03 xe0 xff x03 x00 x00
The "x"'s are required and the values must be in HEX format
Parameters
ADSVALUE * pAdsValue - Returned ADSVALUE of Type OctetString
LPWSTR pwszOctet - String representing OCTET
*/
HRESULT MakeOctetADSVALUE(ADSVALUE * pAdsValue,LPWSTR pwszOctet)
{
int iNumBytes = 0;
int iStrLen = wcslen(pwszOctet);
// Count the number of BYTES in the String
for (int x =0;x <iStrLen;x++)
if (pwszOctet[x] == L'x' || pwszOctet[x] == L'X')
iNumBytes ++;
if (iNumBytes)
{
int iCurrByte =0;
// Allocate the bytes
pAdsValue->OctetString.lpValue = new BYTE [iNumBytes+1];
pAdsValue->OctetString.dwLength = iNumBytes;
for (int x =0;x <iStrLen;x++)
if (pwszOctet[x] == L'x' || pwszOctet[x] == L'X')
{
x++;
int iVal;
// found an x so grab the data
swscanf_s( &pwszOctet[x], L"%x",&iVal);
pAdsValue->OctetString.lpValue[iCurrByte++]= iVal;
// scan past the rest of the string
for (x =x;x<iStrLen && pwszOctet[x] != (WCHAR)' ' ;x++)
;
}
}
else
return E_FAIL;
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* PopulateADSAttrInfo() - Populates the passed ADS_ATTR_INFO from the passed attribute and Value
Parameters
ADS_ATTR_INFO * pattrInfo - Pointer to Element to be added
LPWSTR pwszAttrib - Name of the Attribute
LPWSTR pwszValue - Value of the Attribute
*/
BOOL PopulateADSAttrInfo(ADS_ATTR_INFO * pattrInfo,LPWSTR pwszAttrib,LPWSTR pwszValue)
{
// Look up the attribute name and get the TYPE string for this attribute
LPWSTR pwszType;
LPWSTR pwszSingleMulti;
BOOL bAttribIsSingle = TRUE;
BOOL bret;
bret = MapUserAttribToType(pwszAttrib,&pwszType,&pwszSingleMulti);
if (!bret)
{
wprintf(L"\n!!!Error: unable to map %s\n",pwszAttrib);
return FALSE;
}
if (_wcsicmp(pwszSingleMulti,L"MV")==0)
bAttribIsSingle = FALSE;
else
bAttribIsSingle = TRUE;
// Look up the string and get the corrosponding ADSVALUE...
ADSTYPE adType = MapTypeToADSTYPE(pwszType);
if (adType == ADSTYPE_UNKNOWN)
{
wprintf(L"\n!!!Error: unable to map %s ADS_TYPE unknown\n",pwszAttrib);
return FALSE;
}
// FIll in the Attribute Name
unsigned int attrNameLen = wcslen(pwszAttrib)+1;
pattrInfo->pszAttrName = new WCHAR [attrNameLen];
wcscpy_s(pattrInfo->pszAttrName,attrNameLen,pwszAttrib);
pattrInfo->dwControlCode = ADS_ATTR_UPDATE;
pattrInfo->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
pattrInfo->pADsValues = new ADSVALUE;
pattrInfo->pADsValues->dwType = adType;
pattrInfo->dwNumValues = 1;
// Fill in the VALUE:
switch (adType )
{
case ADSTYPE_DN_STRING:
case ADSTYPE_CASE_EXACT_STRING:
case ADSTYPE_CASE_IGNORE_STRING:
case ADSTYPE_PRINTABLE_STRING:
case ADSTYPE_NUMERIC_STRING:
case ADSTYPE_TYPEDNAME:
case ADSTYPE_FAXNUMBER:
case ADSTYPE_PATH:
case ADSTYPE_OBJECT_CLASS:
{
pattrInfo->pADsValues->CaseIgnoreString = new WCHAR [wcslen(pwszValue)+1];
wcscpy_s(pattrInfo->pADsValues->CaseIgnoreString,wcslen(pwszValue)+1,pwszValue);
break;
}
case ADSTYPE_BOOLEAN:
if (_wcsicmp(pwszValue,L"TRUE")==0)
pattrInfo->pADsValues->Boolean = 1;
else if (_wcsicmp(pwszValue,L"FALSE")==0)
pattrInfo->pADsValues->Boolean = 0;
else if (_wtoi(pwszValue)>0)
pattrInfo->pADsValues->Boolean = 1;
else
pattrInfo->pADsValues->Boolean = 0;
break;
case ADSTYPE_INTEGER:
{
pattrInfo->pADsValues->Integer = _wtoi(pwszValue);
break;
}
case ADSTYPE_OCTET_STRING:
{
// Read the string into an actualy binary blob
HRESULT hr = MakeOctetADSVALUE(pattrInfo->pADsValues ,pwszValue);
if (FAILED(hr))
return FALSE;
break;
}
case ADSTYPE_UTC_TIME:
{
SYSTEMTIME pst;
HRESULT hr = ConvertUTCFromStringToUTCTime( pwszValue,&pst );
if (FAILED(hr))
return FALSE;
pattrInfo->pADsValues->UTCTime = pst;
break;
}
case ADSTYPE_LARGE_INTEGER:
{
pattrInfo->pADsValues->dwType = ADSTYPE_LARGE_INTEGER;
swscanf_s (pwszValue, L"%I64d", &pattrInfo->pADsValues->LargeInteger);
break;
}
default:
{
wprintf(L"\n\n!!!ERROR Unrecognized Type for atrib: %s",pwszAttrib);
return FALSE;
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* PopulateAttrInfoFromFile() - Populates the passed ADS_ATTR_INFO from the passed filename
Parameters
LPWSTR pwszFileName - file from which info is read
ADS_ATTR_INFO * pattrInfo - Pointer to Elements to be added
DWORD &rdwNumPopulated - Returned number populated
*/
BOOL PopulateAttrInfoFromFile(LPWSTR pwszFileName,ADS_ATTR_INFO * pattrInfo,DWORD &rdwNumPopulated )
{
HRESULT hr = S_OK;
BOOL bRet = FALSE;
FILE * fpInput = NULL;
WCHAR pwszLine[4096];
rdwNumPopulated = 0;
errno_t status = 0;
if( (status = _wfopen_s( &fpInput, pwszFileName, L"r" )) == NULL )
{
wprintf(L"\nError Opening Input File:%s",pwszFileName);
return FALSE;
}
while (GetNextLine(fpInput,pwszLine,4096) && SUCCEEDED(hr))
{
Trim(pwszLine);
BSTR bsAttrib;
BSTR bsValue;
// Read the line into our BSTRS
// if S_FALSE is returned, then we do not have a line
// if E_FAIL is returned, then we have an error condition
hr = ReadDataFromLine(pwszLine,&bsAttrib,&bsValue);
if (hr == S_OK)
{
wprintf(L" attrib:%s value:%s\n",bsAttrib,bsValue);
// Take the attribute and value and add them to the Array
if (!PopulateADSAttrInfo(&pattrInfo[rdwNumPopulated],bsAttrib,bsValue))
{
hr = E_FAIL;
break;
}
SysFreeString(bsAttrib);
SysFreeString(bsValue);
rdwNumPopulated++;
}
}
fclose(fpInput);
return (SUCCEEDED(hr));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* CreateUserFromFile() - Function for creating a basic User
Parameters
IDirectoryObject *pDirObject - Parent Directory Object for the new User
LPWSTR pwCommonName - Common Name for the new User
IDirectoryObject ** ppDirObjRet - Pointer to the Pointer which will receive the new User
int iUserType - Bitflags for new User:
ADS_User_TYPE_GLOBAL_User,
ADS_User_TYPE_DOMAIN_LOCAL_User,
ADS_User_TYPE_UNIVERSAL_User,
ADS_User_TYPE_SECURITY_ENABLED
*/
HRESULT CreateUserFromFile(IDirectoryObject *pDirObject, LPWSTR pwCommonName,LPWSTR pwSamAcctName,IDirectoryObject ** ppDirObjRet,LPWSTR pwszFileName)
{
// To simply things, allocate a fixed array:
ADS_ATTR_INFO attrInfo [MAX_ATTRIBS+1];
HRESULT hr = S_OK;
DWORD dwNumPopulated;
LPDISPATCH pDisp;
*ppDirObjRet = NULL;
WCHAR pwCommonNameFull[MAX_PATH*2];
BOOL bRet = FALSE;
FILE * fpInput = NULL;
WCHAR pwszLine[4096];
dwNumPopulated = 0;
errno_t status = 0;
if( (status = _wfopen_s( &fpInput, pwszFileName, L"r" )) == NULL )
{
wprintf(L"\nError Opening Input File:%s",pwszFileName);
return FALSE;
}
while (GetNextLine(fpInput,pwszLine,4096) && SUCCEEDED(hr))
{
Trim(pwszLine);
BSTR bsAttrib;
BSTR bsValue;
// Read the line into our BSTRS
// if S_FALSE is returned, then we do not have a line
// if E_FAIL is returned, then we have an error condition
hr = ReadDataFromLine(pwszLine,&bsAttrib,&bsValue);
if (hr == S_OK)
{
wprintf(L" attrib:%s value:%s\n",bsAttrib,bsValue);
// Take the attribute and value and add them to the Array
if (!PopulateADSAttrInfo(&attrInfo[dwNumPopulated],bsAttrib,bsValue))
{
hr = E_FAIL;
break;
}
SysFreeString(bsAttrib);
SysFreeString(bsValue);
dwNumPopulated++;
}
}
fclose(fpInput);
wsprintfW(pwCommonNameFull,L"CN=%s",pwCommonName);
hr = pDirObject->CreateDSObject( pwCommonNameFull, attrInfo,
dwNumPopulated, &pDisp );
if (SUCCEEDED(hr))
{
hr = pDisp->QueryInterface(IID_IDirectoryObject,(void**) ppDirObjRet);
pDisp->Release();
pDisp = NULL;
}
//FreeAttrInfo(attrInfo);
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* CreateUser() - Function for creating a basic User
Parameters
IDirectoryObject *pDirObject - Parent Directory Object for the new User
LPWSTR pwCommonName - Common Name for the new User
IDirectoryObject ** ppDirObjRet - Pointer to the Pointer which will receive the new User
int iUserType - Bitflags for new User:
ADS_User_TYPE_GLOBAL_User,
ADS_User_TYPE_DOMAIN_LOCAL_User,
ADS_User_TYPE_UNIVERSAL_User,
ADS_User_TYPE_SECURITY_ENABLED
*/
HRESULT CreateUser(IDirectoryObject *pDirObject, LPWSTR pwCommonName,LPWSTR pwSamAcctName,IDirectoryObject ** ppDirObjRet)
{
assert(pDirObject);
if (wcslen(pwSamAcctName) >20)
{
MessageBox(NULL,L"SamAccountName CANNOT be bigger than 20 characters",L"Error: CreateSimpleUser()",MB_ICONSTOP);
assert(0);
return E_FAIL;
}
HRESULT hr;
ADSVALUE sAMValue;
ADSVALUE classValue;
LPDISPATCH pDisp;
WCHAR pwCommonNameFull[1024];
ADS_ATTR_INFO attrInfo[] =
{
{ L"objectClass", ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING, &classValue, 1 },
{L"sAMAccountName", ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING, &sAMValue, 1},
};
DWORD dwAttrs = sizeof(attrInfo)/sizeof(ADS_ATTR_INFO);
classValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
classValue.CaseIgnoreString = L"User";
sAMValue.dwType=ADSTYPE_CASE_IGNORE_STRING;
sAMValue.CaseIgnoreString = pwSamAcctName;
wsprintfW(pwCommonNameFull,L"CN=%s",pwCommonName);
hr = pDirObject->CreateDSObject( pwCommonNameFull, attrInfo,
dwAttrs, &pDisp );
if (SUCCEEDED(hr))
{
hr = pDisp->QueryInterface(IID_IDirectoryObject,(void**) ppDirObjRet);
pDisp->Release();
pDisp = NULL;
}
return hr;
}