1 /* libmoonshot - Moonshot client library
2 * Copyright (c) 2011, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Author: Sam Thursfield <samthursfield@codethink.co.uk>
39 #include <msrpc-mingw.h>
42 #include "libmoonshot.h"
43 #include "libmoonshot-common.h"
44 #include "moonshot-msrpc.h"
50 #define MOONSHOT_ENDPOINT_NAME "/org/janet/Moonshot"
51 #define MOONSHOT_INSTALL_PATH_KEY "Software\\Moonshot"
52 #define MOONSHOT_STARTUP_ARGS "--dbus-launched"
54 void *__RPC_USER MIDL_user_allocate (size_t size) {
58 void __RPC_USER MIDL_user_free (void *data) {
65 void moonshot_free (void *data)
70 static MoonshotError *moonshot_error_new_from_status (MoonshotErrorCode code,
73 MoonshotError *error = malloc (sizeof (MoonshotError));
75 error->message = malloc (256);
77 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPSTR)error->message, 255, NULL);
81 static MoonshotError *moonshot_error_new_with_status (MoonshotErrorCode code,
83 const char *format, ...)
85 MoonshotError *error = malloc (sizeof (MoonshotError));
90 va_start (args, format);
94 buffer = malloc (strlen (format) + 256 + 3);
95 strcpy (buffer, format);
96 strcat (buffer, ": ");
98 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
102 (LPSTR)buffer + strlen (format) + 3,
106 length = _vscprintf (buffer, args);
107 error->message = malloc (length + 1);
108 _vsnprintf (error->message, length, buffer, args);
116 static void launch_server (MoonshotError **error) {
118 STARTUPINFO startup_info = { 0 };
119 PROCESS_INFORMATION process_info = { 0 };
123 DWORD commandline_length;
125 char* commandline=NULL;
128 status = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
129 MOONSHOT_INSTALL_PATH_KEY,
134 if (status == ERROR_FILE_NOT_FOUND) {
135 *error = moonshot_error_new
136 (MOONSHOT_ERROR_INSTALLATION_ERROR,
137 "Moonshot is not installed correctly on this system. "
138 "(Registry key HKLM\\%s was not found).",
139 MOONSHOT_INSTALL_PATH_KEY);
141 } else if (status != 0) {
142 *error = moonshot_error_new_with_status
143 (MOONSHOT_ERROR_OS_ERROR,
145 "Unable to read registry key HKLM\\%s",
146 MOONSHOT_INSTALL_PATH_KEY);
150 status = RegQueryValueEx (key, NULL, NULL, &value_type, (PVOID )exe_path, &length);
151 if (status == ERROR_SUCCESS) {
152 exe_path = (char *)malloc(length + 1);
153 if (exe_path != NULL) {
154 status = RegQueryValueEx (key, NULL, NULL, &value_type, (PVOID )exe_path, &length);
156 *error = moonshot_error_new
157 (MOONSHOT_ERROR_OS_ERROR,
158 "Out of memory allocating %d bytes for registry value",
164 if (status != ERROR_SUCCESS) {
165 *error = moonshot_error_new_with_status
166 (MOONSHOT_ERROR_OS_ERROR,
168 "Unable to read value of registry key HKLM\\%s",
169 MOONSHOT_INSTALL_PATH_KEY);
173 if (value_type != REG_SZ) {
174 *error = moonshot_error_new_with_status
175 (MOONSHOT_ERROR_INSTALLATION_ERROR,
177 "Value of registry key HKLM\\%s is invalid. Please set it "
178 "to point to the location of moonshot.exe",
179 MOONSHOT_INSTALL_PATH_KEY);
183 exe_path[length] = 0;
184 startup_info.cb = sizeof (startup_info);
185 commandline_length = length + 1 + sizeof(MOONSHOT_STARTUP_ARGS);
186 commandline = malloc(commandline_length + 1);
187 if (commandline == NULL) {
188 *error = moonshot_error_new
189 (MOONSHOT_ERROR_OS_ERROR,
190 "Out of memory allocating %d bytes for moonshot commandline.",
194 snprintf(commandline, commandline_length, "%s %s", exe_path, MOONSHOT_STARTUP_ARGS);
195 commandline[commandline_length] = 0;
196 success = CreateProcess (exe_path,
204 &startup_info, &process_info);
207 *error = moonshot_error_new_with_status
208 (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
210 "Unable to spawn the moonshot server at '%s'",
221 static void bind_rpc (MoonshotError **error)
226 status = rpc_client_bind (&moonshot_binding_handle,
227 MOONSHOT_ENDPOINT_NAME,
230 if (status != RPC_S_OK) {
231 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
236 status = RpcMgmtIsServerListening (moonshot_binding_handle);
238 if (status == RPC_S_NOT_LISTENING) {
239 launch_server (error);
244 /* Allow 1 minute for the server to launch before we time out */
245 for (i=0; i<600; i++) {
246 Sleep (100); /* ms */
248 status = RpcMgmtIsServerListening (moonshot_binding_handle);
250 if (status == RPC_S_OK)
253 if (status != RPC_S_NOT_LISTENING)
258 if (status != RPC_S_OK)
259 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
263 static void init_rpc (MoonshotError **error)
265 static volatile LONG binding_init_flag = 2;
267 /* Hack to avoid requiring a moonshot_init() function. Windows does not
268 * provide any synchronisation primitives that can be statically init'ed,
269 * but we can use its atomic variable access functions to achieve the same.
270 * See: http://msdn.microsoft.com/en-us/library/ms684122%28v=vs.85%29.aspx
273 if (binding_init_flag == 0)
276 if (InterlockedCompareExchange (&binding_init_flag, 1, 2) == 2) {
279 /* We'll handle all exceptions locally to avoid interfering with any
280 * other RPC/other exception handling that goes on in the process,
281 * and so we can store the problem in a MooshotError instead of
284 rpc_set_global_exception_handler_enable (FALSE);
286 if (InterlockedCompareExchange (&binding_init_flag, 0, 1) != 1) {
287 /* This should never happen */
288 fprintf (stderr, "moonshot: Internal synchronisation error");
291 while (binding_init_flag != 0)
292 Sleep (100); /* ms */
297 int moonshot_get_identity (const char *nai,
298 const char *password,
302 char **server_certificate_hash_out,
303 char **ca_certificate_out,
304 char **subject_name_constraint_out,
305 char **subject_alt_name_constraint_out,
306 MoonshotError **error)
316 rpc_async_call_init (&call);
318 if (nai == NULL) nai = "";
319 if (password == NULL) password = "";
320 if (service == NULL) service = "";
323 *password_out = NULL;
324 *server_certificate_hash_out = NULL;
325 *ca_certificate_out = NULL;
326 *subject_name_constraint_out = NULL;
327 *subject_alt_name_constraint_out = NULL;
330 c_moonshot_get_identity_rpc (&call,
336 server_certificate_hash_out,
338 subject_name_constraint_out,
339 subject_alt_name_constraint_out);
341 success = rpc_async_call_complete_int (&call);
344 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
345 RPC_GET_EXCEPTION_CODE ());
352 if (success == FALSE) {
353 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
354 "No identity was returned by the Moonshot "
363 int moonshot_get_default_identity (char **nai_out,
365 char **server_certificate_hash_out,
366 char **ca_certificate_out,
367 char **subject_name_constraint_out,
368 char **subject_alt_name_constraint_out,
369 MoonshotError **error)
379 rpc_async_call_init (&call);
382 *password_out = NULL;
383 *server_certificate_hash_out = NULL;
384 *ca_certificate_out = NULL;
385 *subject_name_constraint_out = NULL;
386 *subject_alt_name_constraint_out = NULL;
389 c_moonshot_get_default_identity_rpc (&call,
392 server_certificate_hash_out,
394 subject_name_constraint_out,
395 subject_alt_name_constraint_out);
397 success = rpc_async_call_complete_int (&call);
400 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
401 RPC_GET_EXCEPTION_CODE ());
408 if (success == FALSE) {
409 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
410 "No identity was returned by the Moonshot "
418 int moonshot_install_id_card (const char *display_name,
419 const char *user_name,
420 const char *password,
422 char *rules_patterns[],
423 int rules_patterns_length,
424 char *rules_always_confirm[],
425 int rules_always_confirm_length,
430 const char *subject_alt,
431 const char *server_cert,
432 int force_flat_file_store,
433 MoonshotError **error)
441 if (user_name == NULL) user_name = "";
442 if (password == NULL) password = "";
443 if (realm == NULL) realm = "";
444 if (ca_cert == NULL) ca_cert = "";
445 if (subject == NULL) subject = "";
446 if (subject_alt == NULL) subject_alt = "";
447 if (server_cert == NULL) server_cert = "";
450 success = c_moonshot_install_id_card_rpc (display_name,
455 rules_patterns_length,
456 rules_always_confirm,
457 rules_always_confirm_length,
464 force_flat_file_store);
467 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
468 RPC_GET_EXCEPTION_CODE ());
474 BOOL WINAPI DllMain (HINSTANCE hinst,
478 if (reason == DLL_PROCESS_DETACH) {
479 /* Process exiting/DLL being unloaded. This is a good
480 * opportunity to free the RPC binding.
482 * FIXME: we can't use the msrpc-mingw routine for this in case
483 * it was already unloaded. I'd love to work out how to link
484 * that library statically into libmoonshot-0.dll.
486 RpcBindingFree (&moonshot_binding_handle);