using System; using System.Runtime.InteropServices; using System.Text; using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke { public static partial class NTDSApi { /// /// /// The DS_MANGLE_FOR enumeration is used to define whether a relative distinguished name is mangled (encoded) and in what /// form the mangling occurs. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/ne-dsparse-_ds_mangle_for typedef enum _DS_MANGLE_FOR { // DS_MANGLE_UNKNOWN , DS_MANGLE_OBJECT_RDN_FOR_DELETION , DS_MANGLE_OBJECT_RDN_FOR_NAME_CONFLICT } DS_MANGLE_FOR; [PInvokeData("dsparse.h", MSDNShortId = "79a66a54-889e-464e-8199-ad911ea84a86")] public enum DS_MANGLE_FOR { /// Indicates that the relative distinguished name is not mangled or that the type of mangling is unknown. DS_MANGLE_UNKNOWN, /// Indicates that the relative distinguished name has been mangled for deletion. DS_MANGLE_OBJECT_RDN_FOR_DELETION, /// Indicates that the relative distinguished name has been mangled due to a naming conflict. DS_MANGLE_OBJECT_RDN_FOR_NAME_CONFLICT, } /// /// The DsCrackSpn function parses a service principal name (SPN) into its component strings. /// /// /// /// Pointer to a constant null-terminated string that contains the SPN to parse. The SPN has the following format, in which the /// <service class> and <instance name> components must be present and the <port number> and <service name> /// components are optional. The <port number> component must be a numeric string value. /// /// /// /// /// Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the ServiceClass buffer, including the /// terminating null character. On exit, this parameter contains the number of TCHARs in the ServiceClass string, including /// the terminating null character. /// /// If this parameter is NULL, contains zero, or ServiceClass is NULL, this parameter and ServiceClass are ignored. /// /// To obtain the number of characters required for the ServiceClass string, including the null terminator, call this function with a /// valid SPN, a non- NULL ServiceClass and this parameter set to 1. /// /// /// /// /// Pointer to a TCHAR buffer that receives a null-terminated string containing the <service class> component of the /// SPN. This buffer must be at least *pcServiceClass TCHARs in size. This parameter may be NULL if the service class /// is not required. /// /// /// /// /// Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the ServiceName buffer, including the /// terminating null character. On exit, this parameter contains the number of TCHARs in the ServiceName string, including the /// terminating null character. /// /// If this parameter is NULL, contains zero, or ServiceName is NULL, this parameter and ServiceName are ignored. /// /// To obtain the number of characters required for the ServiceName string, including the null terminator, call this function with a /// valid SPN, a non- NULL ServiceName and this parameter set to 1. /// /// /// /// /// Pointer to a TCHAR buffer that receives a null-terminated string containing the <service name> component of the SPN. /// This buffer must be at least *pcServiceName TCHARs in size. If the <service name> component is not present in the /// SPN, this buffer receives the <instance name> component. This parameter may be NULL if the service name is not required. /// /// /// /// /// Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the InstanceName buffer, including the /// terminating null character. On exit, this parameter contains the number of TCHARs in the InstanceName string, including /// the terminating null character. /// /// If this parameter is NULL, contains zero, or InstanceName is NULL, this parameter and InstanceName are ignored. /// /// To obtain the number of characters required for the InstanceName string, including the null terminator, call this function with a /// valid SPN, a non- NULL InstanceName and this parameter set to 1. /// /// /// /// /// Pointer to a TCHAR buffer that receives a null-terminated string containing the <instance name> component of the /// SPN. This buffer must be at least *pcInstanceName TCHARs in size. This parameter may be NULL if the instance name /// is not required. /// /// /// /// /// Pointer to a DWORD value that receives the integer value of the <port number> component of the SPN. If the SPN does /// not contain a <port number> component, this parameter receives zero. This parameter may be NULL if the port number /// is not required. /// /// /// /// Returns a Win32 error code, including the following. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dscrackspna DSPARSE DWORD DsCrackSpnA( LPCSTR pszSpn, // LPDWORD pcServiceClass, LPSTR ServiceClass, LPDWORD pcServiceName, LPSTR ServiceName, LPDWORD pcInstanceName, LPSTR InstanceName, // USHORT *pInstancePort ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "65c81c23-a259-480c-9c1e-03484d3e89c9")] public static extern Win32Error DsCrackSpn(string pszSpn, ref uint pcServiceClass, StringBuilder ServiceClass, ref uint pcServiceName, StringBuilder ServiceName, ref uint pcInstanceName, StringBuilder InstanceName, out ushort pInstancePort); /// /// /// The DsCrackUnquotedMangledRdn function unmangles (unencodes) a given relative distinguished name and returns both the /// decoded GUID and the mangling type used. /// /// /// /// /// Pointer to a string that contains the relative distinguished name (RDN) to translate. This string length is specified by the /// cchRDN parameter, so this string is not required to be null-terminated. This string must be in unquoted form. For more /// information about unquoted relative distinguished names, see DsUnquoteRdnValue. /// /// /// /// Contains the length, in characters, of the pszRDN string. /// /// /// /// Pointer to GUID value that receives the GUID of the unmangled relative distinguished name. This parameter can be NULL. /// /// /// /// /// Pointer to a DS_MANGLE_FOR value that receives the type of mangling used in the mangled relative distinguished name. This /// parameter can be NULL. /// /// /// /// /// This function returns TRUE if the relative distinguished name is mangled or FALSE otherwise. If this function /// returns FALSE, neither pGuid or peDsMangleFor receive any data. /// /// /// /// /// This function attempts to decode (unmangle) an RDN that has been previously mangled due to a deletion or a naming conflict. If /// the relative distinguished name is mangled, the function returns TRUE and retrieves the GUID and mangle type, if /// requested. If the relative distinguished name is not mangled, the function returns FALSE. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dscrackunquotedmangledrdna DSPARSE BOOL // DsCrackUnquotedMangledRdnA( LPCSTR pszRDN, DWORD cchRDN, GUID *pGuid, DS_MANGLE_FOR *peDsMangleFor ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "30711d2d-f541-46b4-a301-a0f9fc7d6676")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DsCrackUnquotedMangledRdn(string pszRDN, uint cchRDN, out Guid pGuid, out DS_MANGLE_FOR peDsMangleFor); /// /// /// The DsGetRdnW function retrieves the key and value of the first relative distinguished name and a pointer to the next /// relative distinguished name from a distinguished name string. /// /// /// /// /// Address of a Unicode string pointer that, on entry, contains the distinguished name string to be parsed. The length of this /// string is specified in the pcDN parameter. If the function succeeds, this parameter is adjusted to point to the remainder of the /// distinguished name exclusive of current relative distinguished name. For example, if this parameter points to the string /// "dc=corp,dc=fabrikam,dc=com", after the function is complete this parameter points to the string ",dc=fabrikam,dc=com". /// /// /// /// /// Pointer to a DWORD value that, on entry, contains the number of characters in the ppDN string. If the function succeeds, /// this parameter receives the number of characters in the remainder of the distinguished name. These values do not include the /// null-terminated character. /// /// /// /// /// Pointer to a LPCWCH value that, if the function succeeds, receives a pointer to the key in the relative distinguished name /// string. This pointer is within the ppDN string and is not null-terminated. The pcKey parameter receives the number of characters /// in the key. This parameter is undefined if pcKey receives zero. /// /// /// /// /// Pointer to a DWORD value that, if the function succeeds, receives the number of characters in the key string represented /// by the ppKey parameter. If this parameter receives zero, ppKey is undefined. /// /// /// /// /// Pointer to a LPCWCH value that, if the function is successful, receives a pointer to the value in the relative /// distinguished name string. This pointer is within the ppDN string and is not null-terminated. The pcVal parameter receives the /// number of characters in the value. This parameter is undefined if pcVal receives zero. /// /// /// /// /// Pointer to a DWORD value that, if the function succeeds, receives the number of characters in the value string represented /// by the ppVal parameter. If this parameter receives zero, ppVal is undefined. /// /// /// /// /// Returns ERROR_SUCCESS if successful or a Win32 error code otherwise. Possible error codes include the following values. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dsgetrdnw DSPARSE DWORD DsGetRdnW( LPCWCH *ppDN, DWORD // *pcDN, LPCWCH *ppKey, DWORD *pcKey, LPCWCH *ppVal, DWORD *pcVal ); [DllImport(Lib.NTDSApi, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)] [PInvokeData("dsparse.h", MSDNShortId = "22627f2e-adfb-49de-bae5-20aaf69830ac")] public static extern Win32Error DsGetRdnW(ref IntPtr ppDN, ref uint pcDN, ref IntPtr ppKey, out uint pcKey, ref IntPtr ppVal, out uint pcVal); /// /// The DsGetRdnW function retrieves the key and value of the first relative distinguished name and a pointer to the next /// relative distinguished name from a distinguished name string. /// /// Address of a string that contains the distinguished name string to be parsed. /// A string that recieves the remainder of the distinguished name exclusive of current relative distinguished name. /// A string that, if the function succeeds, receives the key in the relative distinguished name string. /// A string that, if the function is successful, receives the value in the relative distinguished name string. /// Returns ERROR_SUCCESS if successful or a Win32 error code otherwise. [PInvokeData("dsparse.h", MSDNShortId = "22627f2e-adfb-49de-bae5-20aaf69830ac")] public static Win32Error DsGetRdnW(string fullDN, out string dn, out string key, out string val) { var s = new SafeCoTaskMemString(fullDN, CharSet.Unicode); IntPtr ppDN = s.DangerousGetHandle(), ppKey = IntPtr.Zero, ppVal = IntPtr.Zero; var cDN = (uint)fullDN.Length; var ret = DsGetRdnW(ref ppDN, ref cDN, ref ppKey, out var cKey, ref ppVal, out var cVal); if (ret != 0) { dn = key = val = null; } else { dn = StringHelper.GetString(ppDN, (int)cDN, CharSet.Unicode); key = StringHelper.GetString(ppKey, (int)cKey, CharSet.Unicode); val = StringHelper.GetString(ppVal, (int)cVal, CharSet.Unicode); } return ret; } /// /// /// The DsIsMangledDn function determines if the first relative distinguished name (RDN) in a distinguished name (DN) is a /// mangled name of a given type. /// /// /// /// /// Pointer to a null-terminated string that contains the distinguished name to retrieve the relative distinguished name from. This /// can also be a quoted distinguished name as returned by other directory service functions. /// /// /// /// Contains one of the DS_MANGLE_FOR values that specifies the type of name mangling to look for. /// /// /// /// Returns TRUE if the first relative distinguished name in pszDn is mangled in the manner specified by eDsMangleFor or /// FALSE otherwise. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dsismangleddna DSPARSE BOOL DsIsMangledDnA( LPCSTR pszDn, // DS_MANGLE_FOR eDsMangleFor ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "e4aaa83c-3bd6-48db-9d34-367b76ba629c")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DsIsMangledDn(string pszDn, DS_MANGLE_FOR eDsMangleFor); /// /// /// The DsIsMangledRdnValue function determines if a given relative distinguished name value is a mangled name of the given type. /// /// /// /// /// Pointer to a null-terminated string that contains the relative distinguished name to determine if it is mangled. The cRdn /// parameter contains the number of characters in this string. /// /// /// /// Contains the number of characters in the pszRdn string. /// /// /// Contains one of the DS_MANGLE_FOR values that specifies the type of name mangling to search for. /// /// /// /// Returns TRUE if the relative distinguished name is mangled and the mangle type is the same as specified. Returns /// FALSE if the relative distinguished name is not mangled or the mangle type is different than specified. /// /// /// /// /// This function determines if the given relative distinguished name value is mangled and mangled in the given type. The pszRdn /// parameter should only contain the value of the relative distinguished name and not the key. The relative distinguished name value /// may be quoted or unquoted. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dsismangledrdnvaluea DSPARSE BOOL DsIsMangledRdnValueA( // LPCSTR pszRdn, DWORD cRdn, DS_MANGLE_FOR eDsMangleForDesired ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "adf5e133-9e48-4e97-af0c-4f8ea9b8bf8f")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DsIsMangledRdnValue(string pszRdn, uint cRdn, DS_MANGLE_FOR eDsMangleForDesired); /// /// The DsMakeSpn function constructs a service principal name (SPN) that identifies a service instance. /// /// A client application uses this function to compose an SPN, which it uses to authenticate the service instance. For example, the /// client can pass an SPN in the pszTargetName parameter of the InitializeSecurityContext function. /// /// /// /// /// Pointer to a constant null-terminated string that specifies the class of the service. This parameter can be any string unique to /// that service; either the protocol name, for example, ldap, or the string form of a GUID are acceptable. /// /// /// /// /// Pointer to a constant null-terminated string that specifies the DNS name, NetBIOS name, or distinguished name (DN). This /// parameter must be non- NULL. /// /// /// For more information about how the ServiceName, InstanceName and InstancePort parameters are used to compose an SPN, see the /// following Remarks section. /// /// /// /// /// Pointer to a constant null-terminated string that specifies the DNS name or IP address of the host for an instance of the service. /// /// If ServiceName specifies the DNS or NetBIOS name of the service host computer, the InstanceName parameter must be NULL. /// /// If ServiceName specifies a DNS domain name, the name of a DNS SRV record, or a distinguished name, such as the DN of a service /// connection point, the InstanceName parameter must specify the DNS or NetBIOS name of the service host computer. /// /// /// /// /// Port number for an instance of the service. Use 0 for the default port. If this parameter is zero, the SPN does not include a /// port number. /// /// /// /// /// Pointer to a constant null-terminated string that specifies the DNS name of the host that gave an IP address referral. This /// parameter is ignored unless the ServiceName parameter specifies an IP address. /// /// /// /// /// Pointer to a variable that contains the length, in characters, of the buffer that will receive the new constructed SPN. This /// value may be 0 to request the final buffer size in advance. /// /// The pcSpnLength parameter also receives the actual length of the SPN created, including the terminating null character. /// /// /// /// Pointer to a null-terminated string that receives the constructed SPN. This buffer should be the length specified by pcSpnLength. /// The pszSpn parameter may be NULL to request the final buffer size in advance. /// /// /// /// /// If the function returns an SPN, the return value is ERROR_SUCCESS. If the function fails, the return value can be one of /// the following error codes. /// /// /// /// /// The format of the SPN produced by the DsMakeSpn function depends on the input parameters. There are two basic formats. /// Both formats begin with the ServiceClass string followed by a host computer name and an optional InstancePort component. /// /// Note This format is used by host-based services. /// To produce an SPN with the "<ServiceClass>/<host>" format /// /// /// /// Set the ServiceName parameter to the DNS name of the host computer for the service instance. This is the host component of the SPN. /// /// /// /// Set the InstanceName and Referrer parameters to NULL. /// /// /// Set the InstancePort parameter to zero. If InstancePort is nonzero, the SPN has the following format: /// /// /// Note This format is used by replicable services. /// To produce an SPN with the "<ServiceClass>/<host>:<InstancePort>" format /// /// /// Set the InstanceName parameter to the DNS name of the host computer for the service instance. This is the host component. /// /// /// /// Set the ServiceName parameter to a string that identifies an instance of the service. For example, it could be the distinguished /// name of the service connection point for this service instance. /// /// /// /// Set the Referrer parameter to NULL. /// /// /// Set the InstancePort parameter to zero. If InstancePort is nonzero, the SPN has the following format: /// /// /// /// The Referrer parameter is used only if the ServiceName parameter specifies the IP address of the service's host computer. In this /// case, Referrer specifies the DNS name of the computer that gave the IP address as a referral. The SPN has the following format: /// /// /// where the host component is the InstanceName string or the ServiceName string if InstanceName is NULL, and the /// InstancePort component is optional. /// /// String parameters cannot include the forward slash (/) character, as it is used to separate the components of the SPN. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dsmakespnw DSPARSE DWORD DsMakeSpnW( LPCWSTR ServiceClass, // LPCWSTR ServiceName, LPCWSTR InstanceName, USHORT InstancePort, LPCWSTR Referrer, DWORD *pcSpnLength, LPWSTR pszSpn ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "fca3c59c-bb81-42a0-acd3-2e55c902febe")] public static extern Win32Error DsMakeSpn(string ServiceClass, string ServiceName, string InstanceName, ushort InstancePort, string Referrer, ref uint pcSpnLength, StringBuilder pszSpn); /// /// /// The DsQuoteRdnValue function converts an RDN into a quoted RDN value, if the RDN value contains characters that require /// quotes. The quoted RDN can then be submitted as part of a distinguished name (DN) to the directory service using various APIs /// such as LDAP. An example of an RDN that would require quotes would be one that has a comma-separated value, such as an RDN for a /// name that uses the format "last,first". /// /// /// /// The number of characters in the psUnquotedRdnValue string. /// /// /// The string that specifies the unquoted RDN value. /// /// /// The maximum number of characters in the psQuotedRdnValue string. /// The following flags are the output for this parameter. /// ERROR_SUCCESS /// Indicates that the correct number of characters were found in psQuotedRdnValue. /// ERROR_BUFFER_OVERFLOW /// Indicates that the number of characters in the string do not match psQuotedRdnValue. /// /// /// The string that receives the converted, and perhaps quoted, RDN value. /// /// /// The following list contains the possible values returned for the DsQuoteRdnValue function. /// /// /// /// Quotes are not added to the RDN if none are required. In this case, the output RDN value is the same as the input RDN value. /// /// /// When quoting is required, the RDN is quoted in accordance with the specification "Lightweight Directory Access Protocol (v3): /// UTF-8 String Representation of Distinguished Names," RFC 2253. /// /// The input and output RDN values are not NULL-terminated strings. /// To revert changes made by this call, call the DsUnquoteRdnValue function. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dsquoterdnvaluea DSPARSE DWORD DsQuoteRdnValueA( DWORD // cUnquotedRdnValueLength, IN LPCCH psUnquotedRdnValue, DWORD *pcQuotedRdnValueLength, LPCH psQuotedRdnValue ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "a1e8a4c0-965a-4061-aab3-3e719ec6374d")] public static extern Win32Error DsQuoteRdnValue(uint cUnquotedRdnValueLength, string psUnquotedRdnValue, ref uint pcQuotedRdnValueLength, StringBuilder psQuotedRdnValue); /// /// /// The DsUnquoteRdnValue function is a client call that converts a quoted RDN value back to an unquoted RDN value. Because /// the RDN was originally put into quotes because it contained characters that could be misinterpreted when it was embedded within a /// distinguished name (DN), the unquoted RDN value should not be submitted as part of a DN to the directory service using various /// APIs such as LDAP. /// /// /// /// The number of characters in the psQuotedRdnValue string. /// /// /// The RDN value that may be quoted and escaped. /// /// /// The input value for this argument is the maximum length, in characters, of psQuotedRdnValue. /// The output value for this argument includes the following flags. /// ERROR_SUCCESS /// This is returned if the number of characters match the string used in psQuotedRdnValue. /// ERROR_BUFFER_OVERFLOW /// This is returned if the number of characters do not match the string used in psQuotedRdnValue. /// /// /// The converted, unquoted RDN value. /// /// /// The following list contains the possible values that are returned for the DsUnquoteRdnValue function. /// /// /// When psQuotedRdnValue is quoted: /// /// /// The leading and trailing quotes are removed. /// /// /// White space before the first quote is discarded. /// /// /// White space trailing the last quote is discarded. /// /// /// Escapes are removed and the character following the escape is kept. /// /// /// The following actions are taken when psQuotedRdnValue is unquoted: /// /// /// The leading white space is discarded. /// /// /// The trailing white space is kept. /// /// /// Escaped non-special characters return an error. /// /// /// Unescaped special characters return an error. /// /// /// /// RDN values beginning with # (ignoring leading white space) are handled as a BER value that has previously been converted to a /// string, and converted accordingly. /// /// /// /// Escaped hex digits (\89) are converted into a binary byte (0x89). /// /// /// Escapes are removed from escaped special characters. /// /// /// The following actions are always taken: /// /// /// Escaped special characters are unescaped. /// /// /// The input and output RDN values are not null-terminated values. /// /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsparse/nf-dsparse-dsunquoterdnvaluea DSPARSE DWORD DsUnquoteRdnValueA( DWORD // cQuotedRdnValueLength, LPCCH psQuotedRdnValue, DWORD *pcUnquotedRdnValueLength, LPCH psUnquotedRdnValue ); [DllImport(Lib.NTDSApi, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsparse.h", MSDNShortId = "6e3dd220-ba98-46b5-8522-93cbe2029aa4")] public static extern Win32Error DsUnquoteRdnValue(uint cQuotedRdnValueLength, string psQuotedRdnValue, ref uint pcUnquotedRdnValueLength, StringBuilder psUnquotedRdnValue); } }