Windows


Or: letting my wife see my personal calendar.

So yes, I keep all my personal calendar items in the totalnetsolutions.net O365-hosted account calendar. But that doesn’t stop our family from having the calendar sharing problems that apps like GetClockwise https://www.getclockwise.com/ Cozi https://www.cozi.com/ or even shared Google or iCloud calendars try to solve.

The problems we ran into with Cozi were that we had to actually put the items there, then subscribe to the Cozi calendar from everywhere, when most of the time i’m looking at a calendar, I want to look at a single calendar. Can I agree to host this PTO event, or is my wife going to be out of town? Seeing the free/busy from her calendar, my calendar, etc. in one place got difficult.

So I went back to basics: Exchange can publish free/busy data. If everyone is an O365 subscriber, can’t we just share cross-organization? And the answer is that yes we can… IF the organization allows it! Since I am the admin for the TNS organization, I can share my calendar out, and not have to forward events everywhere. here’s how:

First, the admin has to follow the steps here: https://docs.microsoft.com/en-us/office365/admin/manage/share-calendars-with-external-users?view=o365-worldwide – Log into the Admin Center, click “Show all”, then “Settings” and finally “Serivces & add-ins”. The list of add-ins will change (as of today it includes Azure MFA, Calendar, Cortana, Directory Synchronization, and a host of other services), but you’re looking for “Calendar”. Click that and you’ll get this pane slide in from the left:

O365 Admin Center Calendar Sharing Settings

Click “Let your users share their calendars with people outside of your organization who have Office365 or Exchange” and “Save Changes”.

BUT WAIT, THERE’S MORE! Now click “Go to the Exchange admin center to manage additional settings”, and click “organization”:

O365 Admin Center Organization Sharing page

From here, under the “individual sharing” section you can create a new policy (which has to be assigned to users), or hit the pen to edit he “Default Sharing Policy” and get this page, where you can add the domain you want, and the amount of data to allow users to share (up to and including):

O365 Sharing Rule for Default Policy

Once that’s shared, you can save everything and log out. Now it’s up to the individual users to follow the settings here:

https://support.office.com/en-us/article/share-your-calendar-in-outlook-on-the-web-7ecef8ae-139c-40d9-bae2-a23977ee58d5#bkmk_beta

But realize that private events will NOT be visible in a shared calendar view. You’ll be able to load the free/busy data when scheduling, but not see the events in an overlay, even if you allow greater organizational sharing (as I have in the screenshot above). Since my wife’s work, and my BeyondTrust work are both O365 tenants, I was able to share more-relaxed versions of my calendar with both organizations, send to the individual email addresses, and now we can see synchronized calendar overlays in our own work Outlook calendars.

