Thanks Joe. I really appreciate all the tips. I had originally
planned on it being a "quick tool" and it has really grown. The reason
I wrote it is because I wanted to learn some AD programming, and make
my life easier. At least I got one of those two
The lines that caused the anonymous GC query were:
CDOEXM.IMailboxStore mailbox;
mailbox = (IMailboxStore)userentry.NativeObject;
mailbox.CreateMailbox(MailServerList.SelectedValue.ToString());
userentry.CommitChanges();
//Give Mailbox some properties, like email address.
userentry.Properties["mailNickname"].Add(iFname.Text + "." +
iLName.Text);
userentry.Properties["mail"].Add(ioemailaddress.Text +
emaildomain.Text);
userentry.CommitChanges();
The subsystem apparently makes the query as anon if you aren't an admin
(or something like that) Anon read access to GC and things were happy.
Joe Kaplan (MVP - ADSI) wrote:
I was really just trying to suggest that checking permissions for DA's
probably isn't that helpful. If you could, you might consider
determining
if the user is a DA and not filtering your list if they are. You can
do
this by getting the user's tokenGroups attribute and seeing if the DA
group
SID is in there. You can also get this directly from the user's
WindowsIdentity.Groups property (which is probably easier).
In our environment with >150K users and ~80K groups, this performance
hit
would really work.

Neither would showing someone a list of 80K
groups
though.
It is probably best to avoid doing queries that return
allowedAttributesEffective against many many objects, as that result
is
fairly expensive for the DC to produce. However, if you are trying to
trim
a list, it is hard not to use it.
A way to get much better perf would be to add your own attribute that
contains the DNs of groups that are allowed to use that particular
group
and
query against that. Then, of course, you need a way to keep the
permissions
delegations in sync with the contents of that attribute, but your UI
will
be
much snappier and your DCs will be lest beaten up servicing that
query.
It is weird that your helpdesk users can't search the GC. That should
work
fine. Authenticated Users can typically query the GC, just like the
standard LDAP ports.
The rest of the stuff doesn't surprise me though. The way this kind
of
thing is often implemented is using a trusted subsystem design, where
your
client calls some server process that does have the credentials to
perform
the required operations, but then provides its own authorization layer
to
implement a role-based security mechanism. The role-based security
mechanism is often a PITA to build and test, but it can gain you a
bunch
of
important functionality. Some companies have whole products based on
providing role-based delegation of operations against AD, so you could
also
consider buying something.
Best of luck with your solution. It sounds like you've made a lot of
progress. We have a book out there that might have helped you with
some
of
the stuff you are doing if you are interested.
Joe K.
--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services
Programming"
http://www.directoryprogramming.net
--
Here's the gist of what I've created (some might call it a monster)
Our environment had a number of domain admins (which we are now
working
on pruning) People would create users and not put in alot of the
information ("Too much work...") so I've created a front end app
that
will:
a) create the user
b) create a home directory on a server of choice (based on which OU
they are in)
c) create a share for the home directory from that server.
d) create an exchange mailbox on a designated mailserver (based on
OU)
and email address for the user.
e) place the user in a default group based on which OU they are in.
f) give the creator a list of other groups into which they have
permission to add the user. (This was the part that I needed this
last
bit of help for)
This was all fine with DA's. Then we created a "HelpDesks" group.
Suddenly things like D$ weren't available, remote WMI, Distributed
COM,
reading the GC for email addresses, all fell apart. The last few
weeks
I have been rewriting the code to handle the lower privs. When a
"HelpDesk" user creates a new user, they are now only presented with
the groups that they can "legally" add a user, not all
Now, like I said, my only problem is that my DA's get a list of
about
500+ groups, and adding that process takes upwards of 60 seconds.
Here's what I'm doing for that:
ADNode = new System.DirectoryServices.DirectoryEntry("LDAP://" +
domainstr);
System.DirectoryServices.DirectorySearcher ADSearch = new
System.DirectoryServices.DirectorySearcher(ADNode);
ADSearch.CacheResults = true;
ADSearch.PropertiesToLoad.Add("cn");
ADSearch.PropertiesToLoad.Add("allowedAttributesEffective");
ADSearch.Filter = "(&(objectCategory=group)(!cn=domain
computers)(!cn=domain controllers))";
GroupList.Sorted = true;
foreach (System.DirectoryServices.SearchResult
ADSearchres
in ADSearch.FindAll())
{
//ActiveDs.ADSearchres.Properties["ntSecurityDescriptor"]
if
(ADSearchres.Properties["allowedAttributesEffective"].Contains("member"))
{
ADChild = ADSearchres.GetDirectoryEntry();
GroupListAddItem(ADChild);
if (ADChild.Name == "CN=G Env Env")
GroupListAddSelectedItems(ADChild);
}
}
Note, the calls to "functions" are delegates for background thread
update via invoke. Am I doing something horribly wrong?
Joe Kaplan (MVP - ADSI) wrote:
There isn't really any point of running this for a DA. DAs
generally
are
given full control over all objects and can typically take
ownership
of
any
object that has that ACE removed, so there is no real way to
prevent a
DA
from modifying just about anything. You should always assume that
DAs
can
do anything they want to any object in the forest.