Bug 39720 - Clumsy semantics when connecting to session bus owned by another user
Summary: Clumsy semantics when connecting to session bus owned by another user
Status: RESOLVED MOVED
Alias: None
Product: dbus
Classification: Unclassified
Component: core (show other bugs)
Version: 1.5
Hardware: All All
: medium normal
Assignee: Simon McVittie
QA Contact: D-Bus Maintainers
URL: http://cgit.collabora.com/git/user/ka...
Whiteboard: review-, needs rebase/re-testing
Keywords: patch
Depends on:
Blocks: dbus-1.5
  Show dependency treegraph
 
Reported: 2011-08-01 08:07 UTC by David Zeuthen (not reading bugmail)
Modified: 2018-10-12 21:12 UTC (History)
6 users (show)

See Also:
i915 platform:
i915 features:


Attachments
Factor out DBusAuthorization from DBusTransport (31.21 KB, patch)
2011-10-03 09:38 UTC, Cosimo Alfarano
Details | Splinter Review
Use DBusAuthorization (5.84 KB, patch)
2011-10-03 09:50 UTC, Cosimo Alfarano
Details | Splinter Review
avoid assertions calling methods with collateral effects (1.25 KB, patch)
2011-10-03 09:54 UTC, Cosimo Alfarano
Details | Splinter Review
Fix doc (1.18 KB, patch)
2011-10-03 10:00 UTC, Cosimo Alfarano
Details | Splinter Review
Fix confusion between "is it authenticated?" and "try to authenticate" (12.50 KB, patch)
2011-10-04 09:47 UTC, Simon McVittie
Details | Splinter Review
Factor out DBusAuthorization from DBusTransport (36.66 KB, patch)
2011-10-11 09:03 UTC, Cosimo Alfarano
Details | Splinter Review
Use DBusAuthorization (9.30 KB, patch)
2011-10-11 09:04 UTC, Cosimo Alfarano
Details | Splinter Review
rename authorized_identity (5.73 KB, patch)
2011-10-11 09:08 UTC, Cosimo Alfarano
Details | Splinter Review
Allow ANONONYMOUS in tests (2.37 KB, patch)
2011-10-11 09:11 UTC, Cosimo Alfarano
Details | Splinter Review
Do not authorize twice (2.14 KB, patch)
2011-10-11 09:14 UTC, Cosimo Alfarano
Details | Splinter Review
no refcounting for DBusAuth and DBusAuthorization (16.79 KB, patch)
2011-10-11 09:18 UTC, Cosimo Alfarano
Details | Splinter Review
free window's callback as well (1.05 KB, patch)
2011-10-11 09:19 UTC, Cosimo Alfarano
Details | Splinter Review
fix connection_set_allow_anonymous doc (1.16 KB, patch)
2011-10-18 04:17 UTC, Cosimo Alfarano
Details | Splinter Review
Add a simple manual test for authentication/authorization (14.18 KB, patch)
2012-02-27 05:09 UTC, Simon McVittie
Details | Splinter Review
trivial: re-word authorization failure message (963 bytes, patch)
2012-03-12 06:16 UTC, Simon McVittie
Details | Splinter Review
_dbus_transport_get_is_authenticated: avoid unnecessary unref (1.14 KB, patch)
2012-03-12 06:16 UTC, Simon McVittie
Details | Splinter Review
Add a test-case for trying to connect with the wrong GUID (3.46 KB, patch)
2012-03-12 06:17 UTC, Simon McVittie
Details | Splinter Review
Remove transport-s-call-to-dbus-authorization (update) (2.07 KB, patch)
2013-08-22 23:59 UTC, Ralf Habacker
Details | Splinter Review
Remove transport-s-call-to-dbus-authorization (update2) (2.38 KB, patch)
2013-08-23 00:53 UTC, Ralf Habacker
Details | Splinter Review

Description David Zeuthen (not reading bugmail) 2011-08-01 08:07:26 UTC
I believe that the way D-Bus currently works is that connecting to a session bus instance owned by another user should fail. This sorta works but is currently implemented in a way by which the authentication step succeeds BUT the peer is immediately disconnected.. which is apparent when the peer invokes the Hello() method. See [1] for evidence of this.

This is really clumsy... dbus-daemon(1) really shouldn't be sending back the 'OK' response just to disconnect the user immediately after. Instead the bus daemon should be sending the 'REJECTED' response so either a) another authentication method can be tried; or b) a better error can be returned.

(whether connecting to another user's session bus really _should_ fail is another discussion... of which I agree that current behavior is correct... but let's just assume that this is the way we want it to work.)

[1] : For convenience I'm using GDBus' G_DBUS_DEBUG facilities but anything else should work too

[davidz@x61 ~]$ echo $DBUS_SESSION_BUS_ADDRESS 
unix:abstract=/tmp/dbus-I9MbTQdGMl,guid=c74094a2a6b2e14e32b300260000001a
[davidz@x61 ~]$ su - bateman
Password: 
[bateman@x61 ~]$ export DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-I9MbTQdGMl,guid=c74094a2a6b2e14e32b300260000001a

[bateman@x61 ~]$ G_DBUS_DEBUG=all gdbus introspect --session --dest org.freedesktop.DBus --object-path /
GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `session'
GDBus-debug:Address: env var DBUS_SESSION_BUS_ADDRESS=`unix:abstract=/tmp/dbus-I9MbTQdGMl,guid=c74094a2a6b2e14e32b300260000001a'
GDBus-debug:Address: env var DBUS_SYSTEM_BUS_ADDRESS is not set
GDBus-debug:Address: env var DBUS_STARTER_BUS_TYPE is not set
GDBus-debug:Address: Returning address `unix:abstract=/tmp/dbus-I9MbTQdGMl,guid=c74094a2a6b2e14e32b300260000001a' for bus type `session'
GDBus-debug:Auth: CLIENT: initiating
GDBus-debug:Auth: CLIENT: sent credentials `GCredentials:linux-ucred:pid=9630,uid=501,gid=501'
GDBus-debug:Auth: CLIENT: writing `AUTH\r\n'
GDBus-debug:Auth: CLIENT: WaitingForReject
GDBus-debug:Auth: CLIENT: WaitingForReject, read 'REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS'
GDBus-debug:Auth: CLIENT: Trying to choose mechanism
GDBus-debug:Auth: CLIENT: Trying mechanism `EXTERNAL'
GDBus-debug:Auth: CLIENT: writing `AUTH EXTERNAL 353031\r\n'
GDBus-debug:Auth: CLIENT: WaitingForOK
GDBus-debug:Auth: CLIENT: WaitingForOK, read `OK c74094a2a6b2e14e32b300260000001a'
GDBus-debug:Auth: CLIENT: writing `NEGOTIATE_UNIX_FD\r\n'
GDBus-debug:Auth: CLIENT: WaitingForAgreeUnixFD
GDBus-debug:Auth: CLIENT: WaitingForAgreeUnixFD, read=`AGREE_UNIX_FD'
GDBus-debug:Auth: CLIENT: writing `BEGIN\r\n'
GDBus-debug:Auth: CLIENT: Done, authenticated=1
========================================================================
GDBus-debug:Call:
 >>>> SYNC org.freedesktop.DBus.Hello()
      on object /org/freedesktop/DBus
      owned by name org.freedesktop.DBus
========================================================================
GDBus-debug:Call:
 <<<< SYNC COMPLETE org.freedesktop.DBus.Hello()
      FAILED: The connection is closed
