1 /* fides.c - Light-weight, decentralised trust and authorisation management
2 Copyright (C) 2008-2009 Guus Sliepen <guus@tinc-vpn.org>
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.
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.
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/>.
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>
34 #include <sys/types.h>
44 Botan::LibraryInitializer libinit;
45 Botan::AutoSeeded_RNG fides::rng;
47 // Public key functions
49 fides::publickey::publickey(): pub(0), trust(0) {
52 fides::publickey::~publickey() {
56 void fides::publickey::load(istream &in) {
58 Botan::DataSource_Stream source(in);
59 pub = dynamic_cast<Botan::ECDSA_PublicKey *>(Botan::X509::load_key(source));
60 } catch(Botan::Exception &e) {
61 throw exception(e.what());
65 void fides::publickey::load(const std::string &filename) {
66 ifstream in(filename.c_str());
70 void fides::publickey::save(ostream &out) {
74 void fides::publickey::save(const std::string &filename) {
75 ofstream out(filename.c_str());
79 void fides::publickey::from_string(const std::string &in) {
81 Botan::DataSource_Memory source(in);
82 pub = dynamic_cast<Botan::ECDSA_PublicKey *>(Botan::X509::load_key(source));
83 } catch(Botan::Exception &e) {
84 throw exception(e.what());
88 string fides::publickey::to_string() {
89 return Botan::X509::PEM_encode(*pub);
92 string fides::publickey::fingerprint(unsigned int bits) {
93 // TODO: find out if there is a standard way to get a hash of an ECDSA public key
94 Botan::SHA_256 sha256;
95 Botan::SecureVector<Botan::byte> hash = sha256.process(Botan::X509::PEM_encode(*pub));
96 return string((const char *)hash.begin(), bits / 8);
99 bool fides::publickey::verify(const std::string &statement, const std::string &signature) {
100 auto_ptr<Botan::PK_Verifier> verifier(Botan::get_pk_verifier(*pub, "EMSA1(SHA-512)"));
101 verifier->update((const Botan::byte *)statement.data(), statement.size());
102 Botan::SecureVector<Botan::byte> sig;
103 sig.set((const Botan::byte *)signature.data(), signature.size());
104 return verifier->check_signature(sig);
107 // Private key functions
109 fides::privatekey::privatekey(): priv(0) {
112 fides::privatekey::~privatekey() {
117 void fides::privatekey::generate(const std::string &field) {
118 Botan::EC_Domain_Params domain = Botan::get_EC_Dom_Pars_by_oid(field);
119 pub = priv = new Botan::ECDSA_PrivateKey(rng, domain);
122 void fides::privatekey::generate(unsigned int bits) {
124 case 112: return generate("1.3.132.0.6");
125 case 128: return generate("1.3.132.0.28");
126 case 160: return generate("1.3.132.0.9");
127 case 192: return generate("1.3.132.0.31");
128 case 224: return generate("1.3.132.0.32");
129 case 256: return generate("1.3.132.0.10");
130 case 384: return generate("1.3.132.0.34");
131 case 521: return generate("1.3.132.0.35");
132 default: throw exception("Unsupported number of bits for private key");
136 void fides::privatekey::load_private(istream &in) {
138 Botan::DataSource_Stream stream(in);
139 pub = priv = dynamic_cast<Botan::ECDSA_PrivateKey *>(Botan::PKCS8::load_key(stream, rng, ""));
140 } catch(Botan::Exception &e) {
141 throw exception(e.what());
145 void fides::privatekey::load_private(const std::string &filename) {
146 ifstream in(filename.c_str());
150 void fides::privatekey::save_private(ostream &out) {
151 out << Botan::PKCS8::PEM_encode(*priv);
154 void fides::privatekey::save_private(const std::string &filename) {
155 ofstream out(filename.c_str());
159 string fides::privatekey::sign(const std::string &statement) {
160 auto_ptr<Botan::PK_Signer> signer(Botan::get_pk_signer(*priv, "EMSA1(SHA-512)"));
161 Botan::SecureVector<Botan::byte> sig = signer->sign_message((const Botan::byte *)statement.data(), statement.size(), rng);
162 return string((const char *)sig.begin(), (size_t)sig.size());
165 // Base64 and hex encoding/decoding functions
167 string fides::hexencode(const string &in) {
168 Botan::Pipe pipe(new Botan::Hex_Encoder);
169 pipe.process_msg((Botan::byte *)in.data(), in.size());
170 return pipe.read_all_as_string();
173 string fides::hexdecode(const string &in) {
174 Botan::Pipe pipe(new Botan::Hex_Decoder);
175 pipe.process_msg((Botan::byte *)in.data(), in.size());
176 return pipe.read_all_as_string();
179 string fides::b64encode(const string &in) {
180 Botan::Pipe pipe(new Botan::Base64_Encoder);
181 pipe.process_msg((Botan::byte *)in.data(), in.size());
182 return pipe.read_all_as_string();
185 string fides::b64decode(const string &in) {
186 Botan::Pipe pipe(new Botan::Base64_Decoder);
187 pipe.process_msg((Botan::byte *)in.data(), in.size());
188 return pipe.read_all_as_string();
191 // Certificate functions
193 fides::certificate::certificate(publickey *key, struct timeval timestamp, const std::string &statement, const std::string &signature): signer(key), timestamp(timestamp), statement(statement), signature(signature) {}
195 bool fides::certificate::validate() {
196 string data = signer->fingerprint(256);
197 data += string((const char *)×tamp, sizeof timestamp);
199 return signer->verify(data, signature);
202 fides::certificate::certificate(privatekey *key, struct timeval timestamp, const std::string &statement): signer(key), timestamp(timestamp), statement(statement) {
203 string data = signer->fingerprint(256);
204 data += string((const char *)×tamp, sizeof timestamp);
206 signature = key->sign(data);
209 string fides::certificate::fingerprint(unsigned int bits) {
210 return signature.substr(signature.size() - bits / 8);
213 string fides::certificate::to_string() const {
214 string data = fides::hexencode(signer->fingerprint());
217 snprintf(ts, sizeof ts, "%lu.%06lu", timestamp.tv_sec, timestamp.tv_usec);
220 data += fides::b64encode(signature);
226 static void help(ostream &out, const string &argv0) {
227 out << "Usage: " << argv0 << "<command> [arguments]\n"
229 "Available commands are:\n"
231 " init Initialise fides, generate a public/private keypair.\n"
232 " version Show version and copyright information.\n"
233 " help Show this help message.\n"
236 " Trust allow/deny packets signed by the specified key.\n"
237 " distrust <keyid>\n"
238 " Distrust allow/deny packets signed by the specified key.\n"
240 " Don't care about allow/deny packets signed by the specified key.\n"
241 " is_trusted <keyid>\n"
242 " Returns 0 if key is trusted, 1 otherwise\n"
243 " is_distrusted <keyid>\n"
244 " Returns 0 if key is distrusted, 1 otherwise\n"
246 " sign <stuff ...>\n"
248 " allow <stuff ...>\n"
250 " deny <stuff ...> \n"
252 " dontcare <stuff ...> \n"
253 " Don't care about stuff.\n"
254 " is_allowed <stuff ...>\n"
255 " Returns 0 if stuff is allowed, 1 otherwise\n"
256 " is_denied <stuff ...>\n"
257 " Returns 0 if stuff is denied, 1 otherwise\n"
259 " import [filename]\n"
260 " Import keys and certificates from file, or stdin if unspecified.\n"
261 " export [filename]\n"
262 " Export keys and certificates to file, or stdout if unspecified.\n"
263 " test <stuff ...>\n"
264 " Tell whether stuff is allowed or not by counting relevant certificates\n"
266 " Find all certificates matching regexp\n"
267 " fsck Verify the signature on all information collected.\n";
270 static void version(ostream &out = cout) {
271 out << "fides version 0.1\n"
272 "Copyright (c) 2008-2009 Guus Sliepen <guus@tinc-vpn.org>\n"
274 "This program is free software; you can redistribute it and/or modify\n"
275 "it under the terms of the GNU General Public License as published by\n"
276 "the Free Software Foundation; either version 2 of the License, or\n"
277 "(at your option) any later version.\n";
282 static vector<string> dirlist(const string &path) {
283 vector<string> files;
285 DIR *dir = opendir(path.c_str());
289 struct dirent entry, *result = &entry;
292 readdir_r(dir, &entry, &result);
296 if(result->d_type == DT_UNKNOWN) {
297 if(stat((path + "/" + result->d_name).c_str(), &st))
299 if(S_ISREG(st.st_mode))
300 files.push_back(result->d_name);
301 } else if(result->d_type == DT_REG) {
302 files.push_back(result->d_name);
311 void fides::certificate_save(const certificate *cert, const string &filename) {
312 ofstream file(filename.c_str());
313 file << cert->to_string() << '\n';
316 fides::certificate *fides::certificate_load(const string &filename) {
317 ifstream file(filename.c_str());
320 return certificate_from_string(data);
323 fides::certificate *fides::certificate_from_string(const string &data) {
325 e = data.find(' ', 0);
326 if(e == string::npos)
327 throw exception("Invalid certificate");
328 string fingerprint = hexdecode(data.substr(0, e));
329 publickey *signer = find_key(fingerprint);
331 throw exception("Unknown public key");
333 e = data.find('.', b);
334 if(e == string::npos)
335 throw exception("Invalid certificate");
336 struct timeval timestamp;
337 timestamp.tv_sec = atol(data.c_str() + b);
339 timestamp.tv_usec = atol(data.c_str() + b);
340 e = data.find(' ', b);
341 if(e == string::npos)
342 throw exception("Invalid certificate");
344 e = data.find(' ', b);
345 if(e == string::npos)
346 throw exception("Invalid certificate");
347 string signature = fides::b64decode(data.substr(b, e - b));
349 string statement = data.substr(b);
351 return new certificate(signer, timestamp, statement, signature);
354 // Fides main functions
356 fides::fides(const string &dir): homedir(dir) {
357 cerr << "Fides initialising\n";
359 // Set homedir to provided directory, or $FIDES_HOME, or $HOME/.fides, or as a last resort $PWD/.fides
361 homedir = getenv("FIDES_HOME") ?: "";
362 if(homedir.empty()) {
364 homedir = getenv("HOME") ?: getcwd(cwd, sizeof cwd);
365 homedir += "/.fides";
368 // Derived directories
370 certdir = homedir + "certs/";
371 keydir = homedir + "keys/";
372 obsoletedir = homedir + ".obsolete_certs/";
374 // Ensure the homedir and its subdirectories exist
375 mkdir(homedir.c_str(), 0700);
376 mkdir(certdir.c_str(), 0700);
377 mkdir(keydir.c_str(), 0700);
378 mkdir(obsoletedir.c_str(), 0700);
381 mykey.load_private(homedir + "priv");
383 } catch(fides::exception &e) {
384 cerr << "Fides generating keypair\n";
386 mykey.save_private(homedir + "priv");
387 mykey.save(keydir + hexencode(mykey.fingerprint()));
390 vector<string> files = dirlist(keydir);
391 for(size_t i = 0; i < files.size(); ++i) {
392 cerr << "Loading key " << files[i] << '\n';
394 publickey *key = new publickey();
395 key->load(keydir + files[i]);
396 keys[hexdecode(files[i])] = key;
399 keys[mykey.fingerprint()] = &mykey;
401 files = dirlist(certdir);
402 for(size_t i = 0; i < files.size(); ++i) {
403 cerr << "Loading certificate " << files[i] << '\n';
404 certificate *cert = certificate_load(certdir + files[i]);
405 if(false && !cert->validate()) {
406 cerr << "Bad certificate!\n";
409 certs[hexdecode(files[i])] = cert;
412 // TODO: save and load this value
420 cerr << "Fides exitting\n";
421 for(map<string, certificate *>::iterator i = certs.begin(); i != certs.end(); ++i)
423 for(map<string, publickey *>::iterator i = keys.begin(); i != keys.end(); ++i)
424 if(i->second != &mykey)
431 for(map<string, certificate *>::iterator i = certs.begin(); i != certs.end(); ++i) {
432 if(!i->second->validate()) {
433 cerr << "Validation of certificate failed: " << i->second->to_string() << '\n';
438 cerr << errors << " errors in " << certs.size() << " certificates\n";
442 string fides::get_homedir() {
446 bool fides::is_firstrun() {
450 fides::publickey *fides::find_key(const string &fingerprint) {
451 map<string, publickey *>::iterator i;
452 i = keys.find(fingerprint);
459 vector<fides::certificate *> fides::find_certificates(publickey *signer, const string ®ex) {
460 vector<certificate *> found;
461 map<string, certificate *>::iterator i;
462 regexp regexp(regex);
463 for(i = certs.begin(); i != certs.end(); ++i) {
465 cerr << "No certificate for " << hexencode(i->first) << '\n';
468 if(i->second->signer == signer)
469 if(regexp.match(i->second->statement))
470 found.push_back(i->second);
475 vector<fides::certificate *> fides::find_certificates(const string ®ex) {
476 vector<certificate *> found;
477 map<string, certificate *>::iterator i;
478 regexp regexp(regex);
479 for(i = certs.begin(); i != certs.end(); ++i)
480 if(regexp.match(i->second->statement))
481 found.push_back(i->second);
485 vector<fides::certificate *> fides::find_certificates(publickey *signer) {
486 vector<certificate *> found;
487 map<string, certificate *>::iterator i;
488 for(i = certs.begin(); i != certs.end(); ++i)
489 if(i->second->signer == signer)
490 found.push_back(i->second);
494 void fides::import_all(istream &in) {
498 while(getline(in, line)) {
502 if(is_pem || !line.compare(0, 11, "-----BEGIN ")) {
504 if(!line.compare(0, 9, "-----END ")) {
505 fides::publickey *key = new publickey();
506 key->from_string(pem);
507 cerr << "Imported key " << hexencode(key->fingerprint()) << '\n';
516 fides::certificate *cert = certificate_from_string(line);
517 cerr << "Importing certificate " << hexencode(cert->fingerprint()) << '\n';
522 void fides::export_all(ostream &out) {
523 for(map<string, publickey *>::iterator i = keys.begin(); i != keys.end(); ++i)
524 out << i->second->to_string();
525 for(map<string, certificate *>::iterator i = certs.begin(); i != certs.end(); ++i)
526 out << i->second->to_string() << '\n';
531 if(fides.is_firstrun()) {
532 cout << "New keys generated in " << fides.get_homedir() << '\n';
534 cout << "Fides already initialised\n";
539 void fides::trust(publickey *key) {
540 string full = "t+ " + hexencode(key->fingerprint());
544 void fides::distrust(publickey *key) {
545 string full = "t- " + hexencode(key->fingerprint());
549 void fides::dctrust(publickey *key) {
550 string full = "t0 " + hexencode(key->fingerprint());
554 static int is_trusted(int argc, char *const argv[]) {
559 fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
561 cerr << "Unknown key!\n";
564 return fides.is_trusted(key) ? 0 : 1;
567 static int is_distrusted(int argc, char *const argv[]) {
572 fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
574 cerr << "Unknown key!\n";
577 return fides.is_distrusted(key) ? 0 : 1;
580 static int trust(int argc, char *const argv[]) {
585 fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
589 cerr << "Unknown key!\n";
595 static int dctrust(int argc, char *const argv[]) {
600 fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
604 cerr << "Unknown key!\n";
610 static int distrust(int argc, char *const argv[]) {
615 fides::publickey *key = fides.find_key(fides::hexdecode(argv[0]));
619 cerr << "Unknown key!\n";
625 void fides::update_trust() {
626 // clear trust on all keys
627 for(map<string, publickey *>::iterator i = keys.begin(); i != keys.end(); ++i)
628 i->second->trust = 0;
630 // Start by checking all trust certificates from ourself.
631 // If another key is positively or negatively trusted, update its trust score
632 // and add it to the the list of new keys to check.
633 // Then add our own key to the list of already checked keys.
634 // Then check all the trust certificates of those on the tocheck list, etc.
635 // Already checked keys are never updated anymore (TODO: is that smart?)
636 // Certificates of keys with a zero or negative trust score are not processed.
638 set<publickey *> checked;
639 set<publickey *> tocheck;
640 set<publickey *> newkeys;
641 set<publickey *>::iterator i;
644 tocheck.insert(&mykey);
646 while(tocheck.size()) {
648 checked.insert(tocheck.begin(), tocheck.end());
651 // loop over all keys whose certificates need to be checked
653 for(i = tocheck.begin(); i != tocheck.end(); ++i) {
654 cerr << "Trust for key " << hexencode((*i)->fingerprint()) << " set to " << (*i)->trust << '\n';
656 // except if this key is not trusted
661 // find all non-zero trust certificates of this key
663 vector<certificate *> matches = find_certificates(*i, "^t[+-] ");
665 // update trust value of those keys
667 for(size_t j = 0; j < matches.size(); j++) {
668 publickey *other = find_key(hexdecode(matches[j]->statement.substr(3)));
671 cerr << "Trust certificate for unknown key: " << matches[j]->to_string() << '\n';
675 // except for keys we already checked
677 if(checked.find(other) != checked.end()) {
678 cerr << "Skipping trust certificate for already checked key: " << matches[j]->to_string() << '\n';
684 if(matches[j]->statement[1] == '+')
689 newkeys.insert(other);
697 void fides::merge(publickey *key) {
698 if(keys.find(key->fingerprint()) != keys.end()) {
699 cerr << "Key already known\n";
703 keys[key->fingerprint()] = key;
704 key->save(keydir + hexencode(key->fingerprint()));
707 void fides::merge(certificate *cert) {
708 // TODO: check if cert is already in database
709 // TODO: check if cert obsoletes other certs
711 // If we already know this certificate, drop it.
712 if(certs.find(cert->fingerprint()) != certs.end()) {
713 cerr << "Certificate already known\n";
717 // If the certificate does not validate, drop it.
718 if(!cert->validate()) {
719 // TODO: this should not happen, be wary of DoS attacks
720 cerr << "Certificate invalid\n";
724 // TODO: move these regexps to the class?
725 regexp authexp("^a[+0-] ");
726 regexp trustexp("^t[+0-] ");
727 vector<certificate *> others;
729 // Is this an authorisation cert?
730 if(authexp.match(cert->statement)) {
731 // Find certs identical except for the +/-/0
732 // TODO: escape statement in regexp
733 others = find_certificates(cert->signer, string("^a[+0-] ") + cert->statement.substr(3) + '$');
735 if(timercmp(&others[0]->timestamp, &cert->timestamp, >)) {
736 cerr << "Certificate is overruled by a newer certificate\n";
739 if(timercmp(&others[0]->timestamp, &cert->timestamp, ==)) {
740 // TODO: this should not happen, be wary of DoS attacks
741 cerr << "Certificate has same timestamp as another timestamp!\n";
744 cerr << "Certificate overrules an older certificate!\n";
745 // save new cert first
746 certificate_save(cert, certdir + hexencode(cert->fingerprint()));
747 certs[cert->fingerprint()] = cert;
750 rename((certdir + hexencode(others[0]->fingerprint())).c_str(), (obsoletedir + hexencode(others[0]->fingerprint())).c_str());
751 certs.erase(others[0]->fingerprint());
757 // Is this a trust cert?
758 // TODO: it's just the same as above!
759 if(trustexp.match(cert->statement)) {
760 // Find certs identical except for the +/-/0
761 // TODO: escape statement in regexp
762 others = find_certificates(cert->signer, string("^t[+0-] ") + cert->statement.substr(3) + '$');
764 if(timercmp(&others[0]->timestamp, &cert->timestamp, >)) {
765 cerr << "Certificate is overruled by a newer certificate\n";
768 if(timercmp(&others[0]->timestamp, &cert->timestamp, ==)) {
769 // TODO: this should not happen, be wary of DoS attacks
770 cerr << "Certificate has same timestamp as another timestamp!\n";
773 cerr << "Certificate overrules an older certificate!\n";
775 rename((certdir + hexencode(others[0]->fingerprint())).c_str(), (obsoletedir + hexencode(others[0]->fingerprint())).c_str());
776 certs.erase(others[0]->fingerprint());
778 certs[cert->fingerprint()] = cert;
779 certificate_save(cert, certdir + hexencode(cert->fingerprint()));
784 // Did somebody sign the exact same statement twice?
785 // Could happen if there is a different, conflicting statement between this new and the corresponding old one.
786 others = find_certificates(cert->signer, string("^") + cert->statement + '$');
788 if(timercmp(&others[0]->timestamp, &cert->timestamp, >)) {
789 cerr << "Certificate is overruled by a newer certificate\n";
792 if(timercmp(&others[0]->timestamp, &cert->timestamp, ==)) {
793 // TODO: this should not happen, be wary of DoS attacks
794 cerr << "Certificate has same timestamp as another timestamp!\n";
797 cerr << "Certificate overrules an older certificate!\n";
799 rename((certdir + hexencode(others[0]->fingerprint())).c_str(), (obsoletedir + hexencode(others[0]->fingerprint())).c_str());
800 certs.erase(others[0]->fingerprint());
802 certs[cert->fingerprint()] = cert;
803 certificate_save(cert, certdir + hexencode(cert->fingerprint()));
807 cerr << "Certificate is new\n";
808 certs[cert->fingerprint()] = cert;
809 certificate_save(cert, certdir + hexencode(cert->fingerprint()));
812 void fides::auth_stats(const string &statement, int &self, int &trusted, int &all) {
813 self = trusted = all = 0;
814 vector<certificate *> matches = find_certificates(string("^a[+0-] ") + statement + '$');
815 for(size_t i = 0; i < matches.size(); ++i) {
816 char code = matches[i]->statement[1];
822 if(matches[i]->signer == &mykey)
824 if(matches[i]->signer->trust > 0)
830 bool fides::is_trusted(publickey *key) {
831 return key->trust > 0;
834 bool fides::is_distrusted(publickey *key) {
835 return key->trust < 0;
838 bool fides::is_allowed(const string &statement, publickey *key) {
839 int self, trusted, all;
842 auth_stats(hexencode(key->fingerprint()) + " " + statement, self, trusted, all);
844 auth_stats(statement, self, trusted, all);
854 bool fides::is_denied(const string &statement, publickey *key) {
855 int self, trusted, all;
858 auth_stats(hexencode(key->fingerprint()) + " " + statement, self, trusted, all);
860 auth_stats(statement, self, trusted, all);
870 void fides::sign(const string &statement) {
871 // Try to set "latest" to now, but ensure monoticity
873 gettimeofday(&now, 0);
874 if(timercmp(&latest, &now, >=)) {
876 if(latest.tv_usec >= 1000000) {
878 latest.tv_usec -= 1000000;
884 // Create a new certificate and merge it with our database
885 merge(new certificate(&mykey, latest, statement));
888 void fides::allow(const string &statement, publickey *key) {
891 full += hexencode(key->fingerprint()) + ' ';
896 void fides::dontcare(const string &statement, publickey *key) {
899 full += hexencode(key->fingerprint()) + ' ';
904 void fides::deny(const string &statement, publickey *key) {
907 full += hexencode(key->fingerprint()) + ' ';
912 static int sign(int argc, char *const argv[]) {
921 static int allow(int argc, char *const argv[]) {
926 fides.allow(argv[0]);
930 static int dontcare(int argc, char *const argv[]) {
935 fides.dontcare(argv[0]);
939 static int deny(int argc, char *const argv[]) {
948 static int import(int argc, char *const argv[]) {
952 ifstream in(argv[0]);
953 fides.import_all(in);
955 fides.import_all(cin);
959 static int exprt(int argc, char *const argv[]) {
963 ofstream out(argv[0]);
964 fides.export_all(out);
966 fides.export_all(cout);
970 static int find(int argc, char *const argv[]) {
974 // Find certificates matching statement
976 const vector<fides::certificate *> &certs = fides.find_certificates(argv[0]);
977 for(size_t i = 0; i < certs.size(); ++i)
978 cout << i << ' ' << certs[i]->to_string() << '\n';
982 static int is_allowed(int argc, char *const argv[]) {
987 return fides.is_allowed(argv[0]) ? 0 : 1;
990 static int is_denied(int argc, char *const argv[]) {
995 return fides.is_denied(argv[0]) ? 0 : 1;
998 static int test(int argc, char *const argv[]) {
1003 int self, trusted, all;
1004 fides.auth_stats(argv[0], self, trusted, all);
1005 cout << "Self: " << self << ", trusted: " << trusted << ", all: " << all << '\n';
1012 cout << "Everything OK\n";
1015 cout << "Integrity failure!\n";
1020 int main(int argc, char *const argv[]) {
1024 static struct option const long_options[] = {
1025 {"homedir", required_argument, NULL, 2},
1026 {"help", no_argument, NULL, 'h'},
1027 {"version", no_argument, NULL, 3},
1031 while((r = getopt_long(argc, argv, "h", long_options, &option_index)) != EOF) {
1033 case 0: /* long option */
1035 case 1: /* non-option */
1038 //homedir = strdup(optarg);
1044 help(cout, argv[0]);
1050 help(cerr, argv[0]);
1054 if(!strcmp(argv[1], "help")) {
1055 help(cout, argv[0]);
1059 if(!strcmp(argv[1], "version")) {
1064 if(!strcmp(argv[1], "init"))
1067 if(!strcmp(argv[1], "trust"))
1068 return trust(argc - 2, argv + 2);
1070 if(!strcmp(argv[1], "dctrust"))
1071 return dctrust(argc - 2, argv + 2);
1073 if(!strcmp(argv[1], "distrust"))
1074 return distrust(argc - 2, argv + 2);
1076 if(!strcmp(argv[1], "is_trusted"))
1077 return is_trusted(argc - 2, argv + 2);
1079 if(!strcmp(argv[1], "is_distrusted"))
1080 return is_distrusted(argc - 2, argv + 2);
1082 if(!strcmp(argv[1], "is_allowed"))
1083 return is_allowed(argc - 2, argv + 2);
1085 if(!strcmp(argv[1], "is_denied"))
1086 return is_denied(argc - 2, argv + 2);
1088 if(!strcmp(argv[1], "allow"))
1089 return allow(argc - 2, argv + 2);
1091 if(!strcmp(argv[1], "dontcare"))
1092 return dontcare(argc - 2, argv + 2);
1094 if(!strcmp(argv[1], "deny"))
1095 return deny(argc - 2, argv + 2);
1097 if(!strcmp(argv[1], "sign"))
1098 return sign(argc - 2, argv + 2);
1100 if(!strcmp(argv[1], "import"))
1101 return import(argc - 2, argv + 2);
1103 if(!strcmp(argv[1], "export"))
1104 return exprt(argc - 2, argv + 2);
1106 if(!strcmp(argv[1], "test"))
1107 return test(argc - 2, argv + 2);
1109 if(!strcmp(argv[1], "find"))
1110 return find(argc - 2, argv + 2);
1112 if(!strcmp(argv[1], "fsck"))
1115 cerr << "Unknown command: " << argv[1] << '\n';