Property Sets and Default Security Descriptors

I made a brief mention of some of the default security permissions that apply to users in my article on Delegating Privileges in Active Directory for Windows IT Pro. I’ve gotten a couple of e-mail questions so I thought I’d elaborate here since I don’t have to worry about how many words I have to work with in this space. Every object class definition in the Active Directory schema has the option to define a “defaultSecurityDescriptor” value which holds the initial ACL that will apply to any new instances of that object when they are created. This rule doesn’t hold true if you specify a security descriptor explicitly when creating an object, however, as in this case the defaultSecurityDescriptor will be ignored.

The default value for the defaultSecurityDescriptor for the user class has a couple of entries in it which most administrators don’t know about, and fortunately neither do many end users. Out of the box, the user which an object in AD represents has permissions to modify quite a few attributes on their own account. Anyone who can figure out how to make an LDAP call against their object in the directory can take advantage of this. The easiest way to edit or view the value for this attribute is using the Active Directory Schema MMC. Browse to the Classes folder and then open the properties of the user class. Switch to the Default Security tab and click Advanced.

Note: By default the Active Directory Schema MMC snap-in is not available. To use it you must first register the COM DLL it depends on by running “regsvr32 schmmgmt.dll” from an elevated command prompt. Once you do this, you will be able to open a new MMC and go to File>Add/Remove Snap-ins and add the Active Directory Schema snap-in to your console.

If you sort on the Name column and scroll down to SELF, you’ll see three entries (highlighted in yellow below) which are interesting:

image

These three ACEs grant the user permissions to write to the attributes in those three property sets for their account. If you’re not familiar with Property Sets, they’re a construct that allows you to group attributes and apply security for all the attributes in a single ACE which applies to the property set. An easy way to get a nice list of the attributes in these property sets is with adfind. The first thing you’ll need to do is convert the friendly display name (e.g. Personal Information) into the GUID of the property set:

adfind -sc findpropsetrg:"Personal Information"

You should get a result similar to this:

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: BRIAN-RTDC01.brianlab.local:389

Directory: Windows Server 2003

Base DN: cn=extended-rights,CN=Configuration,DC=brianlab,DC=local

dn:CN=Personal-Information,CN=Extended-Rights,CN=Configuration,DC=brianlab,DC=local

>rightsGuid: 77B5B886-944A-11d1-AEBD-0000F80367C1

You can paste that GUID into a second adfind command to list all of the attributes in the property set:

adfind -sc propsetmembersl:"77b5b886-944a-11d1-aebd-0000f80367c1"

Depending on the schema your directory has, your results might vary a bit, but in my test forest this is the result:

assistant

c

facsimileTelephoneNumber

homePhone

homePostalAddress

info

internationalISDNNumber

ipPhone

l

mobile

mSMQDigests

mSMQSignCertificates

otherFacsimileTelephoneNumber

otherHomePhone

otherIpPhone

otherMobile

otherPager

otherTelephone

pager

personalTitle

physicalDeliveryOfficeName

postalAddress

postalCode

postOfficeBox

preferredDeliveryMethod

primaryInternationalISDNNumber

primaryTelexNumber

publicDelegates

registeredAddress

st

street

streetAddress

telephoneNumber

teletexTerminalIdentifier

telexNumber

thumbnailPhoto

userCert

userCertificate

userSharedFolder

userSharedFolderOther

userSMIMECertificate

x121Address

If you’ve got an automated system that populates any of these attributes, hypothetically an end user could put other data in them and start breaking things. I’ve only ever heard once or twice of this happening, and I’m not fully aware of all the implications of removing these ACEs if you wanted to prevent the possibility. Keep in mind that this is applied as an individual ACE to each user as it’s created, so, in order to clean this up in an existing forest you’d need a script to go through and remove the ACEs from each user individually. New users would get the updated defaults based on modifying the defaultSecurityDescriptor of the user class, though.

Looking Back on 2010

Last year I put up a quick chart of all the travel for 2009. I thought I’d do the same this year as I’ve just finished wrapping up my two big travel points spreadsheets for Q4.

Countries 6
US States 10
US Cities Visited 35 (approx)
Airplanes 83
Miles Flown 129,666 (approx)
Hotels Visited 49
Hotel Nights 122
Days on the Road 176

A bit of Pivot Table magic says that I spent the most time in:

  1. Los Angeles (17 nights)
  2. Beijing (15 nights)
  3. San Francisco (11 nights)

In all that there were definitely a few highlights amongst the routine customer visit trips:

  • Customer visits in Napa, California and Sonoma, California – can’t beat this if food and wine are your thing
  • Cold and wet hiking through a Redwood forest in Humboldt County, California
  • Customer visits in Beijing and all the fun that comes with a trip to China
  • An early morning walk through the Seoul Fish Market. Any Deadliest Catch fans?
  • Touring Gettysburg. The museum is great and the battlefield tour is conveniently operated by your rental car.

All the best for 2011!

Active Directory SPN Mappings and Kerberos

I had an interesting customer problem today where Kerberos was being attempted for a service principal name (SPN) which simply didn’t exist in Active Directory. This was causing the applications (Exchange) involved to fail as they couldn’t authenticate to one another. The client machine involved was logging numerous errors similar to the following indicating that it was presenting a service ticket encrypted by another machine to the server in question.

Log Name:      System
Source:        Microsoft-Windows-Security-Kerberos
Date:          12/6/2010 2:03:11 PM
Event ID:      4
Level:         Error
Description:
The Kerberos client received a KRB_AP_ERR_MODIFIED error from the server server01$. The target name used was HTTP/webmail.customer.com. This indicates that the target server failed to decrypt the ticket provided by the client. This can occur when the target server principal name (SPN) is registered on an account other than the account the target service is using. Please ensure that the target SPN is registered on, and only registered on, the account used by the server. This error can also happen when the target service is using a different password for the target service account than what the Kerberos Key Distribution Center (KDC) has for the target service account. Please ensure that the service on the server and the KDC are both updated to use the current password. If the server name is not fully qualified, and the target domain (CUSTOMER.COM) is different from the client domain (CUSTOMER.COM), check if there are identically named server accounts in these two domains, or use the fully-qualified name to identify the server.

The tricky part about this was that Kerberos shouldn’t have been being used at all but instead NTLM. With SPNEGO enabled on the IIS virtual directory, once Kerberos is deemed possible, we can’t fall back to NTLM. My first step was to search Active Directory for an object which had the http/webmail.customer.com SPN adfind:

adfind -f "servicePrincipalName=http/webmail.customer.com" -gcb

I came up empty, though. This makes things even more interesting since there’s no way Kerberos could be attempted if there’s no user or machine account in the directory with a matching SPN. My next step was to do a search for any accounts which had the HOST/webmail.customer.com SPN registered:

adfind -f "servicePrincipalName=HOST/webmail.customer.com" -gcb

This time I came up with a computer account called WEBMAIL. The server had long since been retired, but, the orphaned computer account was still in AD. The root cause of the issue here is a function in Active Directory which matches the HOST service component to several dozen other services. There are numerous services (like RPC or NetLogon) which every single Windows machine has, and it would be a huge waste of space to store SPNs for those services on every computer account in the directory. To mitigate this, Active Directory has an attribute called spnMappings on the CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=… object in the Configuration NC. One of the services in this list is “HTTP” which was causing the KDC to issue a service ticket encrypted with this old machine account’s secret for http/webmail.customer.com.

Each time the KDC receives a request for a service ticket, it first does an explicit search to see if there is an account with the requested SPN in the directory. If there are no matches, the KDC then checks to see if the service component (HTTP in this case) is listed in the spnMappings attribute. If this is the case, then a search of the directory is performed to find a user or computer matching HOST/some-name.domain.com. If there’s a match, then a service ticket is issued. Below is a copy of a slide from a presentation I gave at TEC this year which summarizes this functionality.

image

Date and Time Math with PowerShell

How many times have you had to figure out what date was X days, months, or years ago, or perhaps what time was Y minutes, hours, or seconds ago? Producing a report of all the users who have not logged in during the past 90 days is a pretty common request. There’s two ways to go about doing this – the lazy way and the precise way. The lazy way is to say well 90 days is about three months ago, and it’s 11/24 today so that would be 8/24. The precise way is to realize that 90 days go is actually 8/26. If you’ve got Windows PowerShell on your desktop (Windows 7 includes it out of the box), it’s super easy to calculate these sorts of things. The .NET Framework includes a couple of data structures that you can use for figuring out all sorts of date math – DateTime and TimeSpan.

90 days before today:

[DateTime]::Now.Subtract([TimeSpan]::FromDays(90))

Thursday, August 26, 2010 5:53:39 PM

90 days after today:

[DateTime]::Now.Add([TimeSpan]::FromDays(90))

Tuesday, February 22, 2011 6:03:16 PM

2 years before today:

[DateTime]::Now.Subtract([TimeSpan]::FromDays(2 * 365))

Monday, November 24, 2008 6:06:59 PM

2 years after today:

[DateTime]::Now.Add([TimeSpan]::FromDays(2 * 365))

Friday, November 23, 2012 6:06:51 PM

Note: We’re not taking leap years in to account in the above two examples.

37 minutes ago:

[DateTime]::Now.Subtract([TimeSpan]::FromMinutes(37))

Wednesday, November 24, 2010 5:32:18 PM

37 minutes from now:

[DateTime]::Now.Add([TimeSpan]::FromMinutes(37))

Wednesday, November 24, 2010 6:47:41 PM

Finally, if you’re looking to construct an LDAP filter based on a timestamp attribute (e.g. pwdLastSet, lastLogonTimeStamp, etc.), you can either use adfind (which will do the encoding for you) or you can convert the time you want to filter on to a standard Windows File Time:

[DateTime]::Now.ToFileTime()

129351176175846050

You can use the ToFileTime() method on any of the above expressions, so, if for example you wanted 90 days ago in this format you could do this:

[DateTime]::Now.Subtract([TimeSpan]::FromDays(90)).ToFileTime()

Error When Removing Exchange 2000 or 2003 Server

There are a litany of issues that will cause Exchange setup to fail when you try to uninstall an Exchange server. It’s really tempting to just skip the uninstall and go delete the server entry from AD using something like ADSI Edit, but, you’re always better off just fixing the problem. Michael B. Smith has a good review of these, however I thought I’d touch on one more, specifically the error "One or more users currently use a mailbox store on this server". This can be really frustrating, especially when you’ve checked each mailbox store for mailboxes and done a search using AD Users and Computers for mailboxes on that server and turned up nothing. Exchange setup is doing a search of AD for users who have a msExchHomeServerName value which is equal to the legacyExchangeDN of the server you’re trying to remove.

There’s a handy KB article, 924170, which suggests a mechanism to find the problem users, but, my experience tonight is that the directions don’t really actually work. The good news this is really easy to straighten out with adfind and possible admod. What you want to do is two-fold. First, find the legacyExchangeDN of the server you’re trying to remove. You can do this with adfind:

adfind -config -f "cn=SOME-SERVER" legacyExchangeDN

You should get a result something like this:

/o=Brian Lab/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=BRIAN-XMB01

What you’ll want to do now is find all the users who reference this value in their msExchHomeServerName attribute:

adfind -gcb -f "msExchHomeServerName=/o=Brian Lab/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=BRIAN-XMB01"

If there’s only a few results, the easiest solution is to just find each user using AD Users and Computers on a machine with Exchange System Manager installed, right click the user, select Exchange Tasks, and then use the Remove Exchange Attributes option.

If there’s a lot of users, you’ll probably want a more automated solution. You can use adfind with admod to clear the msExchHomeServerName attribute on a lot of users at once.

Warning: Be careful with this – there’s no undo function! You can use the –upto switch in lieu of –unsafe to process a limited number of objects.
adfind -gcb -f "msExchHomeServerName=/o=Brian Lab/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=BRIAN-XMB01" -adcsv | admod -unsafe msExchHomeServerName:-:

