On Sat, 1 Nov 2014 17:24:53 +0100
Jakub Hrozek <jhrozek(a)redhat.com> wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
> === Providers ===
> The providers are dynamically loadable libraries that are loaded by
> the `sssd_be` process. After startup, the sssd_be process dlopens
> the provider library and dlsyms the handlers. During sssd
> operation, the `sssd_be` process mostly unpacks requests arriving
> on the SBUS and calls the provider-specific handlers.
>
> We have two options here - either drop the privileges in the
> provider library itself or directly in the `sssd_be` process.
> Dropping privileges in the `sssd_be` process has the advantage of
> modifying only one place and being sure that no matter the back
> end, the privileges would always be dropped.
>
> On the other hand, becoming user in the library itself might be
> beneficial for scenarios where the back end requires root access for
> initialization. Also, if some third-party proprietary module
> absolutely requires to run as root, we shouldn't enforce the
> privilege drop.
>
> If we don't care about the third party modules, we could take an
> approach where the provider would drop privilege as soon as it can
> and after all the initialization was completed, the sssd_be process
> would ensure the privileges are indeed dropped. Because there are
> no third party back ends so far and there was no attempt to write
> one, this is currently safe.
After some experimentation and poking at the krb5 code, I think a
different route is needed. We can't reasonably drop the privileges in
the provider's setup routines themselves, because we don't know if
another provider needs root privileges or not. For example consider a
LDAP + Kerberos combination, the LDAP ID provider can't drop
privileges until Kerberos provider initializes because the Kerberos
provider might need root privileges to check exisiting ccaches for
renewal after startup.
We can drop privileges after the whole initialization finishes, but we
should strive to reduce the privileged code even further.
Michal had an idea of adding another function to the providers that
would perform privileged init, then sssd_be would drop privs and
proceed with the rest of the init.
So the initialization would change from:
id_provider = dlopen()
id_init = dlsym(id_provider)
id_init()
auth_provider = dlopen()
auth_init = dlsym(auth_provider)
auth_init()
[...]
become_user(sssd)
to something like:
id_provider = dlopen()
auth_provider = dlopen()
privileged_id_init = dlsym(id_provider)
privileged_auth_init = dlsym(auth_provider)
privileged_id_init()
privileged_auth_init()
become_user(sssd)
id_init()
auth_init()
The privileged init would initialize private data the provider needs
and pass it on to the non-privileged init code.
There are some other alternatives, like a setuid setup process or
performing the initialization in the monitor, but I like this option
the best because passing on complex data structures between processes
is tricky. This way we also keep no knowledge about provider internals
outside the provider code.
Simo, I CC-ed you directly because I know you prefer to be aware of
changes to the data_provider_be.c module. Do you agree with this plan?
Are we sure we will be able to meaningfully separate "privileged
initialization" from non-privileged items ?
My fear is that we complicate the init system and end up having all
initialization in privileged_*_init() anyway, and *_init() become empty
shells.
I am comfortable with keeping the whole init privileged TBH.
Simo.
--
Simo Sorce * Red Hat, Inc * New York