//+-------------------------------------------------------------------------
//
//
// File: dsasignaturemod.c
//
// This is a sample program for setting or clearing the
// DRA_INHIBIT_BACKUP_AUTO_STAMP flag in the dSASignature
// attribute on the schema NC.
//
//--------------------------------------------------------------------------
#include <windows.h>
#include <winldap.h>
#include <winber.h>
#include <strsafe.h>
#include <stdio.h>
#include <conio.h>
#define CHECKLDAP(result, op) if (result) { printf("%s failed with LDAP error=0x%x(%d)\n", op, result, result); goto Exit; }
#define CHECKLDAPLE(result, op) if (!result) { printf("%s failed with LDAP error=0x%x(%d)\n", op, LdapGetLastError(), LdapGetLastError()); goto Exit; }
//
// Type definitions for the dsaSignature attribute
//
#define DRA_INHIBIT_BACKUP_AUTO_STAMP (0x1)
typedef struct _BACKUP_NC_HEAD_DSA_SIGNATURE_STATE_V1 {
DWORD dwFlags;
LONGLONG BackupErrorLatencySecs;
UUID dsaGuid;
} BACKUP_NC_HEAD_DSA_SIGNATURE_STATE_V1;
typedef struct _BACKUP_NC_HEAD_DSA_SIGNATURE_STATE {
DWORD dwVersion;
DWORD cbSize;
union
{
BACKUP_NC_HEAD_DSA_SIGNATURE_STATE_V1 V1;
};
} BACKUP_NC_HEAD_DSA_SIGNATURE_STATE;
// Whether we are setting or clearing the bit
BOOL gfSet = FALSE;
// Whether we are querying the bit
BOOL gfGet = FALSE;
// Whether we are automating and want to skip PromptForOK()
BOOL skipPrompt = FALSE;
// Copy of the schema NC DN
LPWSTR pszSchemaNCCopy = NULL;
BOOL PromptForOK()
{
int prompt;
BOOL ret = skipPrompt;
printf("\n");
printf("This program is about to %s the DRA_INHIBIT_BACKUP_AUTO_STAMP flag in\n", gfSet ? "set" : "clear");
printf("the dSASignature attribute on the following directory NC:\n");
printf("\n");
printf(" %S\n", pszSchemaNCCopy);
printf("\n");
if (!skipPrompt) {
printf("Do you wish to continue? (Y\\N)");
prompt = _getch();
printf("\n");
ret = (prompt == 'Y' || prompt == 'y') ? TRUE : FALSE;
}
return ret;
}
void Usage()
{
CHAR szExeName[MAX_PATH];
ZeroMemory(szExeName, sizeof(szExeName));
GetModuleFileNameA(NULL, szExeName, ARRAYSIZE(szExeName));
printf("Usage:\n");
printf("\n");
printf("%s [/get | /set | /clear] [/auto]\n", szExeName);
printf("\n");
printf(" /get - queries current state of the DRA_INHIBIT_BACKUP_AUTO_STAMP flag\n");
printf(" /set - sets the DRA_INHIBIT_BACKUP_AUTO_STAMP flag\n");
printf(" /clear - clears the DRA_INHIBIT_BACKUP_AUTO_STAMP flag\n");
printf(" /auto - skips the prompt for proceeding (for automation purposes)\n");
printf("\n");
}
BOOL ParseArgs(int argc, __in char ** argv)
{
BOOL ret = FALSE;
if (argc >= 2)
{
if (!_stricmp("/get", argv[1])) {
gfGet = TRUE;
ret = TRUE;
}
else if (!_stricmp("/set", argv[1])) {
gfSet = TRUE;
ret = TRUE;
}
else if (!_stricmp("/clear", argv[1])) {
gfSet = FALSE;
ret = TRUE;
}
if (argc >= 3)
{
if (!_stricmp("/auto", argv[2])) {
skipPrompt = TRUE;
}
}
}
return ret;
}
void __cdecl main(int argc, __in char ** argv)
{
BOOL fFoundDSASignature = FALSE;
BOOL fFlagSet = FALSE;
LDAP* ldap = NULL;
ULONG cb = 0;
ULONG cch = 0;
ULONG result = 0;
LPWSTR pszAttrs[2] = { 0 };
LPWSTR* ppszSchemaNC = NULL;
LDAPMod mod;
LDAPMod* mods[2];
LDAPMessage* pldapMsg = NULL;
LDAPMessage* pldapResults = NULL;
struct berval valMod;
struct berval* vals[2];
struct berval** val = NULL;
BACKUP_NC_HEAD_DSA_SIGNATURE_STATE dsaSignature;
ZeroMemory(&dsaSignature, sizeof(dsaSignature));
if (!ParseArgs(argc, argv)) {
Usage();
return;
}
printf("\n");
//
// Init connection handle
//
ldap = ldap_init(NULL, LDAP_PORT);
CHECKLDAPLE(ldap, "ldap_init");
//
// Connect to DC
//
result = ldap_connect(ldap, NULL);
CHECKLDAP(result, "ldap_connect");
//
// Retrieve schema NC name
//
pszAttrs[0] = L"schemaNamingContext";
pszAttrs[1] = NULL;
result = ldap_search_sW(ldap,
NULL,
LDAP_SCOPE_BASE,
L"(objectclass=*)",
pszAttrs,
0,
&pldapResults);
CHECKLDAP(result, "ldap_search_s for schemaNamingContext");
pldapMsg = ldap_first_entry(ldap, pldapResults);
CHECKLDAPLE(pldapMsg, "ldap_first_entry");
//
// Make a copy of the schema NC name
//
ppszSchemaNC = (LPWSTR*)ldap_get_valuesW(ldap, pldapMsg, L"schemaNamingContext");
cch = wcslen(ppszSchemaNC[0]) + 1;
pszSchemaNCCopy = (LPWSTR)malloc(cch * sizeof(WCHAR));
StringCchCopy(pszSchemaNCCopy, cch, ppszSchemaNC[0]);
ldap_value_free(ppszSchemaNC);
ppszSchemaNC = NULL;
ldap_msgfree(pldapResults);
pldapResults = NULL;
//
// Bind to the DC
//
result = ldap_bind_s(ldap, pszSchemaNCCopy, NULL, LDAP_AUTH_NEGOTIATE);
CHECKLDAP(result, "ldap_bind_s");
//
// Retrieve current value of the dSASignature attribute
//
pszAttrs[0] = L"dSASignature";
pszAttrs[1] = NULL;
result = ldap_search_sW(ldap,
pszSchemaNCCopy,
LDAP_SCOPE_BASE,
L"(objectclass=*)",
pszAttrs,
0,
&pldapResults);
CHECKLDAP(result, "ldap_search_s for dSASignature");
pldapMsg = ldap_first_entry(ldap, pldapResults);
CHECKLDAPLE(pldapMsg, "ldap_first_entry");
//
// Make a copy of the dSASignature attribute.
//
val = (struct berval**)ldap_get_values_len(ldap, pldapMsg, L"dSASignature");
// Make sure that the value was there and seems to be the correct size.
if (val && val[0]) {
if (val[0]->bv_len == sizeof(BACKUP_NC_HEAD_DSA_SIGNATURE_STATE)) {
memcpy(&dsaSignature, val[0]->bv_val, val[0]->bv_len);
fFoundDSASignature = TRUE;
}
}
ldap_value_free_len(val);
val = NULL;
ldap_msgfree(pldapResults);
pldapResults = NULL;
//
// Sanity check
//
if (!fFoundDSASignature ||
dsaSignature.dwVersion != 1) {
printf("The dSASignature attribute was either not\n");
printf("found or was in an unexpected format.\n");
goto Exit;
}
//
// Cache whether the flag is set already or not
//
fFlagSet = (DRA_INHIBIT_BACKUP_AUTO_STAMP & dsaSignature.V1.dwFlags) ? TRUE : FALSE;
//
// If query-only mode, display current setting and leave
//
if (gfGet) {
printf("The target directory %s have the DRA_INHIBIT_BACKUP_AUTO_STAMP set.\n",
fFlagSet ? "DOES" : "DOES NOT");
goto Exit;
}
//
// If doing a modification, see whether there is anything to do.
//
if (gfSet && fFlagSet) {
printf("The /set operation was specified but the target directory already\n");
printf(" has the flag set. Exiting with no changes.\n");
goto Exit;
}
else if (!gfSet && !fFlagSet) {
printf("The /clear operation was specified but the target directory already\n");
printf(" has the flag cleared. Exiting with no changes.\n");
goto Exit;
}
//
// Yes there is work to do; prompt the admin
// for approval before you continue.
//
if (!PromptForOK()) {
goto Exit;
}
//
// Set or clear the bit in our local copy
//
if (gfSet) {
dsaSignature.V1.dwFlags |= DRA_INHIBIT_BACKUP_AUTO_STAMP;
}
else {
dsaSignature.V1.dwFlags &= (~DRA_INHIBIT_BACKUP_AUTO_STAMP);
}
//
// Prepare for the modify
//
ZeroMemory(&valMod, sizeof(valMod));
valMod.bv_len = sizeof(dsaSignature);
valMod.bv_val = (PCHAR)&dsaSignature;
vals[0] = &valMod;
vals[1] = NULL;
ZeroMemory(&mod, sizeof(mod));
mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
mod.mod_type = L"dSASignature";
mod.mod_vals.modv_bvals = vals;
mods[0] = &mod;
mods[1] = NULL;
//
// And do it:
//
result = ldap_modify_s(ldap,
pszSchemaNCCopy,
mods);
CHECKLDAP(result, "ldap_modify_s for dSASignature");
printf("\n");
printf("Modification succeeded!\n");
Exit:
if (pszSchemaNCCopy) {
free(pszSchemaNCCopy);
}
if (ldap) {
ldap_unbind(ldap);
}
printf("\n");
return;
}
The following are the sample program outputs:
C:\>dsasignaturemod.exe /get
The target directory DOES NOT have the DRA_INHIBIT_BACKUP_AUTO_STAMP set.
C:\>dsasignaturemod.exe /set
This program is about to set the DRA_INHIBIT_BACKUP_AUTO_STAMP flag in
the dSASignature attribute on the following directory NC:
CN=Schema,CN=Configuration,DC=rootdomain,DC=com
Do you wish to continue? (Y\N)
Modification succeeded!
C:\>dsasignaturemod.exe /set /auto
This program is about to set the DRA_INHIBIT_BACKUP_AUTO_STAMP flag in
the dSASignature attribute on the following directory NC:
CN=Schema,CN=Configuration,DC=rootdomain,DC=com
Modification succeeded!
C:\>dsasignaturemod.exe /get
The target directory DOES have the DRA_INHIBIT_BACKUP_AUTO_STAMP set.
C:\>dsasignaturemod.exe /clear
This program is about to clear the DRA_INHIBIT_BACKUP_AUTO_STAMP flag in
the dSASignature attribute on the following directory NC:
CN=Schema,CN=Configuration,DC=rootdomain,DC=com
Do you wish to continue? (Y\N)
Modification succeeded!
C:\>dsasignaturemod.exe /clear /auto
This program is about to clear the DRA_INHIBIT_BACKUP_AUTO_STAMP flag in
the dSASignature attribute on the following directory NC:
CN=Schema,CN=Configuration,DC=rootdomain,DC=com
Modification succeeded!