Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-29 Thread Dominik George
Hi,

> Just add the capability to the service unit file.

Sure, I can do that.

My doubts are not about how to do it, but whether it is a good idea. 
CAP_SYS_ADMIN is a rather huge pile of capabilities, and certainly there is a 
reason userdbd runs with a very constrained set now?

-nik

Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-29 Thread Lennart Poettering
On Di, 29.11.22 11:50, Dominik George (n...@naturalnet.de) wrote:

> Hi,
>
> > in theory, I have implemented that now […]
>
> In practice now, as well:
>
>   https://github.com/systemd/systemd/pull/25556
>
> However, something kicked back here a bit… systemd-userdbd drops all
> capabilities, and sending SO_PASSCRED requires CAP_SYS_ADMIN…
>
> What do we do about that?

Just add the capability to the service unit file.

Lennart

--
Lennart Poettering, Berlin


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-29 Thread Dominik George
Hi,

> in theory, I have implemented that now […]

In practice now, as well:

  https://github.com/systemd/systemd/pull/25556

However, something kicked back here a bit… systemd-userdbd drops all
capabilities, and sending SO_PASSCRED requires CAP_SYS_ADMIN…

What do we do about that?

Cheers,
Nik


signature.asc
Description: PGP signature


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-28 Thread Dominik George
Hi,

> in theory, I have implemented that now, but I somehow cannot make
> userdbd send credentials on, because it does not seem to call
> varlink_write at all. I am a bit lost with that, because as I
> understand the code, all parts of userdbd and homed should be using
> varlink_write when calling methods on remote services and when
> replying. Yet, attaching gdb to userdbd and setting a breakpoint in
> varlink_write does not break…

OK, wait… that seems to be a red herring. The interaction between the
multiplexer and the sockets in /run/systemd/userdb does not seem to
work at all in the container spawned by mkosi.

-nik


signature.asc
Description: PGP signature


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-28 Thread Dominik George
Hi Lennart,

in theory, I have implemented that now, but I somehow cannot make
userdbd send credentials on, because it does not seem to call
varlink_write at all. I am a bit lost with that, because as I
understand the code, all parts of userdbd and homed should be using
varlink_write when calling methods on remote services and when
replying. Yet, attaching gdb to userdbd and setting a breakpoint in
varlink_write does not break…

Can you give me a hint on what part of the picture I might be missing?

Cheers,
Nik


signature.asc
Description: PGP signature


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-28 Thread Lennart Poettering
On Mo, 28.11.22 16:27, Dominik George (n...@naturalnet.de) wrote:

> Hi,
>
> > You don't have to send that really, the kernel will implicitly attach it
> > automatically whenever the sender's credentials change. Thus, a
> > receiver can safely assume that the ucred remains the same as the
> > SO_PEERCRED data until it receives a new SCM_CREDENTIALS that says
> > otherwise.
> >
> > You want to send SCM_CREDENTIALS explicitly only when you actively try
> > to impersonate someone else.
>
> I'm not convinced of that. Of course, sending the creds if it does not
> differ from the process running would be sufficient, but doing it in
> all cases removes a lot of complexity.

>From the receiving side there's very little difference in behaviour:
the kernel will automatically send this stuff *anyway* if needed.

hence on the receiving side in the Varlink object just add a new
"struct ucred" field that stores the last SCM_CREDENTIALS ucred that
was received. Update it whenever a new SCM_CREDENTIALS is received. It
will look the exact same way from the receiving side if on the sending
side the kernel sent it automatically because the sender's uid changed
or if the sender appended it explicitly because it felt like it, for
example because it wants to impersonate someone.

> Sending SCM_CREDENTIALS selectively would mean we would have to
> introduce a distinction between systemd-userdbd acting as multiplexer
> and not doing so, which would require moving quite a bit of code
> around that is now neatly generic.

userdbd should always impersonate the client it received the request
on. What I am saying is that regular varlink client code (i.e. not
userdbd, not an impersonator) should not bother with this at all,
since the kernel well attach this info anyway if needed. Only
impersonators need to attach SCM_CREDENTIALS explicitly, and userdb
should be one of these impersonators.

Lennart