Cleanup User Objects with Invalid MailNicknames

Exchange 2000 and Exchange 2003 have no problem with users (or groups and contacts) which have a space in their mailNickname attribute. Unfortunately if you try to work with one of these users using Exchange 2007 or Exchange 2010, the PowerShell cmdlets will throw a validation error similar to the following:

Property expression "John Doe" isn’t valid. Valid values are: Strings formed with characters from A to Z (uppercase or lowercase), digits from 0 to 9, !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } or ~. One or more periods may be embedded in an alias, but each period should be preceded and followed by at least one of the other characters. Unicode characters from U+00A1 to U+00FF are also valid in an alias, but they will be mapped to a best-fit US-ASCII string in the e-mail address, which is generated from such an alias.
    + CategoryInfo          : NotSpecified: (brianlab.local…Doe, John:ADObjectId) [Update-Recipient], DataValidationException
    + FullyQualifiedErrorId : 385167D4,Microsoft.Exchange.Management.RecipientTasks.UpdateRecipient

Cleaning this up is more or less a pre-requisite to a migration. I put a quick VBScript together which will do this. The script below handles users but you can easily update the LDAP filter to grab groups or contacts as well. You’ll need to update the search base and DC at the top of the script.

'==========================================================================
' NAME: Cleanup mailNickname's with spaces
'
' AUTHOR: Brian Desmond, brian@briandesmond.com
' DATE  : 11/6/2010
'
' COMMENT: 
'
'==========================================================================

Option Explicit

Const SEARCH_BASE = "DC=brianlab,DC=local"
Const AD_DC = "BRIAN-RTDC01"

Dim cnxn
Set cnxn = WScript.CreateObject("ADODB.Connection")
cnxn.Provider = "ADsDSOObject"
cnxn.Open "Active Directory Provider"

Dim cmd
Set cmd = WScript.CreateObject("ADODB.Command")
cmd.ActiveConnection = cnxn

cmd.CommandText = "<LDAP://" AD_DC & "/" & SEARCH_BASE & ">;(&(objectCategory=person)(objectClass=user)(mailNickname=*\20*));distinguishedName,mailNickname;subtree"
cmd.Properties("Page Size") = 100
cmd.Properties("Timeout") = 30
cmd.Properties("Cache Results") = False

WScript.Echo cmd.CommandText

Dim rs
Set rs = cmd.Execute

Dim nickName
Dim dn

While Not rs.eof 
    nickName = rs.Fields("mailNickname").Value
    dn = rs.Fields("distinguishedName").Value
    
    WScript.Echo "Fixing " & nickName & "(" & dn & ")"
    
    SetAttribute dn, "mailNickname", Replace(nickName, " ", "")
    
    rs.MoveNext
Wend 

rs.close
cnxn.Close

Set rs = Nothing
Set cmd = Nothing
Set cnxn = Nothing 

Sub SetAttribute(objectDn, name, value)
    Dim obj
    Set obj = GetObject("LDAP://" & objectDn)
    
    obj.Put name, value
    obj.SetInfo
    
    Set obj = Nothing 
End Sub

Viewing the History of an Active Directory Object with Replication Metadata

I answered a question via Twitter the other day as to whether or not it was possible to see when someone was added to a group without relying on audit information. The good news is that the answer is “Yes!” – assuming your forest is running in the Windows Server 2003 Forest Functional Level (FFL2) or better, and that the user was added after you upgraded your forest to this level. You can also see when a user was removed, however once they’ve been removed you won’t be able to see when they were added.

Start with FFL2, linked values, such as group membership replicate individually via linked value replication (LVR). In Windows 2000, linked attributes replicated as a single block of data which led to issues around groups with large memberships. Active Directory also stores some additional data called Replication Metadata. Inside the metadata is information about the versions of attributes, when they were last changed, and where the change originated. Since links replicate individually, each link value has metadata you can use to determine when the user was added to the group. To look at the replication metadata for an object, you’ll need to provide the object’s distinguished name. In this case, I’m going to look at the group “Test Group” in my domain:

