[glib] gcredentials: add Solaris support



commit 5a269e5a90181a5cafce90e7e5d7bc4f42f47f52
Author: Dan Winship <danw gnome org>
Date:   Thu Sep 19 16:09:38 2013 -0400

    gcredentials: add Solaris support
    
    Based on patches from Igor Pashev.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=705029

 gio/gcredentials.c            |   52 +++++++++++++++++++++++++++++++++++++---
 gio/gcredentialsprivate.h     |   12 +++++++++
 gio/gioenums.h                |    4 ++-
 gio/gsocket.c                 |   36 ++++++++++++++++++++++-----
 gio/gunixcredentialsmessage.c |    2 +
 gio/tests/credentials.c       |   18 ++++++++++++++
 6 files changed, 112 insertions(+), 12 deletions(-)
---
diff --git a/gio/gcredentials.c b/gio/gcredentials.c
index b18ccc4..8e9f28a 100644
--- a/gio/gcredentials.c
+++ b/gio/gcredentials.c
@@ -65,6 +65,10 @@
  *
  * On OpenBSD, the native credential type is a <type>struct sockpeercred</type>.
  * This corresponds to %G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED.
+ *
+ * On Solaris (including OpenSolaris and its derivatives), the native
+ * credential type is a <type>ucred_t</type>. This corresponds to
+ * %G_CREDENTIALS_TYPE_SOLARIS_UCRED.
  */
 
 /**
@@ -86,6 +90,8 @@ struct _GCredentials
   struct cmsgcred native;
 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
   struct sockpeercred native;
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  ucred_t *native;
 #else
   #ifdef __GNUC__
   #warning Please add GCredentials support for your OS
@@ -111,7 +117,11 @@ G_DEFINE_TYPE (GCredentials, g_credentials, G_TYPE_OBJECT);
 static void
 g_credentials_finalize (GObject *object)
 {
-  G_GNUC_UNUSED GCredentials *credentials = G_CREDENTIALS (object);
+#if G_CREDENTIALS_USE_SOLARIS_UCRED
+  GCredentials *credentials = G_CREDENTIALS (object);
+
+  ucred_free (credentials->native);
+#endif
 
   if (G_OBJECT_CLASS (g_credentials_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (g_credentials_parent_class)->finalize (object);
@@ -143,6 +153,8 @@ g_credentials_init (GCredentials *credentials)
   credentials->native.pid = getpid ();
   credentials->native.uid = geteuid ();
   credentials->native.gid = getegid ();
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  credentials->native = ucred_get (P_MYID);
 #endif
 }
 
@@ -214,6 +226,19 @@ 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_SOLARIS_UCRED
+  g_string_append (ret, "solaris-ucred:");
+  {
+    id_t id;
+    if ((id = ucred_getpid (credentials->native)) != -1)
+      g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) id);
+    if ((id = ucred_geteuid (credentials->native)) != -1)
+      g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) id);
+    if ((id = ucred_getegid (credentials->native)) != -1)
+      g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) id);
+    if (ret->str[ret->len - 1] == ',')
+      ret->str[ret->len - 1] = '\0';
+  }
 #else
   g_string_append (ret, "unknown");
 #endif
@@ -260,6 +285,9 @@ g_credentials_is_same_user (GCredentials  *credentials,
 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
   if (credentials->native.uid == other_credentials->native.uid)
     ret = TRUE;
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  if (ucred_geteuid (credentials->native) == ucred_geteuid (other_credentials->native))
+    ret = TRUE;
 #else
   g_set_error_literal (error,
                        G_IO_ERROR,
@@ -334,7 +362,9 @@ g_credentials_get_native (GCredentials     *credentials,
   if (!credentials_native_type_check (native_type, "get"))
     return NULL;
 
-#if G_CREDENTIALS_SUPPORTED
+#if G_CREDENTIALS_USE_SOLARIS_UCRED
+  return credentials->native;
+#elif G_CREDENTIALS_SUPPORTED
   return &credentials->native;
 #else
   g_assert_not_reached ();
@@ -364,7 +394,9 @@ g_credentials_set_native (GCredentials     *credentials,
   if (!credentials_native_type_check (native_type, "set"))
     return;
 
-#if G_CREDENTIALS_SUPPORTED
+#if G_CREDENTIALS_USE_SOLARIS_UCRED
+  memcpy (credentials->native, native, ucred_size ());
+#elif G_CREDENTIALS_SUPPORTED
   memcpy (&credentials->native, native, sizeof (credentials->native));
 #else
   g_assert_not_reached ();
@@ -405,6 +437,8 @@ g_credentials_get_unix_user (GCredentials    *credentials,
   ret = credentials->native.cmcred_euid;
 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
   ret = credentials->native.uid;
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  ret = ucred_geteuid (credentials->native);
 #else
   ret = -1;
   g_set_error_literal (error,
@@ -447,6 +481,8 @@ g_credentials_get_unix_pid (GCredentials    *credentials,
   ret = credentials->native.cmcred_pid;
 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
   ret = credentials->native.pid;
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  ret = ucred_getpid (credentials->native);
 #else
   ret = -1;
   g_set_error_literal (error,
@@ -469,7 +505,8 @@ g_credentials_get_unix_pid (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 user.
+ * about the UNIX user. It can also fail if the OS does not allow the
+ * use of "spoofed" credentials.
  *
  * Returns: %TRUE if @uid was set, %FALSE if error is set.
  *
@@ -496,11 +533,18 @@ g_credentials_set_unix_user (GCredentials    *credentials,
 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
   credentials->native.uid = uid;
   ret = TRUE;
+#elif !G_CREDENTIALS_SPOOFING_SUPPORTED
+  g_set_error_literal (error,
+                       G_IO_ERROR,
+                       G_IO_ERROR_PERMISSION_DENIED,
+                       _("Credentials spoofing is not possible on this OS"));
+  ret = FALSE;
 #else
   g_set_error_literal (error,
                        G_IO_ERROR,
                        G_IO_ERROR_NOT_SUPPORTED,
                        _("GCredentials is not implemented on this OS"));
+  ret = FALSE;
 #endif
 
   return ret;
diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h
index d3b5f97..ee7d636 100644
--- a/gio/gcredentialsprivate.h
+++ b/gio/gcredentialsprivate.h
@@ -31,6 +31,7 @@
 #define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct ucred))
 #define G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1
 #define G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED 1
+#define G_CREDENTIALS_SPOOFING_SUPPORTED 1
 
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
 #define G_CREDENTIALS_SUPPORTED 1
@@ -38,6 +39,7 @@
 #define G_CREDENTIALS_NATIVE_TYPE G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED
 #define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct cmsgcred))
 #define G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1
+#define G_CREDENTIALS_SPOOFING_SUPPORTED 1
 
 #elif defined(__OpenBSD__)
 #define G_CREDENTIALS_SUPPORTED 1
@@ -45,6 +47,16 @@
 #define G_CREDENTIALS_NATIVE_TYPE G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED
 #define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct sockpeercred))
 #define G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED 1
+#define G_CREDENTIALS_SPOOFING_SUPPORTED 1
+
+#elif defined(__sun__) || defined(__illumos__) || defined (__OpenSolaris_kernel__)
+#include <ucred.h>
+#define G_CREDENTIALS_SUPPORTED 1
+#define G_CREDENTIALS_USE_SOLARIS_UCRED 1
+#define G_CREDENTIALS_NATIVE_TYPE G_CREDENTIALS_TYPE_SOLARIS_UCRED
+#define G_CREDENTIALS_NATIVE_SIZE (ucred_size ())
+#define G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1
+#define G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED 1
 
 #endif
 
diff --git a/gio/gioenums.h b/gio/gioenums.h
index c8c0e15..b8b8ec6 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1342,6 +1342,7 @@ typedef enum
  * @G_CREDENTIALS_TYPE_LINUX_UCRED: The native credentials type is a <type>struct ucred</type>.
  * @G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED: The native credentials type is a <type>struct cmsgcred</type>.
  * @G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED: The native credentials type is a <type>struct 
sockpeercred</type>. Added in 2.30.
+ * @G_CREDENTIALS_TYPE_SOLARIS_UCRED: The native credentials type is a <type>ucred_t</type>. Added in 2.40.
  *
  * Enumeration describing different kinds of native credential types.
  *
@@ -1352,7 +1353,8 @@ typedef enum
   G_CREDENTIALS_TYPE_INVALID,
   G_CREDENTIALS_TYPE_LINUX_UCRED,
   G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED,
-  G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED
+  G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED,
+  G_CREDENTIALS_TYPE_SOLARIS_UCRED
 } GCredentialsType;
 
 /**
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 5e66902..714e0b3 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -4449,6 +4449,8 @@ g_socket_get_credentials (GSocket   *socket,
   ret = NULL;
 
 #if G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED
+
+#ifdef SO_PEERCRED
   {
     guint8 native_creds_buf[G_CREDENTIALS_NATIVE_SIZE];
     socklen_t optlen = sizeof (native_creds_buf);
@@ -4464,17 +4466,37 @@ g_socket_get_credentials (GSocket   *socket,
                                   G_CREDENTIALS_NATIVE_TYPE,
                                   native_creds_buf);
       }
-    else
+  }
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  {
+    ucred_t *ucred = NULL;
+
+    if (getpeerucred (socket->priv->fd, &ucred) == 0)
       {
-        int errsv = get_socket_errno ();
-        g_set_error (error,
-                     G_IO_ERROR,
-                     socket_io_error_from_errno (errsv),
-                     _("Unable to read socket credentials: %s"),
-                     socket_strerror (errsv));
+        ret = g_credentials_new ();
+        g_credentials_set_native (ret,
+                                  G_CREDENTIALS_TYPE_SOLARIS_UCRED,
+                                  ucred);
+        ucred_free (ucred);
       }
   }
 #else
+  #error "G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED is set but this is no code for this platform"
+#endif
+
+  if (!ret)
+    {
+      int errsv = get_socket_errno ();
+
+      g_set_error (error,
+                   G_IO_ERROR,
+                   socket_io_error_from_errno (errsv),
+                   _("Unable to read socket credentials: %s"),
+                   socket_strerror (errsv));
+    }
+
+#else
+
   g_set_error_literal (error,
                        G_IO_ERROR,
                        G_IO_ERROR_NOT_SUPPORTED,
diff --git a/gio/gunixcredentialsmessage.c b/gio/gunixcredentialsmessage.c
index 25432a0..351aea7 100644
--- a/gio/gunixcredentialsmessage.c
+++ b/gio/gunixcredentialsmessage.c
@@ -89,6 +89,8 @@ g_unix_credentials_message_get_msg_type (GSocketControlMessage *message)
   return SCM_CREDENTIALS;
 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
   return SCM_CREDS;
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+  return SCM_UCRED;
 #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
diff --git a/gio/tests/credentials.c b/gio/tests/credentials.c
index 53a42ec..5134e38 100644
--- a/gio/tests/credentials.c
+++ b/gio/tests/credentials.c
@@ -59,12 +59,22 @@ test_basic (void)
   g_assert_no_error (error);
 
   set = g_credentials_set_unix_user (other, not_me, &error);
+#if G_CREDENTIALS_SPOOFING_SUPPORTED
   g_assert_no_error (error);
   g_assert (set);
 
   g_assert_cmpuint (g_credentials_get_unix_user (other, &error), ==, not_me);
   g_assert (!g_credentials_is_same_user (creds, other, &error));
   g_assert_no_error (error);
+#else
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+  g_assert (!set);
+  g_clear_error (&error);
+
+  g_assert_cmpuint (g_credentials_get_unix_user (other, &error), ==, geteuid ());
+  g_assert (g_credentials_is_same_user (creds, other, &error));
+  g_assert_no_error (error);
+#endif
 
   stringified = g_credentials_to_string (creds);
   g_test_message ("%s", stringified);
@@ -98,6 +108,14 @@ test_basic (void)
           g_assert_cmpuint (native->uid, ==, geteuid ());
           g_assert_cmpuint (native->pid, ==, getpid ());
         }
+#elif G_CREDENTIALS_USE_SOLARIS_UCRED
+        {
+          ucred_t *native = g_credentials_get_native (creds,
+              G_CREDENTIALS_TYPE_SOLARIS_UCRED);
+
+          g_assert_cmpuint (ucred_geteuid (native), ==, geteuid ());
+          g_assert_cmpuint (ucred_getpid (native), ==, getpid ());
+        }
 #else
 #error "G_CREDENTIALS_SUPPORTED is set but there is no test for this platform"
 #endif


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