--
Lennart Poettering, Berlin


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-28 Thread Dominik George
Hi,

> You don't have to send that really, the kernel will implicitly attach it
> automatically whenever the sender's credentials change. Thus, a
> receiver can safely assume that the ucred remains the same as the
> SO_PEERCRED data until it receives a new SCM_CREDENTIALS that says
> otherwise.
> 
> You want to send SCM_CREDENTIALS explicitly only when you actively try
> to impersonate someone else.

I'm not convinced of that. Of course, sending the creds if it does not
differ from the process running would be sufficient, but doing it in
all cases removes a lot of complexity.

Sending SCM_CREDENTIALS selectively would mean we would have to
introduce a distinction between systemd-userdbd acting as multiplexer
and not doing so, which would require moving quite a bit of code
around that is now neatly generic.

On the other hand, the only downside of always sending the credentials
is a few bytes overhead on the wire.

In my opinion, saving htese few bytes does not justify the added
complexity by making a distinction between the code paths.

What do you think?

> In the varlink API please report the SCM_CREDENTIALS ucred seperately
> from the SO_PEERCRED though (i.e. from the current ucreds we already
> store). For various purposes it is interesting to know the identity of
> the process initiating the connection, if it's different from the
> process actually sending messages over it.

Sure!

Cheers,
Nik


signature.asc
Description: PGP signature


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-28 Thread Lennart Poettering
On Mo, 28.11.22 00:14, Dominik George (n...@naturalnet.de) wrote:
65;6800;1c
> Hi,
>
> > The approach brings me a bit farther away from being able to implement it 
> > myself, but not too far I guess ;).
>
> I've spent some time reading the userdb code now, and it actually
> seems pretty easy to do.
>
> Here's my rough plan:
>
>  1. In src/userdb/userdbd-manager.c manager_startup(), set teh
> SO_PASSCRED socket option
>  2. In src/shared/varlink.c, change the behaviour in two places:
>  - In varlink_read, use recvmsg to read the SCM_CREDENTIALS
>message and, if we get one and its uid is valid, store the
>ucred in the varlink struct and set its ucred_acquired to truw
>  - In varlink_write, always send an SCM_CREDENTIALS message —
>if ucred_acquired is true on the varlink object, send this
>ucred struct' if it is false, send an empty message to use
>our real credentials

You don't have to send that really, the kernel will implicitly attach it
automatically whenever the sender's credentials change. Thus, a
receiver can safely assume that the ucred remains the same as the
SO_PEERCRED data until it receives a new SCM_CREDENTIALS that says
otherwise.

You want to send SCM_CREDENTIALS explicitly only when you actively try
to impersonate someone else.

> Given that all userdbd services in systemd, including the multiplexer,
> use the same code, this should be all there is to it to enable the
> discussed behaviour in systemd, and downstream service implementations
> could start using it.
>
> If yhere is nothing fundamentally wrong with my assessment, I'll give
> the implementation a shot.

Sounds great! Happy to review a PR for that.

In the varlink API please report the SCM_CREDENTIALS ucred seperately
from the SO_PEERCRED though (i.e. from the current ucreds we already
store). For various purposes it is interesting to know the identity of
the process initiating the connection, if it's different from the
process actually sending messages over it.

Lennart

--
Lennart Poettering, Berlin


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-27 Thread Dominik George
> 1. In src/userdb/userdbd-manager.c manager_startup(), set teh
> SO_PASSCRED socket option

OK, correct that: We need to set the option on the new fd from accept() instead.

-nik

Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-27 Thread Dominik George
Hi,

> The approach brings me a bit farther away from being able to implement it 
> myself, but not too far I guess ;).

I've spent some time reading the userdb code now, and it actually
seems pretty easy to do.

Here's my rough plan:

 1. In src/userdb/userdbd-manager.c manager_startup(), set teh
SO_PASSCRED socket option
 2. In src/shared/varlink.c, change the behaviour in two places:
 - In varlink_read, use recvmsg to read the SCM_CREDENTIALS
   message and, if we get one and its uid is valid, store the
   ucred in the varlink struct and set its ucred_acquired to truw
 - In varlink_write, always send an SCM_CREDENTIALS message —
   if ucred_acquired is true on the varlink object, send this
   ucred struct' if it is false, send an empty message to use
   our real credentials

