]> WPIA git - cassiopeia.git/blob - src/main.cpp
upd: add file I/O util funcs.
[cassiopeia.git] / src / main.cpp
1 #include <sys/stat.h>
2 #include <unistd.h>
3
4 #include <iostream>
5 #include <fstream>
6 #include <streambuf>
7
8 #include "database.h"
9 #include "mysql.h"
10 #include "simpleOpensslSigner.h"
11 #include "util.h"
12
13 #ifdef NO_DAEMON
14 #define DAEMON false
15 #else
16 #define DAEMON true
17 #endif
18
19 std::string keyDir;
20 std::vector<Profile> profiles;
21 std::string sqlHost, sqlUser, sqlPass, sqlDB;
22
23 std::string writeBackFile( uint32_t serial, std::string cert ) {
24     std::string filename = "keys";
25     mkdir( filename.c_str(), 0755 );
26     filename += "/crt";
27     mkdir( filename.c_str(), 0755 );
28     filename += "/" + std::to_string( serial / 1000 );
29     mkdir( filename.c_str(), 0755 );
30     filename += "/" + std::to_string( serial ) + ".crt";
31     writeFile( filename, cert );
32     std::cout << "wrote to " << filename << std::endl;
33     return filename;
34 }
35
36 int main( int argc, const char* argv[] ) {
37     ( void ) argc;
38     ( void ) argv;
39     bool once = false;
40
41     if( argc == 2 && std::string( "--once" ) == std::string( argv[1] ) ) {
42         once = true;
43     }
44
45     std::ifstream config;
46
47     if( DAEMON ) {
48         config.open( "/etc/cacert/cassiopeia/cassiopeia.conf" );
49     } else {
50         config.open( "config.txt" );
51     }
52
53     if( !config.is_open() ) {
54         std::cerr << "config missing" << std::endl;
55         return 1;
56     }
57
58     std::string line1;
59
60     while( config >> line1 ) {
61         if( line1[0] == '#' ) {
62             continue;
63         }
64
65         int splitter = line1.find( "=" );
66
67         if( splitter == -1 ) {
68             std::cerr << "Ignoring malformed config line: " << line1 << std::endl;
69             continue;
70         }
71
72         std::string key = line1.substr( 0, splitter );
73         std::string value = line1.substr( splitter + 1 );
74
75         if( key == "key.directory" ) {
76             keyDir = value;
77             continue;
78         } else if( key == "sql.host" ) {
79             sqlHost = value;
80         } else if( key == "sql.user" ) {
81             sqlUser = value;
82         } else if( key == "sql.password" ) {
83             sqlPass = value;
84         } else if( key == "sql.database" ) {
85             sqlDB = value;
86         }
87
88         if( key.compare( 0, 8, "profile." ) == 0 ) {
89             int numE = key.find( ".", 9 );
90
91             if( numE == 0 ) {
92                 std::cout << "invalid line: " << line1 << std::endl;
93                 continue;
94             }
95
96             unsigned int i = atoi( key.substr( 8, numE - 8 ).c_str() );
97             std::string rest = key.substr( numE + 1 );
98
99             if( i + 1 > profiles.size() ) {
100                 profiles.resize( i + 1 );
101             }
102
103             if( rest == "key" ) {
104                 profiles[i].key = value;
105             } else if( rest == "cert" ) {
106                 profiles[i].cert = value;
107             } else {
108                 std::cout << "invalid line: " << line1 << std::endl;
109                 continue;
110             }
111         }
112     }
113
114     std::cout << profiles.size() << " profiles loaded." << std::endl;
115
116     if( keyDir == "" ) {
117         std::cerr << "Missing config property key.directory" << std::endl;
118         return -1;
119     }
120
121     config.close();
122
123     std::shared_ptr<JobProvider> jp( new MySQLJobProvider( sqlHost, sqlUser, sqlPass, sqlDB ) );
124     std::shared_ptr<Signer> sign( new SimpleOpensslSigner() );
125
126     while( true ) {
127         std::shared_ptr<Job> job = jp->fetchJob();
128
129         if( !job ) {
130             std::cout << "Nothing to work on" << std::endl;
131             sleep( 5 );
132             continue;
133         }
134
135         if( job->task == "sign" ) {
136             try {
137                 std::shared_ptr<TBSCertificate> cert = jp->fetchTBSCert( job );
138
139                 if( !cert ) {
140                     std::cout << "wasn't able to load CSR" << std::endl;
141                     return 2;
142                 }
143
144                 std::cout << "Found a CSR at '" << cert->csr << "' signing" << std::endl;
145                 cert->csr_content = readFile( cert->csr );
146
147                 std::shared_ptr<SignedCertificate> res = sign->sign( cert );
148                 std::string fn = writeBackFile( atoi( job->target.c_str() ), res->certificate );
149                 res->crt_name = fn;
150                 jp->writeBack( job, res );
151             } catch( const char* c ) {
152                 std::cerr << "ERROR: " << c << std::endl;
153                 return 2;
154             } catch( std::string c ) {
155                 std::cerr << "ERROR: " << c << std::endl;
156                 return 2;
157             }
158         } else {
159             std::cout << "Unknown job type" << job->task << std::endl;
160         }
161
162         if( DAEMON && !jp->finishJob( job ) ) {
163             return 1;
164         }
165
166         if( !DAEMON || once ) {
167             return 0;
168         }
169     }
170 }