📄 smpd_adreg.cpp
字号:
/* -*- Mode: C; c-basic-offset:4 ; -*- *//* * (C) 2001 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */#include <winsock2.h>#include <windows.h>#include <iads.h>#include "smpd_service.h"#include <ntdsapi.h>#include <dsgetdc.h>#include <lm.h>#define SECURITY_WIN32#include <security.h>#include <adshlp.h>#include <atlbase.h>#include <adserr.h>static HRESULT AllowAccessToScpProperties(LPWSTR wszAccountSAM, IADs *pSCPObject);typedef struct tagADSERRMSG{ HRESULT hr; LPCTSTR pszError;} ADSERRMSG;#define ADDADSERROR(x) x, _T(#x)static ADSERRMSG adsErr[] ={ ADDADSERROR(E_ADS_BAD_PATHNAME), ADDADSERROR(E_ADS_INVALID_DOMAIN_OBJECT), ADDADSERROR(E_ADS_INVALID_USER_OBJECT), ADDADSERROR(E_ADS_INVALID_COMPUTER_OBJECT), ADDADSERROR(E_ADS_UNKNOWN_OBJECT), ADDADSERROR(E_ADS_PROPERTY_NOT_SET), ADDADSERROR(E_ADS_PROPERTY_NOT_SUPPORTED), ADDADSERROR(E_ADS_PROPERTY_INVALID), ADDADSERROR(E_ADS_BAD_PARAMETER), ADDADSERROR(E_ADS_OBJECT_UNBOUND), ADDADSERROR(E_ADS_PROPERTY_NOT_MODIFIED), ADDADSERROR(E_ADS_PROPERTY_MODIFIED), ADDADSERROR(E_ADS_CANT_CONVERT_DATATYPE), ADDADSERROR(E_ADS_PROPERTY_NOT_FOUND), ADDADSERROR(E_ADS_OBJECT_EXISTS), ADDADSERROR(E_ADS_SCHEMA_VIOLATION), ADDADSERROR(E_ADS_COLUMN_NOT_SET), ADDADSERROR(E_ADS_INVALID_FILTER), ADDADSERROR(0),};static LPCTSTR GetADSIError( HRESULT hr ){ if ( hr & 0x00005000 ) { int idx=0; while (adsErr[idx].hr != 0 ) { if ( adsErr[idx].hr == hr ) { return adsErr[idx].pszError; } idx++; } } return _T("");}static LPCTSTR GetErrorMessage( HRESULT hr ){ BOOL bRet; static TCHAR s[1024]; LPTSTR lpBuffer=NULL; if ( SUCCEEDED(hr) ) { return _T("Success"); } if ( hr & 0x00005000) /* standard ADSI Errors */ { _tcscpy(s, GetADSIError(hr)); } else if ( HRESULT_FACILITY(hr)==FACILITY_WIN32 ) { bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), (LPTSTR) &lpBuffer, 0, NULL); if ( !bRet ) { _sntprintf(s, 1024, _T("Error %ld"), hr); } if ( lpBuffer ) { _tcscpy(s, lpBuffer); LocalFree( lpBuffer ); } } else /* Non Win32 Error */ { _sntprintf(s, 1024, _T("%X"), hr ); return s; } WCHAR szBuffer[MAX_PATH]; WCHAR szName[MAX_PATH]; DWORD dwError; hr = ADsGetLastError( &dwError, szBuffer, (sizeof(szBuffer)/sizeof(WCHAR))-1, szName, (sizeof(szName)/sizeof(WCHAR))-1 ); if ( SUCCEEDED(hr) && dwError != ERROR_INVALID_DATA && wcslen(szBuffer)) { USES_CONVERSION; _tcscat(s, _T(" -- Extended Error --- \n")); _tcscat(s, OLE2T(szName)); _tcscat(s, _T(":\n")); _tcscat(s, OLE2T( szBuffer )); } return s;}static void ReportError(TCHAR *msg, HRESULT hr){ _tprintf(TEXT("HRESULT=%d\nError message: %s\nError Text: %s\n"), hr, msg, GetErrorMessage(hr));}static void ReportServiceError(char *msg, DWORD error){ printf("error=%d\nError message: %s\nError Text: %s\n", error, msg, GetErrorMessage(error));}/* ScpCreateCreate a new service connection point as a child object of thelocal server computer object.*/static DWORD ScpCreate( USHORT usPort, /* Service's default port to store in SCP. */ LPTSTR szClass, /* Service class string to store in SCP. */ LPTSTR szAccount, /* Logon account that must access SCP. */ UINT ccDN, /* Length of the pszDN buffer in characters */ TCHAR *pszDN) /* Returns distinguished name of SCP. */{ DWORD dwStat, dwAttr, dwLen; HRESULT hr; IDispatch *pDisp; /* Returned dispinterface of new object. */ IDirectoryObject *pComp; /* Computer object; parent of SCP. */ IADs *pIADsSCP; /* IADs interface on new object. */ TCHAR szServer[MAX_PATH]; TCHAR szDn[MAX_PATH]; TCHAR szAdsPath[MAX_PATH]; TCHAR szPort[6]; HKEY hReg; DWORD dwDisp; TCHAR szRelativeDistinguishedName[MAX_PATH]; ADSVALUE cn, objclass, keywords[4], binding, classname, dnsname, nametype; BSTR bstrGuid = NULL; TCHAR pwszBindByGuidStr[1024]; VARIANT var; /* Values for SCPs keywords attribute. */ TCHAR* KwVal[] = { TEXT(SMPD_SERVICE_VENDOR_GUID), /* Vendor GUID. */ TEXT(SMPD_SERVICE_GUID), /* Product GUID. */ TEXT(SMPD_PRODUCT_VENDOR), /* Vendor Name. */ TEXT(SMPD_PRODUCT), /* Product Name. */ }; /* SCP attributes to set during creation of SCP. */ ADS_ATTR_INFO ScpAttribs[] = { {TEXT("cn"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &cn, 1}, {TEXT("objectClass"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &objclass, 1}, {TEXT("keywords"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, keywords, 4}, {TEXT("serviceDnsName"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &dnsname, 1}, {TEXT("serviceDnsNameType"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &nametype, 1}, {TEXT("serviceClassName"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &classname, 1}, {TEXT("serviceBindingInformation"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &binding, 1}, }; if (!szClass /*|| !szAccount*/ || !pszDN || !(ccDN > 0)) { hr = ERROR_INVALID_PARAMETER; ReportError(TEXT("Invalid parameter."), hr); return hr; } /* Get the DNS name of the local computer. */ dwLen = sizeof(szServer); if (!GetComputerNameEx(ComputerNameDnsFullyQualified, szServer, &dwLen)) { _tprintf(TEXT("GetComputerNameEx failed: Error %d\n"), GetLastError()); return GetLastError(); } /*_tprintf(TEXT("GetComputerNameEx: %s\n"), szServer);*/ /* Enter the attribute values to be stored in the SCP. */ keywords[0].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[1].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[2].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[3].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[0].CaseIgnoreString = KwVal[0]; keywords[1].CaseIgnoreString = KwVal[1]; keywords[2].CaseIgnoreString = KwVal[2]; keywords[3].CaseIgnoreString = KwVal[3]; cn.dwType = ADSTYPE_CASE_IGNORE_STRING; cn.CaseIgnoreString = TEXT(SMPD_SERVICE_NAME); objclass.dwType = ADSTYPE_CASE_IGNORE_STRING; objclass.CaseIgnoreString = TEXT("serviceConnectionPoint"); dnsname.dwType = ADSTYPE_CASE_IGNORE_STRING; dnsname.CaseIgnoreString = szServer; classname.dwType = ADSTYPE_CASE_IGNORE_STRING; classname.CaseIgnoreString = szClass; _sntprintf(szPort, 6, TEXT("%d"), usPort); binding.dwType = ADSTYPE_CASE_IGNORE_STRING; binding.CaseIgnoreString = szPort; nametype.dwType = ADSTYPE_CASE_IGNORE_STRING; nametype.CaseIgnoreString = TEXT("A"); /* Get the distinguished name of the computer object for the local computer. */ dwLen = sizeof(szDn); if (!GetComputerObjectName(NameFullyQualifiedDN, szDn, &dwLen)) { _tprintf(TEXT("GetComputerObjectName failed: Error %d\n"), GetLastError()); return GetLastError(); } /*_tprintf(TEXT("GetComputerObjectName: %s\n"), szDn);*/ /* Compose the ADSpath and bind to the computer object for the local computer. */ _tcsncpy(szAdsPath,TEXT("LDAP://"),MAX_PATH); _tcsncat(szAdsPath, szDn, MAX_PATH - _tcslen(szAdsPath)); hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pComp); if (FAILED(hr)) { _tprintf(TEXT("ADsGetObject('%s') failed\n"), szAdsPath); ReportError(TEXT("Failed to bind Computer Object."),hr); return hr; } _tprintf(TEXT("Bound to Active directory object:\n%s\n"), szDn); /******************************************************************** * Publish the SCP as a child of the computer object *********************************************************************/ /* Calculate attribute count. */ dwAttr = sizeof(ScpAttribs)/sizeof(ADS_ATTR_INFO); /* Complete the action. */ _sntprintf(szRelativeDistinguishedName, MAX_PATH, TEXT("cn=%s"), TEXT(SMPD_SERVICE_NAME)); /* Delete the previous object if it exists */ hr = pComp->DeleteDSObject(szRelativeDistinguishedName); /* Create a new object */ hr = pComp->CreateDSObject(szRelativeDistinguishedName, ScpAttribs, dwAttr, &pDisp); if (FAILED(hr)) { ReportError(TEXT("Failed to create SCP:"), hr); pComp->Release(); return hr; } pComp->Release(); /* Query for an IADs pointer on the SCP object. */ hr = pDisp->QueryInterface(IID_IADs,(void **)&pIADsSCP); if (FAILED(hr)) { ReportError(TEXT("Failed to QueryInterface for IADs:"), hr); pDisp->Release(); return hr; } pDisp->Release(); /* Set ACEs on the SCP so a service can modify it. */ hr = AllowAccessToScpProperties( szAccount, /* Service account to allow access. */ pIADsSCP); /* IADs pointer to the SCP object. */ if (FAILED(hr)) { ReportError(TEXT("Failed to set ACEs on SCP DACL:"), hr); return hr; } /* Get the distinguished name of the SCP. */ VariantInit(&var); hr = pIADsSCP->Get(CComBSTR("distinguishedName"), &var); if (FAILED(hr)) { ReportError(TEXT("Failed to get distinguishedName:"), hr); pIADsSCP->Release(); return hr; } /*_tprintf(TEXT("distinguishedName via IADs: %s\n"), var.bstrVal);*/ _tcsncpy(pszDN, var.bstrVal, ccDN); /* Retrieve the SCP objectGUID in format suitable for binding. */ hr = pIADsSCP->get_GUID(&bstrGuid); if (FAILED(hr)) { ReportError(TEXT("Failed to get GUID:"), hr); pIADsSCP->Release(); return hr; } /* Build a string for binding to the object by GUID. */ _tcsncpy(pwszBindByGuidStr, TEXT("LDAP://<GUID="), 1024); _tcsncat(pwszBindByGuidStr, bstrGuid, 1024 -_tcslen(pwszBindByGuidStr)); _tcsncat(pwszBindByGuidStr, TEXT(">"), 1024 -_tcslen(pwszBindByGuidStr)); /*_tprintf(TEXT("GUID binding string: %s\n"), pwszBindByGuidStr);*/ pIADsSCP->Release(); /* Create a registry key to save the GUID binding string */ dwStat = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(SMPD_SERVICE_REGISTRY_KEY), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hReg, &dwDisp); if (dwStat != NO_ERROR) { ReportError(TEXT("RegCreateKeyEx failed:"), dwStat); return dwStat; } /* Cache the GUID binding string under the registry key. */ dwStat = RegSetValueEx(hReg, TEXT("GUIDBindingString"), 0, REG_SZ, (const BYTE *)pwszBindByGuidStr, (DWORD)(2*(_tcslen(pwszBindByGuidStr)))); if (dwStat != NO_ERROR) { ReportError(TEXT("RegSetValueEx failed:"), dwStat); return dwStat; } RegCloseKey(hReg); /* Cleanup should delete the SCP and registry key if an error occurs. */ return dwStat;}static DWORD SpnCompose( TCHAR ***pspn, /* Output: an array of SPNs */ unsigned long *pulSpn, /* Output: the number of SPNs returned */ TCHAR *pszDNofSCP, /* Input: DN of the service's SCP */ TCHAR* pszServiceClass) /* Input: the name of the service class */{ DWORD dwStatus; dwStatus = DsGetSpn( DS_SPN_SERVICE, /* Type of SPN to create (enumerated type) */ pszServiceClass, /* Service class - a name in this case */ pszDNofSCP, /* Service name - DN of the service SCP */ 0, /* Default: omit port component of SPN */ 0, /* Number of entries in hostnames and ports arrays */ NULL, /* Array of hostnames. Default is local computer */ NULL, /* Array of ports. Default omits port component */ pulSpn, /* Receives number of SPNs returned in array */ pspn /* Receives array of SPN(s) */ ); return dwStatus;}/***************************************************************************SpnRegister()Register or unregister the SPNs under the service's account.If the service runs in LocalSystem account, pszServiceAcctDN is thedistinguished name of the local computer account.Parameters:pszServiceAcctDN - Contains the distinguished name of the logonaccount for this instance of the service.pspn - Contains an array of SPNs to register.ulSpn - Contains the number of SPNs in the array.Operation - Contains one of the DS_SPN_WRITE_OP values that determinesthe type of operation to perform on the SPNs.***************************************************************************/static DWORD SpnRegister(TCHAR *pszServiceAcctDN, TCHAR **pspn, unsigned long ulSpn, DS_SPN_WRITE_OP Operation){ DWORD dwStatus; HANDLE hDs; TCHAR szSamName[512]; DWORD dwSize = sizeof(szSamName); PDOMAIN_CONTROLLER_INFO pDcInfo; /* Bind to a domain controller. */ /* Get the domain for the current user. */ if (GetUserNameEx(NameSamCompatible, szSamName, &dwSize)) { TCHAR *pWhack = _tcschr(szSamName, '\\'); if (pWhack) { *pWhack = '\0'; } } else { return GetLastError(); } /*_tprintf(TEXT("szSamName: %s\n"), szSamName);*/ /* Get the name of a domain controller in that domain. */ dwStatus = DsGetDcName(NULL, szSamName, NULL, NULL, DS_IS_FLAT_NAME | DS_RETURN_DNS_NAME | DS_DIRECTORY_SERVICE_REQUIRED, &pDcInfo); if (dwStatus != 0) { return dwStatus; } /* Bind to the domain controller. */ dwStatus = DsBind(pDcInfo->DomainControllerName, NULL, &hDs); /* Free the DOMAIN_CONTROLLER_INFO buffer. */ NetApiBufferFree(pDcInfo); if (dwStatus != ERROR_SUCCESS) { return dwStatus; } for (unsigned long i=0; i<ulSpn; i++) { _tprintf(TEXT("Service Principal Name =\n%s\n"), pspn[i]); } fflush(stdout); /* Write the SPNs to the service account or computer account. */ dwStatus = DsWriteAccountSpn( hDs, /* Handle to the directory. */ Operation, /* Add or remove SPN from account's existing SPNs. */ pszServiceAcctDN, /* DN of service account or computer account. */ ulSpn, /* Number of SPNs to add. */ (const TCHAR **)pspn); /* Array of SPNs. */ /* Unbind the DS in any case. */ DsUnBind(&hDs); return dwStatus;}SMPD_BOOL smpd_setup_scp(){ DWORD dwStatus; TCHAR szDNofSCP[100] = TEXT(""); TCHAR **pspn; unsigned long ulSpn; LPWSTR pwszComputerName; DWORD dwLen; SMPD_BOOL result = SMPD_TRUE; CoInitialize(NULL); /* Create the service's Service Connection Point (SCP). */ dwStatus = ScpCreate( SMPD_LISTENER_PORT, TEXT(SMPD_SERVICE_NAME), NULL, /* Null defaults to the Local SYSTEM account */ 100, szDNofSCP /* Buffer returns the Distinguished Name of the SCP */ ); if (dwStatus != 0) { _tprintf(TEXT("ScpCreate failed: %d\n"), dwStatus); result = SMPD_FALSE; goto fn_exit; } /*_tprintf(TEXT("szDNofSCP: %s\n"), szDNofSCP);*/ /* Get the size required for the DN account name. */ dwLen = 0; GetComputerObjectNameW(NameFullyQualifiedDN, NULL, &dwLen); pwszComputerName = new WCHAR[dwLen + 1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -