GNOME Bugzilla – Bug 668866
GDBus credentials don’t work on OS X
Last modified: 2018-05-24 13:43:51 UTC
gdbus seems to not work in OSX, using dbus-glib works without problems instead. I paste here the result of this gdbus call: G_DBUS_DEBUG=all gdbus call --session --dest org.freedesktop.DBus --object-path / --method org.freedesktop.DBus.Introspectable.Introspect 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:path=/var/tmp/dbus-2NueBBNucP,guid=03e803c1756cc9d241c903dd4f227e67' 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:path=/var/tmp/dbus-2NueBBNucP,guid=03e803c1756cc9d241c903dd4f227e67' for bus type `session' GDBus-debug:Auth: CLIENT: initiating GDBus-debug:Auth: CLIENT: didn't send any credentials 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: Mechanism `EXTERNAL' says it is not supported 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 353031\r\n' GDBus-debug:Auth: CLIENT: WaitingForData GDBus-debug:Auth: CLIENT: WaitingForData, read=`DATA 6f72675f667265656465736b746f705f67656e6572616c20363834383139313432206566643037396431646138613230653532306333333035343531346265396531' GDBus-debug:Auth: CLIENT: writing `DATA 44336b594a657476323930474a63436f2039396565653266643664646164333361306139386634393431313537623332303236663164656465\r\n' GDBus-debug:Auth: CLIENT: WaitingForOK GDBus-debug:Auth: CLIENT: WaitingForOK, read `OK 03e803c1756cc9d241c903dd4f227e67' 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 ------------------------------------------------------------------------ dbus-send works without problems, I used this command: dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.Introspectable.Introspect Also, seems that other users already report this: http://sourceforge.net/apps/phpbb/gtk-osx/viewtopic.php?f=3&t=74#p400
> GDBus-debug:Auth: CLIENT: didn't send any credentials Is most probably why this is happening [1]. Now, why do we print this? See http://git.gnome.org/browse/glib/tree/gio/gdbusauth.c?id=2.31.12#n612 So this can only happen if A. GLib is built without G_OS_UNIX defined in which case you've built GLib incorrectly; or B. auth->priv->stream is not a GUnixConnection which contradicts this debug statement > GDBus-debug:Address: env var DBUS_SESSION_BUS_ADDRESS=`unix:path=/var/tmp/dbus-2NueBBNucP,guid=03e803c1756cc9d241c903dd4f227e67' I would suggest adding a debug statement to print the name of the GType of auth->priv->stream. The bug report is light on information - please state what version of GLib you are using, what patches you use for GLib, how GLib is built (in particular if G_OS_UNIX is defined), the version of dbus being used (and what patches) and so on. [1] : yes, the error mode is confusing - Q: why does authentication succeed and then we're getting kicked off? A: because how dbus works ... see https://bugs.freedesktop.org/show_bug.cgi?id=39720
To build GLib I used the gtk-osx tools, as described here: https://live.gnome.org/GTK%2B/OSX/Building moduleset definition here: http://git.gnome.org/browse/gtk-osx/tree/modulesets-stable/gtk-osx.modules#n67 So no aditional patches are applied. I tried with both stable ans unstable version of dbus, ie, 1.4.16 and 1.5.8 G_OS_UNIX seems to be defined, also taking a look to GLibs configure.ac confirms this: http://git.gnome.org/browse/glib/tree/configure.ac#n3396
<davidz> oh, I get it <davidz> 2.28.8 has <davidz> if (G_IS_UNIX_CONNECTION (auth->priv->stream) && g_unix_credentials_message_is_supported ()) <davidz> while master has <davidz> if (G_IS_UNIX_CONNECTION (auth->priv->stream)) <davidz> so that's why <davidz> let me check git blame on why we removed that <davidz> (it was correct to remove) <davidz> it was done when credentials support for OpenBSD was added <davidz> jjardon: so that's why, basically <davidz> use git master and you should get a more descriptive error <davidz> (please do try that and let me know what the behavior is) <jjardon> davidz: cool, thanks! I keep the bug updated with my findings <davidz> the next step is then to add GCredentials support for OS X <davidz> shouldn't be that hard <davidz> https://bugzilla.gnome.org/show_bug.cgi?id=650885 should provide some guidance in that <davidz> respect <davidz> in particular the patch in comment 26
There is unlikely to be any progress on this unless a macOS user pushes it forward: the majority of GLib contributors don't have access to macOS. According to https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man4/unix.4.html there is a mechanism the same "shape" as Linux SO_PEERCRED, OpenBSD SO_PEERCRED, NetBSD LOCAL_PEEREID etc., namely LOCAL_PEERCRED. (Of course because this is credentials-passing, it has a pointlessly different constant name and struct name, because $deity forbid any two OSs implement the same API for this.) macOS might also implement getpeereid(), which is a cross-platform credentials-passing API resembling SO_PEERCRED (but with just the euid, not the pid or primary egid). libdbus uses getpeereid() generically (based on an Autoconf check for HAVE_GETPEEREID rather than OS-specific conditionals), although it prefers to use an OS-specific mechanism that gets both the uid and pid if one is available: /* getpeereid() originates from D.J. Bernstein and is fairly * widely-supported. According to a web search, it might be present in * any/all of: * * - AIX? * - Blackberry? * - Cygwin * - FreeBSD 4.6+ (but we prefer SCM_CREDS: it carries the pid) * - Mac OS X * - Minix 3.1.8+ * - MirBSD? * - NetBSD 5.0+ (but LOCAL_PEEREID would be better: it carries the pid) * - OpenBSD 3.0+ (but we prefer SO_PEERCRED: it carries the pid) * - QNX? */ See dbus/dbus-sysdeps-unix.c in libdbus for more background on what to interoperate with.
Created attachment 368518 [details] [review] Rough sketch at adding macOS support for gcredentials Here's a first sketch at adding gcredentials support. Note that I'm pretty much out of my depth here. Unfortunately it looks like I did break something or did not add everything necessary, since I'm getting: % LANG=C G_DBUS_DEBUG=all gdbus call --session --dest org.freedesktop.DBus --object-path / --method org.freedesktop.DBus.Introspectable.Introspect 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:path=/tmp/dbus,guid=c5fb3dafccbfd55532550c425a86c683' 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:path=/tmp/dbus,guid=c5fb3dafccbfd55532550c425a86c683' for bus type 'session' GDBus-debug:Auth: CLIENT: initiating GDBus-debug:Auth: CLIENT: Done, authenticated=0 Error connecting: Error sending credentials: Error sending message: Bad file descriptor Or could 'Bad file descriptor' be unrelated to my changes, indicating another incompatibility w/ macOS?
Created attachment 368529 [details] [review] Rough sketch at adding macOS support for gcredentials
Review of attachment 368529 [details] [review]: GIO supports two ways to transfer credentials: * G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED: The side being authenticated (D-Bus client) sends a message (1 or more bytes, or sometimes 0 bytes) with out-of-band credentials attached to it, by using sendmsg(); the kernel ensures that the out-of-band credentials are correct; and the side authenticating it (D-Bus server) receives the message with recvmsg() and parses the attached out-of-band data. Examples: Linux SCM_CREDENTIALS, FreeBSD SCM_CREDS. * G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED: The side being authenticated (D-Bus client) doesn't do anything special, and the side authenticating it asks the kernel "who opened this socket?", with either a special getsockopt() call for an "option" typically namespaced with SO_ or LOCAL_, or the semi-portable function getpeereid(). Examples: Linux SO_PEERCRED, NetBSD LOCAL_PEEREID, semi-portable getpeereid(). A platform can implement neither, either or both of those, and GIO can implement support for neither, either or both. For example, GIO currently has: macOS OpenBSD FreeBSD Linux G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED x x G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED x x You seem to be trying to move macOS into the same category as Linux, but so far I haven't seen any evidence that macOS supports the "credentials message" mode, so I think it would be more appropriate to move it in the same category as OpenBSD, with only the "get credentials" mode available. The "get credentials" style is normally better anyway, because it doesn't require the side being authenticated (the D-Bus client) to do anything special. The reference implementation of D-Bus doesn't bother to implement the "credentials message" mode for Linux either - Linux is treated like OpenBSD there. ::: gio/gcredentials.c @@ +58,3 @@ + * On Apple operating systems (including iOS, tvOS, and macOS), + * the native credential type is a struct cmsghdr. + * This corresponds to %G_CREDENTIALS_TYPE_APPLE_CMSGHDR. You said APPLE_XUCRED elsewhere, which appears to mean the native credential type is a struct xucred. @@ +153,3 @@ credentials->native.gid = getegid (); +#elif G_CREDENTIALS_USE_APPLE_XUCRED + credentials->native.cr_uid = geteuid (); Doesn't struct xucred have other members, like the pid and one or more group IDs? If it does, please fill them in. @@ +227,3 @@ + g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cr_uid); + if (ret->str[ret->len - 1] == ',') + ret->str[ret->len - 1] = '\0'; Please append anything else that's in the struct, too. ::: gio/gcredentialsprivate.h @@ +74,3 @@ +#define G_CREDENTIALS_NATIVE_TYPE G_CREDENTIALS_TYPE_APPLE_XUCRED +#define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct xucred) ) +#define G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1 As I mentioned in the overview comment, I don't think G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED should be defined here. ::: gio/gsocket.c @@ +5699,3 @@ + if (getsockopt (socket->priv->fd, + 0, + LOCAL_PEERCRED, Googling for LOCAL_PEERCRED suggests that maybe it's meant to be getsockopt (socket->priv->fd, LOCAL_PEERCRED, 1, ...)? If in doubt, find the implementation of getpeereid() in the macOS libc and do the same thing it does. @@ +5701,3 @@ + LOCAL_PEERCRED, + &cred, + &optlen) == 0) For completeness, maybe also check that optlen == sizeof (cred) after the call? Googling for LOCAL_PEERCRED suggests that you're also meant to check that cred.cr_version == XUCRED_VERSION, to guard against kernel ABI breaks, before reading the contents of the struct. ::: gio/gunixcredentialsmessage.c @@ +89,3 @@ return SCM_CREDENTIALS; +#elif G_CREDENTIALS_USE_APPLE_XUCRED + return LOCAL_PEERCRED; I don't think this is right. LOCAL_PEERCRED looks like a getsockopt() option, and getsockopt() options aren't the same thing as socket control message numbers. Just delete this bit, unless you happen to know how to implement the equivalent of FreeBSD SCM_CREDS on macOS. (Because the Darwin kernel is derived from FreeBSD, maybe the equivalent *is* FreeBSD SCM_CREDS...)
(In reply to Simon McVittie from comment #7) > Just delete this bit, unless you happen to know how to implement the > equivalent of FreeBSD SCM_CREDS on macOS. (Because the Darwin kernel is > derived from FreeBSD, maybe the equivalent *is* FreeBSD SCM_CREDS...) Alternatively, if you find that macOS implements SCM_CREDS with the same API as FreeBSD, you might be able to discard all those changes, and instead add __APPLE__ to all the conditionals that guard SCM_CREDS - that would mean it's treated the same as FreeBSD, kFreeBSD, GNU Hurd and DragonflyBSD. (Unfortunately, I don't think the design of GCredentials is really set up for platforms where there is more than one native credentials type, for example struct cmsgcred and struct xucred if Darwin implements both SCM_CREDS and LOCAL_PEERCRED - but perhaps someone more knowledgeable than me can describe a way to make that work.)
Simon, thanks for your details comments! I will learn more about the two ways for credentials passing. While I had preferred the easy way, it's not going to work. Here's the relevant excerpt from sys/socket.h: #ifndef __APPLE__ /* * While we may have more groups than this, the cmsgcred struct must * be able to fit in an mbuf, and NGROUPS_MAX is too large to allow * this. */ #define CMGROUP_MAX 16 /* * Credentials structure, used to verify the identity of a peer * process that has sent us a message. This is allocated by the * peer process but filled in by the kernel. This prevents the * peer from lying about its identity. (Note that cmcred_groups[0] * is the effective GID.) */ struct cmsgcred { pid_t cmcred_pid; /* PID of sending process */ uid_t cmcred_uid; /* real UID of sending process */ uid_t cmcred_euid; /* effective UID of sending process */ gid_t cmcred_gid; /* real GID of sending process */ short cmcred_ngroups; /* number or groups */ gid_t cmcred_groups[CMGROUP_MAX]; /* groups */ }; #endif So, no struct cmsgcred for us. Whenever I have time again for this, I will continue exploring the road of G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED for __APPLE__. Btw., struct xecred really only contains the uid: /* * This is the external representation of struct ucred. */ struct xucred { u_int cr_version; /* structure layout version */ uid_t cr_uid; /* effective user id */ short cr_ngroups; /* number of advisory groups */ gid_t cr_groups[NGROUPS]; /* advisory group list */ }; Also, if I were to go the getpeereid(), wouldn't a patch look way more simple then?
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME'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.gnome.org/GNOME/glib/issues/507.