websitepanel/WebsitePanel.Installer/Sources/WebsitePanel.Setup/Common/SecurityUtils.cs
2013-11-27 17:39:00 +03:00

1136 lines
35 KiB
C#

// Copyright (c) 2012, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.IO;
using System.Text;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Collections.Generic;
using System.Management;
using WebsitePanel.Setup.Windows;
using System.Globalization;
namespace WebsitePanel.Setup
{
/// <summary>
/// Security utils class.
/// </summary>
public sealed class SecurityUtils
{
private static WmiHelper wmi = new WmiHelper("root\\cimv2");
#region private constants
private const int UF_SCRIPT = 0x0001;
private const int UF_ACCOUNTDISABLE = 0x0002;
private const int UF_HOMEDIR_REQUIRED = 0x0008;
private const int UF_LOCKOUT = 0x0010;
private const int UF_PASSWD_NOTREQD = 0x0020;
private const int UF_PASSWD_CANT_CHANGE = 0x0040;
private const int UF_TEMP_DUPLICATE_ACCOUNT = 0x0100;
private const int UF_NORMAL_ACCOUNT = 0x0200;
private const int UF_INTERDOMAIN_TRUST_ACCOUNT = 0x0800;
private const int UF_WORKSTATION_TRUST_ACCOUNT = 0x1000;
private const int UF_SERVER_TRUST_ACCOUNT = 0x2000;
private const int UF_DONT_EXPIRE_PASSWD = 0x10000;
private const int UF_MNS_LOGON_ACCOUNT = 0x20000;
#endregion
#region NTFS permissions
/// <summary>
/// Grants NTFS permissions by username
/// </summary>
/// <param name="path"></param>
/// <param name="accountName"></param>
/// <param name="permissions"></param>
/// <param name="inheritParentPermissions"></param>
/// <param name="preserveOriginalPermissions"></param>
internal static void GrantNtfsPermissions(string path, string domain, string accountName,
NtfsPermission permissions, bool inheritParentPermissions, bool preserveOriginalPermissions)
{
GrantNtfsPermissionsBySid(path, GetSid(accountName, domain), permissions, inheritParentPermissions,
preserveOriginalPermissions);
}
/// <summary>
/// Grants NTFS permissions by SID
/// </summary>
/// <param name="path"></param>
/// <param name="sid"></param>
/// <param name="permissions"></param>
/// <param name="inheritParentPermissions"></param>
/// <param name="preserveOriginalPermissions"></param>
internal static void GrantNtfsPermissionsBySid(string path, string sid,
NtfsPermission permissions, bool inheritParentPermissions, bool preserveOriginalPermissions)
{
// remove trailing slash if any
if(path.EndsWith("\\"))
path = path.Substring(0, path.Length - 1);
// get security settings
ManagementObject logicalFileSecuritySetting = wmi.GetObject(String.Format(
"Win32_LogicalFileSecuritySetting.Path='{0}'", path));
// get original security descriptor
ManagementBaseObject outParams = logicalFileSecuritySetting.InvokeMethod("GetSecurityDescriptor", null, null);
ManagementBaseObject originalDescriptor = ((ManagementBaseObject)(outParams.Properties["Descriptor"].Value));
// create new descriptor
ManagementBaseObject descriptor = wmi.GetClass("Win32_SecurityDescriptor").CreateInstance();
descriptor.Properties["ControlFlags"].Value = inheritParentPermissions ? (uint)33796 : (uint)37892;
// get original ACEs
ManagementBaseObject[] originalAces = ((ManagementBaseObject[])(originalDescriptor.Properties["DACL"].Value ) );
// create a new ACEs list
List<ManagementBaseObject> aces = new List<ManagementBaseObject>();
// copy original ACEs if required
if(preserveOriginalPermissions)
{
foreach(ManagementBaseObject originalAce in originalAces)
{
// we don't want to include inherited and current ACEs
ManagementBaseObject objTrustee = (ManagementBaseObject)originalAce.Properties["Trustee"].Value;
string trusteeSid = (string)objTrustee.Properties["SIDString"].Value;
bool inheritedAce = ((AceFlags)originalAce.Properties["AceFlags"].Value & AceFlags.INHERITED_ACE) > 0;
if(String.Compare(trusteeSid, sid, true) != 0 && !inheritedAce)
aces.Add(originalAce);
}
}
// create new trustee object
ManagementObject trustee = GetTrustee(sid);
// system access mask
uint mask = 0;
if((permissions & NtfsPermission.FullControl) > 0)
mask |= 0x1f01ff;
if((permissions & NtfsPermission.Modify) > 0)
mask |= 0x1301bf;
if((permissions & NtfsPermission.Write) > 0)
mask |= 0x100116 | 0x10000 | 0x40;
if((permissions & NtfsPermission.Read) > 0)
mask |= 0x120089;
bool executeEnabled = ((permissions & NtfsPermission.Execute) > 0);
bool listEnabled = ((permissions & NtfsPermission.ListFolderContents) > 0);
bool equalState = (executeEnabled == listEnabled);
// create and add to be modified ACE
ManagementObject ace;
if(equalState ||
(permissions & NtfsPermission.FullControl) > 0 ||
(permissions & NtfsPermission.Modify) > 0) // both "Execute" and "List" enabled or disabled
{
if((permissions & NtfsPermission.Execute) > 0)
mask |= (uint)SystemAccessMask.FILE_TRAVERSE;
ace = wmi.GetClass("Win32_Ace").CreateInstance();
ace["Trustee"] = trustee;
ace["AceFlags"] = AceFlags.OBJECT_INHERIT_ACE | AceFlags.CONTAINER_INHERIT_ACE;
ace["AceType"] = 0; // "Allow" type
ace["AccessMask"] = mask;
aces.Add(ace);
}
else // either "Execute" or "List" enabled or disabled
{
// we should place a separate permissions for folders and files
// add FOLDER specific permissions
uint foldersMask = mask;
if((permissions & NtfsPermission.ListFolderContents) > 0)
foldersMask |= (uint)SystemAccessMask.FILE_TRAVERSE;
ace = wmi.GetClass("Win32_Ace").CreateInstance();
ace["Trustee"] = trustee;
ace["AceFlags"] = AceFlags.CONTAINER_INHERIT_ACE;
ace["AceType"] = 0; // "Allow" type
ace["AccessMask"] = foldersMask; // set default permissions
aces.Add(ace);
// add files specific permissions
uint filesMask = mask;
if((permissions & NtfsPermission.Execute) > 0)
filesMask |= (uint)SystemAccessMask.FILE_TRAVERSE;
ace = wmi.GetClass("Win32_Ace").CreateInstance();
ace["Trustee"] = trustee;
ace["AceFlags"] = AceFlags.OBJECT_INHERIT_ACE;
ace["AceType"] = 0; // "Allow" type
ace["AccessMask"] = filesMask; // set default permissions
aces.Add(ace);
}
// set newly created ACEs
ManagementBaseObject[] newAces = aces.ToArray();
descriptor.Properties["DACL"].Value = newAces;
// set security descriptor
ManagementBaseObject inParams = logicalFileSecuritySetting.GetMethodParameters("SetSecurityDescriptor");
inParams["Descriptor"] = descriptor;
outParams = logicalFileSecuritySetting.InvokeMethod("SetSecurityDescriptor", inParams, null);
// check results
uint result = (uint)(outParams.Properties["ReturnValue"].Value);
logicalFileSecuritySetting.Dispose();
}
/// <summary>
/// Removes NTFS permissions by username
/// </summary>
/// <param name="path"></param>
/// <param name="accountName"></param>
internal static void RemoveNtfsPermissions(string path, string accountName)
{
RemoveNtfsPermissionsBySid(path, GetSid(accountName));
}
/// <summary>
/// Removes NTFS permissions by SID
/// </summary>
/// <param name="path"></param>
/// <param name="sid"></param>
internal static void RemoveNtfsPermissionsBySid(string path, string sid)
{
// remove trailing slash if any
if(path.EndsWith("\\"))
path = path.Substring(0, path.Length - 1);
// get security settings
ManagementObject logicalFileSecuritySetting = wmi.GetObject(String.Format(
"Win32_LogicalFileSecuritySetting.Path='{0}'", path));
// get original security descriptor
ManagementBaseObject outParams = logicalFileSecuritySetting.InvokeMethod("GetSecurityDescriptor", null, null);
ManagementBaseObject originalDescriptor = ((ManagementBaseObject)(outParams.Properties["Descriptor"].Value));
// create new descriptor
ManagementBaseObject descriptor = wmi.GetClass("Win32_SecurityDescriptor").CreateInstance();
descriptor.Properties["ControlFlags"].Value = originalDescriptor.Properties["ControlFlags"].Value;
// get original ACEs
ManagementBaseObject[] originalAces = ((ManagementBaseObject[])(originalDescriptor.Properties["DACL"].Value ) );
// create a new ACEs list
List<ManagementBaseObject> aces = new List<ManagementBaseObject>();
// copy original ACEs if required
foreach(ManagementBaseObject originalAce in originalAces)
{
// we don't want to include inherited and current ACEs
ManagementBaseObject objTrustee = (ManagementBaseObject)originalAce.Properties["Trustee"].Value;
string trusteeSid = (string)objTrustee.Properties["SIDString"].Value;
bool inheritedAce = ((AceFlags)originalAce.Properties["AceFlags"].Value & AceFlags.INHERITED_ACE) > 0;
if(String.Compare(trusteeSid, sid, true) != 0 && !inheritedAce)
aces.Add(originalAce);
}
// set newly created ACEs
ManagementBaseObject[] newAces = aces.ToArray();
descriptor.Properties["DACL"].Value = newAces;
// set security descriptor
ManagementBaseObject inParams = logicalFileSecuritySetting.GetMethodParameters("SetSecurityDescriptor");
inParams["Descriptor"] = descriptor;
outParams = logicalFileSecuritySetting.InvokeMethod("SetSecurityDescriptor", inParams, null);
// check results
uint result = (uint)(outParams.Properties["ReturnValue"].Value);
logicalFileSecuritySetting.Dispose();
}
/// <summary>
/// Resets NTFS permissions by username
/// </summary>
/// <param name="path"></param>
internal static void ResetNtfsPermissions(string path)
{
// remove trailing slash if any
if(path.EndsWith("\\"))
path = path.Substring(0, path.Length - 1);
ManagementObject logicalFileSecuritySetting = wmi.GetObject(String.Format(
"Win32_LogicalFileSecuritySetting.Path='{0}'", path));
// get security descriptor
ManagementBaseObject outParams =
logicalFileSecuritySetting.InvokeMethod("GetSecurityDescriptor",
null, null);
ManagementObject newDescriptor = wmi.GetClass("Win32_SecurityDescriptor").CreateInstance();
newDescriptor.Properties["DACL"].Value = new ManagementBaseObject[]{};
newDescriptor.Properties["ControlFlags"].Value = 33796; // inherit permissions
ManagementBaseObject inParams = null;
inParams = logicalFileSecuritySetting.GetMethodParameters("SetSecurityDescriptor");
inParams["Descriptor"] = newDescriptor;
outParams = logicalFileSecuritySetting.InvokeMethod("SetSecurityDescriptor",
inParams, null);
// This line is where I get a result back of 1307 in ASP.NET
uint result = (uint)(outParams.Properties["ReturnValue"].Value);
logicalFileSecuritySetting.Dispose();
}
private static ManagementObject GetTrustee(string sid)
{
// try to get user account
ManagementObject account = wmi.GetObject(String.Format(
"Win32_SID.SID='{0}'",
sid));
string userAccount = (string)account.Properties["AccountName"].Value;
string domain = (string)account.Properties["ReferencedDomainName"].Value;
ManagementObject trustee = wmi.GetClass("Win32_Trustee").CreateInstance();
trustee.Properties["Domain"].Value = domain;
trustee.Properties["Name"].Value = userAccount;
trustee.Properties["SIDString"].Value = sid;
return trustee;
}
/// <summary>
/// Returns SID by account name
/// </summary>
/// <param name="userAccount"></param>
/// <returns></returns>
internal static string GetSid(string userAccount)
{
return GetSid(userAccount, null);
}
/// <summary>
/// Returns SID by account name and domain
/// </summary>
/// <param name="userAccount"></param>
/// <param name="domain"></param>
/// <returns></returns>
internal static string GetSid(string userAccount, string domain)
{
if(domain == null)
domain = Environment.MachineName;
// try to get user account
string sid = null;
ManagementObject account = null;
try
{
account = wmi.GetObject(String.Format(
"Win32_Account.Name='{0}',Domain='{1}'",
userAccount, domain));
sid = account.Properties["SID"].Value.ToString();
}
catch{}
if(sid == null)
{
try
{
// try to look in DOMAIN
account = wmi.GetObject(String.Format(
"Win32_Account.Name='{0}',Domain='{1}'",
userAccount, Environment.UserDomainName));
sid = account.Properties["SID"].Value.ToString();
}
catch{}
}
return sid;
}
private static string GetUserPath(string netbiosDomain, string userName)
{
if (string.IsNullOrEmpty(netbiosDomain))
netbiosDomain = Environment.MachineName;
return string.Format("WinNT://{0}/{1}", netbiosDomain, userName);
}
/// <summary>
/// Returns account name by SID
/// </summary>
/// <param name="sid"></param>
/// <returns></returns>
internal static string GetAccountName(string sid)
{
// try to get user account
ManagementObject account = wmi.GetObject(String.Format("Win32_SID.SID='{0}'", sid));
return (account != null) ? account.Properties["AccountName"].Value.ToString() : null;
}
#endregion
#region User and Group methods
/// <summary>
/// Check for existing user
/// </summary>
internal static bool UserExists(string domain, string userName)
{
bool found = false;
// check whether user account already exists
if (string.IsNullOrEmpty(domain))
{
found = (wmi.ExecuteQuery(
String.Format("SELECT * FROM Win32_UserAccount WHERE Domain='{0}' AND Name='{1}'",
Environment.MachineName, userName))).Count > 0;
}
else
{
string path = GetUserDN(domain, userName);
if ( !string.IsNullOrEmpty(path))
{
found = ADObjectExists(path);
}
}
return found;
}
private static string GetUserDN(string domain, string user)
{
string ret = null;
string path = GetDomainUsersContainer(domain);
if (!string.IsNullOrEmpty(path))
{
path = path.Substring(7);
ret = string.Format("LDAP://CN={0},{1}", user, path);
}
return ret;
}
internal static string GetFullDomainName(string friendlyDomainName)
{
string ldapPath = null;
try
{
DirectoryContext objContext = new DirectoryContext(DirectoryContextType.Domain, friendlyDomainName);
Domain objDomain = Domain.GetDomain(objContext);
ldapPath = objDomain.Name;
}
catch(Exception ex)
{
Log.WriteError("Get domain name error", ex);
}
return ldapPath;
}
internal static DirectoryEntry GetDomainEntry(string domainName)
{
DirectoryEntry de = null;
try
{
DirectoryContext objContext = new DirectoryContext(DirectoryContextType.Domain, domainName);
Domain objDomain = Domain.GetDomain(objContext);
de = objDomain.GetDirectoryEntry();
}
catch (Exception ex)
{
Log.WriteError("Get domain entry error", ex);
}
return de;
}
/// <summary>
/// Creates user
/// </summary>
/// <param name="userInfo">User</param>
internal static void CreateUser(SystemUserItem userInfo)
{
try
{
DirectoryEntry root = null;
DirectoryEntry user = null;
if (string.IsNullOrEmpty(userInfo.Domain))
{
// create user
root = new DirectoryEntry(String.Format("WinNT://{0}", Environment.MachineName));
user = root.Children.Add(userInfo.Name, "user");
user.Invoke("SetPassword", new object[] { userInfo.Password });
user.Properties["FullName"].Add(userInfo.FullName);
user.Properties["Description"].Add(userInfo.Description);
user.Properties["UserFlags"].Add(BuildUserFlags(
userInfo.PasswordCantChange,
userInfo.PasswordNeverExpires,
userInfo.AccountDisabled));
// save account
user.CommitChanges();
}
else
{
// root entry
string rootPath = SecurityUtils.GetDomainUsersContainer(userInfo.Domain);
if (string.IsNullOrEmpty(rootPath))
throw new Exception(string.Format("Users container not found in domain {0}", userInfo.Domain));
root = new DirectoryEntry(rootPath);
// add user
user = root.Children.Add("CN=" + userInfo.Name, "user");
SetADObjectProperty(user, "description", userInfo.Description);
SetADObjectProperty(user, "UserPrincipalName", userInfo.Name);
SetADObjectProperty(user, "sAMAccountName", userInfo.Name);
//SetObjectProperty(user, "UserPassword", userInfo.Password);
user.Properties["userAccountControl"].Value =
ADAccountOptions.UF_NORMAL_ACCOUNT | ADAccountOptions.UF_PASSWD_NOTREQD;
user.CommitChanges();
// set password
user.Invoke("SetPassword", new object[] { userInfo.Password });
ADAccountOptions userFlags = ADAccountOptions.UF_NORMAL_ACCOUNT;
if (userInfo.PasswordCantChange)
userFlags |= ADAccountOptions.UF_PASSWD_CANT_CHANGE;
if (userInfo.PasswordNeverExpires)
userFlags |= ADAccountOptions.UF_DONT_EXPIRE_PASSWD;
if (userInfo.AccountDisabled)
userFlags |= ADAccountOptions.UF_ACCOUNTDISABLE;
user.Properties["userAccountControl"].Value = userFlags;
user.CommitChanges();
}
AddUserToGroups(userInfo.Domain, userInfo.Name, userInfo.MemberOf);
}
catch (Exception ex)
{
throw new Exception("Can't create user", ex);
}
}
private static void AddUserToGroups(string domain, string user, string[] groups)
{
try
{
if (groups != null)
{
foreach (string group in groups)
{
AddUserToGroup(domain, user, group);
}
}
}
catch (Exception ex)
{
Log.WriteError("Can't add user to groups", ex);
}
}
private static void AddUserToGroup(string domain, string userName, string groupName)
{
string groupPath = groupName;
string userPath = userName;
DirectoryEntry group = null;
try
{
//AD group
if (groupPath.StartsWith("AD:"))
{
//only AD users can be added to the AD group
if (!string.IsNullOrEmpty(domain))
{
groupPath = groupPath.Substring(3);
group = FindADGroup(groupPath);
DirectoryEntry deUser = FindADUser(domain, userName);
userPath = (deUser != null) ? deUser.Path : null;
}
}
//local group
else
{
DirectoryEntry computer = new DirectoryEntry(string.Format("WinNT://{0}", Environment.MachineName));
// check if this is a SID
if (groupPath.StartsWith("SID:"))
groupPath = GetAccountName(groupName.Substring(4));
group = computer.Children.Find(groupPath, "group");
string netbiosDomain = domain;
if (!string.IsNullOrEmpty(domain))
{
netbiosDomain = GetNETBIOSDomainName(domain);
}
userPath = GetUserPath(netbiosDomain, userName);
}
if ((group != null) && !string.IsNullOrEmpty(userPath))
{
group.Invoke("Add", new object[] { userPath });
group.CommitChanges();
group.Close();
}
}
catch (Exception ex)
{
Log.WriteError(
string.Format("Can't add '{0}' user to '{1}' group", userPath, groupPath),
ex);
}
}
private static DirectoryEntry FindADUser(string domain, string userName)
{
DirectoryEntry ret = null;
DirectorySearcher dSearch = new DirectorySearcher();
dSearch.SearchRoot = GetDomainEntry(domain);
dSearch.Filter = string.Format("(&(objectClass=user) (cn={0}))", userName);
SearchResultCollection results = dSearch.FindAll();
if (results.Count > 0)
{
ret = results[0].GetDirectoryEntry();
}
return ret;
}
private static DirectoryEntry FindADGroup(string groupName)
{
DirectoryEntry ret = null;
DirectorySearcher dSearch = new DirectorySearcher();
dSearch.SearchRoot = Domain.GetComputerDomain().GetDirectoryEntry();
dSearch.Filter = string.Format("(&(objectClass=group) (cn={0}))", groupName);
SearchResultCollection results = dSearch.FindAll();
if (results.Count > 0)
{
ret = results[0].GetDirectoryEntry();
}
return ret;
}
public static void RemoveUserFromGroups(string domain, string user, string[] groups)
{
try
{
if (groups != null)
{
foreach (string group in groups)
{
RemoveUserFromGroup(domain, user, group);
}
}
}
catch (Exception ex)
{
Log.WriteError("Can't remove user from groups", ex);
}
}
private static void RemoveUserFromGroup(string domain, string userName, string groupName)
{
string groupPath = groupName;
string userPath = userName;
DirectoryEntry group = null;
try
{
//AD group
if (groupPath.StartsWith("AD:"))
{
//only AD users can be added to the AD group
if (!string.IsNullOrEmpty(domain))
{
groupPath = groupPath.Substring(3);
group = FindADGroup(groupPath);
DirectoryEntry deUser = FindADUser(domain, userName);
userPath = (deUser != null) ? deUser.Path : null;
}
}
//local group
else
{
DirectoryEntry computer = new DirectoryEntry(string.Format("WinNT://{0}", Environment.MachineName));
// check if this is a SID
if (groupPath.StartsWith("SID:"))
groupPath = GetAccountName(groupName.Substring(4));
group = computer.Children.Find(groupPath, "group");
string netbiosDomain = domain;
if (!string.IsNullOrEmpty(domain))
{
netbiosDomain = GetNETBIOSDomainName(domain);
}
userPath = GetUserPath(netbiosDomain, userName);
}
if ((group != null) && !string.IsNullOrEmpty(userPath))
{
group.Invoke("Remove", new object[] { userPath });
group.CommitChanges();
group.Close();
}
}
catch (Exception ex)
{
Log.WriteError(
string.Format("Can't remove '{0}' user from '{1}' group", userPath, groupPath),
ex);
}
}
internal static void ChangeUserPassword(string userName, string password)
{
try
{
// get user entry
DirectoryEntry user = new DirectoryEntry(
String.Format("WinNT://{0}/{1},user", Environment.MachineName, userName));
// change user password
user.Invoke("SetPassword", new object[] { password });
// save account
user.CommitChanges();
}
catch (Exception ex)
{
throw new Exception("Can't change user password", ex);
}
}
/// <summary>
/// Deletes user
/// </summary>
/// <param name="userName">Username</param>
internal static void DeleteUser(string domain, string userName)
{
try
{
DirectoryEntry user = null;
if (String.IsNullOrEmpty(domain))
{
//local computer
user = new DirectoryEntry(
String.Format("WinNT://{0}/{1},user", Environment.MachineName, userName));
user.Parent.Children.Remove(user);
}
else
{
//AD
string path = GetUserDN(domain, userName);
user = new DirectoryEntry(path);
user.Parent.Children.Remove(user);
}
}
catch (Exception ex)
{
throw new Exception("Can't delete user", ex);
}
}
private static int BuildUserFlags(
bool passwordCantChange,
bool passwordNeverExpires,
bool accountDisabled)
{
int flags = UF_NORMAL_ACCOUNT | UF_SCRIPT;
if(passwordCantChange)
flags |= UF_PASSWD_CANT_CHANGE;
if(passwordNeverExpires)
flags |= UF_DONT_EXPIRE_PASSWD;
if(accountDisabled)
flags |= UF_ACCOUNTDISABLE;
return flags;
}
#endregion
#region AD
internal static string GetDomainUsersContainer(string domainName)
{
string ret = null;
if (string.IsNullOrEmpty(domainName))
return ret;
StringBuilder sb = new StringBuilder("LDAP://CN=Users,");
AppendDomainPath(sb, domainName);
return sb.ToString();
}
private static void AppendDomainPath(StringBuilder sb, string domain)
{
if (string.IsNullOrEmpty(domain))
return;
string[] parts = domain.Split('.');
for (int i = 0; i < parts.Length; i++)
{
sb.Append("DC=").Append(parts[i]);
if (i < (parts.Length - 1))
sb.Append(",");
}
}
private static void AppendOUPath(StringBuilder sb, string ou)
{
if (string.IsNullOrEmpty(ou))
return;
string path = ou.Replace("/", "\\");
string[] parts = path.Split('\\');
for (int i = parts.Length - 1; i != -1; i--)
sb.Append("OU=").Append(parts[i]).Append(",");
}
public static bool ADObjectExists(string objectPath)
{
bool found = false;
if (!string.IsNullOrEmpty(objectPath))
{
string path = objectPath;
if (!path.StartsWith("LDAP://"))
path = "LDAP://" + path;
try
{
if (DirectoryEntry.Exists(path))
{
found = true;
}
}
catch(Exception ex)
{
Log.WriteError("AD error", ex);
}
}
return found;
}
private static void SetADObjectProperty(DirectoryEntry oDE, string PropertyName, string PropertyValue)
{
if ((PropertyValue != string.Empty) && (PropertyValue != null))
{
if (oDE.Properties.Contains(PropertyName))
{
oDE.Properties[PropertyName][0] = PropertyValue;
}
else
{
oDE.Properties[PropertyName].Add(PropertyValue);
}
}
}
private static DirectoryEntry GetADObject(string path)
{
return new DirectoryEntry(path);
}
private static object GetADObjectProperty(DirectoryEntry entry, string name)
{
if (entry.Properties.Contains(name))
return entry.Properties[name][0];
else
return String.Empty;
}
/*private static void AddUserToGroup(DirectoryEntry objUser, string groupName,
RemoteServerSettings serverSettings, string groupsOU)
{
DirectoryEntry objGroup = GetGroupObject(groupName, serverSettings, groupsOU);
if (objGroup != null)
{
objGroup.Invoke("Add", new Object[] { objUser.Path.ToString() });
objGroup.Close();
}
}*/
private static string ConvertByteToStringSid(Byte[] sidBytes)
{
StringBuilder strSid = new StringBuilder();
strSid.Append("S-");
// Add SID revision.
strSid.Append(sidBytes[0].ToString());
// Next six bytes are SID authority value.
if (sidBytes[6] != 0 || sidBytes[5] != 0)
{
string strAuth = String.Format
("0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",
(Int16)sidBytes[1],
(Int16)sidBytes[2],
(Int16)sidBytes[3],
(Int16)sidBytes[4],
(Int16)sidBytes[5],
(Int16)sidBytes[6]);
strSid.Append("-");
strSid.Append(strAuth);
}
else
{
Int64 iVal = (Int32)(sidBytes[1]) +
(Int32)(sidBytes[2] << 8) +
(Int32)(sidBytes[3] << 16) +
(Int32)(sidBytes[4] << 24);
strSid.Append("-");
strSid.Append(iVal.ToString());
}
// Get sub authority count...
int iSubCount = Convert.ToInt32(sidBytes[7]);
int idxAuth = 0;
for (int i = 0; i < iSubCount; i++)
{
idxAuth = 8 + i * 4;
UInt32 iSubAuth = BitConverter.ToUInt32(sidBytes, idxAuth);
strSid.Append("-");
strSid.Append(iSubAuth.ToString());
}
return strSid.ToString();
}
internal static string GetNETBIOSDomainName(string domain)
{
Log.WriteStart("GetNETBIOSDomainName");
string ret = string.Empty;
string path = string.Format("LDAP://{0}/RootDSE", domain);
DirectoryEntry rootDSE = GetADObject(path);
string contextPath = GetADObjectProperty(rootDSE, "ConfigurationNamingContext").ToString();
string defaultContext = GetADObjectProperty(rootDSE, "defaultNamingContext").ToString();
DirectoryEntry partitions = GetADObject("LDAP://cn=Partitions," + contextPath);
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchRoot = partitions;
searcher.Filter = string.Format("(&(objectCategory=crossRef)(nCName={0}))", defaultContext);
searcher.SearchScope = SearchScope.OneLevel;
//find the first instance
SearchResult result = searcher.FindOne();
if (result != null)
{
DirectoryEntry partition = GetADObject(result.Path);
ret = GetADObjectProperty(partition, "nETBIOSName").ToString();
partition.Close();
}
partitions.Close();
rootDSE.Close();
Log.WriteEnd("GetNETBIOSDomainName");
return ret;
}
#endregion
#region Licensing
internal enum LicenseTypes
{
Gold = 1,
EnterpriseServerUnlimitedWebSites = 2,
EnterpriseServer50WebSites = 3,
EnterpriseServer250WebSites = 4,
ServerUnlimitedServices = 5,
Server1Service = 6,
Server3Services = 7,
BackupRestoreModule = 8,
ApplicationsInstallerModule = 9,
ECommerceModule = 10,
EnterpriseServerModulesPack = 11,
Monthly = 12,
ExchangeEnterpriseModule = 15,
SharePointEnterpriseModule = 16,
DynamicsCRMEnterpriseModule = 17,
BlackBerryEnterpriseModule = 22,
Standard = 18,
Enterprise = 19,
VPS = 21, // VPS Edition
RemoteServer = 20,
HyperVEnterpriseModule10 = 30,
HyperVEnterpriseModule20 = 31,
HyperVEnterpriseModule30 = 32,
HyperVEnterpriseModule50 = 33,
HyperVEnterpriseModule100 = 34,
// new Hyper-V
HyperVEnterpriseModuleSystem10 = 35,
HyperVEnterpriseModuleHostUnlim = 36,
// Special promo-license
SiteSpark = 41
}
internal class LicenseInfo
{
public string SerialNumber {get;set;}
public LicenseTypes Type {get;set;}
public int Version{get;set;}
public bool Active{get;set;}
}
internal static bool IsEnterpriseServerLicense(string serialNumber)
{
bool result = false;
// extract info license
LicenseInfo license = CreateLicenseFromSerial(serialNumber);
//
if (license != null)
{
switch (license.Type)
{
case LicenseTypes.ApplicationsInstallerModule:
case LicenseTypes.BackupRestoreModule:
case LicenseTypes.ECommerceModule:
case LicenseTypes.EnterpriseServer250WebSites:
case LicenseTypes.EnterpriseServer50WebSites:
case LicenseTypes.EnterpriseServerModulesPack:
case LicenseTypes.EnterpriseServerUnlimitedWebSites:
case LicenseTypes.Gold:
case LicenseTypes.Monthly:
case LicenseTypes.Standard:
case LicenseTypes.Enterprise:
case LicenseTypes.HyperVEnterpriseModuleSystem10:
case LicenseTypes.SiteSpark:
result = true;
break;
}
}
//
return result;
}
private static LicenseInfo CreateLicenseFromSerial(string serialNumber)
{
int componentKey = 0;
int versionKey = 0;
// extract info license
bool validSerial = ExtractLicenseInfo(serialNumber, out componentKey, out versionKey);
if (!validSerial)
return null;
LicenseInfo license = new LicenseInfo();
license.SerialNumber = serialNumber;
license.Type = (LicenseTypes)componentKey;
license.Version = versionKey;
license.Active = true;
return license;
}
private static bool ExtractLicenseInfo(string license, out int componentKey, out int versionKey)
{
componentKey = 0;
versionKey = 0;
if (String.IsNullOrEmpty(license) || license.Length != 36)
return false;
List<byte> list = new List<byte>(16);
UInt32 random8 = UInt32.Parse(license.Substring(0, 8), NumberStyles.HexNumber);
list.AddRange(BitConverter.GetBytes(random8));//8
UInt16 componentMask = UInt16.Parse(license.Substring(9, 4), NumberStyles.HexNumber);
list.AddRange(BitConverter.GetBytes(componentMask));//2
UInt16 componentId = UInt16.Parse(license.Substring(14, 4), NumberStyles.HexNumber);
list.AddRange(BitConverter.GetBytes(componentId));//2
componentId = (UInt16)(~componentId);
componentId = (UInt16)(componentId ^ componentMask);
UInt16 versionId = UInt16.Parse(license.Substring(19, 4), NumberStyles.HexNumber);
list.AddRange(BitConverter.GetBytes(versionId));//2
UInt16 versionMask = UInt16.Parse(license.Substring(24, 4), NumberStyles.HexNumber);
list.AddRange(BitConverter.GetBytes(versionMask));//2
versionId = (UInt16)(~versionId);
versionId = (UInt16)(versionId ^ versionMask);
UInt32 checkHash = UInt32.Parse(license.Substring(28, 8), NumberStyles.HexNumber);
CRC32 crc32 = new CRC32();
crc32.Initialize();
byte[] hash = crc32.ComputeHash(list.ToArray());
UInt32 hash32 = BitConverter.ToUInt32(hash, 0);
componentKey = Convert.ToInt32(componentId);
versionKey = Convert.ToInt32(versionId);
return (hash32 == checkHash);
}
#endregion
#region Windows Services
public static void DeleteService(string serviceName)
{
var wmiService = wmi.GetObject(String.Format("Win32_Service.Name='{0}'", serviceName));
wmiService.Delete();
}
#endregion
}
#region Enums
[Flags]
internal enum ADAccountOptions
{
UF_TEMP_DUPLICATE_ACCOUNT = 256,
UF_NORMAL_ACCOUNT = 512,
UF_INTERDOMAIN_TRUST_ACCOUNT = 2048,
UF_WORKSTATION_TRUST_ACCOUNT = 4096,
UF_SERVER_TRUST_ACCOUNT = 8192,
UF_DONT_EXPIRE_PASSWD = 65536,
UF_SCRIPT = 1,
UF_ACCOUNTDISABLE = 2,
UF_HOMEDIR_REQUIRED = 8,
UF_LOCKOUT = 16,
UF_PASSWD_NOTREQD = 32,
UF_PASSWD_CANT_CHANGE = 64,
UF_ACCOUNT_LOCKOUT = 16,
UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128
}
#endregion
}