#include "libmoonshot-common.h"
#include "moonshot-msrpc.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
#define MOONSHOT_ENDPOINT_NAME "/org/janet/Moonshot"
#define MOONSHOT_INSTALL_PATH_KEY "Software\\Moonshot"
+void *__RPC_USER MIDL_user_allocate (size_t size) {
+ return malloc (size);
+}
+
+void __RPC_USER MIDL_user_free (void *data) {
+ if (data == NULL)
+ return;
+
+ free (data);
+}
+
+void moonshot_free (void *data)
+{
+ free (data);
+}
+
+static MoonshotError *moonshot_error_new_from_status (MoonshotErrorCode code,
+ DWORD status)
+{
+ MoonshotError *error = malloc (sizeof (MoonshotError));
+ error->code = code;
+ error->message = malloc (256);
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPSTR)error->message, 255, NULL);
+ return error;
+}
+
+static MoonshotError *moonshot_error_new_with_status (MoonshotErrorCode code,
+ DWORD status,
+ const char *format, ...)
+{
+ MoonshotError *error = malloc (sizeof (MoonshotError));
+ char *buffer;
+ va_list args;
+ int length;
+
+ va_start (args, format);
+
+ error->code = code;
+
+ buffer = malloc (strlen (format) + 256 + 3);
+ strcpy (buffer, format);
+ strcat (buffer, ": ");
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ status,
+ 0,
+ (LPSTR)buffer + strlen (format) + 3,
+ 255,
+ NULL);
+
+ length = _vscprintf (buffer, args);
+ error->message = malloc (length + 1);
+ _vsnprintf (error->message, length, buffer, args);
+ free (buffer);
+
+ va_end (args);
+
+ return error;
+}
static void launch_server (MoonshotError **error) {
HKEY key = NULL;
STARTUPINFO startup_info = { 0 };
PROCESS_INFORMATION process_info = { 0 };
LONG status;
+ BOOL success;
DWORD value_type;
DWORD length;
char exe_path[1024];
KEY_READ,
&key);
- if (status != 0) {
- *error = _moonshot_error_new (MOONSHOT_ERROR_OS_ERROR,
- "Unable to read registry key HKLM\\%s",
- MOONSHOT_INSTALL_PATH_KEY);
+ if (status == ERROR_FILE_NOT_FOUND) {
+ *error = moonshot_error_new
+ (MOONSHOT_ERROR_INSTALLATION_ERROR,
+ "Moonshot is not installed correctly on this system. "
+ "(Registry key HKLM\\%s was not found).",
+ MOONSHOT_INSTALL_PATH_KEY);
+ return;
+ } else if (status != 0) {
+ *error = moonshot_error_new_with_status
+ (MOONSHOT_ERROR_OS_ERROR,
+ status,
+ "Unable to read registry key HKLM\\%s",
+ MOONSHOT_INSTALL_PATH_KEY);
return;
}
length = 1023;
- status = RegQueryValueEx (key, NULL, NULL, &value_type, exe_path, &length);
+ status = RegQueryValueEx (key, NULL, NULL, &value_type, (LPBYTE )exe_path, &length);
if (value_type != REG_SZ) {
- *error = _moonshot_error_new (MOONSHOT_ERROR_OS_ERROR,
- "Value of registry key HKLM\\%s is invalid. "
- "Please set it to point to the location of "
- "moonshot.exe",
- MOONSHOT_INSTALL_PATH_KEY);
+ *error = moonshot_error_new_with_status
+ (MOONSHOT_ERROR_INSTALLATION_ERROR,
+ status,
+ "Value of registry key HKLM\\%s is invalid. Please set it "
+ "to point to the location of moonshot.exe",
+ MOONSHOT_INSTALL_PATH_KEY);
return;
}
if (status != 0) {
- *error = _moonshot_error_new (MOONSHOT_ERROR_OS_ERROR,
- "Unable to read value of registry key HKLM\\%s",
- MOONSHOT_INSTALL_PATH_KEY);
+ *error = moonshot_error_new_with_status
+ (MOONSHOT_ERROR_OS_ERROR,
+ status,
+ "Unable to read value of registry key HKLM\\%s",
+ MOONSHOT_INSTALL_PATH_KEY);
return;
}
startup_info.cb = sizeof (startup_info);
-
- status = CreateProcess (exe_path, NULL,
- NULL, NULL,
- FALSE, DETACHED_PROCESS,
- NULL, NULL,
- &startup_info, &process_info);
-
- if (status != 0) {
- *error = _moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
- "Unable to spawn the moonshot server at '%s'",
- exe_path);
+ success = CreateProcess (exe_path,
+ NULL,
+ NULL,
+ NULL,
+ TRUE,
+ DETACHED_PROCESS,
+ NULL,
+ NULL,
+ &startup_info, &process_info);
+
+ if (! success) {
+ *error = moonshot_error_new_with_status
+ (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
+ GetLastError (),
+ "Unable to spawn the moonshot server at '%s'",
+ exe_path);
return;
}
}
-/*static void dbus_call_complete_cb (DBusGProxy *proxy,
- DBusGProxyCall *call_id,
- void *user_data)
+static void bind_rpc (MoonshotError **error)
{
- GError *error = NULL;
- GSimpleAsyncResult *token;
- MoonshotIdentityData *identity_data;
- gboolean success;
-
- token = G_SIMPLE_ASYNC_RESULT (user_data);
- identity_data = moonshot_identity_data_new ();
-
- dbus_g_proxy_end_call (moonshot_dbus_proxy,
- call_id,
- &error,
- G_TYPE_STRING, &identity_data->nai,
- G_TYPE_STRING, &identity_data->password,
- G_TYPE_STRING, &identity_data->server_certificate_hash,
- G_TYPE_STRING, &identity_data->ca_certificate,
- G_TYPE_STRING, &identity_data->subject_name_constraint,
- G_TYPE_STRING, &identity_data->subject_alt_name_constraint,
- G_TYPE_BOOLEAN, &success,
- G_TYPE_INVALID);
-
- if (error != NULL) {
- g_simple_async_result_set_from_error (token, error);
- }
- else
- if (success == FALSE) {
- error = g_error_new (MOONSHOT_ERROR,
- MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
- "No matching identity was available");
- g_simple_async_result_set_from_error (token, error);
- g_error_free (error);
+ DWORD status;
+ int i;
+
+ status = rpc_client_bind (&moonshot_binding_handle,
+ MOONSHOT_ENDPOINT_NAME,
+ RPC_PER_USER);
+
+ if (status != RPC_S_OK) {
+ *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
+ status);
+ return;
}
- else {
- g_simple_async_result_set_op_res_gpointer (token,
- identity_data,
- moonshot_identity_data_free);
+
+ status = RpcMgmtIsServerListening (moonshot_binding_handle);
+
+ if (status == RPC_S_NOT_LISTENING) {
+ launch_server (error);
+
+ if (*error != NULL)
+ return;
+
+ /* Allow 1 minute for the server to launch before we time out */
+ for (i=0; i<600; i++) {
+ Sleep (100); /* ms */
+
+ status = RpcMgmtIsServerListening (moonshot_binding_handle);
+
+ if (status == RPC_S_OK)
+ return;
+
+ if (status != RPC_S_NOT_LISTENING)
+ break;
+ }
}
- g_simple_async_result_complete (token);
- g_object_unref (token);
+ if (status != RPC_S_OK)
+ *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
+ status);
}
-*/
+
+static void init_rpc (MoonshotError **error)
+{
+ static volatile LONG binding_init_flag = 2;
+
+ /* Hack to avoid requiring a moonshot_init() function. Windows does not
+ * provide any synchronisation primitives that can be statically init'ed,
+ * but we can use its atomic variable access functions to achieve the same.
+ * See: http://msdn.microsoft.com/en-us/library/ms684122%28v=vs.85%29.aspx
+ */
+
+ if (binding_init_flag == 0)
+ return;
+
+ if (InterlockedCompareExchange (&binding_init_flag, 1, 2) == 2) {
+ bind_rpc (error);
+
+ /* We'll handle all exceptions locally to avoid interfering with any
+ * other RPC/other exception handling that goes on in the process,
+ * and so we can store the problem in a MooshotError instead of
+ * aborting.
+ */
+ rpc_set_global_exception_handler_enable (FALSE);
+
+ if (InterlockedCompareExchange (&binding_init_flag, 0, 1) != 1) {
+ /* This should never happen */
+ fprintf (stderr, "moonshot: Internal synchronisation error");
+ }
+ } else {
+ while (binding_init_flag != 0)
+ Sleep (100); /* ms */
+ }
+}
+
int moonshot_get_identity (const char *nai,
const char *password,
char **subject_alt_name_constraint_out,
MoonshotError **error)
{
- int status;
+ int success = FALSE;
+ RpcAsyncCall call;
- status = rpc_client_bind (&moonshot_binding_handle,
- MOONSHOT_ENDPOINT_NAME,
- RPC_PER_USER);
-
- printf ("RPC status: %i\n", status);
-
- /*DBusGProxyCall *call_id;
- GSimpleAsyncResult *result;
- GError *error = NULL;
+ init_rpc (error);
- if (moonshot_dbus_proxy == NULL)
- moonshot_dbus_proxy = dbus_connect (&error);
+ if (*error != NULL)
+ return FALSE;
- if (moonshot_dbus_proxy == NULL) {
- result = g_simple_async_result_new (NULL,
- callback,
- user_data,
- moonshot_get_identity);
- g_simple_async_result_set_from_error (result, error);
- g_simple_async_result_complete_in_idle (result);
- g_error_free (error);
- return;
+ rpc_async_call_init (&call);
+
+ if (nai == NULL) nai = "";
+ if (password == NULL) password = "";
+ if (service == NULL) service = "";
+
+ *nai_out = NULL;
+ *password_out = NULL;
+ *server_certificate_hash_out = NULL;
+ *ca_certificate_out = NULL;
+ *subject_name_constraint_out = NULL;
+ *subject_alt_name_constraint_out = NULL;
+
+ RPC_TRY_EXCEPT {
+ moonshot_get_identity_rpc (&call,
+ nai,
+ password,
+ service,
+ nai_out,
+ password_out,
+ server_certificate_hash_out,
+ ca_certificate_out,
+ subject_name_constraint_out,
+ subject_alt_name_constraint_out);
+
+ success = rpc_async_call_complete_int (&call);
}
+ RPC_EXCEPT {
+ *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
+ RPC_GET_EXCEPTION_CODE ());
+ }
+ RPC_END_EXCEPT
- g_return_if_fail (DBUS_IS_G_PROXY (moonshot_dbus_proxy));
+ if (*error != NULL)
+ return FALSE;
- result = g_simple_async_result_new (NULL,
- callback,
- user_data,
- moonshot_get_identity);
+ if (success == FALSE) {
+ *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
+ "No identity was returned by the Moonshot "
+ "user interface.");
+ return FALSE;
+ }
- call_id = dbus_g_proxy_begin_call (moonshot_dbus_proxy,
- "GetIdentity",
- dbus_call_complete_cb,
- result, NULL,
- G_TYPE_STRING, nai,
- G_TYPE_STRING, password,
- G_TYPE_STRING, service);*/
+ return TRUE;
}
-/*gboolean moonshot_get_identity_finish (GAsyncResult *result,
- char **nai,
- char **password,
- char **server_certificate_hash,
- char **ca_certificate,
- char **subject_name_constraint,
- char **subject_alt_name_constraint,
- GError **error)
+
+int moonshot_get_default_identity (char **nai_out,
+ char **password_out,
+ char **server_certificate_hash_out,
+ char **ca_certificate_out,
+ char **subject_name_constraint_out,
+ char **subject_alt_name_constraint_out,
+ MoonshotError **error)
{
- MoonshotIdentityData *identity;
+ int success = FALSE;
+ RpcAsyncCall call;
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- NULL,
- moonshot_get_identity),
- FALSE);
+ init_rpc (error);
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ if (*error != NULL)
return FALSE;
- identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+ rpc_async_call_init (&call);
+
+ *nai_out = NULL;
+ *password_out = NULL;
+ *server_certificate_hash_out = NULL;
+ *ca_certificate_out = NULL;
+ *subject_name_constraint_out = NULL;
+ *subject_alt_name_constraint_out = NULL;
+
+ RPC_TRY_EXCEPT {
+ moonshot_get_default_identity_rpc (&call,
+ nai_out,
+ password_out,
+ server_certificate_hash_out,
+ ca_certificate_out,
+ subject_name_constraint_out,
+ subject_alt_name_constraint_out);
+
+ success = rpc_async_call_complete_int (&call);
+ }
+ RPC_EXCEPT {
+ *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
+ RPC_GET_EXCEPTION_CODE ());
+ }
+ RPC_END_EXCEPT
- *nai = identity->nai;
- *password = identity->password;
- *server_certificate_hash = identity->server_certificate_hash;
- *ca_certificate = identity->ca_certificate;
- *subject_name_constraint = identity->subject_name_constraint;
- *subject_alt_name_constraint = identity->subject_alt_name_constraint;
+ if (*error != NULL)
+ return FALSE;
+
+ if (success == FALSE) {
+ *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
+ "No identity was returned by the Moonshot "
+ "user interface.");
+ return FALSE;
+ }
return TRUE;
-}*/
+};
+
+int moonshot_install_id_card (const char *display_name,
+ const char *user_name,
+ const char *password,
+ const char *realm,
+ char *rules_patterns[],
+ int rules_patterns_length,
+ char *rules_always_confirm[],
+ int rules_always_confirm_length,
+ char *services[],
+ int services_length,
+ const char *ca_cert,
+ const char *subject,
+ const char *subject_alt,
+ const char *server_cert,
+ int force_flat_file_store,
+ MoonshotError **error)
+{
+ int success = FALSE;
+ init_rpc (error);
+ if (*error != NULL)
+ return FALSE;
- /**
- * Returns the default identity - most recently used.
- *
- * @param nai_out NAI stored in the ID card
- * @param password_out Password stored in the ID card
- *
- * @return true on success, false if no identities are stored
- */
+ if (user_name == NULL) user_name = "";
+ if (password == NULL) password = "";
+ if (realm == NULL) realm = "";
+ if (ca_cert == NULL) ca_cert = "";
+ if (subject == NULL) subject = "";
+ if (subject_alt == NULL) subject_alt = "";
+ if (server_cert == NULL) server_cert = "";
+
+ RPC_TRY_EXCEPT {
+ success = moonshot_install_id_card_rpc (display_name,
+ user_name,
+ password,
+ realm,
+ rules_patterns,
+ rules_patterns_length,
+ rules_always_confirm,
+ rules_always_confirm_length,
+ services,
+ services_length,
+ ca_cert,
+ subject,
+ subject_alt,
+ server_cert,
+ force_flat_file_store);
+ }
+ RPC_EXCEPT {
+ *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
+ RPC_GET_EXCEPTION_CODE ());
+ }
+ RPC_END_EXCEPT
+ return success;
+}
+
+BOOL WINAPI DllMain (HINSTANCE hinst,
+ DWORD reason,
+ void *reserved)
+{
+ if (reason == DLL_PROCESS_DETACH) {
+ /* Process exiting/DLL being unloaded. This is a good
+ * opportunity to free the RPC binding.
+ *
+ * FIXME: we can't use the msrpc-mingw routine for this in case
+ * it was already unloaded. I'd love to work out how to link
+ * that library statically into libmoonshot-0.dll.
+ */
+ RpcBindingFree (&moonshot_binding_handle);
+ }
+
+ return TRUE;
+}