A customer of our AD Bridge product ( https://github.com/BeyondTrust/pbis-open ) asked me:

What is the best practice around how to ensure the Users you want to “export” are available to define with PBIS settings in the named cell on the RESOURCE side. Essentially, what prerequisite needs to be met so from the RESOURCE side, we can see these users. Is it a universal group?

If it is a universal group, is the expectation that the admins of the USER domain would know when onboarding a user that requires linux access, to put them in that group on their side (the USER side) so they’re available for cell enabling on the RESOURCE side?

a Typical 1-way trust setup has users in the “USER” domain, and the computers joined to the “RESOURCE” domain.  We’ll use those names, but “RESOURCE” could be a DMZ zone, or a partner system, or anything else.  For this discussion, we’ll use the following 2 forests:
ROOT.LOCAL
USER.ROOT.LOCAL

RESOURCE.LOCAL

RESOURCE has a 1-way outbound trust to USER (RESOURCE trusts USER, but accounts in RESOURCE cannot access the USER or ROOT domains. ROOT users cannot log into RESOURCE either)

In Windows, there are 4 kinds of groups ,with different purposes and limitations.  These limitations change slightly depending on the AD forest functional level (nesting is much more restrictive in older Forest Functional levels).  This document describes the AD groups: https://technet.microsoft.com/en-us/library/dn579255(v=ws.11).aspx but to recap the AD group types are “Domain Local”, “Domain Global”, and “Universal”. The 4th is “Computer Local Group” which you manage in the “Local Users and Groups” plugin to the “Computer Management” snap-in in the Windows OS (not in AD).  On Linux, this last one equates somewhat to groups in /etc/group.

  • Universal Groups: can contain any: Domain Global group, Universal Group, or User/Computer account in the same AD forest as the Universal Group.  Universal Groups are stored in the Global Catalog, making updates to them slower than other group types.  You can use them to control rights on any resource anywhere in the forest.
  • Domain Global Groups: can contain any Domain Global group or User/Computer account from the same Domain as the Domain Global group. Domain Global groups can be used to control rights on any resource anywhere in the forest.
  • Domain Local Groups: can contain pretty much any Group from any trusted domain, including across 1-way trusts. Domain Local groups can ONLY go into Domain Local groups in the same domain, or Computer Local groups in Computers on that Domain.  Domain Local groups can only be used to control rights on a resource in the same domain as the local group.

Of note: Universal groups store (in the AD database) a DN reference, which is part of why they can only contain objects form the same domain.  Domain Local groups store a SID reference, which is why they work across one-way trusts. (Domain Local Group membership contains a “foreignKeyReference” as the members, whereas Universal Groups contain a link to the GC object in the DIT which is expanded to the DN of the object on retrieval (meaning that if you move the member, the Universal Group membership doesn’t need to be updated, because the UUID of the object referenced by the link didn’t change).

Think of it this way: Users go into Universal and Domain Global groups.  Domain Global groups go into Domain Local Groups.  Domain Local groups are used to control access to Local resources in the Domain.  What this means is that if USER\rob is in the Domain Local group USER\dlg1, and accesses a server file01.root.local: file01 doesn’t even see that USER\rob is in USER\dlg1, because USER\dlg1 isn’t in the ROOT domain that file01 is in.  AD doesn’t even bother returning any foreign Domain Local groups in the Kerberos Ticket PAC (in the TGS) to file01, since that group can’t be used to control resources outside of the USER domain.

For our BeyondTrust ADB / PBIS (or any other 1-way-enabled AD Bridge like Samba) one-way trust setup, then, which groups can we provision into the cell / Computers in RESOURCE?  PBIS specifically is less restrictive than AD, and will allow you to import the Domain Global and Universal, and even if you try hard enough, the Domain Local groups from USER into the cell in RESOURCE, and use LDAP calls to attempt to resolve the Universal and Domain Global groups and their membership, because everything I just stated above is pretty difficult to explain to a Unix admin on a tech support call. In other words: the BeyondTrust PBIS Product will export the USER Domain Local groups to the RESOURCE domain computers, so that the Unix admins don’t have to know anything in this post.

But, when I’m designing a PBIS Cell design for a customer, I will try to design the customer to build Domain Local groups in the RESOURCE domain, and populate those groups into the Cell, with the membership coming from the USER domain.  This meets the AD design methodologies, means that the Unix team can be delegated rights to control the group membership in the RESOURCE domain themselves, but not have any rights to any user accounts in USER. This also means that any Active Directory auditing tools will pick up and audit the users properly, and when PBIS / BeyondTrust ADB drops this “nice enablement”, the customers I have worked with won’t need to make changes to their environment.

Edit:
The information in this post came primarily from: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd861330(v=ws.11)
and
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc755692(v=ws.10)
When I originally wrote this in late 2017.

The UPS on the lab servers is near the end of its life, so we’ve changed the shutdown script in power outages to simply hard-power off some of the servers (using Rob’s fork of ESXIDown from https://github.com/docsmooth/esxidown ). Of course, the second DC had to be one of them, so that there would be enough battery left for the SQL server and FSMO / PDC to shut down cleanly. THis means that the second DC often fails to boot properly when the power comes back after our yearly ComEd outage.

So, how do you fix this without doing the research every time? Thankfully, modern versions of Windows can be configured to boot to recovery mode. If you log in and launch a command prompt, you can run the following commands to find and repair problems:

  1. Launch the command prompt.

    recovery mode cmd.exe window example

    Launching CMD.EXE in recovery window

  2. navigate to your drive with the NTDS.DIT file (on our lab server, it’s always d:\windows\ntds:
    d:
    cd\windows\ntds
  3. Run an ESENTUTL checksum on the Active Directory database file ntds.dit:
    d:\windows\system32\esentutl.exe /k ntds.dit

    ESENTUTL.exe completed checksum

    ESENTUTL.exe completed checksum

  4. Even though that’s successful, you’ll probably fail an integrity check:
    d:\windows\system32\esentutl.exe /g edb
    On our server, that always generates the error:

    The database is not up-to-date. Integrity check may find that this database is corrupt because data from the log files has yet to be placed in the database. It is strongly recommended the database is brought up-to-date before continuing! Do you wish to abort the operation?

  5. If the checksum passed and you get this error, try rebooting into Directory Services Repair Mode – exit the command prompt and hit “Restart” and then pound on F8 to get the DSRM boot option.
  6. If DSRM bluescreens, then you need to go deeper into esentutl.exe to repair your DB. If this is NOT your only DC, you will have data loss, but it should replicate from other DCs back into this one, so it shouldn’t be a huge problem.
    If DSRM works, try an ntdsutil in cmd.exe:
    ntdsutil.exe
    activate instance ntds
    files
    recover
  7. If ntdsutil file recovery errors with

    Could not initialize the Jet engine: Jet Error -543.
    Failed to open DIT for AD DS/LDS instance NTDS. Error -21478418113

    then you need to do more work with esentutl, but can continue inside DSRM, rather than having to reboot.

    If you couldn’t boot into DSRM, continue as below, but from the recovery install CMD.exe. I’ll continue these commands from THAT pathing, since it turns out not bothering to jump into DSRM makes for a faster recovery, with ensured data loss. I don’t care abuot data loss in our lab though.

  8. Try to recover the database: d:\windows\system32\esenutl.exe /ml d:\windows\ntds\edb
  9. If that doesn’t work, delete the edb.log files, then try recovery again. You’ll get an error like

    Operation terminated with error -501 (JET_errLogFileCorrupt, Log file is corrupt) after 2.123 Seconds.

    So backup your logs to a new location or delete them outright:
    mkdir log-backup
    move edb*.log log-backup
    move edb.chk log-backup

  10. Recreate the log files with a hard recovery of the database:
    d:\windows\system32\esentutl.exe /p d:\windows\ntds\ntds.dit
    You’ll get an error saying you should only run this on damaged or corrupt databases. The checks before this have proven that that is the case in this situation, so click “OK”.
  11. This should restore the database and complete successfully. Reboot and test it. If it doesn’t work, or doesn’t boot, try again in all offline mode without jumping to DSRM.
  12. If that still doesn’t work:
  13. Recheck the database integrity:
    cd \windows\ntds
    esentutl /g: ntds.dit
  14. Do a database repair again:d:\windows\system32\esentutl.exe /p ntds.dit
  15. And reboot when that completes successfully. You *should* now boot properly, and the edb.chk and edb.log files should get rebuilt.

Sometimes it’s nice to know what’s happening under the hood, so let’s talk about how Group Policy is built, by tearing down how to access a particular policy. First, Group Policy is implemented in 2 parts, an LDAP part and a file part, delivered via SMB (CIFS if you’re oldschool) via DFS (Distributed FIle SYstem). Because the DFS part is replicated completely differently than the AD part, there’s a version number for each Group Policy object that’s stored in both places to keep them in sync. Most GPO engines remember the last version they applied by remembering the lowest of the 2 numbers (the LDAP version and the file version in the GPT.INI), if they don’t match.

Let’s talk about the “Default Domain Policy” which everyone will have one of. To find where that policy lives, you have to ask AD. The policy doesn’t actually live in the OU or Domain where it’s linked, so we have to back out the link:
ldap_search_s(ld, "dc=company,dc=com", 2, "(objectClass=organizationalUnit)", gpLink, base, &msg)
We’ll get back something like:

gPLink: [LDAP://CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=company,Dc=com;0]

Now, this is a multi-valued array, because multiple GPOs can be linked, in order, to a single OU or Domain or Site. But we only care about this one, so let’s see what’s in it:

ldap_search_s(ld, "CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=company,DC=com", 2, "(objectClass=*)", gPCMachineExtensionNames;gPCFileSysPath;displayName;versionNumber, 0, &msg)

That’ll get us the Client Side Extensions (where the work actually happens), and what the file path to the files in the estension are stored, as well as the pretty name of the Group Policy Object:

displayName: Default Domain Policy;
gPCFileSysPath: \\child1.lwtest.corp\sysvol\child1.lwtest.corp\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9};
gPCMachineExtensionNames: [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}{53D6AB1D-2488-11D1-A28C-00C04FB94F17}{D02B1F72-3407-48AE-BA88-E8213C6761F1}][{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}][{B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}];
versionNumber: 15;

So we have the Default Domain Policy, as desired, but there are a bunch of client side extensions here. It’d be nice to know what they all do generically, without having to inspect each one.
And TechNet delivers on that desire: a list of all Client Side Extensions (in 2010) by GUID for easy reference. Now, I’m writing this, because someone asked where the Password Policy for the domain was stored. Well, that appears to be in: {827D319E-6EAC-11D2-A4EA-00C04F79F83A} Security, which our Default Domain policy applies. So, let’s go find the data!

One of the attributes in the list we last requested was gPCFileSysPath which returned a normal SMB share. If you browse to that share, you’ll see 3 objects:

  • A folder named “MACHINE”
  • A folder named “USER”
  • a file named “GPT.INI”

The GPT.INI will only have 2 lines:

[General]
Version=15

That’s the version number, that you can compare to the “versionNumber” property from the object. If they’re the same, you’re good. If not, your AD isn’t in sync.

In the “MACHINE” Folder are all the Computer Policy settings, and in the “User” folder are all the User Policy settings. Since we were talking about the Password Policy, which is affected on the SAM on the server, it’s a MACHINE setting. If you were to poke through, eventually you’d find this file:

\\domain\sysvol\domain\\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf

with this data:

[Registry Settings]
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge=4,15

And there’s your password policy, via LDAP and SMB only.

For a bit of additional background, when a computer processes this data, in this order, it will actually only apply CSEs from the gPCMachineExtensionNames that the computer recognizes and has DLLs (or whatever code, if it’s non-Microsoft vendor CSE) that can apply the CSE. This makes it technically safe to put multiple GPOs for multiple Operating sytsems on the same OU structure, knowing that the client computer won’t even bother downloading the files for un-recognized CSEs.

Now, that’s a lot of stuff to type into ldp.exe, how can we make a report on this a bit easier? Well, PowerShell could do it, but one of the products I work on is PowerBroker Open https://github.com/BeyondTrust/pbis-open and https://www.beyondtrust.com/products/powerbroker-identity-services-open/ which includes a CLI for browing ldap called “adtool”. With a bit of bash, we can list out all the group policy objects by name attached to a single OU:

$ cat report-gpos-by-ou.sh
GP=`adtool -a lookup-object --dn "$@" --attr gPLink`;
GPO=`echo $GP | sed -e 's/\[LDAP:\/\///g' -e 's/;[[:digit:]]\]/ /g'`
if [ -n "$GPO" ]; then
echo "";
echo "$OU";
for P in $GPO; do
G=`adtool -a lookup-object --dn "$P" --attr displayName`;
grep -q "$G" /tmp/gpos.txt;
if [ $? -ne 0 ]; then
echo $G >> /tmp/gpos.txt;
fi;
echo "$G";
done;
fi;
$ ./report-gpos-by-ou.sh "OU=Company,DC=domain,DC=com"
OU=Company,DC=domain,DC=com
PBUL Basics
GP-Preferences
$

Our primary lab here at totalnetsolutions.net is a bit space-constrained (RAM constantly 50% overcommited in ESX), so we have it limited to only 2 domains, a parent, and a child. There’s 2 sites, one of them is a “BranchOffice” with only an RODC. This serves us well for the majority of customer cases, especially since the DHCP pool serves the BranchOffice site, which is routed via DSL to the CorpOffice site.

Recently we needed a 3rd domain (2nd child) for testing a particular user/group creation scheme for a customer. Upon completing testing in August, to reduce RAM utilization on the ESX host (and because it makes the AD Schema even more “real-world”, we dcpromo’ed the DC for the 3rd domain, deleting the entire domain. We deleted the objects, and ran the ntdsutil metadata cleanup, like good AD admins. Then we watched the logs fill up with Information events only for a few weeks, and forgot about the episode.

The thing was: the DC in the 3rd domain, because it was short-lived, was left with its DHCP address (it was never a DNS server), so it got added to the BranchOffice site. According to this 2009 Technet AD Troubleshooting Blog entry from Ingolfur Strangeland, RODCs won’t register as the Intersite Topology Generator (ISTG) for the site, but they will perform that role for themselves. (Background on the ISTG.) Because of this, the *new* DC, which was writeable, took over the role of the ISTG for the site, and made sure that all the replication connections went through it, as the only writeable DC in the site.

The problem is, we removed this server. When we removed the writeable DC in the BranchOffice site, there was no other server available to write “I’m now the ISTG” and replicate that setting outbound to the other site(s)… because the only remaining server was an RODC.

We discovered the problem 2 months later (Rob had a baby and wasn’t paying any attention to the lab for a while) when, after creating 1,000,000 new users in the lab, replication was surprisingly slow, but only into the Branch office. So slow that when we joined new computers, they’d boot up with “Service Principal Unknown” errors, and AD users couldn’t log in. In Active Directory Sites and Services we saw that the ISTG Server and Site were both “Invalid”.  This post from 2011 discusses how to move this, but not if it works for RODCs… the good news is that it does:

  1. open the Configuration container, like with adsiedit.msc
  2. Expand CN=Sites, and then the site with the broken ISTG (likely the site with the RODC)
  3. Double-click to open the properties of CN=NTDS Settings
  4. Find the value: “InterSiteTopologyGenerator” and paste in the full DN (from the Configuration Container, not the RootDN) of the RODC
    1. This is the “distinguishedName” value of the CN=<servername>,CN=<sitename>,CN=Sites,CN=Configuration object of the server in the site in question that *should* be the ISTG.
  5. Click “OK” to Save, use ‘repadmin’ or dssite.msc (AD Sites and Services) to force replication and wait 15 minutes (or your own inter-site replication time)

 

Next Page »