Error connecting: The connection is closed
Comment 1 David Zeuthen (not reading bugmail) 2011-08-01 08:09:54 UTC
Possibly relevant GDBus bug: https://bugzilla.gnome.org/show_bug.cgi?id=655664
Comment 2 Simon McVittie 2011-08-02 02:59:37 UTC
(In reply to comment #0)
> I believe that the way D-Bus currently works is that connecting to a session
> bus instance owned by another user should fail. This sorta works but is
> currently implemented in a way by which the authentication step succeeds BUT
> the peer is immediately disconnected.. which is apparent when the peer invokes
> the Hello() method.

You're right, that is clearly not how it should be. I'd be happy to review a patch (or write one, if you'll review it + some of the backlog).
Comment 3 David Zeuthen (not reading bugmail) 2011-08-03 12:01:40 UTC
I'll try to work on a patch for this...
Comment 4 Simon McVittie 2011-09-23 04:23:39 UTC
Any progress on this? Cosimo might steal this bug if you're not working on it?
Comment 5 David Zeuthen (not reading bugmail) 2011-09-23 06:45:53 UTC
Yeah, sorry, didn't get to do any work on this bug yet.
Comment 6 Cosimo Alfarano 2011-09-23 08:28:41 UTC
(In reply to comment #5)
> Yeah, sorry, didn't get to do any work on this bug yet.

I'll give a look at it then, if you don't mind
Comment 7 David Zeuthen (not reading bugmail) 2011-09-26 07:41:33 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > Yeah, sorry, didn't get to do any work on this bug yet.
> 
> I'll give a look at it then, if you don't mind

I don't mind at all - thanks for looking into it!
Comment 8 jidanni 2011-09-27 05:01:49 UTC
See also http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=633652
Comment 9 Simon McVittie 2011-09-27 08:10:28 UTC
(In reply to comment #0)
> I believe that the way D-Bus currently works is that connecting to a session
> bus instance owned by another user should fail. This sorta works but is
> currently implemented in a way by which the authentication step succeeds BUT
> the peer is immediately disconnected.. which is apparent when the peer invokes
> the Hello() method. See [1] for evidence of this.

Cosimo and I discussed this on IRC, this is a summary.

I believe (but I could be wrong - I suspect only Havoc really understands this stuff) that the intention is that the SASL stuff at the beginning provides authentication, but not authorization. (If you are bateman connecting to davidz's bus: it confirms that you are really bateman, but does not confirm that you are allowed to connect to davidz's bus.)

Then, we do the authorization (is bateman allowed to connect to this bus? no.) once the D-Bus session is fully up. In theory, this would allow sending back useful error messages. (But it's never that easy in D-Bus land.)

I started off suggesting that Cosimo should do authorization during authentication, but we've more or less come to the conclusion that that would be a layering violation (dbus-auth needs to call the DBusConnection's DBusAllowUnixUserFunction), and perhaps it can't send back useful error messages anyway (or perhaps it can, I don't know the SASL stuff in detail).

My next suggestion was to reply to Hello() with an error, then terminate the connection. However, that makes us DoS'able, unless done very carefully: bateman can connect to davidz's bus n times, where n is the fd limit for a single process, and not send Hello(); and now davidz can't connect.

Another option is to define a new signal, something like:

    signal org.freedesktop.DBus.Disconnecting(s: error_code, s: message)
    @error_code: a D-Bus error name, typically
        "org.freedesktop.DBus.Error.AccessDenied" or
        "org.freedesktop.DBus.Error.CorruptMessage"
    @message: a human-readable message describing the error in the C locale

    Emitted by org.freedesktop.DBus:/org/freedesktop/DBus just before it
    disconnects you for a protocol violation, authorization failure or
    other fatal error. This is similar to an ERROR reply, but instead of
    being a reply to a single message, it is a reply to an error that
    invalidates the entire connection, such as authorization failure
    (connecting to someone else's session bus) or sending a corrupt message.

    It is appropriate for clients to map the error code and message to
    their native representation (e.g. GError) in the same way they would
    for an ERROR reply's ERROR_NAME field and first string argument.

    Clients may assume that no more messages will follow this one.

    This message may be received before the reply to Hello().
    If it is, it will not have a DESTINATION field.

... which would also solve Bug #34726 while we're at it (by introducing the new CorruptMessage error).

Technicalities: sending the signal might be a best-effort thing: if the buffer is full or there isn't enough memory, we'd just disconnect the bad client. That should only happen to abusive clients anyway - in practice, sockets should have at least a few KiB of buffer space into which we can write the message. See Bug #34726 for more details.
Comment 10 David Zeuthen (not reading bugmail) 2011-09-27 09:31:55 UTC
Hey,

I'm not sure it's useful to make the distinction between authentication and authorization at the connection setup level (e.g. the part up to and including the BEGIN command). Specifically, the SASL authentication part is very explicitly a _proper_ subset of the whole connection setup ordeal - there's no reason that authorization shouldn't happen at that level. In fact, it's a good idea to terminate the connection as early as possible if we know that an authenticated identity is not authorized to connect.

For the record, other notable parts of the connection setup include negotiating e.g. unix fd capability and in the future a bunch of other things... surely, making decisions on whether we want to exchange FDs or accept values with the MAYBE type is even more a 'layering violation' than actually deciding if the authenticated identity is authorized.

Either way, the libdbus implementation is free to do what it wants... but I don't think inventing extensions to the connection setup part of the protocol (e.g. causing other implementations to support those extensions if we want better error handling in other implementations) is a good idea ... and note that in the GDBus implementation, we allow authorization decisions as part of the connection setup

 http://developer.gnome.org/gio/unstable/GDBusAuthObserver.html#GDBusAuthObserver.description

In fact, with the way this is set up, we can add new policy hooks without breaking ABI in GDBus (for example, a GDBusConnection::allow-maybe-types signal to determine if the connection should allow the use of MAYBE types).
Comment 11 Cosimo Alfarano 2011-09-28 07:49:59 UTC
Layers apart, which I'd like to keep as clean as possible, dbus-auth.c has no clue of the DBusTransport, which I somehow need in order to understand if I'm acting as session or system bus.

System buses in fact should allow connection from anybody, while the identity restriction will apply only for sessions buses.

Acting on Hello() return values, beside being DoS prone, would not really work (or it would be harder than expected) since the connection is dropped before even knowing that the method call is Hello().

The authorization steps are taken on any passing message (AFAIK), which makes sense.

I started considering adding a state to the DBusAuth automaton after AUTHENTICATED, it would be an hidden state, which would be included in the AUTH answer (OK -> both results succeeded, REJECT, one failed).

This state can be explicit or implicitly done at the end of the AUTHENTICATED state (it might be seen a layer mixup, but we can make it clear that it's authorization by big comments)

This state would use for the first time during the connection initialization the user_function, but not forcing a disconnection upon being not authorized, giving back a proper Error instead.

Authorization in SASL, for what I can see, is usually done via some callbacks, which for dbus are user functions I believe.

Not sure if it will break something spec side or for backward compatibility, as long as we don't add any handshake step the client should wait for.
It should be the same, as far as I can see.
Comment 12 Cosimo Alfarano 2011-09-28 10:23:52 UTC
It's actually harder than what I thought and it needs some refactoring in order to be able to call DBusAllowUnixUserFunction and the Win one from DBusAuth or a similar approach.

The user functions are in DBusTransport and need a DBusConnection.

The solution of passing to _dbus_auth_server_new() a DBusTransport* (which would be the class where DBusAuth cronstructor is call, actually) is the fastest but it would have circular references. transport->auth->transport, which I dislike.

I'd delegate the authorization step (ie the policy checking + uid/sid checking) to another class (DBusAuthorize?) which would contain the user functions and references to whatever they need (DBusConnection in primis).

This object would be instantiated from DBusTransport and be used within both DBusTransport to authorize each message when DBusAuth is already in AUTHENTICATED state (as it happens now) disconnecting on FAIL, and to authorize the first time the user in the connection during SASL, as it is required in order to REJECT the handshake ASAP.

It should be possible.
I'll go deeper in thinking about it if the solution is considered good enough.
Comment 13 Cosimo Alfarano 2011-10-03 09:38:18 UTC
Created attachment 51903 [details] [review]
Factor out DBusAuthorization from DBusTransport

Authorization is currently held in DBusTransport, indepentently from the authtentication process, which means that there was no way to answer REJECTED if the user's identity is not authorized; instead the connection was simply cut off.

The first step is to take those authorization bits off the transport and put them in a different structure.
Comment 14 Cosimo Alfarano 2011-10-03 09:50:57 UTC
Created attachment 51904 [details] [review]
Use DBusAuthorization

within DBusAuth, use DBusAuthorization at the end of the EXTERNAL mech, pretty much the same way it is done in the transport, but REJECTing instead of disconnecting.

Also the auth script is using the authorization struct, but not having any callback (user_functions) set up, it will be tested against the default_rules.

bus/connection.c will set the daemon's own callbacks which is not run by dbus/dbus-test
Comment 15 Cosimo Alfarano 2011-10-03 09:54:54 UTC
Created attachment 51905 [details] [review]
avoid assertions calling methods with collateral effects

This is not related to this bug.

assertions shouldn't call functions that actually act on the state of the connection. In this case if the transport is not authenticated, it will be called _do_work() which triggers the authentication automaton.

When DBUS_DISABLE_ASSERTION is set, the method would not be called.

Either this this or check only if the transport->authenticated bit is set without processing anything else are viable solution, depending on what should be done.
Comment 16 Cosimo Alfarano 2011-10-03 10:00:29 UTC
Created attachment 51906 [details] [review]
Fix doc

This docstring is not precise, it lacks to things:

1- a move in the auth automaton might be triggered, better specify it.

2- a bit of confusion on when the method returns TRUE:
- it will return true when it has been authenticated and then disconnected.
- but if transport->authenticated is FALSE, it will return FALSE if transport->disconnected is TRUE.
Comment 17 Cosimo Alfarano 2011-10-03 10:06:40 UTC
I'm aware that DBusAuthorization is lacking refs for DBusConnection, I got a bit confused about how to do it properly.

_set_connection is called with the connection's lock held, so I can use
_dbus_connection_ref_unlocked()

What about unreferencing it? During finalization the lock is not held, is it safe to hold it while calling _unref_unlocked()?
DBusConnection at this time should already be disconnected (not verified, though).

Calling the public method dbus_connection_unref() fails asserting about the dbus generation, probably shutdown has been called, which AFAIK it does not make it suitable to be used in this situation.


Also, testing is tricky since the actual user_functions are defined in 
bus/connection.c but the auth script is run in dbus/dbut-test.
SILLY_CREDENTIALS should check it, but I'm not 100% sure of it. I'll give it a look ASAP, if the approach taken with those patches does not break anything.
Comment 18 Cosimo Alfarano 2011-10-04 03:52:15 UTC
This is gdbus output on connecting on someone else's session bus

GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `session'
GDBus-debug:Address: env var DBUS_SESSION_BUS_ADDRESS=`unix:abstract=/tmp/dbus-QljWevEAYD,guid=22e4054d1b52f8a68b26f288000608a9'
GDBus-debug:Address: env var DBUS_SYSTEM_BUS_ADDRESS is not set
GDBus-debug:Address: env var DBUS_STARTER_BUS_TYPE is not set
GDBus-debug:Address: Returning address `unix:abstract=/tmp/dbus-QljWevEAYD,guid=22e4054d1b52f8a68b26f288000608a9' for bus type `session'
GDBus-debug:Auth: CLIENT: initiating
GDBus-debug:Auth: CLIENT: sent credentials `GCredentials:linux-ucred:pid=16704,uid=1000,gid=1000'
GDBus-debug:Auth: CLIENT: writing `AUTH\r\n'
GDBus-debug:Auth: CLIENT: WaitingForReject
GDBus-debug:Auth: CLIENT: WaitingForReject, read 'REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS'
GDBus-debug:Auth: CLIENT: Trying to choose mechanism
GDBus-debug:Auth: CLIENT: Trying mechanism `EXTERNAL'
GDBus-debug:Auth: CLIENT: writing `AUTH EXTERNAL 31303030\r\n'
GDBus-debug:Auth: CLIENT: WaitingForOK
GDBus-debug:Auth: CLIENT: WaitingForOK, read `REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS'
GDBus-debug:Auth: CLIENT: Trying to choose mechanism
GDBus-debug:Auth: CLIENT: Trying mechanism `DBUS_COOKIE_SHA1'
GDBus-debug:Auth: CLIENT: writing `AUTH DBUS_COOKIE_SHA1 31303030\r\n'
GDBus-debug:Auth: CLIENT: WaitingForData
GDBus-debug:Auth: CLIENT: WaitingForData, read=`REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS'
GDBus-debug:Auth: CLIENT: Done, authenticated=0
Error connecting: In WaitingForData: unexpected response `REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS'

While the system one authenticates.
Comment 19 Simon McVittie 2011-10-04 08:21:45 UTC
(In reply to comment #18)
> GDBus-debug:Auth: CLIENT: sent credentials
> `GCredentials:linux-ucred:pid=16704,uid=1000,gid=1000'
> GDBus-debug:Auth: CLIENT: writing `AUTH\r\n'
> GDBus-debug:Auth: CLIENT: WaitingForReject
> GDBus-debug:Auth: CLIENT: WaitingForReject, read 'REJECTED EXTERNAL
> DBUS_COOKIE_SHA1 ANONYMOUS'
> GDBus-debug:Auth: CLIENT: Trying to choose mechanism
> GDBus-debug:Auth: CLIENT: Trying mechanism `EXTERNAL'
> GDBus-debug:Auth: CLIENT: writing `AUTH EXTERNAL 31303030\r\n'
> GDBus-debug:Auth: CLIENT: WaitingForOK
> GDBus-debug:Auth: CLIENT: WaitingForOK, read `REJECTED EXTERNAL
> DBUS_COOKIE_SHA1 ANONYMOUS'

I feel as though the REJECTED response isn't necessarily right here: the client side seems to treat REJECTED as "you're not going to get in with that mechanism, but try again". As far as I can tell, in the same situation GDBus' service-side would just summarily disconnect the client. The client can distinguish between this and a later disconnection, because authorization failure occurs before BEGIN, and the sort of disconnection that should trigger exit-on-disconnect occurs after.

Ideally, we'd perhaps negotiate a way for the server to tell the client what was wrong, with an error domain and code? Maybe something like this:

    C: AUTH
    S: REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS
    C: NEGOTIATE_FATAL
    S: AGREE_FATAL
    C: AUTH EXTERNAL 31303030
    S: FATAL org.freedesktop.DBus.Error.AccessDenied This bus belongs to uid 1234, but your authenticated uid is 1000.
    S: <disconnects, without waiting for a reply>

(I didn't include quoting in FATAL: libdbus includes double quotes whenever it says ERROR, but I don't know why, since any parsing is simpler without them. I don't think we need a quoting mechanism, we can just say that FATAL messages never include newlines.)

Or we could even remove the negotiation of support for FATAL: the server is about to disconnect the client anyway, so it doesn't matter if the client won't understand.

I'll have a look at your patches in detail.
Comment 20 Simon McVittie 2011-10-04 08:38:03 UTC
(In reply to comment #15)
> avoid assertions calling methods with collateral effects
> 
> This is not related to this bug.
> 
> assertions shouldn't call functions that actually act on the state of the
> connection. In this case if the transport is not authenticated, it will be
> called _do_work() which triggers the authentication automaton.
> 
> When DBUS_DISABLE_ASSERTION is set, the method would not be called.
> 
> Either this this or check only if the transport->authenticated bit is set
> without processing anything else are viable solution, depending on what should
> be done.

Well spotted, this is nasty.

This is not actually a bug, since _dbus_connection_queue_received_message_link can't be called until the transport has already finished authentication and there's nothing more to do (hence the assertion) - but it's stupid that a function with a name like _dbus_transport_get_is_authenticated can ever have side-effects!

I think I'm going to apply it anyway, just for clarity (and then rename the function (on master), to have a more useful name).
Comment 21 David Zeuthen (not reading bugmail) 2011-10-04 09:18:52 UTC
(In reply to comment #19)
> (In reply to comment #18)
> > GDBus-debug:Auth: CLIENT: sent credentials
> > `GCredentials:linux-ucred:pid=16704,uid=1000,gid=1000'
> > GDBus-debug:Auth: CLIENT: writing `AUTH\r\n'
> > GDBus-debug:Auth: CLIENT: WaitingForReject
> > GDBus-debug:Auth: CLIENT: WaitingForReject, read 'REJECTED EXTERNAL
> > DBUS_COOKIE_SHA1 ANONYMOUS'
> > GDBus-debug:Auth: CLIENT: Trying to choose mechanism
> > GDBus-debug:Auth: CLIENT: Trying mechanism `EXTERNAL'
> > GDBus-debug:Auth: CLIENT: writing `AUTH EXTERNAL 31303030\r\n'
> > GDBus-debug:Auth: CLIENT: WaitingForOK
> > GDBus-debug:Auth: CLIENT: WaitingForOK, read `REJECTED EXTERNAL
> > DBUS_COOKIE_SHA1 ANONYMOUS'
> 
> I feel as though the REJECTED response isn't necessarily right here: the client
> side seems to treat REJECTED as "you're not going to get in with that
> mechanism, but try again". As far as I can tell, in the same situation GDBus'
> service-side would just summarily disconnect the client. The client can
> distinguish between this and a later disconnection, because authorization
> failure occurs before BEGIN, and the sort of disconnection that should trigger
> exit-on-disconnect occurs after.
> 
> Ideally, we'd perhaps negotiate a way for the server to tell the client what
> was wrong, with an error domain and code? Maybe something like this:
> 
>     C: AUTH
>     S: REJECTED EXTERNAL DBUS_COOKIE_SHA1 ANONYMOUS
>     C: NEGOTIATE_FATAL
>     S: AGREE_FATAL
>     C: AUTH EXTERNAL 31303030
>     S: FATAL org.freedesktop.DBus.Error.AccessDenied This bus belongs to uid
> 1234, but your authenticated uid is 1000.
>     S: <disconnects, without waiting for a reply>
> 
> (I didn't include quoting in FATAL: libdbus includes double quotes whenever it
> says ERROR, but I don't know why, since any parsing is simpler without them. I
> don't think we need a quoting mechanism, we can just say that FATAL messages
> never include newlines.)

I don't think we need FATAL - for all we know, it could be that the client actually possesses a credential that will work with, say, the DBUS_COOKIE_SHA1 authentication method (or whatever authentication methods are left, if any). But the server doesn't know this so it shouldn't tell the client "nah, don't try again". Therefore, I think it's appropriate to use REJECTED.

(I do agree, however, it would be nice to include more information but retain the semantics of REJECTED, maybe REJECTED_WITH_REASON or something like that?)
Comment 22 Simon McVittie 2011-10-04 09:42:17 UTC
(In reply to comment #21)
> I don't think we need FATAL - for all we know, it could be that the client
> actually possesses a credential that will work with, say, the DBUS_COOKIE_SHA1
> authentication method (or whatever authentication methods are left, if any).

By way of background, just to make sure everyone is using the same terminology:

Authentication is proving that you are who you say you are. It's a technical process.

Authorization is deciding whether you are allowed access. It's a policy decision.

The model used by SASL involves two identities: the identity associated with the authentication credentials (authentication identity), and an identity to act as (authorization identity). They're usually the same, but can differ (for instance, in some systems - with appropriate super-user powers - I could authenticate as smcv and be authorized to act as root, authenticate as root and be authorized to impersonate davidz, or even authenticate as smcv and be authorized to impersonate davidz).

A SASL server performs both authentication and authorization. A successful outcome of a SASL handshake is that the server believes that you are davidz (authentication) *and* is willing to let davidz connect and act as the authorization identity, which is usually also davidz (authorization).

One failed outcome of SASL is an authorization failure: "yes, I believe that you are davidz, but no, this is smcv's session bus and you're not allowed in".

Another failed outcome of SASL is an authentication failure: "you haven't proved to my satisfaction that you're davidz", or even (e.g. with Unix credentials-passing) "I know you're definitely not davidz".

---

It certainly makes sense to be able to retry after authentication failure, because the common case of authentication failure is "you still haven't proved it", and you might be able to prove it in a different way.

I don't think it necessarily makes sense to (be able to) retry after authorization failure, particularly if you don't/can't change who you're authenticating as: however many times you prove that you're davidz, you still can't connect to my session bus. It might be better to use a REJECTED_REASON extension to signal this, and let the *client* decide to stop sooner, though (if the client keeps trying, knowing it will fail, it's potentially a DoS - but I think dbus-daemon handles this correctly, by dropping the oldest authentication attempts when it runs out of incomplete-connection "slots").
Comment 23 Simon McVittie 2011-10-04 09:47:46 UTC
Created attachment 51967 [details] [review]
Fix confusion between "is it authenticated?" and "try to  authenticate"

Historically, _dbus_transport_get_is_authenticated() has had the
side-effect of trying to advance the authentication state machine (if
there's enough buffered input to do so). This seems an inappropriate
activity for what looks like a simple getter.

Split it into _dbus_transport_try_to_authenticate (which does what it
always used to do) and _dbus_transport_peek_is_authenticated (which
is the simple getter version).

To minimize the difference in behaviour for the stable branch of D-Bus,
I've only used _dbus_transport_peek_is_authenticated where it was used
in an assertion, which should clearly not have side effects (and I've
checked that the asserting function cannot be called until both
authentication and authorization have completed). Replacing most of the
calls to try_to_authenticate with peek_is_authenticated is a possible
piece of future work (the ones in DBusConnection certainly look as
though they really want to be peek_is_authenticated).

Based on patches from Cosimo Alfarano, who noticed this
assertion-with-side-effects.

---

(In reply to comment #20)
> I think I'm going to apply it anyway, just for clarity (and then rename the
> function (on master), to have a more useful name).

On second thoughts, calling it for its side-effects looks rather silly, when what the function really wants to do is assert that the SASL dance has finished and we're in "actually D-Bus" mode: so I propose this patch for 1.4, and we can try the future work mentioned in the commit message for 1.5.
Comment 24 David Zeuthen (not reading bugmail) 2011-10-04 10:05:43 UTC
(In reply to comment #22)
> I don't think it necessarily makes sense to (be able to) retry after
> authorization failure, particularly if you don't/can't change who you're
> authenticating as: however many times you prove that you're davidz, you still
> can't connect to my session bus. It might be better to use a REJECTED_REASON
> extension to signal this, and let the *client* decide to stop sooner, though
> (if the client keeps trying, knowing it will fail, it's potentially a DoS - but
> I think dbus-daemon handles this correctly, by dropping the oldest
> authentication attempts when it runs out of incomplete-connection "slots").

I think it's entirely reasonable for the decider-component of an authorization engine to base its decision on the data exchanged in the authentication session(s) - in fact, that's exactly how the trivial "only allow uid XYZ to connect" policy is implemented - by looking at the UID passed along as data in the EXTERNAL authentication method (this is also checked against the UNIX-credentials passed along during the first NUL-byte of the connection setup per the spec - and if it does not match we ERROR out).

But you could imagine more sophisticated setups where you exchange certificates in some authentication method - for example, imagine an authentication method where the client peer presents a certificate signed by someone the system has decided to trust (using some form of CA and PKI). And suppose that your message bus daemon is configured to authorize such clients no matter what their UID is (if any). This is e.g. useful for secure transports where you can't pass UNIX-credentials - for example TCP transports.

In fact, thinking more about it, I think it's entirely unreasonable to disconnect the client just because the authorization engine decides, based on the data from the _first_ used authentication method, that the client is not authorized to connect. Not to mention that this would put an undue burden on the client implementation to try to figure out which authentication method to use first (and such guess-work never really works).
Comment 25 Simon McVittie 2011-10-04 10:32:27 UTC
Copy the copyright information from dbus-transport.[ch] into dbus-authorization.[ch] and update it as appropriate. If you want to fish through git history for any copyright holders who didn't add themselves at the time, or extra copyright years (I'm pretty sure Red Hat employees have written copyrightable things in those files since 2003!), that'd be good too.

Include dbus-internals.h in dbus-authorization.h (even if unneeded) to signal that this is an internal header.

> +  DBusAuthorization *authorization;                    /**< Authorization conversation */

It's not a conversation. "Authorization policy"?

Perhaps call it DBusAuthorizer?

> -void
> +inline void

extern inline is non-portable (the old gcc extension and the ISO meaning are not the same) and highly confusing. Functions should either be static inline (equivalent to a macro, but type-safe) or not marked as inline at all.

The callers of these functions are in a different translation unit (.c file) so they can't be inlined anyway, unless link-time optimization is performed. Just make them normal (extern) functions - they're not on a fast-path or anything.

In _dbus_transport_set_unix_user_function, if transport->is_server is false, you'll need to free the data immediately, otherwise it'll be leaked. Same for Windows.

I'd be inclined to change the signature of _dbus_authorization_do_authorization to look like this:

    dbus_bool_t _dbus_authorization_do_authorization (DBusAuthorization *,
                                                      DBusConnection    *,
                                                      DBusCredentials   *);

and remove _dbus_authorization_set_connection - this would fix the "authorization has a borrowed ref to the connection" problem, by only giving the connection to the authorizer for just long enough to make the authorization decision, during which time the caller is meant to hold a ref. This would also remove your "maybe-FIXME".

> DBusAuthorization *_dbus_authorization_new (void);
> void _dbus_authorization_set_connection (DBusAuthorization *self,
>     DBusConnection *connection);
> DBusAuthorization * _dbus_authorization_ref (DBusAuthorization *self);
> void _dbus_authorization_unref (DBusAuthorization *self);
> void _dbus_authorization_set_unix_authorization_callback (DBusAuthorization *self,
>     DBusAllowUnixUserFunction function, void *data,
>     DBusFreeFunction free_data_function, void **old_data,
>     DBusFreeFunction *old_free_data_function);
> void _dbus_authorization_set_windows_authorization_callback (DBusAuthorization *self,
>     DBusAllowWindowsUserFunction function, void *data,
>     DBusFreeFunction free_data_function, void **old_data,
>     DBusFreeFunction *old_free_data_function);
> dbus_bool_t _dbus_authorization_do_authorization (DBusAuthorization *self, DBusCredentials *creds);
> void _dbus_authorization_set_allow_anonymous (DBusAuthorization *self,
> dbus_bool_t value);

Normal libdbus coding style involves tedious lining-up-arguments, as seen in GNU and GNOME projects. If you don't want to do that, I'll overlook it :-P

> /* Authorization functions, used as callback by SASL (implemented by
>    * DBUsAuth) */

DBusAuth

Does DBusAuthorization need to be refcounted? Does anything ever hold more than one ref?

>  * The callback will be called at the end of the EXTERNAL authentication
>  * mechanism and on every message.

"This is called after authentication, to check whether the authenticated user is authorized"?

You get 10 penguin points for using the word "predicate" correctly. :-)

>   allow = (*self->unix_authorization_cb) (self->connection,
>                                   uid,
>                                   self->unix_data);

I'd prefer "... = (self->unix_authorization_cb) (...)" or even "... = self->unix_authorization_cb (...)".

Coding style: line up the arguments below the first argument. (Yeah yeah I know.)

Pre-existing bug, but since we're unlocking and re-locking around a call out to user code, I'd feel safer if you called _dbus_connection_ref_unlocked before the unlock, and _dbus_connection_unref_unlocked before returning.

The same comments apply to the Windows version.

>   self->allow_anonymous = value != FALSE;

I'd prefer "... = (value != FALSE);".
Comment 26 Simon McVittie 2011-10-04 10:34:21 UTC
>        if (!_dbus_credentials_add_credential (auth->authorized_identity,

Pre-existing: I can't help thinking this should be called "authenticated_identity" or "authorization_identity" (it's being used in an authorization decision, by definition it hasn't been authenticated yet!).
Comment 27 Simon McVittie 2011-10-04 10:41:14 UTC
> +          _dbus_verbose ("%s: desired identity does not match server identity: "
> +              "not authorized\n", DBUS_AUTH_NAME (auth));
> +          return send_rejected (auth);

Misleading debug message: the reason it's authenticated might not be that it doesn't match, it might be that the user-supplied callback arbitrarily decided it doesn't like you any more :-)

This would be the place to send a more informative "REJECTED_BECAUSE" if previously negotiated.

I'd like to see a regression test (perhaps in, or based on, test/loopback.c) that uses user-supplied Unix and Windows uid-filtering functions, rejects everyone in those functions, sets a flag to say they've been called, and asserts that one or the other was called.
Comment 28 Simon McVittie 2011-10-04 11:26:22 UTC
(In reply to comment #24)
> But you could imagine more sophisticated setups where you exchange certificates
> in some authentication method - for example, imagine an authentication method
> where the client peer presents a certificate signed by someone the system has
> decided to trust (using some form of CA and PKI).

A certificate doesn't usually authenticate that you are uid 501, it usually authenticates that you are "CN=David Zeuthen,O=Red Hat Inc." or something. In SASL-land, you can go in one of two directions from here:

* "CN=David Zeuthen,O=Red Hat Inc." (authentication identity =
  authorization identity) is authorized to connect to this session bus

* "CN=David Zeuthen,O=Red Hat Inc." (authentication identity) is authorized
  to act as uid 501 (authorization identity), and hence to connect to this
  session bus

(Or substitute "the holder of the certificate with SHA-1 = blahblahblah" as the authentication identity if you don't trust PKI.)

I believe the client is meant to state up-front who it's trying to act as (authorization identity), rather than having the server guess - except that if no authorization identity is provided, it's implicitly equal to the authentication identity.

The D-Bus Specification isn't an RFC-compliant use of SASL at the moment, because it doesn't define "the syntax and semantics of non-empty authorization identity strings". By inspection of how we implement EXTERNAL, on Unix our authorization identity string is an ASCII numeric uid, and on Windows it's a Windows SID (the hex-encoding looks as though it's meant to be considered to be part of our SASL implementation, rather than part of the authz identity).

We also don't define "how authentication identities (which are mechanism specific) and authorization identities (which are protocol specific) relate to each other", which is a SHOULD. We'd need to do this per SASL mechanism.

Our EXTERNAL implementation currently hard-codes that if you ask for an authorization identity, it must equal your authentication identity, which doesn't seem right somehow; if we want to allow root to connect to users' session buses, 

> In fact, thinking more about it, I think it's entirely unreasonable to
> disconnect the client just because the authorization engine decides, based on
> the data from the _first_ used authentication method, that the client is not
> authorized to connect.

You've convinced me that you and Cosimo are right that using REJECTED is a better way (and REJECTED_BECAUSE would be better still).

Authz failures followed by a success seem pretty unlikely, though? This is a series of authentication failures in pseudo-SASL:

    S: Welcome to Red Hat secret labs. ID please
    C: LIBRARY_CARD David
    S: No, I said ID!
    C: DRIVING_LICENSE David
    S: No, that's expired.
    C: PASSPORT David
    S: Come in.

and this is a series of authorization failures:

    S: Welcome to Red Hat secret labs. ID please
    C: PASSPORT Simon
    S: No, Simon doesn't work here.
    C: PASSPORT Cosimo
    S: No, Cosimo doesn't work here.
    C: PASSPORT David
    S: Come in.
Comment 29 Simon McVittie 2011-10-04 11:33:33 UTC
> Our EXTERNAL implementation currently hard-codes that if you ask for an
> authorization identity, it must equal your authentication identity, which
> doesn't seem right somehow; if we want to allow root to connect to users'
> session buses,

... then it might make more sense to say "if you are authenticated as root, you are authorized to impersonate any user of your choice" (so in the authentication stage you say "I want to impersonate smcv", and the authorization callback decides - based on your credentials - whether to let you get away with it).

Amusingly, DBusTransport's default authz implementation (which Cosimo moved to DBusAuthorization) lets root connect to any DBusServer, but dbus-daemon overrides the unix_user_function, even for the session bus, to not allow that.
Comment 30 Cosimo Alfarano 2011-10-05 08:05:34 UTC
(In reply to comment #25)
> Copy the copyright information from dbus-transport.[ch] into
> dbus-authorization.[ch] and update it as appropriate. If you want to fish
> through git history for any copyright holders who didn't add themselves at the
> time, or extra copyright years (I'm pretty sure Red Hat employees have written
> copyrightable things in those files since 2003!), that'd be good too.

done
 
> Include dbus-internals.h in dbus-authorization.h (even if unneeded) to signal
> that this is an internal header.

done

> > +  DBusAuthorization *authorization;                    /**< Authorization conversation */
> 
> It's not a conversation. "Authorization policy"?

makes sense.


> Perhaps call it DBusAuthorizer?

yeah.

I was also tempted to rename DBusAuth in DBusAuthentication, but then I thought that it has bits of authorization inside and after the refactoring, even more.

Auth anyway is confusing, unless we mean auth*, which might be.

> > -void
> > +inline void
> 
> extern inline is non-portable (the old gcc extension and the ISO meaning are
> not the same) and highly confusing. Functions should either be static inline
> (equivalent to a macro, but type-safe) or not marked as inline at all.
> 
> The callers of these functions are in a different translation unit (.c file) so
> they can't be inlined anyway, unless link-time optimization is performed. Just
> make them normal (extern) functions - they're not on a fast-path or anything.

ok.

> In _dbus_transport_set_unix_user_function, if transport->is_server is false,
> you'll need to free the data immediately, otherwise it'll be leaked. Same for
> Windows.

true, thanks.

> I'd be inclined to change the signature of _dbus_authorization_do_authorization
> to look like this:
> 
>     dbus_bool_t _dbus_authorization_do_authorization (DBusAuthorization *,
>                                                       DBusConnection    *,
>                                                       DBusCredentials   *);
> 
> and remove _dbus_authorization_set_connection - this would fix the
> "authorization has a borrowed ref to the connection" problem, by only giving
> the connection to the authorizer for just long enough to make the authorization
> decision, during which time the caller is meant to hold a ref. This would also
> remove your "maybe-FIXME".

ok, I didn't want to change more than what needed, but it will simplify a lot.

> > DBusAuthorization *_dbus_authorization_new (void);
> > void _dbus_authorization_set_connection (DBusAuthorization *self,
> >     DBusConnection *connection);
> > DBusAuthorization * _dbus_authorization_ref (DBusAuthorization *self);
> > void _dbus_authorization_unref (DBusAuthorization *self);
> > void _dbus_authorization_set_unix_authorization_callback (DBusAuthorization *self,
> >     DBusAllowUnixUserFunction function, void *data,
> >     DBusFreeFunction free_data_function, void **old_data,
> >     DBusFreeFunction *old_free_data_function);
> > void _dbus_authorization_set_windows_authorization_callback (DBusAuthorization *self,
> >     DBusAllowWindowsUserFunction function, void *data,
> >     DBusFreeFunction free_data_function, void **old_data,
> >     DBusFreeFunction *old_free_data_function);
> > dbus_bool_t _dbus_authorization_do_authorization (DBusAuthorization *self, DBusCredentials *creds);
> > void _dbus_authorization_set_allow_anonymous (DBusAuthorization *self,
> > dbus_bool_t value);
> 
> Normal libdbus coding style involves tedious lining-up-arguments, as seen in
> GNU and GNOME projects. If you don't want to do that, I'll overlook it :-P
> 
> > /* Authorization functions, used as callback by SASL (implemented by
> >    * DBUsAuth) */
> 
> DBusAuth
> 
> Does DBusAuthorization need to be refcounted? Does anything ever hold more than
> one ref?

Nope, I'm refcounting it since the same was done for DBusAuth, which is used only in DBusTransport with one refrence (and then tested in dbus-auth-script.c but actually never really used).

I can remove it for simplicity, leave it or remove it from both (which I was tempted to, when I noticed it).

> >  * The callback will be called at the end of the EXTERNAL authentication
> >  * mechanism and on every message.
> 
> "This is called after authentication, to check whether the authenticated user
> is authorized"?

Yes, I was going to add a mention to the fact that the check is done for every message too, but it actually seems not true.

Which turns useless calling _dbus_authorization_do_authorization() in the transport, since either
* it already passed authorization in EXTERNAL (making it useless) or 
* it will never reach that part of code, being REJECTED

once the transport->authenticated is TRUE, it will always return immediately, ie, without authorizing anymore.

Going to cut a bit of more code there.

I fixed also dbus_connection_set_windows_user_function() doc, which still mentioned a disconnection on fail.


> You get 10 penguin points for using the word "predicate" correctly. :-)


Not me unfortunately, it was a comment move from transport's documentation :)

> >   allow = (*self->unix_authorization_cb) (self->connection,
> >                                   uid,
> >                                   self->unix_data);
> 
> I'd prefer "... = (self->unix_authorization_cb) (...)" or even "... =
> self->unix_authorization_cb (...)".

Me too, but in other places (DBusAuth and DBusConnection at least) it's used that way, I kept it consistent. No problem to change it if you insist ;)

> Coding style: line up the arguments below the first argument. (Yeah yeah I
> know.)
> 
> Pre-existing bug, but since we're unlocking and re-locking around a call out to
> user code, I'd feel safer if you called _dbus_connection_ref_unlocked before
> the unlock, and _dbus_connection_unref_unlocked before returning.

Done. not it's around the cb call, to be sure.

transport_get_is_authenticated did already that but DBusAuth didn't and anyway the transport won't authorize directly anymore (which probably means that we can remove the connection ref/unref there? by the comment it seemed to be there just because of user callbacks)
 
> >   self->allow_anonymous = value != FALSE;
> I'd prefer "... = (value != FALSE);".

Just a copied code, but yeah.
Comment 31 Cosimo Alfarano 2011-10-05 08:37:00 UTC
(In reply to comment #26)
> >        if (!_dbus_credentials_add_credential (auth->authorized_identity,
> 
> Pre-existing: I can't help thinking this should be called
> "authenticated_identity" or "authorization_identity" (it's being used in an
> authorization decision, by definition it hasn't been authenticated yet!).

I had the impression that there was a distinction between authorization at connect time and policy as two different stages.

Actually the real authentication part (checking the user is actually who is asserting to be) is not done in DBusAuth, It's pretty much all authorization and verify that the conversation makes sense.

The real Authentication part is done in dbus/dbus-sysdeps-unix.c (for unix) 
_dbus_read_credentials_socket() for instance, since the syscall on the socket will return a trustworthy value, and this method is called before the DBusAuth machine is fired.
For windows it seems all a bit fake, so no real trustworthy SID is obtained in dbys-sysdeps.win.c, but DBusAuth does not care. I might not understand it, though.

Under this assumption, DBusAuth and DBusAuhtorization (or Authorizer) might be merged together only as Authorizer, we remove a struct and clearify that it's actually an authorization process, while the authentication is preventively done . This to call things with their own name.

Otherwise I might try to check if more refactoring is possible bringing the authentication part in DBusAuth, but it really seems useless to mess up with it.

Does it all make sense? I'm a bit foggy today ;)
Comment 32 Simon McVittie 2011-10-05 09:30:32 UTC
(In reply to comment #30)
> Which turns useless calling _dbus_authorization_do_authorization() in the
> transport, since either
> * it already passed authorization in EXTERNAL (making it useless) or 
> * it will never reach that part of code, being REJECTED

Careful. Remember, there's more than one way to authenticate as a given uid - EXTERNAL and DBUS_COOKIE_SHA1, at least. You need to make sure that authorization is done at least once for whatever authentication mechanism is used.

(I agree it'd be better to authorize exactly once if we can, though.)

> I had the impression that there was a distinction between authorization at
> connect time and policy as two different stages.

Policy is a general term, in my mind: bus/policy.c implements both the "is this Unix/Windows user OK?" callbacks (policy for who can connect at all), and policy for individual messages/bus-name-owning transactions.

> Actually the real authentication part (checking the user is actually who is
> asserting to be) is not done in DBusAuth, It's pretty much all authorization
> and verify that the conversation makes sense.

This might be true for EXTERNAL, but DBUS_COOKIE_SHA1 does the authentication at a later stage, I think?

> The real Authentication part is done in dbus/dbus-sysdeps-unix.c (for unix) 
> _dbus_read_credentials_socket() for instance, since the syscall on the socket
> will return a trustworthy value, and this method is called before the DBusAuth
> machine is fired.

Yes, EXTERNAL authentication is a special case - think of it as saying "you already know who I am".

> For windows it seems all a bit fake, so no real trustworthy SID is obtained in
> dbys-sysdeps.win.c, but DBusAuth does not care. I might not understand it,
> though.

I think Windows people mostly use the nonce-tcp: transport instead of tcp:. I'm not entirely clear on what it does - perhaps it adds a redundant authentication layer and uses that to establish trust for EXTERNAL?

(Cc Ralf: how is nonce-tcp formed? Is it better than doing DBUS_COOKIE_SHA1 authentication - which is essentially proof of shared home directory ownership - over a tcp: transport?)
Comment 33 Cosimo Alfarano 2011-10-05 10:28:53 UTC
(In reply to comment #32)
> (In reply to comment #30)
> > Which turns useless calling _dbus_authorization_do_authorization() in the
> > transport, since either
> > * it already passed authorization in EXTERNAL (making it useless) or 
> > * it will never reach that part of code, being REJECTED
> 
> Careful. Remember, there's more than one way to authenticate as a given uid -
> EXTERNAL and DBUS_COOKIE_SHA1, at least. You need to make sure that
> authorization is done at least once for whatever authentication mechanism is
> used.

Yes, but this was needed anyway if we need to REJECT on not authorized credentials when SHA1 is chosen. Otherwise on SHA1, connection will be cut as before, which I suppose it's not what want anyway.

Yes, each mech is now responsible to use DBusAuthorization (unless it can be called in a common place after specific mech code is executed, I'll check).

> > Actually the real authentication part (checking the user is actually who is
> > asserting to be) is not done in DBusAuth, It's pretty much all authorization
> > and verify that the conversation makes sense.
> 
> This might be true for EXTERNAL, but DBUS_COOKIE_SHA1 does the authentication
> at a later stage, I think?

Yes, EXTERNAL authentication is "contextual", while SHA1 is a proper alice-bob conversation.

The point is that DBusAuth is mixed Authentication and Authorization, depending on the mech, so (renaming proposal a part) why not merging the two structs anyway?

Unless the new DBusAuthorization is actually meant to be the "user's authorization policy", from this POV, it can be either way.
SASL authorization anyway delegates the user('s library) to authorize the identity.


>> I'd be inclined to change the signature of >>_dbus_authorization_do_authorization
>> to look like this:
>> 
>>     dbus_bool_t _dbus_authorization_do_authorization (DBusAuthorization *,
>>                                                       DBusConnection    *,
>>                                                       DBusCredentials   *);
>> 
>> and remove _dbus_authorization_set_connection - this would fix the
>> "authorization has a borrowed ref to the connection" problem, by only giving
>> the connection to the authorizer for just long enough to make the authorization
>> decision, during which time the caller is meant to hold a ref. This would also
>> remove your "maybe-FIXME".
>ok, I didn't want to change more than what needed, but it will simplify a lot

This actually moves the ref problem for the connection into DBusAuth, which has no connection reference and would need one now.
Comment 34 Cosimo Alfarano 2011-10-11 09:03:36 UTC
Created attachment 52219 [details] [review]
Factor out DBusAuthorization from DBusTransport

Fixed Simon suggestions with the exception of connection references.

connection is needed by user functions to be called, hence either DBusAuthorization or DBusAuth need to have DBusConnetion as struct member.

Since the user callback is called from the mech, a connection needs to be at reach (in this case by _do_authorization())
Comment 35 Cosimo Alfarano 2011-10-11 09:04:28 UTC
Created attachment 52220 [details] [review]
Use DBusAuthorization

Same here, Simon review's suggestion applied
Comment 36 Cosimo Alfarano 2011-10-11 09:08:45 UTC
Created attachment 52221 [details] [review]
rename authorized_identity

Applying Simon's suggestion of renaming authorized_identity into authenticated_identity.

Here the authorization is done only as last step, right before the lifetime for the member being over (after authorization, it doesn't matter who we are for DBusAuth, either we are in or we are out)
Comment 37 Cosimo Alfarano 2011-10-11 09:11:29 UTC
Created attachment 52222 [details] [review]
Allow ANONONYMOUS in tests

This fixes testes to allow ANONYMOUS to go through authorization, which wasn't done by the mech before.

Now mechs are responsible for authorizing the identity, which means that anonymous connection needs to be explicitly enabled in order to default_rules to authorized ANONYMOUSly
Comment 38 Cosimo Alfarano 2011-10-11 09:14:21 UTC
Created attachment 52223 [details] [review]
Do not authorize twice

Not that the authorization is within SASL mechs, there is no need to reauthorized in the transport
Comment 39 Cosimo Alfarano 2011-10-11 09:18:30 UTC
Created attachment 52224 [details] [review]
no refcounting for DBusAuth and DBusAuthorization

Refcounting for DBusAuth and DBusAuthorization are useless.

The lifecycle for those two struct is the same of DBusTransport and private to it, there is no possibility of external reference.

From this point of view, referencing the connection within DBusAuthorization is useless (beside being tricky unreferencing it due to connection/transport coupling).

We just keep referencing and lockiong the connection when user's callback are called.
Comment 40 Cosimo Alfarano 2011-10-11 09:19:38 UTC
Created attachment 52225 [details] [review]
free window's callback as well

on connection finalization we don't know what the user set, it's safer to unset both unix and windows CB here
Comment 41 Cosimo Alfarano 2011-10-11 09:21:26 UTC
I forgot to mention that now all the three SASL mechs devined in DBusAuth now do authorization, this is why tests needs to take care of the allow_anonymous bit now and that I removed completely the authorization part within the transport
Comment 42 Cosimo Alfarano 2011-10-18 04:17:33 UTC
Created attachment 52469 [details] [review]
fix connection_set_allow_anonymous doc

Mechs steps have been changed, it's worth to mention that set_allow_anonymous does not grant anymore the OK.

Now that the authorization step can REJECT, if the server sets any user_function there are good chances that the authorization will fail.
This at least because the user_functions cannot check whether the allow_anon bit is set.

So unless the default function (default_rules) or weak user_function is used, it won't be enough.

NOTE: This might break API compatibility or specs, any comment?

dbus_connection_allows_anonymous() can be introduced if needed.
Comment 43 Simon McVittie 2012-02-24 03:44:08 UTC
Comment on attachment 52219 [details] [review]
Factor out DBusAuthorization from DBusTransport

Review of attachment 52219 [details] [review]:
-----------------------------------------------------------------

Looks OK so far
Comment 44 Simon McVittie 2012-02-24 03:48:45 UTC
Comment on attachment 52220 [details] [review]
Use DBusAuthorization

Review of attachment 52220 [details] [review]:
-----------------------------------------------------------------

Still looking good so far.

::: dbus/dbus-auth.c
@@ +1139,5 @@
> +        }
> +      else
> +        {
> +          _dbus_verbose ("%s: desired identity does not match server identity: "
> +                         "not authorized\n", DBUS_AUTH_NAME (auth));

This should say something like "authenticated identity was not authorized by server", I think?
Comment 45 Simon McVittie 2012-02-24 03:54:18 UTC
Comment on attachment 52220 [details] [review]
Use DBusAuthorization

Review of attachment 52220 [details] [review]:
-----------------------------------------------------------------

(In reply to comment #44)
> Still looking good so far.

Actually, not quite...

::: dbus/dbus-auth.c
@@ +1139,5 @@
> +        }
> +      else
> +        {
> +          _dbus_verbose ("%s: desired identity does not match server identity: "
> +                         "not authorized\n", DBUS_AUTH_NAME (auth));

This should say something like "authenticated identity was not authorized by server", I think?

@@ +1247,5 @@
> + 
> +  /* Do a authorization of the transport, in order to REJECT immediately the
> +   * connection if needed (FDO#39720) */
> +  if (!_dbus_authorization_do_authorization (DBUS_AUTH_SERVER (auth)->authorization,
> +                                             auth->authenticated_identity))

This is a behaviour change, because _dbus_authorization_do_authorization() doesn't normally allow anonymous users.

I think the correct logic would be something like this in _dbus_authorization_do_authorization():

if (_dbus_credentials_are_anonymous (auth_identity))
  allow = self->allow_anonymous;
else if (self->unix_authorization_cb ...)
  allow = ...;
else if (self->windows_authorization_cb ...)
  allow = ...;
else
  allow = auth_via_default_rules (...);
Comment 46 Simon McVittie 2012-02-24 03:55:19 UTC
Comment on attachment 52221 [details] [review]
rename authorized_identity

Review of attachment 52221 [details] [review]:
-----------------------------------------------------------------

Sure
Comment 47 Simon McVittie 2012-02-24 03:56:16 UTC
Comment on attachment 52222 [details] [review]
Allow ANONONYMOUS in tests

Review of attachment 52222 [details] [review]:
-----------------------------------------------------------------

Yeah, fine
Comment 48 Simon McVittie 2012-02-24 04:01:54 UTC
Comment on attachment 52223 [details] [review]
Do not authorize twice

Review of attachment 52223 [details] [review]:
-----------------------------------------------------------------

This is the one we need to be most careful with, because it's removing restrictions. :-)

It does look correct, though, except:

::: dbus/dbus-transport.c
@@ -570,5 @@
>        if (transport->disconnected)
>          return FALSE;
>  
> -      /* paranoia ref since we call user callbacks sometimes */
> -      _dbus_connection_ref_unlocked (transport->connection);

You've removed the matching unref at the end, but not removed some matching unrefs in error paths (I can see at least the "Client expected GUID '%s' and we got '%s' from the server\n" case).
Comment 49 Simon McVittie 2012-02-24 04:07:07 UTC
Comment on attachment 52224 [details] [review]
no refcounting for DBusAuth and DBusAuthorization

Review of attachment 52224 [details] [review]:
-----------------------------------------------------------------

OK
Comment 50 Simon McVittie 2012-02-24 04:07:41 UTC
Comment on attachment 52225 [details] [review]
free window's callback as well

Review of attachment 52225 [details] [review]:
-----------------------------------------------------------------

Looks good
Comment 51 Simon McVittie 2012-02-24 04:10:26 UTC
(In reply to comment #42)
> Mechs steps have been changed, it's worth to mention that set_allow_anonymous
> does not grant anymore the OK.

I don't think this is acceptable; but if you do what I suggested in Comment #45, you won't need to change the docs, because the behaviour hasn't changed.
Comment 52 Simon McVittie 2012-02-24 04:18:49 UTC
I think this needs some integration tests, either automatic or manual: in particular, we should check that behaviour hasn't changed, except in the one case where we wanted it to (making authenticated-but-not-authorized connections change from OK-then-disconnect to REJECT).
Comment 53 Simon McVittie 2012-02-27 04:35:30 UTC
(In reply to comment #45)
> This is a behaviour change, because _dbus_authorization_do_authorization()
> doesn't normally allow anonymous users.

This is not, in fact, true. If the auth identity is anonymous, then it contains neither a Unix uid nor a Windows sid, so _dbus_authorization_do_authorization() falls through to auth_via_default_rules(), which respects allow_anonymous.

The thing that's weird, noted in Attachment #52469 [details], is not new: if a unix_user_function or a windows_user_function has been set, then it can reject certain uids or sids, even if anonymous authentication would have been allowed! So I think Attachment #52469 [details] is also fine.

I wrote a manual test for authentication/authorization, and everything seemed OK after applying Cosimo's patches. I'll attach that test, and its results, here.

So the only things needing fixing are:

(In reply to comment #44)
> > +          _dbus_verbose ("%s: desired identity does not match server identity: "
> > +                         "not authorized\n", DBUS_AUTH_NAME (auth));
> 
> This should say something like "authenticated identity was not authorized by
> server", I think?

Trivial, not very important

(In reply to comment #48)
> ::: dbus/dbus-transport.c
> @@ -570,5 @@
> >        if (transport->disconnected)
> >          return FALSE;
> >  
> > -      /* paranoia ref since we call user callbacks sometimes */
> > -      _dbus_connection_ref_unlocked (transport->connection);
> 
> You've removed the matching unref at the end, but not removed some matching
> unrefs in error paths (I can see at least the "Client expected GUID '%s'
> and we got '%s' from the server\n" case).

This is a potential use-after-free and needs fixing
Comment 54 Simon McVittie 2012-02-27 05:08:47 UTC
Here are some test results.

I ran servers under my own uid, and connected to them with both Unix and TCP
sockets from my own and another uid. I used GDBus, which tries another
authentication mechanism if the first one is REJECTed.

Key to servers:
- normal: default policy
- anon-allowed: allow_anonymous(TRUE)
- anon-only: allow_anonymous(TRUE), Unix/Windows user functions reject all
- anon mech only: ANONYMOUS is the only allowed mechanism,
                  allow_anonymous(TRUE)
- anon disallowed: ANONYMOUS is the only allowed mechanism but the
                   anonymous user is not authorized
- permissive: Unix/Windows user functions allow all
- unhappy: Unix/Windows user functions reject all
- same-uid: Unix user function only allows the dbus-daemon uid
- same-uid or anon: allow_anonymous(TRUE), same Unix user function as same-uid

Key to results:
- me: authenticated and authorized as the same user as the server
- other: authenticated and authorized as the other user
- anon: authenticated and authorized as ANONYMOUS
- closed: not authenticated, or authenticated but not authorized;
          failure is reported as "OK" followed by the connection being
          closed ("Error: The connection is closed" in GDBus)
- rejected: all auth attempts were REJECTed and the client gave up
            ("Error connecting: Exhausted all available authentication
            mechanisms" in GDBus)

With current master:

                   me, Unix    other, Unix     me, TCP    other, TCP
normal               me           closed         me         closed
anon-allowed         me           other[1]       me          anon[2]
anon-only          closed[3]      closed[3]    closed[3]     anon[2]
anon mech only      anon           anon         anon         anon
anon disallowed    closed         closed       closed       closed
permissive           me           other          me         closed[4]
unhappy            closed         closed       closed       closed
same-uid             me           closed         me         closed
same-uid or anon     me           closed[3]      me          anon[2]

[1] This only works because allow_anonymous(TRUE) changes the default
    policy to allow all uids too

[2] EXTERNAL cannot be used over TCP; DBUS_COOKIE_SHA1 is not
    authenticated because it can only prove that you are the same uid
    as the server, not that you are another uid; so ANONYMOUS is used

[3] This is a bit silly; the client could have authenticated as ANONYMOUS
    if it had known that specifying the user ID would fail

[4] The TCP client cannot authenticate except as the unauthorized anonymous
    user, for the same reason as [2]

With Cosimo's patches:

                   me, Unix    other, Unix     me, TCP    other, TCP
normal               me          rejected        me        rejected
anon-allowed         me           other[1]       me          anon[2]
anon-only           anon[5]        anon[5]     anon[5]       anon[2]
anon mech only      anon           anon         anon         anon
anon disallowed   rejected       rejected     rejected     rejected
permissive           me           other          me        rejected[4]
unhappy           rejected       rejected     rejected     rejected
same-uid             me          rejected        me        rejected
same-uid or anon     me            anon[5]       me          anon[2]

[5] non-anonymous connection is not authorized and is rejected, so the
    client falls back to ANONYMOUS and succeeds

All cases without footnote [5] are the same as before, except that
closed becomes rejected, as requested in Comment #0. So I think the branch
is good, if it gets the fixes from Comment #53.
Comment 55 Simon McVittie 2012-02-27 05:09:55 UTC
Created attachment 57713 [details] [review]
Add a simple manual test for authentication/authorization

Here's the manual test-case I added, please review.
Comment 56 Simon McVittie 2012-03-12 06:15:42 UTC
(In reply to comment #53)
> So the only things needing fixing are:

I've picked these up myself. Code review required.

> > This should say something like "authenticated identity was not authorized by
> > server", I think?

Done

> (In reply to comment #48)
> > You've removed the matching unref at the end, but not removed some matching
> > unrefs in error paths (I can see at least the "Client expected GUID '%s'
> > and we got '%s' from the server\n" case).
> 
> This is a potential use-after-free and needs fixing

Done, and added a test which crashes without the fix/passes with it.
Comment 57 Simon McVittie 2012-03-12 06:16:11 UTC
Created attachment 58314 [details] [review]
trivial: re-word authorization failure message
Comment 58 Simon McVittie 2012-03-12 06:16:56 UTC
Created attachment 58315 [details] [review]
_dbus_transport_get_is_authenticated: avoid unnecessary  unref

The commit "Remove transport's call to
_dbus_authorization_do_authorization()" removed a ref/unref pair
in the normal code path, but did not remove the corresponding unref
from an error case.

---

This could be squashed into Attachment #52223 [details].
Comment 59 Simon McVittie 2012-03-12 06:17:28 UTC
Created attachment 58316 [details] [review]
Add a test-case for trying to connect with the wrong  GUID

---

This catches the bug fixed by Attachment #58315 [details].
Comment 60 Cosimo Alfarano 2012-03-12 08:29:02 UTC
Comment on attachment 51967 [details] [review]
Fix confusion between "is it authenticated?" and "try to  authenticate"

Review of attachment 51967 [details] [review]:
-----------------------------------------------------------------

I like it and it makes sense. I don't understand the reason for "despite its name" note, now that it's called "try_to_authenticate": isn't it clear that there's an action involved after the renaming?
Comment 61 Simon McVittie 2012-03-28 04:15:54 UTC
(In reply to comment #60)
> I don't understand the reason for "despite its
> name" note, now that it's called "try_to_authenticate": isn't it clear that
> there's an action involved after the renaming?

I meant that as "despite its name, dbus_connection_get_is_authenticated() has side-effects" (and the same for get_unix_user(), get_unix_process_id(), get_adt_audit_session_data(), get_windows_user()).

You're right, it'd be clearer if I replaced "this function" with the actual function name (or at least its unique tail) in each case.

Any opinions (from anyone...) on my four other patches here, which follow/fix your branch?
Comment 62 Simon McVittie 2012-06-05 03:57:17 UTC
(In reply to comment #61)
> Any opinions (from anyone...) on my four other patches here, which follow/fix
> your branch?

This is not going to be in 1.6.0, I've given up on waiting for feedback.
Comment 63 Simon McVittie 2013-08-22 17:12:01 UTC
(In reply to comment #61)
> Any opinions (from anyone...) on my four other patches here, which
> follow/fix your branch?
Comment 64 Ralf Habacker 2013-08-22 19:53:22 UTC
Comment on attachment 58314 [details] [review]
trivial: re-word authorization failure message

Review of attachment 58314 [details] [review]:
-----------------------------------------------------------------

looks good
Comment 65 Ralf Habacker 2013-08-22 21:49:07 UTC
Comment on attachment 52219 [details] [review]
Factor out DBusAuthorization from DBusTransport

Review of attachment 52219 [details] [review]:
-----------------------------------------------------------------

do not apply to git master, conflicts in dbus/Makefile.am and dbus/dbus-transport.c
Comment 66 Ralf Habacker 2013-08-22 21:52:11 UTC
Comment on attachment 52221 [details] [review]
rename authorized_identity

Review of attachment 52221 [details] [review]:
-----------------------------------------------------------------

error: patch failed: dbus/dbus-auth.c:1132
error: dbus/dbus-auth.c: patch does not apply
Comment 67 Ralf Habacker 2013-08-22 21:54:44 UTC
Comment on attachment 52223 [details] [review]
Do not authorize twice

Review of attachment 52223 [details] [review]:
-----------------------------------------------------------------

error: patch failed: dbus/dbus-auth.c:1132
error: dbus/dbus-auth.c: patch does not apply
Comment 68 Ralf Habacker 2013-08-22 21:56:20 UTC
Comment on attachment 52224 [details] [review]
no refcounting for DBusAuth and DBusAuthorization

Review of attachment 52224 [details] [review]:
-----------------------------------------------------------------

error: patch failed: dbus/dbus-auth.c:2358
error: dbus/dbus-auth.c: patch does not apply
error: patch failed: dbus/dbus-authorization.c:29
error: dbus/dbus-authorization.c: patch does not apply
error: patch failed: dbus/dbus-authorization.h:33
error: dbus/dbus-authorization.h: patch does not apply
Patch failed at 0001 Remove refcounting from DBusAuth and DBusAuthorization
Comment 69 Ralf Habacker 2013-08-22 21:58:14 UTC
Comment on attachment 57713 [details] [review]
Add a simple manual test for authentication/authorization

Review of attachment 57713 [details] [review]:
-----------------------------------------------------------------

error: patch failed: test/Makefile.am:95
error: test/Makefile.am: patch does not apply
Patch failed at 0001 Add a simple manual test for authentication/authorization
Comment 70 Ralf Habacker 2013-08-22 22:06:41 UTC
Remaining patches does not apply because of failed earlier patches. Need to be rebased to recent git master.

Also applying patches is very hard because file names do not match entries displayed attachement list and are number prefix are not ordered ascending, which makes git am 39720/*.patch impossible.
Comment 71 Ralf Habacker 2013-08-22 22:14:20 UTC
Comment on attachment 52225 [details] [review]
free window's callback as well

Review of attachment 52225 [details] [review]:
-----------------------------------------------------------------

may be applied independent of the other patches.
Comment 72 Ralf Habacker 2013-08-22 22:20:09 UTC
Comment on attachment 52225 [details] [review]
free window's callback as well

committed, as this has already been reviewed by simon.
Comment 73 Ralf Habacker 2013-08-22 22:32:16 UTC
Comment on attachment 51967 [details] [review]
Fix confusion between "is it authenticated?" and "try to  authenticate"

Review of attachment 51967 [details] [review]:
-----------------------------------------------------------------

The comments "Note that despite its name,..." should be removed.
Comment 74 Ralf Habacker 2013-08-22 22:48:35 UTC
Comment on attachment 51967 [details] [review]
Fix confusion between "is it authenticated?" and "try to  authenticate"

removed note and commited to master
Comment 75 Ralf Habacker 2013-08-22 23:23:51 UTC
Comment on attachment 52219 [details] [review]
Factor out DBusAuthorization from DBusTransport

rebased and applied to git master
Comment 76 Ralf Habacker 2013-08-22 23:33:34 UTC
Comment on attachment 52220 [details] [review]
Use DBusAuthorization

fixed review issue and commited to git master
Comment 77 Ralf Habacker 2013-08-22 23:44:23 UTC
Comment on attachment 52221 [details] [review]
rename authorized_identity

fixed patch and applied to master
Comment 78 Ralf Habacker 2013-08-22 23:49:55 UTC
Comment on attachment 52222 [details] [review]
Allow ANONONYMOUS in tests

applied to master
Comment 79 Ralf Habacker 2013-08-22 23:59:22 UTC
Created attachment 84480 [details] [review]
Remove transport-s-call-to-dbus-authorization (update)

rebased
Comment 80 Ralf Habacker 2013-08-23 00:14:54 UTC
Comment on attachment 52224 [details] [review]
no refcounting for DBusAuth and DBusAuthorization

rebased and applied to git master
Comment 81 Ralf Habacker 2013-08-23 00:17:26 UTC
Comment on attachment 52469 [details] [review]
fix connection_set_allow_anonymous doc

Review of attachment 52469 [details] [review]:
-----------------------------------------------------------------

looks good.
Comment 82 Ralf Habacker 2013-08-23 00:20:27 UTC
Comment on attachment 52469 [details] [review]
fix connection_set_allow_anonymous doc

applied to git master
Comment 83 Ralf Habacker 2013-08-23 00:38:57 UTC
Comment on attachment 57713 [details] [review]
Add a simple manual test for authentication/authorization

Review of attachment 57713 [details] [review]:
-----------------------------------------------------------------

rebased patch, which now compiles and runs on linux - looks good so far except the one check on which test test app print the following message and hangs. 

** Message: Same-UID-or-anon server:
tcp:host=127.0.0.1,port=56081,guid=5f604d1b5a41540ebd4000cf5216ae6f
Comment 84 Ralf Habacker 2013-08-23 00:52:58 UTC
Comment on attachment 58315 [details] [review]
_dbus_transport_get_is_authenticated: avoid unnecessary  unref

Review of attachment 58315 [details] [review]:
-----------------------------------------------------------------

I'm going to merge this into the related patch.
Comment 85 Ralf Habacker 2013-08-23 00:53:43 UTC
Created attachment 84481 [details] [review]
Remove transport-s-call-to-dbus-authorization (update2)
Comment 86 Ralf Habacker 2013-08-23 00:58:40 UTC
Comment on attachment 57713 [details] [review]
Add a simple manual test for authentication/authorization

rebased and applied
Comment 87 Ralf Habacker 2013-08-23 01:03:04 UTC
Comment on attachment 58314 [details] [review]
trivial: re-word authorization failure message

rebased and applied
Comment 88 Ralf Habacker 2013-08-23 01:11:21 UTC
Comment on attachment 58316 [details] [review]
Add a test-case for trying to connect with the wrong  GUID

looks good, applied to master
Comment 89 Ralf Habacker 2013-08-23 01:45:41 UTC
(In reply to comment #83)
> Comment on attachment 57713 [details] [review] [review]
> Add a simple manual test for authentication/authorization
> 
> Review of attachment 57713 [details] [review] [review]:
> -----------------------------------------------------------------
> 
> rebased patch, which now compiles and runs on linux - looks good so far
> except the one check on which test test app print the following message and
> hangs. 
> 
> ** Message: Same-UID-or-anon server:
> tcp:host=127.0.0.1,port=56081,guid=5f604d1b5a41540ebd4000cf5216ae6f

Got it: the test app only starts server, print out the server addresses to which a dbus client should connect to ?
Comment 90 Ralf Habacker 2013-08-23 07:03:31 UTC
Comment on attachment 84481 [details] [review]
Remove transport-s-call-to-dbus-authorization (update2)

applied
Comment 91 Ralf Habacker 2013-08-23 07:56:29 UTC
(In reply to comment #89)
> (In reply to comment #83)
> > Comment on attachment 57713 [details] [review] [review] [review]
> > Add a simple manual test for authentication/authorization
> > 
> > Review of attachment 57713 [details] [review] [review] [review]:
> > -----------------------------------------------------------------
> > 
> > rebased patch, which now compiles and runs on linux - looks good so far
> > except the one check on which test test app print the following message and
> > hangs. 
> > 
> > ** Message: Same-UID-or-anon server:
> > tcp:host=127.0.0.1,port=56081,guid=5f604d1b5a41540ebd4000cf5216ae6f
> 
> Got it: the test app only starts server, print out the server addresses to
> which a dbus client should connect to ?

I tried to connect to the "normal" server on linux with a different user and got

24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH EXTERNAL 31303030"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism EXTERNAL
24262: [dbus/dbus-auth.c(1638):process_data] server: data: '1000'
24262: [dbus/dbus-userdb.c(166):_dbus_user_database_lookup] No cache for UID 1002
24262: [dbus/dbus-userdb.c(166):_dbus_user_database_lookup] No cache for UID 1000
24262: [dbus/dbus-auth.c(1144):handle_server_data_external_mech] server: desired identity not found in socket credentials
24262: [dbus/dbus-auth.c(430):shutdown_mech] server: Shutting down mechanism EXTERNAL


24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH DBUS_COOKIE_SHA1 31303030"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism DBUS_COOKIE_SHA1
24262: [dbus/dbus-auth.c(1638):process_data] server: data: '1000'
24262: [dbus/dbus-userdb.c(156):_dbus_user_database_lookup] Using cache for UID 1000 information
24262: [dbus/dbus-userdb.c(156):_dbus_user_database_lookup] Using cache for UID 1000 information
Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid
24262: [dbus/dbus-keyring.c(805):_dbus_keyring_new_for_credentials] didn't load an existing keyring: No such file or directory
24262: [dbus/dbus-keyring.c(818):_dbus_keyring_new_for_credentials] Creating keyring directory: Failed to create directory /home/admin/.dbus-keyrings: Permission denied

24262: [dbus/dbus-auth.c(619):sha1_handle_first_client_response] server: Could not get a cookie ID to send to client: No such file or directory
24262: [dbus/dbus-auth.c(430):shutdown_mech] server: Shutting down mechanism DBUS_COOKIE_SHA1

24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH ANONYMOUS 6c69626462757320312e352e3132"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism ANONYMOUS
24262: [dbus/dbus-auth.c(1638):process_data] server: data: 'libdbus 1.5.12'
24262: [dbus/dbus-auth.c(1224):handle_server_data_anonymous_mech] server: ANONYMOUS client sent trace string: 'libdbus 1.5.12'
24262: [dbus/dbus-auth.c(2148):goto_state] server: going from state WaitingForAuth to state WaitingForBegin
24262: [dbus/dbus-auth.c(1242):handle_server_data_anonymous_mech] server: authenticated client as anonymous


According to comment #54, which is   

.. 
                   me, Unix    other, Unix     me, TCP    other, TCP
normal               me          rejected        me        rejected
... 

should this not be rejected  ?
Comment 92 Ralf Habacker 2013-08-23 08:18:16 UTC
(In reply to comment #89)
> (In reply to comment #83)
> > Comment on attachment 57713 [details] [review] [review] [review]
> > Add a simple manual test for authentication/authorization
> > 
> > Review of attachment 57713 [details] [review] [review] [review]:
> > -----------------------------------------------------------------
> > 
> > rebased patch, which now compiles and runs on linux - looks good so far
> > except the one check on which test test app print the following message and
> > hangs. 
> > 
> > ** Message: Same-UID-or-anon server:
> > tcp:host=127.0.0.1,port=56081,guid=5f604d1b5a41540ebd4000cf5216ae6f
> 
> Got it: the test app only starts server, print out the server addresses to
> which a dbus client should connect to ?

I tried to connect to the "normal" server on linux with a different user and got

24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH EXTERNAL 31303030"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism EXTERNAL
24262: [dbus/dbus-auth.c(1638):process_data] server: data: '1000'
24262: [dbus/dbus-userdb.c(166):_dbus_user_database_lookup] No cache for UID 1002
24262: [dbus/dbus-userdb.c(166):_dbus_user_database_lookup] No cache for UID 1000
24262: [dbus/dbus-auth.c(1144):handle_server_data_external_mech] server: desired identity not found in socket credentials
24262: [dbus/dbus-auth.c(430):shutdown_mech] server: Shutting down mechanism EXTERNAL


24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH DBUS_COOKIE_SHA1 31303030"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism DBUS_COOKIE_SHA1
24262: [dbus/dbus-auth.c(1638):process_data] server: data: '1000'
24262: [dbus/dbus-userdb.c(156):_dbus_user_database_lookup] Using cache for UID 1000 information
24262: [dbus/dbus-userdb.c(156):_dbus_user_database_lookup] Using cache for UID 1000 information
Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid
24262: [dbus/dbus-keyring.c(805):_dbus_keyring_new_for_credentials] didn't load an existing keyring: No such file or directory
24262: [dbus/dbus-keyring.c(818):_dbus_keyring_new_for_credentials] Creating keyring directory: Failed to create directory /home/admin/.dbus-keyrings: Permission denied

24262: [dbus/dbus-auth.c(619):sha1_handle_first_client_response] server: Could not get a cookie ID to send to client: No such file or directory
24262: [dbus/dbus-auth.c(430):shutdown_mech] server: Shutting down mechanism DBUS_COOKIE_SHA1

24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH ANONYMOUS 6c69626462757320312e352e3132"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism ANONYMOUS
24262: [dbus/dbus-auth.c(1638):process_data] server: data: 'libdbus 1.5.12'
24262: [dbus/dbus-auth.c(1224):handle_server_data_anonymous_mech] server: ANONYMOUS client sent trace string: 'libdbus 1.5.12'
24262: [dbus/dbus-auth.c(2148):goto_state] server: going from state WaitingForAuth to state WaitingForBegin
24262: [dbus/dbus-auth.c(1242):handle_server_data_anonymous_mech] server: authenticated client as anonymous


According to comment #54, which is   

.. 
                   me, Unix    other, Unix     me, TCP    other, TCP
normal               me          rejected        me        rejected
... 

should this not be rejected  ?

24262: [dbus/dbus-auth.c(2201):process_command] server: got command "AUTH ANONYMOUS 6c69626462757320312e352e3132"
24262: [dbus/dbus-auth.c(1718):handle_auth] server: Trying mechanism ANONYMOUS

The reason is that anonymous is in the all_mechanisms[] list, which is fetched in handle_auth.c.
Comment 93 Simon McVittie 2013-08-23 10:00:46 UTC
(In reply to comment #70)
> Remaining patches does not apply because of failed earlier patches. Need to
> be rebased to recent git master.

Sorry, I should have tried the rebase before pinging reviewers.

Something has gone wrong in the rebase process, so I'm afraid I'm probably going to back out the whole lot and try again later. I now get the same failure mode as you: "Normal server" (and all the others) accept ANONYMOUS connections from another uid.

A good way to test this is:

* run manual-authz (listens on TCP by default)
* as the same and a different user, run "gdbus call -a $addr -d org.freedesktop.DBus -o / -m org.freedesktop.DBus.Peer.Ping" where $addr is one of the many addresses that manual-authz prints
* re-run manual-authz as "manual-authz unix:tmpdir=/tmp" and repeat with the resulting Unix addresses

You don't need verbose mode for that: it's enough to observe that gdbus does or doesn't print error messages.
Comment 94 Simon McVittie 2013-08-23 10:07:39 UTC
> 24262: [dbus/dbus-auth.c(1242):handle_server_data_anonymous_mech] server:
> authenticated client as anonymous

That's not directly harmful; what *is* harmful is that, having decided that the peer is the anonymous pseudo-user, we don't fail the authorization step. See Comment #22 for the subtle distinction between authentication and authorization.
Comment 95 Simon McVittie 2013-08-23 10:24:25 UTC
I reverted this whole patch series, except for:

(In reply to comment #86)
> Add a simple manual test for authentication/authorization
> Add a test-case for trying to connect with the wrong  GUID
> Fix confusion between "is it authenticated?" and "try to  authenticate"
> free window's callback as well

We should make sure the manual test produces the expected results before landing this stuff. Sorry about that.
Comment 96 Ralf Habacker 2013-08-23 13:03:56 UTC
(In reply to comment #94)
> > 24262: [dbus/dbus-auth.c(1242):handle_server_data_anonymous_mech] server:
> > authenticated client as anonymous
> 
> That's not directly harmful; what *is* harmful is that, having decided that
> the peer is the anonymous pseudo-user, we don't fail the authorization step.
> See Comment #22 for the subtle distinction between authentication and
> authorization.

You are sure, that this patch set worked in 2013-03 as expected ? I did not see an reports from that time.
Comment 97 Simon McVittie 2013-08-23 13:18:30 UTC
(In reply to comment #96)
> You are sure, that this patch set worked in 2013-03 as expected ? I did not
> see an reports from that time.

What happened in 2013-03?

I'm pretty sure these worked in 2012-03 when I last tested them... yes, they've had a significant amount of time to diverge :-(
Comment 98 Ralf Habacker 2013-08-24 23:27:35 UTC
(In reply to comment #62)
> (In reply to comment #61)
> > Any opinions (from anyone...) on my four other patches here, which follow/fix
> > your branch?
> 
> This is not going to be in 1.6.0, I've given up on waiting for feedback.

Do you have any idea about the reasons, why these feature did not get in last year ? It looks like a useful security feature. 

I can imagine that the stuff may be to complex for contributors, which starts with a little problem and, while working, may be faced with more an more details and requirements, which may exceed peoples budget in time or knowledge,.especially for non daily hackers. 

I personally putted several attempts to extend/fix things on the windows side on hold, like a dbus installer for windows, dbus as windows service and others. It's a pitty that the donated time seems to be lost, which may result into motivation downgrades for further work and not implemented features. :-(

The question is if there are ways to optimize the current situation for example 
- to reduce the learning curve
- to makes dbus hackers donated budgets more effective ? 
- to provide a development roadmap/priorisation, so that people can concentrate on the most important things 
- to get more maintenance and development resources from companies or single peoples  
- to reduce dbus complexity and/or make development more transparent
Comment 99 Simon McVittie 2013-08-29 10:32:18 UTC
(In reply to comment #98)
> Do you have any idea about the reasons, why these feature did not get in
> last year ?

When I reviewed Cosimo's patches, I found problems (which Cosimo wasn't able to fix immediately). After a few weeks I fixed those problems myself, but there was nobody to review my changes...

> It looks like a useful security feature. 

It's security-related (which is why it's particularly important to get it right!) but more of a usability fix than a security fix. The current behaviour is secure, but unhelpful: it behaves as if authentication/authorization had succeeded, then immediately disconnects the connection (which, for a client, is indistinguishable from successful authn/authz followed by the dbus-daemon crashing). The idea of these patches is that in the same situation, authentication/authorization should actually report failure.
Comment 100 GitLab Migration User 2018-10-12 21:12:26 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/dbus/dbus/issues/53.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.