Given that all userdbd services in systemd, including the multiplexer,
use the same code, this should be all there is to it to enable the
discussed behaviour in systemd, and downstream service implementations
could start using it.

If yhere is nothing fundamentally wrong with my assessment, I'll give
the implementation a shot.

-nik

 


signature.asc
Description: PGP signature


Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-25 Thread Dominik George
Hi Lennart,

thanks for your once again fast, yet very thoughtthrough answer!

> Does that make sense?

Absolutely, yes.

The approach brings me a bit farther away from being able to implement it 
myself, but not too far I guess ;).

Cheers,
Nik

Re: [systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-25 Thread Lennart Poettering
On Fr, 25.11.22 15:19, Dominik George (n...@naturalnet.de) wrote:

> Hi,
>
> I would like to extend the methods of the User/Group Lookup API[1]
> with an optional argument "onBehalfOf" that carries the authenticated
> user who made the initial method call.
>
> The argument must only be set by a privileged client.
>
> When a client makes a lookup request to the multiplexer, the
> multiplexer authenticates the client using SO_PEERCRED. In each
> subsequent call to other services, it sets the authenticated user in
> the onBehalfOf argument to the method call.
>
> Services must only honour the argument if the connecting client was
> identified as a privileged client, i.e. it would receive the
> "privileged" section of the User or Group Record. In all other cases,
> they must ignore the argument and use SO_PEERCRED themselves to
> determine the client user.
>
> The concrete use case for this is to allow a service to take more
> fine-grained control of the data it returns, e.g. it strips location
> or realName from the record if an unprivileged user make a query, or
> chooses a user-bound OAuth token to make calls to a Web API in
> response to the request.
>
> What do others think of this?

Sounds superficially OK to do. I presume you intend to pass the numer
UID there?

Usually passing around numeric UIDs is a bit problematic, due to
user namespaces and so on. i.e. the two ends of an AF_UNIX stream might live in
different userns and thus have a different idea what UID 4711 means.

This hence raises the question if we can find a better way. Right now,
systemd's varlink implementation uses exclusively SO_PEERCRED to
identify the peer i.e. a UID pinned at connection time.

But there's also SCM_CREDENTIALS, which allows receiving and sending
UIDs at arbitrary times. When sending them, clients can only send
their own uids (euid or uid), or if they are privileged any. Hence, we
could just build on that: when reading messages of the varlink socket
do so with recvmsg() so that we get this info. Then when doing lookups
we'd use SCM_CREDENTIAL info when available, and SO_PEERCRED
otherwise. A client could then transmit its varlink messages with a
SCM_CREDENTIAL metadata field to execute stuff on-behalf of some other
client.

The big benefits of this approach would be: automatic translation of
UIDs by the kernel in regards to userns, and the kernel will
implicitly validate for us whether the on-behalf-of impersonation
shall be allowed or not.

Does that make sense?

Lennart

--
Lennart Poettering, Berlin


[systemd-devel] RFC: Passing on initial client user in systemd-userdbd

2022-11-25 Thread Dominik George
Hi,

I would like to extend the methods of the User/Group Lookup API[1]
with an optional argument "onBehalfOf" that carries the authenticated
user who made the initial method call.

The argument must only be set by a privileged client.

When a client makes a lookup request to the multiplexer, the
multiplexer authenticates the client using SO_PEERCRED. In each
subsequent call to other services, it sets the authenticated user in
the onBehalfOf argument to the method call.

Services must only honour the argument if the connecting client was
identified as a privileged client, i.e. it would receive the
"privileged" section of the User or Group Record. In all other cases,
they must ignore the argument and use SO_PEERCRED themselves to
determine the client user.

The concrete use case for this is to allow a service to take more
fine-grained control of the data it returns, e.g. it strips location
or realName from the record if an unprivileged user make a query, or
chooses a user-bound OAuth token to make calls to a Web API in
response to the request.

What do others think of this?

Cheers,
Nik


 [1] https://systemd.io/USER_GROUP_API/


signature.asc
Description: PGP signature