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>
37 #include <msrpc-mingw.h>
39 #include "libmoonshot.h"
40 #include "libmoonshot-common.h"
41 #include "moonshot-msrpc.h"
47 #define MOONSHOT_ENDPOINT_NAME "/org/janet/Moonshot"
48 #define MOONSHOT_INSTALL_PATH_KEY "Software\\Moonshot"
50 void *__RPC_USER MIDL_user_allocate (size_t size) {
54 void __RPC_USER MIDL_user_free (void *data) {
61 void moonshot_free (void *data)
66 static MoonshotError *moonshot_error_new_from_status (MoonshotErrorCode code,
69 MoonshotError *error = malloc (sizeof (MoonshotError));
71 error->message = malloc (256);
73 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPSTR)error->message, 255, NULL);
77 static MoonshotError *moonshot_error_new_with_status (MoonshotErrorCode code,
79 const char *format, ...)
81 MoonshotError *error = malloc (sizeof (MoonshotError));
86 va_start (args, format);
90 buffer = malloc (strlen (format) + 256 + 3);
91 strcpy (buffer, format);
92 strcat (buffer, ": ");
94 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
98 (LPSTR)buffer + strlen (format) + 3,
102 length = _vscprintf (buffer, args);
103 error->message = malloc (length + 1);
104 _vsnprintf (error->message, length, buffer, args);
112 static void launch_server (MoonshotError **error) {
114 STARTUPINFO startup_info = { 0 };
115 PROCESS_INFORMATION process_info = { 0 };
122 status = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
123 MOONSHOT_INSTALL_PATH_KEY,
128 if (status == ERROR_FILE_NOT_FOUND) {
129 *error = moonshot_error_new
130 (MOONSHOT_ERROR_INSTALLATION_ERROR,
131 "Moonshot is not installed correctly on this system. "
132 "(Registry key HKLM\\%s was not found).",
133 MOONSHOT_INSTALL_PATH_KEY);
135 } else if (status != 0) {
136 *error = moonshot_error_new_with_status
137 (MOONSHOT_ERROR_OS_ERROR,
139 "Unable to read registry key HKLM\\%s",
140 MOONSHOT_INSTALL_PATH_KEY);
145 status = RegQueryValueEx (key, NULL, NULL, &value_type, exe_path, &length);
147 if (value_type != REG_SZ) {
148 *error = moonshot_error_new_with_status
149 (MOONSHOT_ERROR_INSTALLATION_ERROR,
151 "Value of registry key HKLM\\%s is invalid. Please set it "
152 "to point to the location of moonshot.exe",
153 MOONSHOT_INSTALL_PATH_KEY);
159 *error = moonshot_error_new_with_status
160 (MOONSHOT_ERROR_OS_ERROR,
162 "Unable to read value of registry key HKLM\\%s",
163 MOONSHOT_INSTALL_PATH_KEY);
167 startup_info.cb = sizeof (startup_info);
169 success = CreateProcess (exe_path,
177 &startup_info, &process_info);
180 *error = moonshot_error_new_with_status
181 (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
183 "Unable to spawn the moonshot server at '%s'",
189 static void bind_rpc (MoonshotError **error)
194 status = rpc_client_bind (&moonshot_binding_handle,
195 MOONSHOT_ENDPOINT_NAME,
198 if (status != RPC_S_OK) {
199 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
204 status = RpcMgmtIsServerListening (moonshot_binding_handle);
206 if (status == RPC_S_NOT_LISTENING) {
207 launch_server (error);
212 /* Allow 1 minute for the server to launch before we time out */
213 for (i=0; i<600; i++) {
214 Sleep (100); /* ms */
216 status = RpcMgmtIsServerListening (moonshot_binding_handle);
218 if (status == RPC_S_OK)
221 if (status != RPC_S_NOT_LISTENING)
226 if (status != RPC_S_OK)
227 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
231 static void init_rpc (MoonshotError **error)
233 static volatile LONG binding_init_flag = 2;
236 /* Hack to avoid requiring a moonshot_init() function. Windows does not
237 * provide any synchronisation primitives that can be statically init'ed,
238 * but we can use its atomic variable access functions to achieve the same.
239 * See: http://msdn.microsoft.com/en-us/library/ms684122%28v=vs.85%29.aspx
242 if (binding_init_flag == 0)
245 if (InterlockedCompareExchange (&binding_init_flag, 1, 2) == 2) {
248 /* We'll handle all exceptions locally to avoid interfering with any
249 * other RPC/other exception handling that goes on in the process,
250 * and so we can store the problem in a MooshotError instead of
253 rpc_set_global_exception_handler_enable (FALSE);
255 if (InterlockedCompareExchange (&binding_init_flag, 0, 1) != 1) {
256 /* This should never happen */
257 fprintf (stderr, "moonshot: Internal synchronisation error");
260 while (binding_init_flag != 0)
261 Sleep (100); /* ms */
266 int moonshot_get_identity (const char *nai,
267 const char *password,
271 char **server_certificate_hash_out,
272 char **ca_certificate_out,
273 char **subject_name_constraint_out,
274 char **subject_alt_name_constraint_out,
275 MoonshotError **error)
285 rpc_async_call_init (&call);
288 *password_out = NULL;
289 *server_certificate_hash_out = NULL;
290 *ca_certificate_out = NULL;
291 *subject_name_constraint_out = NULL;
292 *subject_alt_name_constraint_out = NULL;
295 moonshot_get_identity_rpc (&call,
301 server_certificate_hash_out,
303 subject_name_constraint_out,
304 subject_alt_name_constraint_out);
306 success = rpc_async_call_complete_int (&call);
309 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
310 RPC_GET_EXCEPTION_CODE ());
317 if (success == FALSE) {
318 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
319 "No identity was returned by the Moonshot "
328 int moonshot_get_default_identity (char **nai_out,
330 char **server_certificate_hash_out,
331 char **ca_certificate_out,
332 char **subject_name_constraint_out,
333 char **subject_alt_name_constraint_out,
334 MoonshotError **error)
344 rpc_async_call_init (&call);
347 *password_out = NULL;
348 *server_certificate_hash_out = NULL;
349 *ca_certificate_out = NULL;
350 *subject_name_constraint_out = NULL;
351 *subject_alt_name_constraint_out = NULL;
354 moonshot_get_default_identity_rpc (&call,
357 server_certificate_hash_out,
359 subject_name_constraint_out,
360 subject_alt_name_constraint_out);
362 success = rpc_async_call_complete_int (&call);
365 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
366 RPC_GET_EXCEPTION_CODE ());
373 if (success == FALSE) {
374 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
375 "No identity was returned by the Moonshot "
383 BOOL WINAPI DllMain (HINSTANCE hinst,
387 if (reason == DLL_PROCESS_DETACH) {
388 /* Process exiting/DLL being unloaded. This is a good
389 * opportunity to free the RPC binding.
391 * FIXME: we can't use the msrpc-mingw routine for this in case
392 * it was already unloaded. I'd love to work out how to link
393 * that library statically into libmoonshot-0.dll.
395 RpcBindingFree (&moonshot_binding_handle);