using C4IT_IAM_Engine; using C4IT_IAM; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; using System.IO; using System.Linq; using System.Net; using System.Security; using System.Security.AccessControl; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; using C4IT.Logging; using static C4IT.Logging.cLogManager; using System.Reflection; namespace C4IT_IAM_GET { public enum AccessRights { Owner = 2032127, Write = 1245631, Read = 1179817 } public enum PermissionGroupStrategy { AGP, AGDLP } public class DataArea_FileSystem { public const string constApplicationDataPath = "%ProgramData%\\Consulting4IT GmbH\\LIAM"; public string domainName; public string DomainIPAddress; public string username; private SecureString password; private cNetworkConnection Connection; public string groupWildCard_Owner; public string groupWildCard_Read; public string groupWildCard_Write; public string groupWildCard_Traverse; public string groupGOwnerWildcard = string.Empty; public string groupGWriteWildcard = string.Empty; public string groupGReadWildcard = string.Empty; public string groupTraverseWildcard = string.Empty; public string groupDLOwnerWildcard = string.Empty; public string groupDLWriteWildcard = string.Empty; public string groupDLReadWildcard = string.Empty; public IDictionary groupCustomTags; public string groupDLTag; public string groupGTag; public string groupOwnerTag; public string groupReadTag; public string groupWriteTag; public string groupTraverseTag; public string groupPrefix; public PermissionGroupStrategy groupPermissionStrategy; public string groupLDAPFilter; private string exportFolder; private PrincipalContext ctx; public string ConfigID; public int maxDepth = 1; public string groupLDAPPath; public bool console; private string startDir; public string SecGroupXML; public string DataAreasXML; public SecureString Password { get => password; set => password = value; } public string StartDir { get => startDir; set => startDir = value; } public string ExportFolder { get => exportFolder; set => exportFolder = value; } private ResultToken checkRequiredVariables() { ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString()); resultToken.resultErrorId = 0; if (String.IsNullOrEmpty(ConfigID)) { resultToken.resultErrorId = 20001; resultToken.resultMessage = "Keine Config ID angegeben"; return resultToken; } if (String.IsNullOrEmpty(StartDir)) { resultToken.resultErrorId = 20007; resultToken.resultMessage = "Kein Startverzeichnis gewählt "; return resultToken; } if (string.IsNullOrEmpty(username) | String.IsNullOrEmpty(new NetworkCredential("", password).Password) | String.IsNullOrEmpty(domainName)) { resultToken.resultErrorId = 20002; resultToken.resultMessage = "Fehlende Anmeldeinformationen"; return resultToken; } if (String.IsNullOrEmpty(groupWildCard_Owner) | String.IsNullOrEmpty(groupWildCard_Read) | String.IsNullOrEmpty(groupWildCard_Write)) { resultToken.resultErrorId = 20004; resultToken.resultMessage = "Keine AD Gruppen Wildcards"; return resultToken; } if (String.IsNullOrEmpty(groupLDAPFilter)) { resultToken.resultErrorId = 20005; resultToken.resultMessage = "Kein LDAP Gruppenfilter angegeben"; return resultToken; } if (String.IsNullOrEmpty(groupLDAPPath)) { resultToken.resultErrorId = 20006; resultToken.resultMessage = "Kein LDAP Pfad angegeben"; return resultToken; } return resultToken; } public DataArea_FileSystem() { var logDirectory = Environment.ExpandEnvironmentVariables(constApplicationDataPath); Helper.CreatePathWithWriteAccess(logDirectory); var LogPath = Path.Combine(logDirectory, "Logs"); cLogManagerFile.CreateInstance(Path.Combine(LogPath, "LIAM.log")); DefaultLogger.LogEntry(LogLevels.Info, "================================================="); DefaultLogger.LogEntry(LogLevels.Info, $"LIAM engine v{Assembly.GetExecutingAssembly().GetName().Version} started"); } private void FillMatchingGroups() { LogMethodBegin(MethodBase.GetCurrentMethod()); try { groupWildCard_Owner = (groupPermissionStrategy == PermissionGroupStrategy.AGP ? groupGOwnerWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupGTag) : groupDLOwnerWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupDLTag)).Replace("{{GROUPTYPEPOSTFIX}}", groupOwnerTag).ReplaceTags(groupCustomTags); groupWildCard_Write = (groupPermissionStrategy == PermissionGroupStrategy.AGP ? groupGWriteWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupGTag) : groupDLWriteWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupDLTag)).Replace("{{GROUPTYPEPOSTFIX}}", groupWriteTag).ReplaceTags(groupCustomTags); groupWildCard_Read = (groupPermissionStrategy == PermissionGroupStrategy.AGP ? groupGReadWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupGTag) : groupDLReadWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupDLTag)).Replace("{{GROUPTYPEPOSTFIX}}", groupReadTag).ReplaceTags(groupCustomTags); groupWildCard_Traverse = (groupPermissionStrategy == PermissionGroupStrategy.AGP ? groupTraverseWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupGTag) : groupTraverseWildcard.Replace("{{PREFIX}}", groupPrefix).Replace("{{SCOPETAG}}", groupDLTag)).Replace("{{GROUPTYPEPOSTFIX}}", groupTraverseTag).ReplaceTags(groupCustomTags); DefaultLogger.LogEntry(LogLevels.Debug, $"Owner regex: {groupWildCard_Owner}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Write regex: {groupWildCard_Write}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Read regex: {groupWildCard_Read}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Traverse regex: {groupWildCard_Traverse}"); } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } public ResultToken BuildRootStructureWrapper() { LogMethodBegin(MethodBase.GetCurrentMethod()); FillMatchingGroups(); ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString()); resultToken.resultErrorId = 0; try { if (checkRequiredVariables().resultErrorId == 0) { if (Connection != null) Connection.Dispose(); DefaultLogger.LogEntry(LogLevels.Debug, $"Establishing connection to {startDir}, User: {username}, Password: {Helper.MaskAllButLastAndFirst(new NetworkCredential("", password).Password)}"); using (Connection = new cNetworkConnection(startDir, username, new NetworkCredential("", password).Password)) { DefaultLogger.LogEntry(LogLevels.Debug, $"Creating Domain Context: {domainName}"); ctx = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password); try { BuildRootStructure(startDir); } catch (Exception e) { resultToken.resultErrorId = 20200; resultToken.resultMessage = "Fehler bei der Analyse der Verzeichnisstruktur \n " + e.Message; } } } else { return checkRequiredVariables(); } } catch (Exception E) { DefaultLogger.LogException(E); resultToken.resultErrorId = 20000; resultToken.resultMessage = $"Fehler beim Ermitteln der Dateistruktur \n{E.Message}"; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } return resultToken; } public void BuildRootStructure(string currentDirectory, int currentDepth = 0, DataArea dA = null) { LogMethodBegin(MethodBase.GetCurrentMethod()); var firstRun = false; try { string[] folders = Directory.GetDirectories(currentDirectory); if (dA == null) { firstRun = true; dA = new DataArea(); dA.rootUID = DataArea.GetUniqueDataAreaID(currentDirectory); DirectoryInfo dADir = new DirectoryInfo(currentDirectory); IAM_Folder iamFolder = new IAM_Folder() { Name = dADir.Name, technicalName = dADir.FullName, UID = DataArea.GetUniqueDataAreaID(dADir.FullName), Parent = string.Empty, ParentUID = string.Empty, CreatedDate = dADir.CreationTimeUtc.ToString("s"), Level = 0, targetType = Convert.ToInt32(IAM_TargetType.FileSystem), configurationID = ConfigID }; dA.IAM_Folders.Add(iamFolder); } currentDepth++; DefaultLogger.LogEntry(LogLevels.Debug, $"Current folder: {currentDirectory}, Level: {currentDepth}, Subdirectories: {folders.Length}"); foreach (string folder in folders) { DirectoryInfo dADir = new DirectoryInfo(folder); IAM_Folder iamFolder = new IAM_Folder() { Name = dADir.Name, technicalName = dADir.FullName, UID = DataArea.GetUniqueDataAreaID(dADir.FullName), Parent = dADir.Parent.FullName, ParentUID = DataArea.GetUniqueDataAreaID(dADir.Parent.FullName), CreatedDate = dADir.CreationTimeUtc.ToString("s"), Level = currentDepth, targetType = Convert.ToInt32(IAM_TargetType.FileSystem), configurationID = ConfigID }; var dAACL = dADir.GetAccessControl(); var dAAR = dAACL.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier)); var k = ""; DefaultLogger.LogEntry(LogLevels.Debug, $"Current folder: {folder}, Access Control Rules: {dAAR.Count}"); foreach (FileSystemAccessRule rule in dAAR) { //skip ACLs for user "everyone" if (rule.IdentityReference.Value == "S-1-1-0") continue; k += rule.FileSystemRights + " - "; GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, rule.IdentityReference.Value); if (grp != null) { if (Regex.IsMatch(grp.SamAccountName, groupWildCard_Owner, RegexOptions.IgnoreCase)) { iamFolder.Owner = rule.IdentityReference.Value; DefaultLogger.LogEntry(LogLevels.Debug, $"ACL on folder: {folder}, matching Owner: {grp.Name}"); } else if (Regex.IsMatch(grp.SamAccountName, groupWildCard_Write, RegexOptions.IgnoreCase)) { DefaultLogger.LogEntry(LogLevels.Debug, $"ACL on folder: {folder}, matching Write: {grp.Name}"); iamFolder.Write = rule.IdentityReference.Value; } else if (Regex.IsMatch(grp.SamAccountName, groupWildCard_Read, RegexOptions.IgnoreCase)) { DefaultLogger.LogEntry(LogLevels.Debug, $"ACL on folder: {folder}, matching Read: {grp.Name}"); iamFolder.Read = rule.IdentityReference.Value; } else if (Regex.IsMatch(grp.SamAccountName, groupWildCard_Traverse, RegexOptions.IgnoreCase)) { DefaultLogger.LogEntry(LogLevels.Debug, $"ACL on folder: {folder}, matching Traverse: {grp.Name}"); iamFolder.Traverse = rule.IdentityReference.Value; } else DefaultLogger.LogEntry(LogLevels.Debug, $"No match for: {grp.Name}"); } } dA.IAM_Folders.Add(iamFolder); if (currentDepth < maxDepth) { BuildRootStructure(folder, currentDepth, dA); } DefaultLogger.LogEntry(LogLevels.Debug, $"Max level ({ maxDepth }) reached"); } if (firstRun) SetDataAreaXML(dA); } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); throw E; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } public ResultToken GetRelevantADGroupsWrapper() { LogMethodBegin(MethodBase.GetCurrentMethod()); FillMatchingGroups(); ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString()); resultToken.resultErrorId = 0; try { if (checkRequiredVariables().resultErrorId == 0) { GetRelevantADGroups(); } else { return checkRequiredVariables(); } } catch (Exception E) { resultToken.resultErrorId = 20000; resultToken.resultMessage = "Fehler Ermitteln der AD-Gruppen \n" + E.Message; cLogManager.DefaultLogger.LogException(E); } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } return resultToken; } public void GetRelevantADGroups() { LogMethodBegin(MethodBase.GetCurrentMethod()); try { SecurityGroups secGroups = new SecurityGroups(); var ldapPath = $"LDAP://{domainName}/{groupLDAPPath}"; DefaultLogger.LogEntry(LogLevels.Debug, $"Connecting to LDAP using: Domain: {domainName}, LDAPPath: {ldapPath}, User: {username}, Password: {Helper.MaskAllButLastAndFirst(new NetworkCredential("", password).Password)}"); ctx = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password); DefaultLogger.LogEntry(LogLevels.Debug, $"1 " + ctx.ConnectedServer); DefaultLogger.LogEntry(LogLevels.Debug, $"2 " + ctx.UserName); DefaultLogger.LogEntry(LogLevels.Debug, $"3 " + ctx.ValidateCredentials(username, new NetworkCredential("", password).Password)); // DefaultLogger.LogEntry(LogLevels.Debug, $"3.5 " + ctx.ToString()); DirectoryEntry entry = new DirectoryEntry { Path = ldapPath, Username = username, Password = new NetworkCredential(username, password).Password, AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing }; DefaultLogger.LogEntry(LogLevels.Debug, $"4 " + entry.NativeGuid); DefaultLogger.LogEntry(LogLevels.Debug, $"5 " + entry.Path); var tmpFilter = "(&(" + groupLDAPFilter + ")(objectClass=group))"; DefaultLogger.LogEntry(LogLevels.Debug, $"6 " + tmpFilter); //DefaultLogger.LogEntry(LogLevels.Debug, $"6.5 " + entry.ToString()); DirectorySearcher dSearch = new DirectorySearcher(entry) { Filter = tmpFilter }; dSearch.PageSize = 100000; DefaultLogger.LogEntry(LogLevels.Debug, $"7 " + dSearch.Filter); SearchResultCollection sr = dSearch.FindAll(); DefaultLogger.LogEntry(LogLevels.Debug, $"8 " + sr.Count); if (sr.Count > 0) { foreach (SearchResult k in sr) { IAM_SecurityGroup sec = new IAM_SecurityGroup(); sec.Name = k.Properties["Name"][0].ToString(); setGroupType(sec); SecurityIdentifier sid = new SecurityIdentifier(k.Properties["objectSid"][0] as byte[], 0); sec.UID = sid.Value; sec.technicalName = k.Properties["distinguishedname"][0].ToString(); sec.targetTyp = Convert.ToInt32(IAM_TargetType.FileSystem); var group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, sid.Value); sec.Scope = (GroupScope)group.GroupScope; var filter = "(&(" + groupLDAPFilter + ")(objectClass=group)(memberOf=" + sec.technicalName + "))"; DirectorySearcher iDSearch = new DirectorySearcher(entry) { Filter = filter }; SearchResultCollection iSr = iDSearch.FindAll(); if (iSr.Count > 0 ) { foreach (SearchResult iK in iSr) { IAM_SecurityGroup iSec = new IAM_SecurityGroup(); iSec.Name = iK.Properties["Name"][0].ToString(); setGroupType(iSec); SecurityIdentifier iSid = new SecurityIdentifier(iK.Properties["objectSid"][0] as byte[], 0); iSec.UID = iSid.Value; iSec.technicalName = iK.Properties["distinguishedname"][0].ToString(); iSec.targetTyp = Convert.ToInt32(IAM_TargetType.FileSystem); iSec.Parent = sec.UID; var iGroup = GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, iSid.Value); iSec.Scope = (GroupScope)iGroup.GroupScope; if (!secGroups.IAM_SecurityGroups.Any(s => s.technicalName.Equals(iSec.technicalName))) { secGroups.IAM_SecurityGroups.Add(iSec); DefaultLogger.LogEntry(LogLevels.Debug, $"Found security group: {iSec.technicalName}"); } } } else if (!secGroups.IAM_SecurityGroups.Any(s => s.technicalName.Equals(sec.technicalName))) { secGroups.IAM_SecurityGroups.Add(sec); DefaultLogger.LogEntry(LogLevels.Debug, $"Found security group: {sec.technicalName}"); } } } ctx.Dispose(); entry.Dispose(); dSearch.Dispose(); sr.Dispose(); SetSecGroupXML(secGroups); DefaultLogger.LogEntry(LogLevels.Debug, $"{secGroups.IAM_SecurityGroups.Count} AD groups retrieved with following lDAPQuery {groupLDAPFilter}"); } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); throw E; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } void setGroupType(IAM_SecurityGroup sec) { if (sec.Name.EndsWith(groupOwnerTag)) sec.securityGroupType = SecurityGroupType.Owner; else if (sec.Name.EndsWith(groupReadTag)) sec.securityGroupType = SecurityGroupType.Read; else if (sec.Name.EndsWith(groupWriteTag)) sec.securityGroupType = SecurityGroupType.Write; else if (sec.Name.EndsWith(groupTraverseTag)) sec.securityGroupType = SecurityGroupType.Traverse; } } public void SetDataAreaXML(DataArea dA) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { var xmlserializer = new XmlSerializer(typeof(DataArea)); using (var sww = new StringWriter()) { XmlWriterSettings setting = new XmlWriterSettings(); setting.OmitXmlDeclaration = true; using (XmlWriter writer = XmlWriter.Create(sww, setting)) { xmlserializer.Serialize(writer, dA); XmlDocument xml = new XmlDocument(); xml.LoadXml(sww.ToString()); DataAreasXML = xml.OuterXml; } } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); throw E; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } public void SetSecGroupXML(SecurityGroups secGroups) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { var xmlserializer = new XmlSerializer(typeof(SecurityGroups)); using (var sww = new StringWriter()) { XmlWriterSettings setting = new XmlWriterSettings(); setting.OmitXmlDeclaration = true; using (XmlWriter writer = XmlWriter.Create(sww, setting)) { xmlserializer.Serialize(writer, secGroups); XmlDocument xml = new XmlDocument(); xml.LoadXml(sww.ToString()); SecGroupXML = xml.OuterXml; } } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); throw E; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } } }