]> WPIA git - cassiopeia.git/blob - src/db/psql.cpp
fix: remove leading zeros of serials
[cassiopeia.git] / src / db / psql.cpp
1 #include "psql.h"
2
3 #include <stdio.h>
4
5 #include <iostream>
6
7 #include <log/logger.hpp>
8 #include <exception>
9
10 PostgresJobProvider::PostgresJobProvider( const std::string& server, const std::string& user, const std::string& password, const std::string& database ):
11     c("dbname="+database+" host="+server+" user="+user+" password=" + password + " client_encoding=UTF-8 application_name=cassiopeia-client"){
12     // TODO better connection string generation??
13 }
14
15
16 std::shared_ptr<Job> PostgresJobProvider::fetchJob() {
17     std::string q = "SELECT id, \"targetId\", task, \"executeFrom\", \"executeTo\", warning FROM jobs WHERE state='open' AND warning < 3";
18     pqxx::work txn(c);
19     pqxx::result result = txn.exec(q);
20
21
22     auto job = std::make_shared<Job>();
23
24     if( result.size() == 0 ) {
25         return nullptr;
26     }
27
28     job->id = result[0]["id"].as<std::string>();
29     job->target =  result[0]["\"targetId\""].as<std::string>();
30     job->task = result[0]["task"].as<std::string>();
31     job->from = result[0]["\"executeFrom\""].as<std::string>("");
32     job->to = result[0]["\"executeTo\""].as<std::string>("");
33     job->warning = result[0]["warning"].as<std::string>();
34
35     logger::notef( "Got a job: (id=%s, target=%s, task=%s, from=%s, to=%s, warnings=%s)", job->id, job->target, job->task, job->from, job->to, job->warning );
36
37     return job;
38 }
39
40 void PostgresJobProvider::finishJob( std::shared_ptr<Job> job ) {
41     pqxx::work txn(c);
42
43     std::string q = "UPDATE jobs SET state='done' WHERE id=" + txn.quote( job->id );
44     pqxx::result r = txn.exec(q);
45
46     if( r.affected_rows() != 1 ) {
47         throw std::runtime_error("No database entry found.");
48     }
49     txn.commit();
50 }
51
52 void PostgresJobProvider::failJob( std::shared_ptr<Job> job ) {
53     pqxx::work txn(c);
54
55     std::string q = "UPDATE jobs SET warning = warning + 1 WHERE id=" + txn.quote( job->id );
56     pqxx::result r = txn.exec(q);
57
58     if( r.affected_rows() != 1 ) {
59         throw std::runtime_error("No database entry found.");
60     }
61     txn.commit();
62 }
63
64 std::shared_ptr<TBSCertificate> PostgresJobProvider::fetchTBSCert( std::shared_ptr<Job> job ) {
65     pqxx::work txn(c);
66     auto cert = std::make_shared<TBSCertificate>();
67     std::string q = "SELECT md, profile, csr_name, csr_type, keyname FROM certs INNER JOIN profiles ON profiles.id = certs.profile WHERE certs.id=" + txn.quote( job->target );
68     pqxx::result r = txn.exec(q);
69
70     if( r.size() != 1 ) {
71         throw std::runtime_error("Error, no or multiple certs found");
72      }
73     auto ro = r[0];
74
75     std::string profileName = ro["keyname"].as<std::string>();
76
77     cert->md = ro["md"].as<std::string>();
78     std::string profileId = ro["profile"].as<std::string>();
79
80     while( profileId.size() < 4 ) {
81         profileId = "0" + profileId;
82     }
83
84     cert->profile = profileId + "-" + profileName;
85
86     cert->csr = ro["csr_name"].as<std::string>();
87     cert->csr_type = ro["csr_type"].as<std::string>();
88
89     cert->SANs = std::vector<std::shared_ptr<SAN>>();
90
91     q = "SELECT contents, type FROM \"subjectAlternativeNames\" WHERE \"certId\"=" + txn.quote( job->target );
92     r = txn.exec( q );
93
94     std::cout << "Fetching SANs" << std::endl;
95
96     for( auto row = r.begin(); row != r.end(); ++row) {
97         auto nSAN = std::make_shared<SAN>();
98         nSAN->content = row["contents"].as<std::string>();
99         nSAN->type = row["type"].as<std::string>();
100         cert->SANs.push_back( nSAN );
101     }
102
103     q = "SELECT name, value FROM \"certAvas\" WHERE \"certId\"=" + txn.quote( job->target );
104     r = txn.exec( q );
105
106     for( auto row = r.begin(); row != r.end(); ++row) {
107         auto nAVA = std::make_shared<AVA>();
108         nAVA->name = row["name"].as<std::string>();
109         nAVA->value = row["value"].as<std::string>();
110         cert->AVAs.push_back( nAVA );
111     }
112
113     return cert;
114 }
115
116 std::string pgTime( std::string isoTime){
117         return isoTime.substr(0, 8) + " " + isoTime.substr(8, 6);
118 }
119
120 void PostgresJobProvider::writeBack( std::shared_ptr<Job> job, std::shared_ptr<SignedCertificate> res ) {
121     pqxx::work txn(c);
122     std::string id = "SELECT id FROM cacerts WHERE keyname=" + txn.quote( res->ca_name );
123     pqxx::result r = txn.exec(id);
124
125     std::string read_id;
126
127     if( r.size() != 1) {
128         throw std::runtime_error("Error while inserting new ca cert not found");
129     } else {
130         read_id = r[0]["id"].as<std::string>();
131     }
132     std::string serial = res->serial;
133     std::transform(serial.begin(), serial.end(), serial.begin(), ::tolower);
134     if(serial[0] == '0'){
135         serial = serial.substr(1);
136     }
137     std::string q = "UPDATE certs SET crt_name=" + txn.quote( res->crt_name ) + ", serial=" + txn.quote( serial ) + ", \"caid\" = " + txn.quote( read_id ) + ", created=" + txn.quote( pgTime(res->before) ) + ", expire=" + txn.quote( pgTime(res->after) ) + "  WHERE id=" + txn.quote( job->target );
138     // TODO write more thingies back
139
140     r = txn.exec( q );
141     if( r.affected_rows() != 1 ){
142         throw std::runtime_error("Only one row should be updated.");
143     }
144     txn.commit();
145 }
146
147 std::pair<std::string, std::string> PostgresJobProvider::getRevocationInfo( std::shared_ptr<Job> job ) {
148     pqxx::work txn(c);
149     std::string q = "SELECT certs.serial, cacerts.keyname FROM certs INNER JOIN cacerts ON certs.\"caid\" = cacerts.id WHERE certs.id = " + txn.quote( job->target );
150
151     pqxx::result r = txn.exec( q );
152     if( r.size() != 1) {
153         throw std::runtime_error("Only one row expected but multiple found.");
154     }
155
156     
157     return {r[0][0].as<std::string>(), r[0][1].as<std::string>()};
158 }
159
160 void PostgresJobProvider::writeBackRevocation( std::shared_ptr<Job> job, std::string date ) {
161     logger::notef( "Revoking at %s", date);
162     pqxx::work txn(c);
163     logger::note( "executing" );
164     pqxx::result r = txn.exec( "UPDATE certs SET revoked = " + txn.quote( pgTime( date ) ) + " WHERE id = " + txn.quote( job->target ) );
165     if( r.affected_rows() != 1 ){
166         throw std::runtime_error("Only one row should be updated.");
167     }
168     logger::note( "committing" );
169     txn.commit();
170     logger::note( "committed" );
171 }