2 * Copyright (c) 2011-2016, 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
37 [DBus (name = "org.janet.Moonshot")]
38 public class MoonshotServer : Object {
40 static MoonshotLogger logger = get_logger("MoonshotServer");
42 private string app_name = "Moonshot";
44 private IdentityManagerApp parent_app;
46 public MoonshotServer(IdentityManagerApp app)
48 logger.trace("MoonshotServer.<constructor>; app=" + (app == null ? "null" : "non-null"));
49 this.parent_app = app;
54 logger.trace("MoonshotServer.show_ui");
56 if (parent_app.view == null) {
57 stderr.printf(app_name, "show_ui: parent_app.view is null!\n");
58 logger.warn("show_ui: parent_app.view is null!");
62 parent_app.explicitly_launched = true;
63 logger.trace("MoonshotServer.show_ui: returning true");
67 public async bool get_identity(string nai,
71 out string password_out,
72 out string server_certificate_hash,
73 out string ca_certificate,
74 out string subject_name_constraint,
75 out string subject_alt_name_constraint)
77 logger.trace(@"MoonshotServer.get_identity: nai='$nai'; service='$service'");
78 var request = new IdentityRequest(parent_app,
82 logger.trace(@"MoonshotServer.get_identity: Calling request.execute()");
83 request.set_callback((IdentityRequest) => get_identity.callback());
85 logger.trace(@"MoonshotServer.get_identity: Back from request.execute()");
87 logger.trace(@"MoonshotServer.get_identity: back from yield");
91 server_certificate_hash = "";
93 subject_name_constraint = "";
94 subject_alt_name_constraint = "";
96 var id_card = request.id_card;
98 if ((id_card != null) && (!id_card.is_no_identity())) {
99 nai_out = id_card.nai;
100 if ((request.password != null) && (request.password != ""))
101 password_out = request.password;
103 password_out = id_card.password;
105 server_certificate_hash = id_card.trust_anchor.server_cert;
106 ca_certificate = id_card.trust_anchor.ca_cert;
107 subject_name_constraint = id_card.trust_anchor.subject;
108 subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
112 if (password_out == null)
114 if (server_certificate_hash == null)
115 server_certificate_hash = "";
116 if (ca_certificate == null)
118 if (subject_name_constraint == null)
119 subject_name_constraint = "";
120 if (subject_alt_name_constraint == null)
121 subject_alt_name_constraint = "";
123 logger.trace(@"MoonshotServer.get_identity: returning with nai_out=$nai_out");
128 logger.trace("MoonshotServer.get_identity: returning false");
132 public async bool get_default_identity(out string nai_out,
133 out string password_out,
134 out string server_certificate_hash,
135 out string ca_certificate,
136 out string subject_name_constraint,
137 out string subject_alt_name_constraint)
139 logger.trace("MoonshotServer.get_default_identity");
140 var request = new IdentityRequest.default(parent_app);
141 request.set_callback((IdentityRequest) => get_default_identity.callback());
147 server_certificate_hash = "";
149 subject_name_constraint = "";
150 subject_alt_name_constraint = "";
152 if (request.id_card != null)
154 nai_out = request.id_card.nai;
155 password_out = request.id_card.password;
157 server_certificate_hash = request.id_card.trust_anchor.server_cert;
158 ca_certificate = request.id_card.trust_anchor.ca_cert;
159 subject_name_constraint = request.id_card.trust_anchor.subject;
160 subject_alt_name_constraint = request.id_card.trust_anchor.subject_alt;
164 if (password_out == null)
166 if (server_certificate_hash == null)
167 server_certificate_hash = "";
168 if (ca_certificate == null)
170 if (subject_name_constraint == null)
171 subject_name_constraint = "";
172 if (subject_alt_name_constraint == null)
173 subject_alt_name_constraint = "";
175 logger.trace("MoonshotServer.get_default_identity: returning true");
182 public bool install_id_card(string display_name,
186 string[] ?rules_patterns,
187 string[] ?rules_always_confirm,
193 int force_flat_file_store)
195 IdCard idcard = new IdCard();
197 idcard.display_name = display_name;
198 idcard.username = user_name;
199 idcard.password = password;
200 if ((password != null) && (password != ""))
201 idcard.store_password = true;
202 idcard.issuer = realm;
203 idcard.update_services(services);
204 var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, false);
206 if (!ta.is_empty()) {
207 // We have to set the datetime_added here, because it isn't delivered via IPC.
208 string ta_datetime_added = TrustAnchor.format_datetime_now();
209 ta.set_datetime_added(ta_datetime_added);
210 logger.trace("install_id_card : Set ta_datetime_added for '%s' to '%s'; ca_cert='%s'; server_cert='%s'".printf(idcard.display_name, ta.datetime_added, ta.ca_cert, ta.server_cert));
212 idcard.set_trust_anchor_from_store(ta);
214 logger.trace("install_id_card: Card '%s' has services: '%s'"
215 .printf(idcard.display_name, idcard.get_services_string("; ")));
217 logger.trace(@"Installing IdCard named '$(idcard.display_name)'; ca_cert='$(idcard.trust_anchor.ca_cert)'; server_cert='$(idcard.trust_anchor.server_cert)'");
220 if (rules_patterns.length == rules_always_confirm.length)
222 /* workaround Centos vala array property bug: use temp array */
223 Rule[] rules = new Rule[rules_patterns.length];
225 for (int i = 0; i < rules.length; i++)
227 rules[i].pattern = rules_patterns[i];
228 rules[i].always_confirm = rules_always_confirm[i];
230 idcard.rules = rules;
233 ArrayList<IdCard>? old_duplicates = null;
234 var ret = parent_app.add_identity(idcard, (force_flat_file_store != 0), out old_duplicates);
236 if (old_duplicates != null) {
237 // Printing to stdout here is ugly behavior; but it's old behavior that
238 // may be expected. (TODO: Do we need to keep this?)
239 foreach (IdCard id_card in old_duplicates) {
240 stdout.printf("removed duplicate id for '%s'\n", id_card.nai);
247 public int install_from_file(string file_name)
249 var webp = new WebProvisioning.Parser(file_name);
253 int installed_cards = 0;
254 foreach (IdCard card in webp.cards)
256 string[] rules_patterns = {};
257 string[] rules_always_confirm = {};
259 if (card.rules.length > 0)
262 rules_patterns = new string[card.rules.length];
263 rules_always_confirm = new string[card.rules.length];
264 foreach (Rule r in card.rules)
266 rules_patterns[i] = r.pattern;
267 rules_always_confirm[i] = r.always_confirm;
273 // prevent a crash by holding the reference to otherwise
276 // string[] svcs = card.services.to_array();
277 // string[] svcs = card.services.to_array()[:];
278 string[] svcs = new string[card.services.size];
279 for (int i = 0; i < card.services.size; i++) {
280 svcs[i] = card.services[i];
283 logger.trace(@"install_from_file: Adding card with display name '$(card.display_name)'");
284 result = install_id_card(card.display_name,
289 rules_always_confirm,
291 card.trust_anchor.ca_cert,
292 card.trust_anchor.subject,
293 card.trust_anchor.subject_alt,
294 card.trust_anchor.server_cert,
300 return installed_cards;
303 public async bool confim_ca_certificate(string nai,
307 logger.trace(@"MoonshotServer.confirm_ca_certificate: nai='$nai'; realm='$realm'; ca_hash='$ca_hash'");
318 using MoonshotRpcInterface;
320 /* This class must be a singleton, because we use a global RPC
321 * binding handle. I cannot picture a situation where more than
322 * one instance of the same interface would be needed so this
323 * shouldn't be a problem.
325 * Shutdown is automatically done by the RPC runtime when the
328 public class MoonshotServer : Object {
329 private static IdentityManagerApp parent_app;
331 private static MoonshotServer instance = null;
333 public static void start(IdentityManagerApp app)
336 Rpc.server_start(MoonshotRpcInterface.spec, "/org/janet/Moonshot", Rpc.Flags.PER_USER);
339 public static MoonshotServer get_instance()
341 if (instance == null)
342 instance = new MoonshotServer();
346 [CCode (cname = "moonshot_get_identity_rpc")]
347 public static void get_identity(Rpc.AsyncCall call,
352 ref string password_out,
353 ref string server_certificate_hash,
354 ref string ca_certificate,
355 ref string subject_name_constraint,
356 ref string subject_alt_name_constraint)
358 logger.trace("(static) get_identity");
362 var request = new IdentityRequest(parent_app,
367 // Pass execution to the main loop and block the RPC thread
368 request.mutex = new Mutex();
369 request.cond = new Cond();
370 request.set_callback(return_identity_cb);
372 request.mutex.lock();
373 Idle.add(request.execute);
375 while (request.complete == false)
376 request.cond.wait(request.mutex);
380 server_certificate_hash = "";
382 subject_name_constraint = "";
383 subject_alt_name_constraint = "";
385 var id_card = request.id_card;
387 if (id_card != null) {
388 // The strings are freed by the RPC runtime
389 nai_out = id_card.nai;
390 password_out = id_card.password;
391 server_certificate_hash = id_card.trust_anchor.server_cert;
392 ca_certificate = id_card.trust_anchor.ca_cert;
393 subject_name_constraint = id_card.trust_anchor.subject;
394 subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
396 return_if_fail(nai_out != null);
397 return_if_fail(password_out != null);
398 return_if_fail(server_certificate_hash != null);
399 return_if_fail(ca_certificate != null);
400 return_if_fail(subject_name_constraint != null);
401 return_if_fail(subject_alt_name_constraint != null);
406 // The outputs must be set before this function is called. For this
407 // reason they are 'ref' not 'out' parameters - Vala assigns to the
408 // 'out' parameters only at the end of the function, which is too
410 call.return(&result);
412 request.cond.signal();
413 request.mutex.unlock();
416 [CCode (cname = "moonshot_get_default_identity_rpc")]
417 public static void get_default_identity(Rpc.AsyncCall call,
419 ref string password_out,
420 ref string server_certificate_hash,
421 ref string ca_certificate,
422 ref string subject_name_constraint,
423 ref string subject_alt_name_constraint)
425 logger.trace("(static) get_default_identity");
429 var request = new IdentityRequest.default(parent_app);
430 request.mutex = new Mutex();
431 request.cond = new Cond();
432 request.set_callback(return_identity_cb);
434 request.mutex.lock();
435 Idle.add(request.execute);
437 while (request.complete == false)
438 request.cond.wait(request.mutex);
442 server_certificate_hash = "";
444 subject_name_constraint = "";
445 subject_alt_name_constraint = "";
447 if (request.id_card != null)
449 nai_out = request.id_card.nai;
450 password_out = request.id_card.password;
451 server_certificate_hash = "certificate";
453 return_if_fail(nai_out != null);
454 return_if_fail(password_out != null);
455 return_if_fail(server_certificate_hash != null);
456 return_if_fail(ca_certificate != null);
457 return_if_fail(subject_name_constraint != null);
458 return_if_fail(subject_alt_name_constraint != null);
467 call.return(&result);
469 request.cond.signal();
470 request.mutex.unlock();
473 // Called from the main loop thread when an identity has
475 static void return_identity_cb(IdentityRequest request) {
476 // Notify the RPC thread that the request is complete
477 request.mutex.lock();
478 request.cond.signal();
480 // Block the main loop until the RPC call has returned
481 // to avoid any races
482 request.cond.wait(request.mutex);
483 request.mutex.unlock();
486 [CCode (cname = "moonshot_install_id_card_rpc")]
487 public static bool install_id_card(string display_name,
491 string[] rules_patterns,
492 string[] rules_always_confirm,
498 bool force_flat_file_store)
500 logger.trace("(static) install_id_card");
501 IdCard idcard = new IdCard();
503 bool success = false;
504 Mutex mutex = new Mutex();
505 Cond cond = new Cond();
507 idcard.display_name = display_name;
508 idcard.username = user_name;
509 idcard.password = password;
510 idcard.issuer = realm;
511 idcard.services = services;
512 idcard.trust_anchor.ca_cert = ca_cert;
513 idcard.trust_anchor.subject = subject;
514 idcard.trust_anchor.subject_alt = subject_alt;
515 idcard.trust_anchor.server_cert = server_cert;
517 if (rules_patterns.length == rules_always_confirm.length)
519 idcard.rules = new Rule[rules_patterns.length];
521 for (int i = 0; i < idcard.rules.length; i++)
523 idcard.rules[i].pattern = rules_patterns[i];
524 idcard.rules[i].always_confirm = rules_always_confirm[i];
530 ArrayList<IdCard>? old_duplicates = null;
531 // Defer addition to the main loop thread.
534 success = parent_app.add_identity(idcard, force_flat_file_store, out old_duplicates);
535 foreach (IdCard id_card in old_duplicates) {
536 stdout.printf("removing duplicate id for '%s'\n", new_card.nai);