summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-04-22 07:01:23 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-04-22 07:01:23 -0400
commit44c8871c5c27337dc1905a0b4c9d35d46eb2144a (patch)
treec648d3fc464fe67c6d33c0054102b48be1035188
parentb0c993195a945584bb6de19ba0c205111aeead8f (diff)
Preliminary Win32 and nonce-tpc: support
A lot of this code needs to be cleaned up. And the D-Bus spec needs to mention the SHM hack used to discover the address. And we need to autolaunch the bus if the can't find it. And... Anyway, here goes: http://people.freedesktop.org/~david/gdbus-win32.png Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--gdbus/gdbusaddress.c262
-rw-r--r--gdbus/gdbusauth.c11
-rw-r--r--gdbus/gdbusauthmechanismexternal.c69
-rw-r--r--gdbus/gdbusconnection.c7
4 files changed, 326 insertions, 23 deletions
diff --git a/gdbus/gdbusaddress.c b/gdbus/gdbusaddress.c
index 99ca311..075712e 100644
--- a/gdbus/gdbusaddress.c
+++ b/gdbus/gdbusaddress.c
@@ -22,6 +22,8 @@
#include "config.h"
+#include <stdlib.h>
+
#include <glib/gi18n.h>
#include "gdbusaddress.h"
@@ -55,10 +57,12 @@ g_dbus_address_connect (const gchar *address_entry,
GError **error)
{
GIOStream *ret;
- GSocketAddress *address;
+ GSocketConnectable *connectable;
+ const gchar *nonce_file;
- address = NULL;
+ connectable = NULL;
ret = NULL;
+ nonce_file = NULL;
if (FALSE)
{
@@ -81,13 +85,13 @@ g_dbus_address_connect (const gchar *address_entry,
}
else if (path != NULL)
{
- address = g_unix_socket_address_new (path);
+ connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
}
else if (abstract != NULL)
{
- address = g_unix_socket_address_new_with_type (abstract,
- -1,
- G_UNIX_SOCKET_ADDRESS_ABSTRACT);
+ connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
+ -1,
+ G_UNIX_SOCKET_ADDRESS_ABSTRACT));
}
else
{
@@ -95,6 +99,52 @@ g_dbus_address_connect (const gchar *address_entry,
}
}
#endif
+ else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
+ {
+ const gchar *s;
+ const gchar *host;
+ guint port;
+ gchar *endp;
+
+ host = g_hash_table_lookup (key_value_pairs, "host");
+ if (host == NULL)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_BAD_ADDRESS,
+ _("Error in address `%s' - the host attribute is missing or malformed"),
+ address_entry);
+ goto out;
+ }
+
+ s = g_hash_table_lookup (key_value_pairs, "port");
+ if (s == NULL)
+ s = "0";
+ port = strtol (s, &endp, 10);
+ if ((*s == '\0' || *endp != '\0') || port == 0 || port >= 65536)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_BAD_ADDRESS,
+ _("Error in address `%s' - the port attribute is missing or malformed"),
+ address_entry);
+ goto out;
+ }
+
+ nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
+ if (nonce_file == NULL)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_BAD_ADDRESS,
+ _("Error in address `%s' - the noncefile attribute is missing or malformed"),
+ address_entry);
+ goto out;
+ }
+
+ /* TODO: deal with family? */
+ connectable = g_network_address_new (host, port);
+ }
else
{
g_set_error (error,
@@ -105,24 +155,74 @@ g_dbus_address_connect (const gchar *address_entry,
address_entry);
}
- if (address != NULL)
+ if (connectable != NULL)
{
GSocketClient *client;
GSocketConnection *connection;
+
g_assert (ret == NULL);
client = g_socket_client_new ();
connection = g_socket_client_connect (client,
- G_SOCKET_CONNECTABLE (address),
+ connectable,
cancellable,
error);
if (connection != NULL)
{
ret = G_IO_STREAM (connection);
}
- g_object_unref (address);
+ g_object_unref (connectable);
g_object_unref (client);
+
+ if (nonce_file != NULL)
+ {
+ gchar *nonce_contents;
+ gsize nonce_length;
+
+ /* TODO: too dangerous to read the entire file? (think denial-of-service etc.) */
+ if (!g_file_get_contents (nonce_file,
+ &nonce_contents,
+ &nonce_length,
+ error))
+ {
+ g_prefix_error (error, _("Error reading nonce file `%s':"), nonce_file);
+ g_object_unref (ret);
+ ret = NULL;
+ goto out;
+ }
+
+ if (nonce_length != 16)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_BAD_ADDRESS,
+ _("The nonce-file `%s' was %" G_GSIZE_FORMAT " bytes. Expected 16 bytes."),
+ nonce_file,
+ nonce_length);
+ g_free (nonce_contents);
+ g_object_unref (ret);
+ ret = NULL;
+ goto out;
+ }
+
+ if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
+ nonce_contents,
+ nonce_length,
+ NULL,
+ cancellable,
+ error))
+ {
+ g_prefix_error (error, _("Error write contents of nonce file `%s' to stream:"), nonce_file);
+ g_object_unref (ret);
+ ret = NULL;
+ g_free (nonce_contents);
+ goto out;
+ }
+ g_free (nonce_contents);
+ }
}
+ out:
+
return ret;
}
@@ -347,6 +447,137 @@ g_dbus_address_get_stream_sync (const gchar *address,
/* ---------------------------------------------------------------------------------------------------- */
+#ifdef G_OS_WIN32
+#include <windows.h>
+
+static
+HANDLE _dbus_global_lock (const char *mutexname)
+{
+ HANDLE mutex;
+ DWORD gotMutex;
+
+ mutex = CreateMutexA( NULL, FALSE, mutexname );
+ if( !mutex )
+ {
+ return FALSE;
+ }
+
+ gotMutex = WaitForSingleObject( mutex, INFINITE );
+ switch( gotMutex )
+ {
+ case WAIT_ABANDONED:
+ ReleaseMutex (mutex);
+ CloseHandle (mutex);
+ return 0;
+ case WAIT_FAILED:
+ case WAIT_TIMEOUT:
+ return 0;
+ }
+
+ return mutex;
+}
+
+static
+void _dbus_global_unlock (HANDLE mutex)
+{
+ ReleaseMutex (mutex);
+ CloseHandle (mutex);
+}
+
+static const char *cUniqueDBusInitMutex = "UniqueDBusInitMutex";
+// sync _dbus_get_autolaunch_address
+static const char *cDBusAutolaunchMutex = "DBusAutolaunchMutex";
+// mutex to determine if dbus-daemon is already started (per user)
+static const char *cDBusDaemonMutex = "DBusDaemonMutex";
+// named shm for dbus adress info (per user)
+#ifdef _DEBUG
+static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfoDebug";
+#else
+static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo";
+#endif
+
+static gchar *
+_dbus_get_autolaunch_shm (void)
+{
+ HANDLE sharedMem;
+ const char *shared_addr;
+ int i;
+ gchar *ret;
+
+ ret = NULL;
+
+ // read shm
+ for(i=0;i<20;++i) {
+ // we know that dbus-daemon is available, so we wait until shm is available
+ sharedMem = OpenFileMappingA( FILE_MAP_READ, FALSE, cDBusDaemonAddressInfo );
+ if( sharedMem == 0 )
+ Sleep( 100 );
+ if ( sharedMem != 0)
+ break;
+ }
+
+ if( sharedMem == 0 )
+ return FALSE;
+
+ shared_addr = MapViewOfFile( sharedMem, FILE_MAP_READ, 0, 0, 0 );
+
+ if (shared_addr != NULL)
+ ret = g_strdup (shared_addr);
+
+ // cleanup
+ UnmapViewOfFile( shared_addr );
+
+ CloseHandle( sharedMem );
+
+ return ret;
+}
+
+
+static gchar *
+get_session_address_platform_specific (void)
+{
+ HANDLE lock;
+ HANDLE daemon;
+ gchar *ret;
+
+ ret = NULL;
+
+ // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
+ lock = _dbus_global_lock( cUniqueDBusInitMutex );
+
+ // do checks
+ daemon = CreateMutexA( NULL, FALSE, cDBusDaemonMutex );
+ if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT)
+ {
+ ReleaseMutex (daemon);
+ CloseHandle (daemon);
+
+ _dbus_global_unlock( lock );
+ return FALSE;
+ }
+
+ // read shm
+ ret = _dbus_get_autolaunch_shm ();
+
+ // cleanup
+ CloseHandle ( daemon );
+
+ _dbus_global_unlock( lock );
+
+ return ret;
+}
+
+#else
+
+static gchar *
+get_session_address_platform_specific (void)
+{
+}
+
+#endif
+
+/* ---------------------------------------------------------------------------------------------------- */
+
gchar *
g_dbus_address_get_for_bus (GBusType bus_type,
GError **error)
@@ -370,10 +601,14 @@ g_dbus_address_get_for_bus (GBusType bus_type,
ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
if (ret == NULL)
{
- g_set_error (error,
- G_DBUS_ERROR,
- G_DBUS_ERROR_FAILED,
- _("Cannot determine session bus address (TODO: run dbus-launch to find out)"));
+ ret = get_session_address_platform_specific ();
+ if (ret == NULL)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Cannot determine session bus address (TODO: run dbus-launch to find out)"));
+ }
}
break;
@@ -423,4 +658,3 @@ g_dbus_address_get_for_bus (GBusType bus_type,
out:
return ret;
}
-
diff --git a/gdbus/gdbusauth.c b/gdbus/gdbusauth.c
index 7de9ee4..375aef6 100644
--- a/gdbus/gdbusauth.c
+++ b/gdbus/gdbusauth.c
@@ -325,16 +325,17 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth,
/* OK, decided on a mechanism - let's do this thing */
mech = g_object_new (auth_mech_to_use_gtype, NULL);
-#if 0
- g_printerr ("using auth mechanism with name `%s' of type `%s'\n",
- g_dbus_auth_mechanism_get_name (mech),
- g_type_name (G_TYPE_FROM_INSTANCE (mech)));
-#endif
g_ptr_array_add (attempted_auth_mechs, (gpointer) g_dbus_auth_mechanism_get_name (mech));
initial_response_len = -1;
initial_response = g_dbus_auth_mechanism_client_initiate (mech,
&initial_response_len);
+#if 1
+ g_printerr ("using auth mechanism with name `%s' of type `%s' with initial response `%s'\n",
+ g_dbus_auth_mechanism_get_name (mech),
+ g_type_name (G_TYPE_FROM_INSTANCE (mech)),
+ initial_response);
+#endif
if (initial_response != NULL)
{
//g_printerr ("initial_response = `%s'\n", initial_response);
diff --git a/gdbus/gdbusauthmechanismexternal.c b/gdbus/gdbusauthmechanismexternal.c
index b2f8a3a..952e4ac 100644
--- a/gdbus/gdbusauthmechanismexternal.c
+++ b/gdbus/gdbusauthmechanismexternal.c
@@ -252,11 +252,70 @@ mechanism_client_get_state (GDBusAuthMechanism *mechanism)
return m->priv->state;
}
+#ifdef G_OS_WIN32
+#include <windows.h>
+
+/* Declarations missing in mingw's headers */
+extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR StringSid, PSID *Sid);
+extern BOOL WINAPI ConvertSidToStringSidA (PSID Sid, LPSTR *StringSid);
+
+static gchar *
+_get_win32_sid (void)
+{
+ HANDLE process_token = INVALID_HANDLE_VALUE;
+ TOKEN_USER *token_user = NULL;
+ DWORD n;
+ PSID psid;
+ int retval = FALSE;
+ gchar *sid;
+ gchar *ret;
+
+ ret = NULL;
+
+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token))
+ {
+ g_warning ("OpenProcessToken failed", GetLastError ());
+ goto failed;
+ }
+
+ if ((!GetTokenInformation (process_token, TokenUser, NULL, 0, &n) && GetLastError () != ERROR_INSUFFICIENT_BUFFER) ||
+ ((token_user = alloca (n)) == NULL) ||
+ !GetTokenInformation (process_token, TokenUser, token_user, n, &n))
+ {
+ g_warning ("GetTokenInformation failed", GetLastError ());
+ goto failed;
+ }
+
+ psid = token_user->User.Sid;
+ if (!IsValidSid (psid))
+ {
+ g_warning ("Invalid SID");
+ goto failed;
+ }
+
+ if (!ConvertSidToStringSidA (psid, &sid))
+ {
+ g_warning ("Invalid SID");
+ goto failed;
+ }
+
+ ret = g_strdup (sid);
+ LocalFree (sid);
+
+failed:
+ if (process_token != INVALID_HANDLE_VALUE)
+ CloseHandle (process_token);
+
+ return ret;
+}
+#endif
+
static gchar *
mechanism_client_initiate (GDBusAuthMechanism *mechanism,
gsize *out_initial_response_len)
{
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
+ gchar *initial_response;
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
@@ -267,11 +326,15 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism,
*out_initial_response_len = -1;
/* return the uid */
-#ifdef G_OS_UNIX
- return g_strdup_printf ("%d", geteuid ());
+#if defined(G_OS_UNIX)
+ initial_response = g_strdup_printf ("%d", geteuid ());
+#elif defined(G_OS_WIN32)
+ initial_response = _get_win32_sid ();
#else
- return NULL;
+ initial_response = NULL;
+#error TODO
#endif
+ return initial_response;
}
static void
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
index 0c818ab..e9e369f 100644
--- a/gdbus/gdbusconnection.c
+++ b/gdbus/gdbusconnection.c
@@ -80,13 +80,18 @@ _g_strv_has_string (const gchar* const * haystack,
/* ---------------------------------------------------------------------------------------------------- */
+#ifdef G_OS_WIN32
+#define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE)
+#else
+// TODO: for some reason this doesn't work on Windows
#define CONNECTION_ENSURE_LOCK(obj) do { \
if (G_UNLIKELY (g_mutex_trylock((obj)->priv->lock))) \
{ \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
"CONNECTION_ENSURE_LOCK: GDBusConnection object lock is not locked"); \
} \
- } while (FALSE) \
+ } while (FALSE)
+#endif
#define CONNECTION_LOCK(obj) do { \
g_mutex_lock ((obj)->priv->lock); \