006b503613c6beb31fe298ee850f97c4cd83b92f
[fides] / src / fides.cc
1 /* fides.c - Light-weight, decentralised trust and authorisation management
2    Copyright (C) 2008-2009  Guus Sliepen <guus@tinc-vpn.org>
3   
4    Fides is free software; you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as
6    published by the Free Software Foundation; either version 2.1 of
7    the License, or (at your option) any later version.
8   
9    Fides is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12    GNU Lesser General Public License for more details.
13   
14    You should have received a copy of the GNU Lesser General Public
15    License along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <cstdio>
19 #include <cstring>
20 #include <cstdlib>
21 #include <stdint.h>
22 #include <getopt.h>
23 #include <sysexits.h>
24 #include <iostream>
25 #include <fstream>
26 #include <botan/types.h>
27 #include <botan/botan.h>
28 #include <botan/ecdsa.h>
29 #include <botan/look_pk.h>
30 #include <botan/lookup.h>
31 #include <botan/filters.h>
32 #include <botan/sha2_32.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <dirent.h>
36 #include <list>
37
38 #include "fides.h"
39
40 using namespace std;
41
42 static void help(ostream &out, const string &argv0) {
43         out << "Usage: " << argv0 << "<command> [arguments]\n"
44         "\n"
45         "Available commands are:\n"
46         "\n"
47         "  init      Initialise fides, generate a public/private keypair.\n"
48         "  version   Show version and copyright information.\n"
49         "  help      Show this help message.\n"
50         "\n"
51         "  trust <keyid>\n"
52         "            Trust allow/deny packets signed by the specified key.\n"
53         "  distrust <keyid>\n"
54         "            Distrust allow/deny packets signed by the specified key.\n"
55         "  dctrust <keyid>\n"
56         "            Don't care about allow/deny packets signed by the specified key.\n"
57         "  is_trusted <keyid>\n"
58         "            Returns 0 if key is trusted, 1 otherwise\n"
59         "  is_distrusted <keyid>\n"
60         "            Returns 0 if key is distrusted, 1 otherwise\n"
61         "\n"
62         "  sign <stuff ...>\n"
63         "            Sign stuff.\n"
64         "  allow <stuff ...>\n"
65         "            Allow stuff.\n"
66         "  deny <stuff ...> \n"
67         "            Deny stuff.\n"
68         "  dontcare <stuff ...> \n"
69         "            Don't care about stuff.\n"
70         "  is_allowed <stuff ...>\n"
71         "            Returns 0 if stuff is allowed, 1 otherwise\n"
72         "  is_denied <stuff ...>\n"
73         "            Returns 0 if stuff is denied, 1 otherwise\n"
74         "\n"
75         "  import [filename]\n"
76         "            Import keys and certificates from file, or stdin if unspecified.\n"
77         "  export [filename]\n"
78         "            Export keys and certificates to file, or stdout if unspecified.\n"
79         "  test <stuff ...>\n"
80         "            Tell whether stuff is allowed or not by counting relevant certificates\n"
81         "  find <regexp>\n"
82         "            Find all certificates matching regexp\n"
83         "  fsck      Verify the signature on all information collected.\n";
84 }
85
86 static void version(ostream &out = cout) {
87         out << "fides version 0.1\n"
88         "Copyright (c) 2008-2009 Guus Sliepen <guus@tinc-vpn.org>\n"
89         "\n"
90         "This program is free software; you can redistribute it and/or modify\n"
91         "it under the terms of the GNU General Public License as published by\n"
92         "the Free Software Foundation; either version 2 of the License, or\n"
93         "(at your option) any later version.\n";
94 }
95
96 static int init() {
97         fides fides;
98         if(fides.is_firstrun()) {
99                 cout << "New keys generated in " << fides.get_homedir() << '\n';
100         } else {
101                 cout << "Fides already initialised\n";
102         }
103         return 0;
104 }
105
106 static int is_trusted(int argc, char *const argv[]) {
107         if(argc < 1)
108                 return EX_USAGE;
109
110         fides fides;
111         fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
112         if(!key) {
113                 cerr << "Unknown key!\n";
114                 return 1;
115         }
116         return fides.is_trusted(key) ? 0 : 1;
117 }
118
119 static int is_distrusted(int argc, char *const argv[]) {
120         if(argc < 1)
121                 return EX_USAGE;
122
123         fides fides;
124         fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
125         if(!key) {
126                 cerr << "Unknown key!\n";
127                 return 1;
128         }
129         return fides.is_distrusted(key) ? 0 : 1;
130 }
131
132 static int trust(int argc, char *const argv[]) {
133         if(argc < 1)
134                 return EX_USAGE;
135
136         fides fides;
137         fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
138         if(key)
139                 fides.trust(key);
140         else {
141                 cerr << "Unknown key!\n";
142                 return -1;
143         }
144         return 0;
145 }
146
147 static int dctrust(int argc, char *const argv[]) {
148         if(argc < 1)
149                 return EX_USAGE;
150
151         fides fides;
152         fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
153         if(key)
154                 fides.dctrust(key);
155         else {
156                 cerr << "Unknown key!\n";
157                 return -1;
158         }
159         return 0;
160 }
161
162 static int distrust(int argc, char *const argv[]) {
163         if(argc < 1)
164                 return EX_USAGE;
165
166         fides fides;
167         fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
168         if(key)
169                 fides.distrust(key);
170         else {
171                 cerr << "Unknown key!\n";
172                 return -1;
173         }
174         return 0;
175 }
176
177 static int sign(int argc, char *const argv[]) {
178         if(argc < 1)
179                 return EX_USAGE;
180
181         fides fides;
182         fides.sign(argv[0]);
183         return 0;
184 }
185
186 static int allow(int argc, char *const argv[]) {
187         if(argc < 1)
188                 return EX_USAGE;
189
190         fides fides;
191         fides.allow(argv[0]);
192         return 0;
193 }
194
195 static int dontcare(int argc, char *const argv[]) {
196         if(argc < 1)
197                 return EX_USAGE;
198
199         fides fides;
200         fides.dontcare(argv[0]);
201         return 0;
202 }
203
204 static int deny(int argc, char *const argv[]) {
205         if(argc < 1)
206                 return EX_USAGE;
207
208         fides fides;
209         fides.deny(argv[0]);
210         return 0;
211 }
212
213 static int import(int argc, char *const argv[]) {
214         fides fides;
215         
216         if(argc) {
217                 ifstream in(argv[0]);
218                 fides.import_all(in);
219         } else
220                 fides.import_all(cin);
221         return 0;
222 }
223
224 static int exprt(int argc, char *const argv[]) {
225         fides fides;
226
227         if(argc) {
228                 ofstream out(argv[0]);
229                 fides.export_all(out);
230         } else
231                 fides.export_all(cout);
232         return 0;
233 }
234
235 static int find(int argc, char *const argv[]) {
236         if(argc < 1)
237                 return EX_USAGE;
238
239         // Find certificates matching statement
240         fides fides;
241         const vector<fides::certificate *> &certs = fides.find_certificates(argv[0]);
242         for(size_t i = 0; i < certs.size(); ++i)
243                 cout << i << ' ' << certs[i]->to_string() << '\n';
244         return 0;
245 }
246
247 static int is_allowed(int argc, char *const argv[]) {
248         if(argc < 1)
249                 return EX_USAGE;
250
251         fides fides;
252         return fides.is_allowed(argv[0]) ? 0 : 1;
253 }
254
255 static int is_denied(int argc, char *const argv[]) {
256         if(argc < 1)
257                 return EX_USAGE;
258
259         fides fides;
260         return fides.is_denied(argv[0]) ? 0 : 1;
261 }
262
263 static int test(int argc, char *const argv[]) {
264         if(argc < 1)
265                 return EX_USAGE;
266
267         fides fides;
268         int self, trusted, all;
269         fides.auth_stats(argv[0], self, trusted, all);
270         cout << "Self: " << self << ", trusted: " << trusted << ", all: " << all << '\n';
271         return 0;
272 }
273
274 static int fsck() {
275         fides fides;
276         if(fides.fsck()) {
277                 cout << "Everything OK\n";
278                 return 0;
279         } else {
280                 cout << "Integrity failure!\n";
281                 return 1;
282         }
283 }
284
285 int main(int argc, char *const argv[]) {
286         int r;
287         int option_index;
288
289         static struct option const long_options[] = {
290                 {"homedir", required_argument, NULL, 2},
291                 {"help", no_argument, NULL, 'h'},
292                 {"version", no_argument, NULL, 3},
293                 {NULL, 0, NULL, 0}
294         };
295
296         while((r = getopt_long(argc, argv, "h", long_options, &option_index)) != EOF) {
297                 switch (r) {
298                         case 0:                         /* long option */
299                                 break;
300                         case 1:                         /* non-option */
301                                 break;
302                         case 2:
303                                 //homedir = strdup(optarg);
304                                 break;
305                         case 3:
306                                 version();
307                                 return 0;
308                         case 'h':
309                                 help(cout, argv[0]);
310                                 return 0;
311                 }
312         }
313
314         if(argc < 2) {
315                 help(cerr, argv[0]);
316                 return EX_USAGE;
317         }
318
319         if(!strcmp(argv[1], "help")) {
320                 help(cout, argv[0]);
321                 return 0;
322         }
323
324         if(!strcmp(argv[1], "version")) {
325                 version();
326                 return 0;
327         }
328
329         if(!strcmp(argv[1], "init"))
330                 return init();
331
332         if(!strcmp(argv[1], "trust"))
333                 return trust(argc - 2, argv + 2);
334
335         if(!strcmp(argv[1], "dctrust"))
336                 return dctrust(argc - 2, argv + 2);
337
338         if(!strcmp(argv[1], "distrust"))
339                 return distrust(argc - 2, argv + 2);
340
341         if(!strcmp(argv[1], "is_trusted"))
342                 return is_trusted(argc - 2, argv + 2);
343
344         if(!strcmp(argv[1], "is_distrusted"))
345                 return is_distrusted(argc - 2, argv + 2);
346
347         if(!strcmp(argv[1], "is_allowed"))
348                 return is_allowed(argc - 2, argv + 2);
349
350         if(!strcmp(argv[1], "is_denied"))
351                 return is_denied(argc - 2, argv + 2);
352
353         if(!strcmp(argv[1], "allow"))
354                 return allow(argc - 2, argv + 2);
355
356         if(!strcmp(argv[1], "dontcare"))
357                 return dontcare(argc - 2, argv + 2);
358
359         if(!strcmp(argv[1], "deny"))
360                 return deny(argc - 2, argv + 2);
361
362         if(!strcmp(argv[1], "sign"))
363                 return sign(argc - 2, argv + 2);
364
365         if(!strcmp(argv[1], "import"))
366                 return import(argc - 2, argv + 2);
367
368         if(!strcmp(argv[1], "export"))
369                 return exprt(argc - 2, argv + 2);
370
371         if(!strcmp(argv[1], "test"))
372                 return test(argc - 2, argv + 2);
373
374         if(!strcmp(argv[1], "find"))
375                 return find(argc - 2, argv + 2);
376
377         if(!strcmp(argv[1], "fsck"))
378                 return fsck();
379
380         cerr << "Unknown command: " << argv[1] << '\n';
381         return EX_USAGE;
382 }