Split moonshot-server.vala into moonshot-server-linix.vala and moonshot-server-msrpc...
[moonshot-ui.git] / src / moonshot-server-win32.vala
1 /*
2  * Copyright (c) 2011-2016, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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
30  * SUCH DAMAGE.
31 */
32
33 using Gee;
34
35 #if IPC_DBUS
36
37 [DBus (name = "org.janet.Moonshot")]
38 public class MoonshotServer : Object {
39
40     static MoonshotLogger logger = get_logger("MoonshotServer");
41
42     private string app_name = "Moonshot";
43
44     private IdentityManagerApp parent_app;
45
46     public MoonshotServer(IdentityManagerApp app)
47     {
48         logger.trace("MoonshotServer.<constructor>; app=" + (app == null ? "null" : "non-null"));
49         this.parent_app = app;
50     }
51
52     public bool show_ui()
53     {
54         logger.trace("MoonshotServer.show_ui");
55
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!");
59             return false;
60         }
61         parent_app.show();
62         parent_app.explicitly_launched = true;
63         logger.trace("MoonshotServer.show_ui: returning true");
64         return true;
65     }
66
67     public async bool get_identity(string nai,
68                                    string password,
69                                    string service,
70                                    out string nai_out,
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)
76     {
77         logger.trace(@"MoonshotServer.get_identity: nai='$nai'; service='$service'");
78         var request = new IdentityRequest(parent_app,
79                                           nai,
80                                           password,
81                                           service);
82         logger.trace(@"MoonshotServer.get_identity: Calling request.execute()");
83         request.set_callback((IdentityRequest) => get_identity.callback());
84         request.execute();
85         logger.trace(@"MoonshotServer.get_identity: Back from request.execute()");
86         yield;
87         logger.trace(@"MoonshotServer.get_identity: back from yield");
88
89         nai_out = "";
90         password_out = "";
91         server_certificate_hash = "";
92         ca_certificate = "";
93         subject_name_constraint = "";
94         subject_alt_name_constraint = "";
95
96         var id_card = request.id_card;
97
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;
102             else
103                 password_out = id_card.password;
104
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;
109
110             if (nai_out == null)
111                 nai_out = "";
112             if (password_out == null)
113                 password_out = "";
114             if (server_certificate_hash == null)
115                 server_certificate_hash = "";
116             if (ca_certificate == null)
117                 ca_certificate = "";
118             if (subject_name_constraint == null)
119                 subject_name_constraint = "";
120             if (subject_alt_name_constraint == null)
121                 subject_alt_name_constraint = "";
122
123             logger.trace(@"MoonshotServer.get_identity: returning with nai_out=$nai_out");
124
125             return true;
126         }
127
128         logger.trace("MoonshotServer.get_identity: returning false");
129         return false;
130     }
131
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)
138     {
139         logger.trace("MoonshotServer.get_default_identity");
140         var request = new IdentityRequest.default(parent_app);
141         request.set_callback((IdentityRequest) => get_default_identity.callback());
142         request.execute();
143         yield;
144
145         nai_out = "";
146         password_out = "";
147         server_certificate_hash = "";
148         ca_certificate = "";
149         subject_name_constraint = "";
150         subject_alt_name_constraint = "";
151
152         if (request.id_card != null)
153         {
154             nai_out = request.id_card.nai;
155             password_out = request.id_card.password;
156
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;
161
162             if (nai_out == null)
163                 nai_out = "";
164             if (password_out == null)
165                 password_out = "";
166             if (server_certificate_hash == null)
167                 server_certificate_hash = "";
168             if (ca_certificate == null)
169                 ca_certificate = "";
170             if (subject_name_constraint == null)
171                 subject_name_constraint = "";
172             if (subject_alt_name_constraint == null)
173                 subject_alt_name_constraint = "";
174
175             logger.trace("MoonshotServer.get_default_identity: returning true");
176             return true;
177         }
178
179         return false;
180     }
181
182     public bool install_id_card(string   display_name,
183                                 string   user_name,
184                                 string   ?password,
185                                 string   ?realm,
186                                 string[] ?rules_patterns,
187                                 string[] ?rules_always_confirm,
188                                 string[] ?services,
189                                 string   ?ca_cert,
190                                 string   ?subject,
191                                 string   ?subject_alt,
192                                 string   ?server_cert,
193                                 int      force_flat_file_store)
194     {
195         IdCard idcard = new IdCard();
196
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);
205
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));
211         }
212         idcard.set_trust_anchor_from_store(ta);
213
214         logger.trace("install_id_card: Card '%s' has services: '%s'"
215                      .printf(idcard.display_name, idcard.get_services_string("; ")));
216
217         logger.trace(@"Installing IdCard named '$(idcard.display_name)'; ca_cert='$(idcard.trust_anchor.ca_cert)'; server_cert='$(idcard.trust_anchor.server_cert)'");
218
219
220         if (rules_patterns.length == rules_always_confirm.length)
221         {
222             /* workaround Centos vala array property bug: use temp array */
223             Rule[] rules = new Rule[rules_patterns.length];
224          
225             for (int i = 0; i < rules.length; i++)
226             { 
227                 rules[i].pattern = rules_patterns[i];
228                 rules[i].always_confirm = rules_always_confirm[i];
229             }
230             idcard.rules = rules;
231         }
232
233         ArrayList<IdCard>? old_duplicates = null;
234         var ret = parent_app.add_identity(idcard, (force_flat_file_store != 0), out old_duplicates);
235
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);
241             }
242         }
243         return ret;
244     }
245
246
247     public int install_from_file(string file_name)
248     {
249         var webp = new WebProvisioning.Parser(file_name);
250
251         webp.parse();
252         bool result = false;
253         int installed_cards = 0;
254         foreach (IdCard card in webp.cards)
255         {
256             string[] rules_patterns = {};
257             string[] rules_always_confirm = {};
258         
259             if (card.rules.length > 0)
260             {
261                 int i = 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)
265                 {
266                     rules_patterns[i] = r.pattern;
267                     rules_always_confirm[i] = r.always_confirm;
268                     i++;
269                 }
270             } 
271
272
273             // prevent a crash by holding the reference to otherwise
274             // unowned array(?)
275
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];
281             }
282
283             logger.trace(@"install_from_file: Adding card with display name '$(card.display_name)'");
284             result = install_id_card(card.display_name,
285                                      card.username,
286                                      card.password,
287                                      card.issuer,
288                                      rules_patterns,
289                                      rules_always_confirm,
290                                      svcs,
291                                      card.trust_anchor.ca_cert,
292                                      card.trust_anchor.subject,
293                                      card.trust_anchor.subject_alt,
294                                      card.trust_anchor.server_cert,
295                                      0);
296             if (result) {
297                 installed_cards++;
298             }
299         }
300         return installed_cards;
301     }
302
303     public async bool confim_ca_certificate(string nai,
304                                             string realm,
305                                             string ca_hash)
306     {
307         logger.trace(@"MoonshotServer.confirm_ca_certificate: nai='$nai'; realm='$realm'; ca_hash='$ca_hash'");
308
309         return true;
310     }
311 }
312
313
314
315 #elif IPC_MSRPC
316
317 using Rpc;
318 using MoonshotRpcInterface;
319
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.
324  *
325  * Shutdown is automatically done by the RPC runtime when the
326  * process ends
327  */
328 public class MoonshotServer : Object {
329     private static IdentityManagerApp parent_app;
330
331     private static MoonshotServer instance = null;
332
333     public static void start(IdentityManagerApp app)
334     {
335         parent_app = app;
336         Rpc.server_start(MoonshotRpcInterface.spec, "/org/janet/Moonshot", Rpc.Flags.PER_USER);
337     }
338
339     public static MoonshotServer get_instance()
340     {
341         if (instance == null)
342             instance = new MoonshotServer();
343         return instance;
344     }
345
346     [CCode (cname = "moonshot_get_identity_rpc")]
347     public static void get_identity(Rpc.AsyncCall call,
348                                     string nai,
349                                     string password,
350                                     string service,
351                                     ref string nai_out,
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)
357     {
358         logger.trace("(static) get_identity");
359
360         bool result = false;
361
362         var request = new IdentityRequest(parent_app,
363                                           nai,
364                                           password,
365                                           service);
366
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);
371
372         request.mutex.lock();
373         Idle.add(request.execute);
374
375         while (request.complete == false)
376             request.cond.wait(request.mutex);
377
378         nai_out = "";
379         password_out = "";
380         server_certificate_hash = "";
381         ca_certificate = "";
382         subject_name_constraint = "";
383         subject_alt_name_constraint = "";
384
385         var id_card = request.id_card;
386
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;
395
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);
402
403             result = true;
404         }
405
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
409         // late.
410         call.return(&result);
411
412         request.cond.signal();
413         request.mutex.unlock();
414     }
415
416     [CCode (cname = "moonshot_get_default_identity_rpc")]
417     public static void get_default_identity(Rpc.AsyncCall call,
418                                             ref string nai_out,
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)
424     {
425         logger.trace("(static) get_default_identity");
426
427         bool result;
428
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);
433
434         request.mutex.lock();
435         Idle.add(request.execute);
436
437         while (request.complete == false)
438             request.cond.wait(request.mutex);
439
440         nai_out = "";
441         password_out = "";
442         server_certificate_hash = "";
443         ca_certificate = "";
444         subject_name_constraint = "";
445         subject_alt_name_constraint = "";
446
447         if (request.id_card != null)
448         {
449             nai_out = request.id_card.nai;
450             password_out = request.id_card.password;
451             server_certificate_hash = "certificate";
452
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);
459
460             result = true;
461         }
462         else
463         {
464             result = false;
465         }
466
467         call.return(&result);
468
469         request.cond.signal();
470         request.mutex.unlock();
471     }
472
473     // Called from the main loop thread when an identity has
474     // been selected
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();
479
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();
484     }
485
486     [CCode (cname = "moonshot_install_id_card_rpc")]
487     public static bool install_id_card(string     display_name,
488                                        string     user_name,
489                                        string     password,
490                                        string     realm,
491                                        string[]   rules_patterns,
492                                        string[]   rules_always_confirm,
493                                        string[]   services,
494                                        string     ca_cert,
495                                        string     subject,
496                                        string     subject_alt,
497                                        string     server_cert,
498                                        bool       force_flat_file_store)
499     {
500         logger.trace("(static) install_id_card");
501         IdCard idcard = new IdCard();
502
503         bool success = false;
504         Mutex mutex = new Mutex();
505         Cond cond = new Cond();
506
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;
516
517         if (rules_patterns.length == rules_always_confirm.length)
518         {
519             idcard.rules = new Rule[rules_patterns.length];
520          
521             for (int i = 0; i < idcard.rules.length; i++)
522             { 
523                 idcard.rules[i].pattern = rules_patterns[i];
524                 idcard.rules[i].always_confirm = rules_always_confirm[i];
525             }
526         }
527
528         mutex.lock();
529
530         ArrayList<IdCard>? old_duplicates = null;
531         // Defer addition to the main loop thread.
532         Idle.add(() => {
533                 mutex.lock();
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);
537                 }
538                 cond.signal();
539                 mutex.unlock();
540                 return false;
541             });
542
543         cond.wait(mutex);
544         mutex.unlock();
545
546         return success;
547     }
548 }
549
550 #endif