2 * keydb_pg.c - Routines to store and fetch keys in a PostGres database.
4 * Jonathan McDowell <noodles@earth.li>
6 * Copyright 2002 Project Purple
9 #include <postgresql/libpq-fe.h>
10 #include <postgresql/libpq/libpq-fs.h>
12 //#include <libpq-fe.h>
13 //#include <libpq/libpq-fs.h>
14 #include <sys/types.h>
26 #include "keystructs.h"
31 * dbconn - our connection to the database.
33 static PGconn *dbconn = NULL;
36 * keydb_fetchchar - Fetches a char from a file.
38 static int keydb_fetchchar(void *fd, size_t count, unsigned char *c)
40 return (!lo_read(dbconn, *(int *) fd, c, count));
44 * keydb_putchar - Puts a char to a file.
46 static int keydb_putchar(void *fd, unsigned char c)
48 return !(lo_write(dbconn, *(int *) fd, &c, sizeof(c)));
52 * initdb - Initialize the key database.
54 * This function should be called before any of the other functions in
55 * this file are called in order to allow the DB to be initialized ready
60 dbconn = PQsetdbLogin(NULL, // host
64 "noodles", // database
68 if (PQstatus(dbconn) == CONNECTION_BAD) {
69 fprintf(stderr, "Connection to database failed.\n");
70 fprintf(stderr, "%s\n", PQerrorMessage(dbconn));
78 * cleanupdb - De-initialize the key database.
80 * This function should be called upon program exit to allow the DB to
81 * cleanup after itself.
90 * fetch_key - Given a keyid fetch the key from storage.
91 * @keyid: The keyid to fetch.
92 * @publickey: A pointer to a structure to return the key in.
94 * We use the hex representation of the keyid as the filename to fetch the
95 * key from. The key is stored in the file as a binary OpenPGP stream of
96 * packets, so we can just use read_openpgp_stream() to read the packets
97 * in and then parse_keys() to parse the packets into a publickey
100 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey)
102 struct openpgp_packet_list *packets = NULL;
103 PGresult *result = NULL;
105 char statement[1024];
109 result = PQexec(dbconn, "BEGIN");
112 snprintf(statement, 1023,
113 "SELECT keydata FROM onak_keys WHERE keyid = '%llX'",
115 result = PQexec(dbconn, statement);
117 if (PQresultStatus(result) == PGRES_TUPLES_OK &&
118 PQntuples(result) == 1) {
119 oids = PQgetvalue(result, 0, 0);
120 key_oid = (Oid) atoi(oids);
122 fd = lo_open(dbconn, key_oid, INV_READ);
124 fprintf(stderr, "Can't open large object.\n");
126 read_openpgp_stream(keydb_fetchchar, &fd, &packets);
127 parse_keys(packets, publickey);
128 lo_close(dbconn, fd);
130 } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
131 fprintf(stderr, "Problem retrieving key (%llX) from DB.\n",
137 result = PQexec(dbconn, "COMMIT");
143 * store_key - Takes a key and stores it.
144 * @publickey: A pointer to the public key to store.
146 * Again we just use the hex representation of the keyid as the filename
147 * to store the key to. We flatten the public key to a list of OpenPGP
148 * packets and then use write_openpgp_stream() to write the stream out to
151 int store_key(struct openpgp_publickey *publickey)
153 struct openpgp_packet_list *packets = NULL;
154 struct openpgp_packet_list *list_end = NULL;
155 struct openpgp_publickey *next = NULL;
156 PGresult *result = NULL;
157 char statement[1024];
163 * Delete the key if we already have it.
165 * TODO: Can we optimize this perhaps? Possibly when other data is
166 * involved as well? I suspect this is easiest and doesn't make a lot
167 * of difference though - the largest chunk of data is the keydata and
168 * it definitely needs updated.
170 delete_key(get_keyid(publickey));
172 result = PQexec(dbconn, "BEGIN");
175 next = publickey->next;
176 publickey->next = NULL;
177 flatten_publickey(publickey, &packets, &list_end);
178 publickey->next = next;
180 key_oid = lo_creat(dbconn, INV_READ | INV_WRITE);
182 fprintf(stderr, "Can't create key OID\n");
184 fd = lo_open(dbconn, key_oid, INV_WRITE);
185 write_openpgp_stream(keydb_putchar, &fd, packets);
186 lo_close(dbconn, fd);
189 snprintf(statement, 1023,
190 "INSERT INTO onak_keys (keyid, keydata) VALUES "
192 get_keyid(publickey) & 0xFFFFFFFF,
194 result = PQexec(dbconn, statement);
196 if (PQresultStatus(result) != PGRES_COMMAND_OK) {
197 fprintf(stderr, "Problem storing key in DB.\n");
198 fprintf(stderr, "%s\n", PQresultErrorMessage(result));
202 result = PQexec(dbconn, "COMMIT");
209 * delete_key - Given a keyid delete the key from storage.
210 * @keyid: The keyid to delete.
212 * This function deletes a public key from whatever storage mechanism we
213 * are using. Returns 0 if the key existed.
215 int delete_key(uint64_t keyid)
217 PGresult *result = NULL;
219 char statement[1024];
223 result = PQexec(dbconn, "BEGIN");
226 snprintf(statement, 1023,
227 "SELECT keydata FROM onak_keys WHERE keyid = '%llX'",
229 result = PQexec(dbconn, statement);
231 if (PQresultStatus(result) == PGRES_TUPLES_OK &&
232 PQntuples(result) == 1) {
234 oids = PQgetvalue(result, 0, 0);
235 key_oid = (Oid) atoi(oids);
236 lo_unlink(dbconn, key_oid);
238 snprintf(statement, 1023,
239 "DELETE * FROM onak_keys WHERE keyid = '%llX'",
241 result = PQexec(dbconn, statement);
242 } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
243 fprintf(stderr, "Problem retrieving key (%llX) from DB.\n",
249 result = PQexec(dbconn, "COMMIT");
255 * Include the basic keydb routines.