diff options
author | David Zeuthen <davidz@redhat.com> | 2010-04-22 07:01:23 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-04-22 07:01:23 -0400 |
commit | 44c8871c5c27337dc1905a0b4c9d35d46eb2144a (patch) | |
tree | c648d3fc464fe67c6d33c0054102b48be1035188 | |
parent | b0c993195a945584bb6de19ba0c205111aeead8f (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.c | 262 | ||||
-rw-r--r-- | gdbus/gdbusauth.c | 11 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanismexternal.c | 69 | ||||
-rw-r--r-- | gdbus/gdbusconnection.c | 7 |
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); \ |