First pass at supporting date/time added for Trust Anchors
[moonshot-ui.git] / src / moonshot-server.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 #if IPC_DBUS
33
34 [DBus (name = "org.janet.Moonshot")]
35 public class MoonshotServer : Object {
36
37     static MoonshotLogger logger = get_logger("MoonshotServer");
38
39     private string app_name = "Moonshot";
40
41     private IdentityManagerApp parent_app;
42
43     public MoonshotServer(IdentityManagerApp app)
44     {
45         logger.trace("MoonshotServer.<constructor>; app=" + (app == null ? "null" : "non-null"));
46         this.parent_app = app;
47     }
48
49     public bool show_ui()
50     {
51         logger.trace("MoonshotServer.show_ui");
52
53         if (parent_app.view == null) {
54             stderr.printf(app_name, "show_ui: parent_app.view is null!\n");
55             logger.warn("show_ui: parent_app.view is null!");
56             return false;
57         }
58         parent_app.show();
59         parent_app.explicitly_launched = true;
60         logger.trace("MoonshotServer.show_ui: returning true");
61         return true;
62     }
63
64     public async bool get_identity(string nai,
65                                    string password,
66                                    string service,
67                                    out string nai_out,
68                                    out string password_out,
69                                    out string server_certificate_hash,
70                                    out string ca_certificate,
71                                    out string subject_name_constraint,
72                                    out string subject_alt_name_constraint)
73     {
74         logger.trace(@"MoonshotServer.get_identity: nai='$nai'; service='$service'");
75         var request = new IdentityRequest(parent_app,
76                                           nai,
77                                           password,
78                                           service);
79         logger.trace(@"MoonshotServer.get_identity: Calling request.execute()");
80         request.set_callback((IdentityRequest) => get_identity.callback());
81         request.execute();
82         logger.trace(@"MoonshotServer.get_identity: Back from request.execute()");
83         yield;
84         logger.trace(@"MoonshotServer.get_identity: back from yield");
85
86         nai_out = "";
87         password_out = "";
88         server_certificate_hash = "";
89         ca_certificate = "";
90         subject_name_constraint = "";
91         subject_alt_name_constraint = "";
92
93         var id_card = request.id_card;
94
95         if ((id_card != null) && (id_card.display_name != IdCard.NO_IDENTITY)) {
96             nai_out = id_card.nai;
97             if ((request.password != null) && (request.password != ""))
98                 password_out = request.password;
99             else
100                 password_out = id_card.password;
101
102             server_certificate_hash = id_card.trust_anchor.server_cert;
103             ca_certificate = id_card.trust_anchor.ca_cert;
104             subject_name_constraint = id_card.trust_anchor.subject;
105             subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
106
107             if (nai_out == null)
108                 nai_out = "";
109             if (password_out == null)
110                 password_out = "";
111             if (server_certificate_hash == null)
112                 server_certificate_hash = "";
113             if (ca_certificate == null)
114                 ca_certificate = "";
115             if (subject_name_constraint == null)
116                 subject_name_constraint = "";
117             if (subject_alt_name_constraint == null)
118                 subject_alt_name_constraint = "";
119
120             logger.trace(@"MoonshotServer.get_identity: returning with nai_out=$nai_out");
121
122             return true;
123         }
124
125         logger.trace("MoonshotServer.get_identity: returning false");
126         return false;
127     }
128
129     public async bool get_default_identity(out string nai_out,
130                                            out string password_out,
131                                            out string server_certificate_hash,
132                                            out string ca_certificate,
133                                            out string subject_name_constraint,
134                                            out string subject_alt_name_constraint)
135     {
136         logger.trace("MoonshotServer.get_default_identity");
137         var request = new IdentityRequest.default(parent_app);
138         request.set_callback((IdentityRequest) => get_default_identity.callback());
139         request.execute();
140         yield;
141
142         nai_out = "";
143         password_out = "";
144         server_certificate_hash = "";
145         ca_certificate = "";
146         subject_name_constraint = "";
147         subject_alt_name_constraint = "";
148
149         if (request.id_card != null)
150         {
151             nai_out = request.id_card.nai;
152             password_out = request.id_card.password;
153
154             server_certificate_hash = request.id_card.trust_anchor.server_cert;
155             ca_certificate = request.id_card.trust_anchor.ca_cert;
156             subject_name_constraint = request.id_card.trust_anchor.subject;
157             subject_alt_name_constraint = request.id_card.trust_anchor.subject_alt;
158
159             if (nai_out == null)
160                 nai_out = "";
161             if (password_out == null)
162                 password_out = "";
163             if (server_certificate_hash == null)
164                 server_certificate_hash = "";
165             if (ca_certificate == null)
166                 ca_certificate = "";
167             if (subject_name_constraint == null)
168                 subject_name_constraint = "";
169             if (subject_alt_name_constraint == null)
170                 subject_alt_name_constraint = "";
171
172             logger.trace("MoonshotServer.get_default_identity: returning true");
173             return true;
174         }
175
176         return false;
177     }
178
179     public bool install_id_card(string   display_name,
180                                 string   user_name,
181                                 string   ?password,
182                                 string   ?realm,
183                                 string[] ?rules_patterns,
184                                 string[] ?rules_always_confirm,
185                                 string[] ?services,
186                                 string   ?ca_cert,
187                                 string   ?subject,
188                                 string   ?subject_alt,
189                                 string   ?server_cert,
190                                 int      force_flat_file_store)
191     {
192         IdCard idcard = new IdCard();
193
194         idcard.display_name = display_name;
195         idcard.username = user_name;
196         idcard.password = password;
197         if ((password != null) && (password != ""))
198             idcard.store_password = true;
199         idcard.issuer = realm;
200         idcard.update_services(services);
201         var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, false);
202         if (!ta.is_empty()) {
203             string ta_datetime_added = TrustAnchor.format_datetime_now();
204             ta.set_datetime_added(ta_datetime_added);
205             logger.trace("install_id_card : Set ta_datetime_added for '%s' to '%s'".printf(idcard.display_name, ta_datetime_added));
206             idcard.set_trust_anchor_from_store(ta);
207         }
208
209         logger.trace("install_id_card: Card '%s' has services: '%s'"
210                      .printf(idcard.display_name, idcard.get_services_string("; ")));
211
212         if (rules_patterns.length == rules_always_confirm.length)
213         {
214             /* workaround Centos vala array property bug: use temp array */
215             Rule[] rules = new Rule[rules_patterns.length];
216          
217             for (int i = 0; i < rules.length; i++)
218             { 
219                 rules[i].pattern = rules_patterns[i];
220                 rules[i].always_confirm = rules_always_confirm[i];
221             }
222             idcard.rules = rules;
223         }
224
225         return parent_app.add_identity(idcard, force_flat_file_store!=0);
226     }
227
228
229     public int install_from_file(string file_name)
230     {
231         var webp = new WebProvisioning.Parser(file_name);
232
233         webp.parse();
234         bool result = false;
235         int installed_cards = 0;
236         foreach (IdCard card in webp.cards)
237         {
238             string[] rules_patterns = {};
239             string[] rules_always_confirm = {};
240         
241             if (card.rules.length > 0)
242             {
243                 int i = 0;
244                 rules_patterns = new string[card.rules.length];
245                 rules_always_confirm = new string[card.rules.length];
246                 foreach (Rule r in card.rules)
247                 {
248                     rules_patterns[i] = r.pattern;
249                     rules_always_confirm[i] = r.always_confirm;
250                     i++;
251                 }
252             } 
253
254
255             // prevent a crash by holding the reference to otherwise
256             // unowned array(?)
257
258             // string[] svcs = card.services.to_array();
259             // string[] svcs = card.services.to_array()[:];
260             string[] svcs = new string[card.services.size];
261             for (int i = 0; i < card.services.size; i++) {
262                 svcs[i] = card.services[i];
263             }
264
265             logger.trace(@"install_from_file: Adding card with display name '$(card.display_name)'");
266             result = install_id_card(card.display_name,
267                                      card.username,
268                                      card.password,
269                                      card.issuer,
270                                      rules_patterns,
271                                      rules_always_confirm,
272                                      svcs,
273                                      card.trust_anchor.ca_cert,
274                                      card.trust_anchor.subject,
275                                      card.trust_anchor.subject_alt,
276                                      card.trust_anchor.server_cert,
277                                      0);
278             if (result) {
279                 installed_cards++;
280             }
281         }
282         return installed_cards;
283     }
284 }
285
286
287 #elif IPC_MSRPC
288
289 using Rpc;
290 using MoonshotRpcInterface;
291
292 /* This class must be a singleton, because we use a global RPC
293  * binding handle. I cannot picture a situation where more than
294  * one instance of the same interface would be needed so this
295  * shouldn't be a problem.
296  *
297  * Shutdown is automatically done by the RPC runtime when the
298  * process ends
299  */
300 public class MoonshotServer : Object {
301     private static IdentityManagerApp parent_app;
302
303     private static MoonshotServer instance = null;
304
305     public static void start(IdentityManagerApp app)
306     {
307         parent_app = app;
308         Rpc.server_start(MoonshotRpcInterface.spec, "/org/janet/Moonshot", Rpc.Flags.PER_USER);
309     }
310
311     public static MoonshotServer get_instance()
312     {
313         if (instance == null)
314             instance = new MoonshotServer();
315         return instance;
316     }
317
318     [CCode (cname = "moonshot_get_identity_rpc")]
319     public static void get_identity(Rpc.AsyncCall call,
320                                     string nai,
321                                     string password,
322                                     string service,
323                                     ref string nai_out,
324                                     ref string password_out,
325                                     ref string server_certificate_hash,
326                                     ref string ca_certificate,
327                                     ref string subject_name_constraint,
328                                     ref string subject_alt_name_constraint)
329     {
330         logger.trace("(static) get_identity");
331
332         bool result = false;
333
334         var request = new IdentityRequest(parent_app,
335                                           nai,
336                                           password,
337                                           service);
338
339         // Pass execution to the main loop and block the RPC thread
340         request.mutex = new Mutex();
341         request.cond = new Cond();
342         request.set_callback(return_identity_cb);
343
344         request.mutex.lock();
345         Idle.add(request.execute);
346
347         while (request.complete == false)
348             request.cond.wait(request.mutex);
349
350         nai_out = "";
351         password_out = "";
352         server_certificate_hash = "";
353         ca_certificate = "";
354         subject_name_constraint = "";
355         subject_alt_name_constraint = "";
356
357         var id_card = request.id_card;
358
359         if (id_card != null) {
360             // The strings are freed by the RPC runtime
361             nai_out = id_card.nai;
362             password_out = id_card.password;
363             server_certificate_hash = id_card.trust_anchor.server_cert;
364             ca_certificate = id_card.trust_anchor.ca_cert;
365             subject_name_constraint = id_card.trust_anchor.subject;
366             subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
367
368             return_if_fail(nai_out != null);
369             return_if_fail(password_out != null);
370             return_if_fail(server_certificate_hash != null);
371             return_if_fail(ca_certificate != null);
372             return_if_fail(subject_name_constraint != null);
373             return_if_fail(subject_alt_name_constraint != null);
374
375             result = true;
376         }
377
378         // The outputs must be set before this function is called. For this
379         // reason they are 'ref' not 'out' parameters - Vala assigns to the
380         // 'out' parameters only at the end of the function, which is too
381         // late.
382         call.return(&result);
383
384         request.cond.signal();
385         request.mutex.unlock();
386     }
387
388     [CCode (cname = "moonshot_get_default_identity_rpc")]
389     public static void get_default_identity(Rpc.AsyncCall call,
390                                             ref string nai_out,
391                                             ref string password_out,
392                                             ref string server_certificate_hash,
393                                             ref string ca_certificate,
394                                             ref string subject_name_constraint,
395                                             ref string subject_alt_name_constraint)
396     {
397         logger.trace("(static) get_default_identity");
398
399         bool result;
400
401         var request = new IdentityRequest.default(parent_app);
402         request.mutex = new Mutex();
403         request.cond = new Cond();
404         request.set_callback(return_identity_cb);
405
406         request.mutex.lock();
407         Idle.add(request.execute);
408
409         while (request.complete == false)
410             request.cond.wait(request.mutex);
411
412         nai_out = "";
413         password_out = "";
414         server_certificate_hash = "";
415         ca_certificate = "";
416         subject_name_constraint = "";
417         subject_alt_name_constraint = "";
418
419         if (request.id_card != null)
420         {
421             nai_out = request.id_card.nai;
422             password_out = request.id_card.password;
423             server_certificate_hash = "certificate";
424
425             return_if_fail(nai_out != null);
426             return_if_fail(password_out != null);
427             return_if_fail(server_certificate_hash != null);
428             return_if_fail(ca_certificate != null);
429             return_if_fail(subject_name_constraint != null);
430             return_if_fail(subject_alt_name_constraint != null);
431
432             result = true;
433         }
434         else
435         {
436             result = false;
437         }
438
439         call.return(&result);
440
441         request.cond.signal();
442         request.mutex.unlock();
443     }
444
445     // Called from the main loop thread when an identity has
446     // been selected
447     static void return_identity_cb(IdentityRequest request) {
448         // Notify the RPC thread that the request is complete
449         request.mutex.lock();
450         request.cond.signal();
451
452         // Block the main loop until the RPC call has returned
453         // to avoid any races
454         request.cond.wait(request.mutex);
455         request.mutex.unlock();
456     }
457
458     [CCode (cname = "moonshot_install_id_card_rpc")]
459     public static bool install_id_card(string     display_name,
460                                        string     user_name,
461                                        string     password,
462                                        string     realm,
463                                        string[]   rules_patterns,
464                                        string[]   rules_always_confirm,
465                                        string[]   services,
466                                        string     ca_cert,
467                                        string     subject,
468                                        string     subject_alt,
469                                        string     server_cert,
470                                        bool       force_flat_file_store)
471     {
472         logger.trace("(static) install_id_card");
473         IdCard idcard = new IdCard();
474
475         bool success = false;
476         Mutex mutex = new Mutex();
477         Cond cond = new Cond();
478
479         idcard.display_name = display_name;
480         idcard.username = user_name;
481         idcard.password = password;
482         idcard.issuer = realm;
483         idcard.services = services;
484         idcard.trust_anchor.ca_cert = ca_cert;
485         idcard.trust_anchor.subject = subject;
486         idcard.trust_anchor.subject_alt = subject_alt;
487         idcard.trust_anchor.server_cert = server_cert;
488
489         if (rules_patterns.length == rules_always_confirm.length)
490         {
491             idcard.rules = new Rule[rules_patterns.length];
492          
493             for (int i = 0; i < idcard.rules.length; i++)
494             { 
495                 idcard.rules[i].pattern = rules_patterns[i];
496                 idcard.rules[i].always_confirm = rules_always_confirm[i];
497             }
498         }
499
500         mutex.lock();
501
502         // Defer addition to the main loop thread.
503         Idle.add(() => {
504                 mutex.lock();
505                 success = parent_app.add_identity(idcard, force_flat_file_store);
506                 cond.signal();
507                 mutex.unlock();
508                 return false;
509             });
510
511         cond.wait(mutex);
512         mutex.unlock();
513
514         return success;
515     }
516
517 }
518
519
520 #endif