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"
45 #define MOONSHOT_ENDPOINT_NAME "/org/janet/Moonshot"
46 #define MOONSHOT_INSTALL_PATH_KEY "Software\\Moonshot"
49 static MoonshotError *moonshot_error_new_from_status (MoonshotErrorCode code,
52 MoonshotError *error = malloc (sizeof (MoonshotError));
54 error->message = malloc (256);
56 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPSTR)error->message, 255, NULL);
61 static void launch_server (MoonshotError **error) {
63 STARTUPINFO startup_info = { 0 };
64 PROCESS_INFORMATION process_info = { 0 };
70 status = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
71 MOONSHOT_INSTALL_PATH_KEY,
77 *error = moonshot_error_new (MOONSHOT_ERROR_OS_ERROR,
78 "Unable to read registry key HKLM\\%s",
79 MOONSHOT_INSTALL_PATH_KEY);
84 status = RegQueryValueEx (key, NULL, NULL, &value_type, exe_path, &length);
86 if (value_type != REG_SZ) {
87 *error = moonshot_error_new (MOONSHOT_ERROR_OS_ERROR,
88 "Value of registry key HKLM\\%s is invalid. "
89 "Please set it to point to the location of "
91 MOONSHOT_INSTALL_PATH_KEY);
97 *error = moonshot_error_new (MOONSHOT_ERROR_OS_ERROR,
98 "Unable to read value of registry key HKLM\\%s",
99 MOONSHOT_INSTALL_PATH_KEY);
103 startup_info.cb = sizeof (startup_info);
105 status = CreateProcess (exe_path, NULL,
107 FALSE, DETACHED_PROCESS,
109 &startup_info, &process_info);
112 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
113 "Unable to spawn the moonshot server at '%s'",
119 static void bind_rpc (MoonshotError **error)
124 status = rpc_client_bind (&moonshot_binding_handle,
125 MOONSHOT_ENDPOINT_NAME,
128 if (status != RPC_S_OK) {
129 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
134 status = RpcMgmtIsServerListening (moonshot_binding_handle);
136 if (status == RPC_S_NOT_LISTENING) {
137 //launch_server (error);
139 /* Allow 5 seconds for the server to launch before we time out */
140 //for (i=0; i<50; i++) {
141 // Sleep (100); /* ms */
143 status = RpcMgmtIsServerListening (moonshot_binding_handle);
145 if (status == RPC_S_OK)
148 if (status != RPC_S_NOT_LISTENING)
153 if (status != RPC_S_OK)
154 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
158 static void init_rpc (MoonshotError **error)
160 static volatile LONG binding_init_flag = 2;
163 /* Hack to avoid requiring a moonshot_init() function. Windows does not
164 * provide any synchronisation primitives that can be statically init'ed,
165 * but we can use its atomic variable access functions to achieve the same.
166 * See: http://msdn.microsoft.com/en-us/library/ms684122%28v=vs.85%29.aspx
169 if (binding_init_flag == 0)
172 if (InterlockedCompareExchange (&binding_init_flag, 1, 2) == 2) {
175 /* We'll handle all exceptions locally to avoid interfering with any
176 * other RPC/other exception handling that goes on in the process,
177 * and so we can store the problem in a MooshotError instead of
180 rpc_set_global_exception_handler_enable (FALSE);
182 if (InterlockedCompareExchange (&binding_init_flag, 0, 1) != 1) {
183 /* This should never happen */
184 fprintf (stderr, "moonshot: Internal synchronisation error");
187 while (binding_init_flag != 0)
188 Sleep (100); /* ms */
193 int moonshot_get_identity (const char *nai,
194 const char *password,
198 char **server_certificate_hash_out,
199 char **ca_certificate_out,
200 char **subject_name_constraint_out,
201 char **subject_alt_name_constraint_out,
202 MoonshotError **error)
212 rpc_async_call_init (&call);
216 server_certificate_hash_out = NULL;
217 ca_certificate_out = NULL;
218 subject_name_constraint_out = NULL;
219 subject_alt_name_constraint_out = NULL;
222 moonshot_get_identity_rpc (&call,
228 server_certificate_hash_out,
230 subject_name_constraint_out,
231 subject_alt_name_constraint_out);
233 success = rpc_async_call_complete_int (&call);
236 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
237 RPC_GET_EXCEPTION_CODE ());
244 if (success == FALSE) {
245 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
246 "No identity was returned by the Moonshot "
255 int moonshot_get_default_identity (char **nai_out,
257 char **server_certificate_hash_out,
258 char **ca_certificate_out,
259 char **subject_name_constraint_out,
260 char **subject_alt_name_constraint_out,
261 MoonshotError **error)
271 rpc_async_call_init (&call);
275 server_certificate_hash_out = NULL;
276 ca_certificate_out = NULL;
277 subject_name_constraint_out = NULL;
278 subject_alt_name_constraint_out = NULL;
281 moonshot_get_default_identity_rpc (&call,
284 server_certificate_hash_out,
286 subject_name_constraint_out,
287 subject_alt_name_constraint_out);
289 success = rpc_async_call_complete_int (&call);
292 *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR,
293 RPC_GET_EXCEPTION_CODE ());
300 if (success == FALSE) {
301 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
302 "No identity was returned by the Moonshot "