repadmin /showobjmeta test-dc01 "CN=Test Group,OU=Groups,DC=brianlab,DC=local"

The output of this command will vary, but, in my environment it looks like this:

13 entries.

Loc.USN                      Originating DSA       Org.USN   Org.Time/Date         Ver Attribute

=======                      ===============       ========= =============         === =========

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  objectClass

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  cn

686100                       TestSite\TEST-DC01    686100    2010-10-27 14:06:19    2  description

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  instanceType

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  whenCreated

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  nTSecurityDescriptor

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  name

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  objectSid

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  sAMAccountName

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  sAMAccountType

685899                       TestSite\TEST-DC01    685899    2010-10-25 12:56:19    1  sIDHistory

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  groupType

685896                       TestSite\TEST-DC01    685896    2010-10-25 12:56:19    1  objectCategory

3 entries.

Type     Attribute     Last Mod Time       Originating DSA     Loc.USN Org.USN Ver Distinguished Name

=======  ============  =============       =================   ======= ======= === =============================

ABSENT   member        2010-11-05 16:55:28 TestSite\TEST-DC01  749327  749327   2  CN=Brian Desmond,OU=Users,DC=brianlab,DC=local

PRESENT  member        2010-11-05 16:55:02 TestSite\TEST-DC01  749320  749320   1  CN=Test User 01,OU=Users,DC=brianlab,DC=local

PRESENT  member        2010-11-02 12:48:34 TestSite\TEST-DC01  730720  730720   1  CN=Doe\, John,OU=Users,DC=brianlab,DC=local

There are a couple key takeaways here. The first is that you can see the version numbers of each of the attributes. In this case, none of the attributes have been modified since the group was created, except for the description attribute. Description was updated once a couple days later. At the bottom of the output is the listing for each linked attribute. In this case I only have the member attribute populated, but, if for example the manager linked attribute was populated, it would be listed here as well. On 11/5, my user was removed from the group, and shortly before that, Test User 01 was added. On 11/2 John Doe was added. You can see that Test User 01 was added before I was removed since the USN for Test User 01’s link is a bit lower.

Exchange Server 2010 SP1 Training

If your organization is deploying Exchange Server 2010 or you’re even thinking about it, you should get your manager to send you to this event. I’m working with Tony Redmond and Paul Robichaux who are two of the top Exchange MVPs to build a three day in depth Exchange Server 2010 workshop. Tony and Paul are leading the content delivery and I own the hands on labs. I’ve seen much of the content (it’s almost done!) and it’s far more in depth than any other Exchange courseware I’ve seen, plus it’s up to date with all of the changes (there are a lot of them) in Service Pack 1 for Exchange Server 2010. The hand-on-labs are nearly complete too, and you’ll leave with a USB hard drive loaded with the virtual machines you work on during the course so you can take them back home and continue where you left off as well as have a fully functional test lab.

We’ll be delivering the workshop twice back-to-back in Boston (October 13 – 15) and Anaheim (Los Angeles, October 18 – 20). I’d highly encourage you to check out the website for the event and come join us.

Speaking at TEC EMEA this Fall

I’ll be delivering a couple of sessions in Dusseldorf in a couple weeks for TEC 2010 EMEA. There’s even still time to register if you’re not coming yet. I’ve been to a number of TEC’s now and without a doubt I think TEC is the most technically valuable conference I’ve attended. It’s definitely worth the cost. The two sessions I’m doing are:

  • Designing and Planning AD Schema Extensions – This session examines what makes sense in AD and what doesn’t, shows how to evaluate a proposed schema change and even helps you deal with a fear of schema changes. You’ll learn how to look for attributes that need indexing, how to secure data (such as a confidential flag), and finally, carrying out a schema change (such as LDIF files vs. something else).
  • Inside Kerberos – Joe Kaplan and I will be talking about how Kerberos and Active Directory work together. We’ll take a look at the various tickets and messages involved as well as dive in to delegation and protocol transition. We’ll wrap up with some notes on troubleshooting common problems.