Squashed merge of many commits, including (but not limited to) :
[moonshot-ui.git] / src / moonshot-provisioning-common.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
34
35 namespace WebProvisioning
36 {
37     bool check_stack(SList<string> stack, string[] reference) {
38
39         if (stack.length() < reference.length)
40             return false;
41
42         for (int i = 0; i < reference.length; i++)
43         {
44             if (stack.nth_data(i) != reference[i])
45                 return false;
46         }
47
48         return true;
49     }
50
51     bool always_confirm_handler(SList<string> stack)
52     {
53         string[] always_confirm_path = {"always-confirm", "rule", "selection-rules", "identity", "identities"};
54
55         return check_stack(stack, always_confirm_path);
56     }
57
58     bool
59     pattern_handler(SList<string> stack)
60     {
61         string[] pattern_path = {"pattern", "rule", "selection-rules", "identity", "identities"};
62
63         return check_stack(stack, pattern_path);
64     }
65
66     bool server_cert_handler(SList<string> stack)
67     {
68         string[] server_cert_path = {"server-cert", "trust-anchor", "identity", "identities"};
69
70         return check_stack(stack, server_cert_path);
71     }
72
73     bool subject_alt_handler(SList<string> stack)
74     {
75         string[] subject_alt_path = {"subject-alt", "trust-anchor", "identity", "identities"};
76
77         return check_stack(stack, subject_alt_path);
78     }
79
80     bool subject_handler(SList<string> stack)
81     {
82         string[] subject_path = {"subject", "trust-anchor", "identity", "identities"};
83
84         return check_stack(stack, subject_path);
85     }
86
87     bool ca_cert_handler(SList<string> stack)
88     {
89         string[] ca_path = {"ca-cert", "trust-anchor", "identity", "identities"};
90
91         return check_stack(stack, ca_path);
92     }
93
94     bool realm_handler(SList<string> stack)
95     {
96         string[] realm_path = {"realm", "identity", "identities"};
97
98         return check_stack(stack, realm_path);
99     }
100
101     bool password_handler(SList<string> stack)
102     {
103         string[] password_path = {"password", "identity", "identities"};
104
105         return check_stack(stack, password_path);
106     }
107
108     bool user_handler(SList<string> stack)
109     {
110         string[] user_path = {"user", "identity", "identities"};
111
112         return check_stack(stack, user_path);
113     }
114
115     bool display_name_handler(SList<string> stack)
116     {
117         string[] display_name_path = {"display-name", "identity", "identities"};
118
119         return check_stack(stack, display_name_path);
120     }
121
122     public class Parser : Object
123     {
124         private static MoonshotLogger logger = new MoonshotLogger("WebProvisioning");
125
126         private void start_element_func(MarkupParseContext context,
127                                         string element_name,
128                                         string[] attribute_names,
129                                         string[] attribute_values) throws MarkupError
130         {
131             if (element_name == "identity")
132             {
133                 card = new IdCard();
134                 _cards += card;
135
136                 ta_ca_cert = "";
137                 ta_server_cert = "";
138                 ta_subject = "";
139                 ta_subject_alt = "";
140             }
141             else if (element_name == "rule")
142             {
143                 card.add_rule(Rule());
144             }
145         }
146
147         private void end_element_func(MarkupParseContext context,
148                                       string element_name) throws MarkupError
149         {
150             if (element_name == "identity")
151             {
152                 if (ta_ca_cert != "" || ta_server_cert != "") {
153                     var ta = new TrustAnchor(ta_ca_cert,
154                                              ta_server_cert,
155                                              ta_subject,
156                                              ta_subject_alt);
157                     // Set the datetime_added in moonshot-server.vala, since it doesn't get sent via IPC
158                     card.set_trust_anchor_from_store(ta);
159                 }
160             }
161         }
162
163         private void
164         text_element_func(MarkupParseContext context,
165                           string             text,
166                           size_t             text_len) throws MarkupError {
167             unowned SList<string> stack = context.get_element_stack();
168
169             if (text_len < 1)
170                 return;
171
172             if (stack.nth_data(0) == "display-name" && display_name_handler(stack))
173             {
174                 card.display_name = text;
175             }
176             else if (stack.nth_data(0) == "user" && user_handler(stack))
177             {
178                 card.username = text;
179             }
180             else if (stack.nth_data(0) == "password" && password_handler(stack))
181             {
182                 card.password = text;
183             }
184             else if (stack.nth_data(0) == "realm" && realm_handler(stack))
185             {
186                 card.issuer = text;
187             }
188             else if (stack.nth_data(0) == "service")
189             {
190                 card.services.add(text);
191             }
192
193             /* Rules */
194             else if (stack.nth_data(0) == "pattern" && pattern_handler(stack))
195             {
196                 /* use temp array to workaround valac 0.10 bug accessing array property length */
197                 var temp = card.rules;
198                 card.rules[temp.length - 1].pattern = text;
199             }
200             else if (stack.nth_data(0) == "always-confirm" && always_confirm_handler(stack))
201             {
202                 if (text == "true" || text == "false") {
203                     /* use temp array to workaround valac 0.10 bug accessing array property length*/
204                     var temp = card.rules;
205                     card.rules[temp.length - 1].always_confirm = text;
206                 }
207             }
208             else if (stack.nth_data(0) == "ca-cert" && ca_cert_handler(stack))
209             {
210                 ta_ca_cert = text ?? "";
211             }
212             else if (stack.nth_data(0) == "server-cert" && server_cert_handler(stack))
213             {
214                 ta_server_cert = text ?? "";
215             }
216             else if (stack.nth_data(0) == "subject" && subject_handler(stack))
217             {
218                 ta_subject = text;
219             }
220             else if (stack.nth_data(0) == "subject-alt" && subject_alt_handler(stack))
221             {
222                 ta_subject_alt = text;
223             }
224         }
225
226         private const MarkupParser parser = {
227             start_element_func, end_element_func, text_element_func, null, null
228         };
229
230         private MarkupParseContext ctx;
231
232         private string       text;
233         private string       path;
234
235         private string ta_ca_cert;
236         private string ta_server_cert;
237         private string ta_subject;
238         private string ta_subject_alt;
239
240         private IdCard card;
241         private IdCard[] _cards = {};
242
243         public IdCard[] cards {
244             get {return _cards;}
245             private set {_cards = value ?? new IdCard[0] ;}
246         }
247
248         public Parser(string path) {
249
250             ctx = new MarkupParseContext(parser, 0, this, null);
251
252             text = "";
253             this.path = path;
254
255             var file = File.new_for_path(path);
256
257             try
258             {
259                 var dis = new DataInputStream(file.read());
260                 string line;
261                 while ((line = dis.read_line(null)) != null) {
262                     text += line;
263
264                     // Preserve newlines.
265                     //
266                     // This may add an extra newline at EOF. Maybe use
267                     // dis.read_upto("\n", ...) followed by dis.read_byte() instead?
268                     text += "\n";
269                 }
270             }
271             catch(GLib.Error e)
272             {
273                 error("Could not retreive file size");
274             }
275         }
276
277         public void parse() {
278             try
279             {
280                 ctx.parse(text, text.length);
281             }
282             catch(GLib.Error e)
283             {
284                 error("Could not parse %s, invalid content", path);
285             }
286         }
287     }
288 }