From ec2f60a0088286120e1ef7c0be72324e31006ccb Mon Sep 17 00:00:00 2001 From: "Dr. Michael Lauer" Date: Sun, 18 Feb 2018 15:26:54 +0100 Subject: [PATCH] gio: add gcredential support for macOS [smcv: Apply my review feedback from ] Co-authored-by: Simon McVittie Resolves: https://gitlab.gnome.org/GNOME/glib/issues/507 --- gio/gcredentials.c | 60 ++++++++++++++++++++++++++++++++++- gio/gcredentialsprivate.h | 12 +++++++ gio/gioenums.h | 4 ++- gio/gsocket.c | 36 +++++++++++++++++++++ gio/gunixcredentialsmessage.c | 1 + gio/tests/credentials.c | 8 +++++ gio/tests/gdbus-server-auth.c | 5 +++ 7 files changed, 124 insertions(+), 2 deletions(-) diff --git a/gio/gcredentials.c b/gio/gcredentials.c index 58a7df7ef..146829e7c 100644 --- a/gio/gcredentials.c +++ b/gio/gcredentials.c @@ -55,6 +55,10 @@ * unix(7) man page for details. This corresponds to * %G_CREDENTIALS_TYPE_LINUX_UCRED. * + * On Apple operating systems (including iOS, tvOS, and macOS), + * the native credential type is a `struct xucred`. + * This corresponds to %G_CREDENTIALS_TYPE_APPLE_XUCRED. + * * On FreeBSD, Debian GNU/kFreeBSD, and GNU/Hurd, the native * credential type is a `struct cmsgcred`. This corresponds * to %G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED. @@ -85,6 +89,8 @@ struct _GCredentials #if G_CREDENTIALS_USE_LINUX_UCRED struct ucred native; +#elif G_CREDENTIALS_USE_APPLE_XUCRED + struct xucred native; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED struct cmsgcred native; #elif G_CREDENTIALS_USE_NETBSD_UNPCBID @@ -148,6 +154,22 @@ g_credentials_init (GCredentials *credentials) credentials->native.pid = getpid (); credentials->native.uid = geteuid (); credentials->native.gid = getegid (); +#elif G_CREDENTIALS_USE_APPLE_XUCRED + gsize i; + + credentials->native.cr_version = XUCRED_VERSION; + credentials->native.cr_uid = geteuid (); + credentials->native.cr_ngroups = 1; + credentials->native.cr_groups[0] = getegid (); + + /* FIXME: In principle this could use getgroups() to fill in the rest + * of cr_groups, but then we'd have to handle the case where a process + * can have more than NGROUPS groups, if that's even possible. A macOS + * user would have to develop and test this. + * + * For now we fill it with -1 (meaning "no data"). */ + for (i = 1; i < NGROUPS; i++) + credentials->native.cr_groups[i] = -1; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED memset (&credentials->native, 0, sizeof (struct cmsgcred)); credentials->native.cmcred_pid = getpid (); @@ -202,6 +224,9 @@ gchar * g_credentials_to_string (GCredentials *credentials) { GString *ret; +#if G_CREDENTIALS_USE_APPLE_XUCRED + __typeof__(credentials->native.cr_ngroups) i; +#endif g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL); @@ -216,6 +241,15 @@ g_credentials_to_string (GCredentials *credentials) g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.gid); if (ret->str[ret->len - 1] == ',') ret->str[ret->len - 1] = '\0'; +#elif G_CREDENTIALS_USE_APPLE_XUCRED + g_string_append (ret, "apple-xucred:"); + g_string_append_printf (ret, "version=%u,", credentials->native.cr_version); + if (credentials->native.cr_uid != -1) + g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cr_uid); + for (i = 0; i < credentials->native.cr_ngroups; i++) + g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cr_groups[i]); + if (ret->str[ret->len - 1] == ',') + ret->str[ret->len - 1] = '\0'; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED g_string_append (ret, "freebsd-cmsgcred:"); if (credentials->native.cmcred_pid != -1) @@ -326,6 +360,10 @@ g_credentials_is_same_user (GCredentials *credentials, if (linux_ucred_check_valid (&credentials->native, NULL) && credentials->native.uid == other_credentials->native.uid) ret = TRUE; +#elif G_CREDENTIALS_USE_APPLE_XUCRED + if (credentials->native.cr_version == other_credentials->native.cr_version && + credentials->native.cr_uid == other_credentials->native.cr_uid) + ret = TRUE; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED if (credentials->native.cmcred_euid == other_credentials->native.cmcred_euid) ret = TRUE; @@ -487,6 +525,21 @@ g_credentials_get_unix_user (GCredentials *credentials, ret = credentials->native.uid; else ret = -1; +#elif G_CREDENTIALS_USE_APPLE_XUCRED + if (credentials->native.cr_version == XUCRED_VERSION) + { + ret = credentials->native.cr_uid; + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + /* No point in translating the part in parentheses... */ + "%s (struct xucred cr_version %u != %u)", + _("There is no GCredentials support for your platform"), + credentials->native.cr_version, + XUCRED_VERSION); + ret = -1; + } #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED ret = credentials->native.cmcred_euid; #elif G_CREDENTIALS_USE_NETBSD_UNPCBID @@ -516,7 +569,8 @@ g_credentials_get_unix_user (GCredentials *credentials, * * This operation can fail if #GCredentials is not supported on the * OS or if the native credentials type does not contain information - * about the UNIX process ID. + * about the UNIX process ID (for example this is the case for + * %G_CREDENTIALS_TYPE_APPLE_XUCRED). * * Returns: The UNIX process ID, or -1 if @error is set. * @@ -545,6 +599,7 @@ g_credentials_get_unix_pid (GCredentials *credentials, #elif G_CREDENTIALS_USE_SOLARIS_UCRED ret = ucred_getpid (credentials->native); #else + /* this case includes G_CREDENTIALS_USE_APPLE_XUCRED */ ret = -1; g_set_error_literal (error, G_IO_ERROR, @@ -587,6 +642,9 @@ g_credentials_set_unix_user (GCredentials *credentials, #if G_CREDENTIALS_USE_LINUX_UCRED credentials->native.uid = uid; ret = TRUE; +#elif G_CREDENTIALS_USE_APPLE_XUCRED + credentials->native.cr_uid = uid; + ret = TRUE; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED credentials->native.cmcred_euid = uid; ret = TRUE; diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h index 6d7284bc7..13d3bf327 100644 --- a/gio/gcredentialsprivate.h +++ b/gio/gcredentialsprivate.h @@ -39,6 +39,7 @@ #undef G_CREDENTIALS_USE_NETBSD_UNPCBID #undef G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED #undef G_CREDENTIALS_USE_SOLARIS_UCRED +#undef G_CREDENTIALS_USE_APPLE_XUCRED /* * G_CREDENTIALS_NATIVE_TYPE: @@ -156,6 +157,17 @@ #define G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED 1 #define G_CREDENTIALS_HAS_PID 1 +#elif defined(__APPLE__) +#include +#define G_CREDENTIALS_SUPPORTED 1 +#define G_CREDENTIALS_USE_APPLE_XUCRED 1 +#define G_CREDENTIALS_NATIVE_TYPE G_CREDENTIALS_TYPE_APPLE_XUCRED +#define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct xucred)) +#undef G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED +#define G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED 1 +#define G_CREDENTIALS_SPOOFING_SUPPORTED 1 +#define G_CREDENTIALS_HAS_PID 0 + #endif #endif /* __G_CREDENTIALS_PRIVATE_H__ */ diff --git a/gio/gioenums.h b/gio/gioenums.h index f6cf6f9d9..c426cfe03 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -1428,6 +1428,7 @@ typedef enum * @G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED: The native credentials type is a `struct sockpeercred`. Added in 2.30. * @G_CREDENTIALS_TYPE_SOLARIS_UCRED: The native credentials type is a `ucred_t`. Added in 2.40. * @G_CREDENTIALS_TYPE_NETBSD_UNPCBID: The native credentials type is a `struct unpcbid`. Added in 2.42. + * @G_CREDENTIALS_TYPE_APPLE_XUCRED: The native credentials type is a `struct xucred`. Added in 2.66. * * Enumeration describing different kinds of native credential types. * @@ -1440,7 +1441,8 @@ typedef enum G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED, G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED, G_CREDENTIALS_TYPE_SOLARIS_UCRED, - G_CREDENTIALS_TYPE_NETBSD_UNPCBID + G_CREDENTIALS_TYPE_NETBSD_UNPCBID, + G_CREDENTIALS_TYPE_APPLE_XUCRED, } GCredentialsType; /** diff --git a/gio/gsocket.c b/gio/gsocket.c index 2a15bdd22..1df111357 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -5910,6 +5910,7 @@ g_socket_receive_message (GSocket *socket, * - OpenBSD since GLib 2.30 * - Solaris, Illumos and OpenSolaris since GLib 2.40 * - NetBSD since GLib 2.42 + * - macOS, tvOS, iOS since GLib 2.66 * * Other ways to obtain credentials from a foreign peer includes the * #GUnixCredentialsMessage type and @@ -5951,6 +5952,41 @@ g_socket_get_credentials (GSocket *socket, native_creds_buf); } } +#elif G_CREDENTIALS_USE_APPLE_XUCRED + { + struct xucred cred; + socklen_t optlen = sizeof (cred); + + if (getsockopt (socket->priv->fd, + 0, + LOCAL_PEERCRED, + &cred, + &optlen) == 0) + { + if (cred.cr_version == XUCRED_VERSION) + { + ret = g_credentials_new (); + g_credentials_set_native (ret, + G_CREDENTIALS_NATIVE_TYPE, + &cred); + } + else + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + /* No point in translating this! */ + "struct xucred cr_version %u != %u", + cred.cr_version, XUCRED_VERSION); + /* Reuse a translatable string we already have */ + g_prefix_error (error, + _("Unable to read socket credentials: %s"), + ""); + + return NULL; + } + } + } #elif G_CREDENTIALS_USE_NETBSD_UNPCBID { struct unpcbid cred; diff --git a/gio/gunixcredentialsmessage.c b/gio/gunixcredentialsmessage.c index 02d59c858..9e5c7d32e 100644 --- a/gio/gunixcredentialsmessage.c +++ b/gio/gunixcredentialsmessage.c @@ -96,6 +96,7 @@ g_unix_credentials_message_get_msg_type (GSocketControlMessage *message) #elif G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED #error "G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED is set but there is no msg_type defined for this platform" #else + /* includes G_CREDENTIALS_USE_APPLE_XUCRED */ return 0; #endif } diff --git a/gio/tests/credentials.c b/gio/tests/credentials.c index 98acb5602..2b0f1f787 100644 --- a/gio/tests/credentials.c +++ b/gio/tests/credentials.c @@ -99,6 +99,14 @@ test_basic (void) g_assert_cmpuint (native->uid, ==, geteuid ()); g_assert_cmpuint (native->pid, ==, getpid ()); } +#elif G_CREDENTIALS_USE_APPLE_XUCRED + { + struct xucred *native = g_credentials_get_native (creds, + G_CREDENTIALS_TYPE_APPLE_XUCRED); + + g_assert_cmpuint (native->cr_version, ==, XUCRED_VERSION); + g_assert_cmpuint (native->cr_uid, ==, geteuid ()); + } #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED { struct cmsgcred *native = g_credentials_get_native (creds, diff --git a/gio/tests/gdbus-server-auth.c b/gio/tests/gdbus-server-auth.c index 2554ad6ab..b3ee8aab2 100644 --- a/gio/tests/gdbus-server-auth.c +++ b/gio/tests/gdbus-server-auth.c @@ -244,6 +244,11 @@ assert_expected_uid_pid (InteropFlags flags, * on Linux. */ g_assert_cmpint (uid, ==, getuid ()); g_assert_cmpint (pid, ==, getpid ()); +#elif defined(__APPLE__) + /* We know (or at least suspect) that both GDBus and libdbus support + * passing the uid only on macOS. */ + g_assert_cmpint (uid, ==, getuid ()); + /* No pid here */ #else g_test_message ("Please open a merge request to add appropriate " "assertions for your platform");