Explaining the new SAM

Andrew Bartlett abartlet at samba.org
Wed Oct 2 01:27:59 GMT 2002

It seems the 'new SAM' is suffering a bit on the PR front...  I'm hoping
this is mainly a matter of communication, because we (tried!) to put a
lot of thought into the interface.

Security in the 'new SAM'

One of the biggest problems with passdb is it's implementation of
'security'.  Access control is on a 'are you root at the moment' basis,
and it has no concept of NT ACLs.  Things like ldapsam had to add
'magic' 'are you root' checks.

We took this very seriously when we started work, and the new structure
is designed with this in mind, from the ground up.  Each call to the SAM
has a NT_TOKEN and (if relevant) an 'access desired'.  This is either
provided as a parameter, or implicitly supplied by the object being

For example, when you call 

NTSTATUS sam_get_account_by_name(const SAM_CONTEXT *context, const
NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain,
const char *name, SAM_ACCOUNT_HANDLE **account)

The context can be NULL (and is used to allow import/export by setting
up 2 contexts, and allowing calls on both simultaneously)

The access token *must* be specified.  Normally the user's token out of
current_user, this can also be a global 'system' context.

The access desired is as per the ACL, for passing to the seaccess stuff.

The domain/username are standard.  Even if we only have one domain,
keeping this ensures that we don't get 'unqualified' usernames (same
problem as we had with unqualified SIDs).

We return a 'handle'.  This is opaque to the rest of Samba, but is
operated on by get/set routines, all of which return NTSTATUS.

The access checking is done by the SAM module.   The reason it is not
done 'above' the interface is to ensure a 'choke point'.  I put a lot of
effort into the auth subsystem to ensure we never 'accidentally' forgot
to check for null passwords, missed a restriction etc.  I intend the SAM
to be written with the same caution.

The reason the access checking is not handled by the interface itself is
due to the different implementations it make take on.  For example, on
ADS, you cannot set a password over a non-SSL connection.  Other
backends may have similar requirements - we need to leave this policy up
to the modules.  They will naturally have access to 'helper' procedures
and good examples to avoid mishaps.

(Furthermore, some backends my actually chose to push the whole ACL
issue to the remote server, and - assuming ldap for this example - bind
as the user directly)

Each returned handle has an internal 'access permitted', which allows
the 'get' and 'set' routines to return 'ACCESS_DENIED' for things that
were not able to be retrieved from the backend.  This removes the need
to specify the NT_TOKEN on every operation, and allows for 'object not
present' to be easily distinguished from 'access denied'.

When you 'set' an object (calling sam_update_account) the internal
details are again used.  Each change that has been made to the object
has been flagged, so as to avoid race conditions (on unmodified
components) and to avoid violating any extra ACL requirements on the
actual data store (like the LDAP server).

Finally, we have generic get_sec_desc() and set_sec_desc() routines to
allow external ACL manipulation.  These do lookups based on SID.

Andrew Bartlett

Andrew Bartlett                                 abartlet at pcug.org.au
Manager, Authentication Subsystems, Samba Team  abartlet at samba.org
Student Network Administrator, Hawker College   abartlet at hawkerc.net
http://samba.org     http://build.samba.org     http://hawkerc.net

More information about the samba-technical mailing list