Squashed merge of many commits, including (but not limited to) :
[moonshot-ui.git] / src / moonshot-server-msrpc.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
36 using Rpc;
37 using MoonshotRpcInterface;
38
39 /* This class must be a singleton, because we use a global RPC
40  * binding handle. I cannot picture a situation where more than
41  * one instance of the same interface would be needed so this
42  * shouldn't be a problem.
43  *
44  * Shutdown is automatically done by the RPC runtime when the
45  * process ends
46  */
47 public class MoonshotServer : Object {
48     private static IdentityManagerApp parent_app;
49
50     private static MoonshotServer instance = null;
51
52     public static void start(IdentityManagerApp app)
53     {
54         parent_app = app;
55         Rpc.server_start(MoonshotRpcInterface.spec, "/org/janet/Moonshot", Rpc.Flags.PER_USER);
56     }
57
58     public static MoonshotServer get_instance()
59     {
60         if (instance == null)
61             instance = new MoonshotServer();
62         return instance;
63     }
64
65     [CCode (cname = "moonshot_get_identity_rpc")]
66     public static void get_identity(Rpc.AsyncCall call,
67                                     string nai,
68                                     string password,
69                                     string service,
70                                     ref string nai_out,
71                                     ref string password_out,
72                                     ref string server_certificate_hash,
73                                     ref string ca_certificate,
74                                     ref string subject_name_constraint,
75                                     ref string subject_alt_name_constraint)
76     {
77         logger.trace("(static) get_identity");
78
79         bool result = false;
80
81         var request = new IdentityRequest(parent_app,
82                                           nai,
83                                           password,
84                                           service);
85
86         // Pass execution to the main loop and block the RPC thread
87         request.mutex = new Mutex();
88         request.cond = new Cond();
89         request.set_callback(return_identity_cb);
90
91         request.mutex.lock();
92         Idle.add(request.execute);
93
94         while (request.complete == false)
95             request.cond.wait(request.mutex);
96
97         nai_out = "";
98         password_out = "";
99         server_certificate_hash = "";
100         ca_certificate = "";
101         subject_name_constraint = "";
102         subject_alt_name_constraint = "";
103
104         var id_card = request.id_card;
105
106         if (id_card != null) {
107             // The strings are freed by the RPC runtime
108             nai_out = id_card.nai;
109             password_out = id_card.password;
110             server_certificate_hash = id_card.trust_anchor.server_cert;
111             ca_certificate = id_card.trust_anchor.ca_cert;
112             subject_name_constraint = id_card.trust_anchor.subject;
113             subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
114
115             return_if_fail(nai_out != null);
116             return_if_fail(password_out != null);
117             return_if_fail(server_certificate_hash != null);
118             return_if_fail(ca_certificate != null);
119             return_if_fail(subject_name_constraint != null);
120             return_if_fail(subject_alt_name_constraint != null);
121
122             result = true;
123         }
124
125         // The outputs must be set before this function is called. For this
126         // reason they are 'ref' not 'out' parameters - Vala assigns to the
127         // 'out' parameters only at the end of the function, which is too
128         // late.
129         call.return(&result);
130
131         request.cond.signal();
132         request.mutex.unlock();
133     }
134
135     [CCode (cname = "moonshot_get_default_identity_rpc")]
136     public static void get_default_identity(Rpc.AsyncCall call,
137                                             ref string nai_out,
138                                             ref string password_out,
139                                             ref string server_certificate_hash,
140                                             ref string ca_certificate,
141                                             ref string subject_name_constraint,
142                                             ref string subject_alt_name_constraint)
143     {
144         logger.trace("(static) get_default_identity");
145
146         bool result;
147
148         var request = new IdentityRequest.default(parent_app);
149         request.mutex = new Mutex();
150         request.cond = new Cond();
151         request.set_callback(return_identity_cb);
152
153         request.mutex.lock();
154         Idle.add(request.execute);
155
156         while (request.complete == false)
157             request.cond.wait(request.mutex);
158
159         nai_out = "";
160         password_out = "";
161         server_certificate_hash = "";
162         ca_certificate = "";
163         subject_name_constraint = "";
164         subject_alt_name_constraint = "";
165
166         if (request.id_card != null)
167         {
168             nai_out = request.id_card.nai;
169             password_out = request.id_card.password;
170             server_certificate_hash = "certificate";
171
172             return_if_fail(nai_out != null);
173             return_if_fail(password_out != null);
174             return_if_fail(server_certificate_hash != null);
175             return_if_fail(ca_certificate != null);
176             return_if_fail(subject_name_constraint != null);
177             return_if_fail(subject_alt_name_constraint != null);
178
179             result = true;
180         }
181         else
182         {
183             result = false;
184         }
185
186         call.return(&result);
187
188         request.cond.signal();
189         request.mutex.unlock();
190     }
191
192     // Called from the main loop thread when an identity has
193     // been selected
194     static void return_identity_cb(IdentityRequest request) {
195         // Notify the RPC thread that the request is complete
196         request.mutex.lock();
197         request.cond.signal();
198
199         // Block the main loop until the RPC call has returned
200         // to avoid any races
201         request.cond.wait(request.mutex);
202         request.mutex.unlock();
203     }
204
205     [CCode (cname = "moonshot_install_id_card_rpc")]
206     public static bool install_id_card(string     display_name,
207                                        string     user_name,
208                                        string     password,
209                                        string     realm,
210                                        string[]   rules_patterns,
211                                        string[]   rules_always_confirm,
212                                        string[]   services,
213                                        string     ca_cert,
214                                        string     subject,
215                                        string     subject_alt,
216                                        string     server_cert,
217                                        bool       force_flat_file_store)
218     {
219         logger.trace("(static) install_id_card");
220         IdCard idcard = new IdCard();
221
222         bool success = false;
223         Mutex mutex = new Mutex();
224         Cond cond = new Cond();
225
226         idcard.display_name = display_name;
227         idcard.username = user_name;
228         idcard.password = password;
229         idcard.issuer = realm;
230         idcard.services = services;
231         idcard.trust_anchor.ca_cert = ca_cert;
232         idcard.trust_anchor.subject = subject;
233         idcard.trust_anchor.subject_alt = subject_alt;
234         idcard.trust_anchor.server_cert = server_cert;
235
236         if (rules_patterns.length == rules_always_confirm.length)
237         {
238             idcard.rules = new Rule[rules_patterns.length];
239          
240             for (int i = 0; i < idcard.rules.length; i++)
241             { 
242                 idcard.rules[i].pattern = rules_patterns[i];
243                 idcard.rules[i].always_confirm = rules_always_confirm[i];
244             }
245         }
246
247         mutex.lock();
248
249         ArrayList<IdCard>? old_duplicates = null;
250         // Defer addition to the main loop thread.
251         Idle.add(() => {
252                 mutex.lock();
253                 success = parent_app.add_identity(idcard, force_flat_file_store, out old_duplicates);
254                 foreach (IdCard id_card in old_duplicates) {
255                     stdout.printf("removing duplicate id for '%s'\n", new_card.nai);
256                 }
257                 cond.signal();
258                 mutex.unlock();
259                 return false;
260             });
261
262         cond.wait(mutex);
263         mutex.unlock();
264
265         return success;
266     }
267 }