[glib/wip/smcv/apple-xucred: 55/55] gio: add gcredential support for macOS



commit ec2f60a0088286120e1ef7c0be72324e31006ccb
Author: Dr. Michael Lauer <mickey vanille-media de>
Date:   Sun Feb 18 15:26:54 2018 +0100

    gio: add gcredential support for macOS
    
    [smcv: Apply my review feedback from
    <https://bugzilla.gnome.org/show_bug.cgi?id=668866>]
    
    Co-authored-by: Simon McVittie <smcv collabora com>
    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 <sys/ucred.h>
+#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");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]