]> the.earth.li Git - onak.git/blobdiff - keydb_pg.c
cscvs to tla changeset 18
[onak.git] / keydb_pg.c
index d2a2a55c5df6146e9c1f48af1b310b18ca4e57fc..76129fa0b1565be42a39d46de3176e4cb097828b 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
+#include "hash.h"
 #include "keydb.h"
 #include "keyid.h"
 #include "keyindex.h"
 #include "keystructs.h"
 #include "mem.h"
-#include "onak_conf.h"
+#include "onak-conf.h"
 #include "parsekey.h"
 
 /**
@@ -44,9 +45,9 @@ static int keydb_fetchchar(void *fd, size_t count, unsigned char *c)
 /**
  *     keydb_putchar - Puts a char to a file.
  */
-static int keydb_putchar(void *fd, unsigned char c)
+static int keydb_putchar(void *fd, size_t count, unsigned char *c)
 {
-       return !(lo_write(dbconn, *(int *) fd, &c, sizeof(c)));
+       return !(lo_write(dbconn, *(int *) fd, c, count));
 }
 
 /**
@@ -87,10 +88,43 @@ void cleanupdb(void)
        dbconn = NULL;
 }
 
+/**
+ *     starttrans - Start a transaction.
+ *
+ *     Start a transaction. Intended to be used if we're about to perform many
+ *     operations on the database to help speed it all up, or if we want
+ *     something to only succeed if all relevant operations are successful.
+ */
+bool starttrans(void)
+{
+       PGresult *result = NULL;
+       
+       result = PQexec(dbconn, "BEGIN");
+       PQclear(result);
+
+       return true;
+}
+
+/**
+ *     endtrans - End a transaction.
+ *
+ *     Ends a transaction.
+ */
+void endtrans(void)
+{
+       PGresult *result = NULL;
+
+       result = PQexec(dbconn, "COMMIT");
+       PQclear(result);
+
+       return;
+}
+
 /**
  *     fetch_key - Given a keyid fetch the key from storage.
  *     @keyid: The keyid to fetch.
  *     @publickey: A pointer to a structure to return the key in.
+ *     @intrans: If we're already in a transaction.
  *
  *     We use the hex representation of the keyid as the filename to fetch the
  *     key from. The key is stored in the file as a binary OpenPGP stream of
@@ -98,7 +132,7 @@ void cleanupdb(void)
  *     in and then parse_keys() to parse the packets into a publickey
  *     structure.
  */
-int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey)
+int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey, bool intrans)
 {
        struct openpgp_packet_list *packets = NULL;
        PGresult *result = NULL;
@@ -109,8 +143,10 @@ int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey)
        int numkeys = 0;
        Oid key_oid;
 
-       result = PQexec(dbconn, "BEGIN");
-       PQclear(result);
+       if (!intrans) {
+               result = PQexec(dbconn, "BEGIN");
+               PQclear(result);
+       }
        
        if (keyid > 0xFFFFFFFF) {
                snprintf(statement, 1023,
@@ -146,8 +182,10 @@ int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey)
 
        PQclear(result);
 
-       result = PQexec(dbconn, "COMMIT");
-       PQclear(result);
+       if (!intrans) {
+               result = PQexec(dbconn, "COMMIT");
+               PQclear(result);
+       }
        return (numkeys);
 }
 
@@ -169,34 +207,22 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
        int i = 0;
        int numkeys = 0;
        Oid key_oid;
-       char *dodgychar = NULL;
+       char *newsearch = NULL;
 
        result = PQexec(dbconn, "BEGIN");
        PQclear(result);
 
-       /*
-        * TODO: We really want to use PQescapeString, but this isn't supported
-        * by the version of Postgresql in Debian Stable. Roll on Woody and for
-        * now kludge it.
-        */
-       dodgychar = strchr(search, '\'');
-       while (dodgychar != NULL) {
-               *dodgychar = ' ';
-               dodgychar = strchr(search, '\'');
-       }
-       dodgychar = strchr(search, '\\');
-       while (dodgychar != NULL) {
-               *dodgychar = ' ';
-               dodgychar = strchr(search, '\\');
-       }
-
-       
+       newsearch = malloc(strlen(search) * 2 + 1);
+       memset(newsearch, 0, strlen(search) * 2 + 1);
+       PQescapeString(newsearch, search, strlen(search));
        snprintf(statement, 1023,
                        "SELECT DISTINCT onak_keys.keydata FROM onak_keys, "
                        "onak_uids WHERE onak_keys.keyid = onak_uids.keyid "
                        "AND onak_uids.uid LIKE '%%%s%%'",
-                       search);
+                       newsearch);
        result = PQexec(dbconn, statement);
+       free(newsearch);
+       newsearch = NULL;
 
        if (PQresultStatus(result) == PGRES_TUPLES_OK) {
                numkeys = PQntuples(result);
@@ -228,26 +254,34 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 /**
  *     store_key - Takes a key and stores it.
  *     @publickey: A pointer to the public key to store.
+ *     @intrans: If we're already in a transaction.
+ *     @update: If true the key exists and should be updated.
  *
  *     Again we just use the hex representation of the keyid as the filename
  *     to store the key to. We flatten the public key to a list of OpenPGP
  *     packets and then use write_openpgp_stream() to write the stream out to
- *     the file.
+ *     the file. If update is true then we delete the old key first, otherwise
+ *     we trust that it doesn't exist.
  */
-int store_key(struct openpgp_publickey *publickey)
+int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
 {
        struct openpgp_packet_list *packets = NULL;
        struct openpgp_packet_list *list_end = NULL;
        struct openpgp_publickey *next = NULL;
+       struct openpgp_signedpacket_list *curuid = NULL;
        PGresult *result = NULL;
        char statement[1024];
        Oid key_oid;
        int fd;
        char **uids = NULL;
        char *primary = NULL;
-       char *dodgychar = NULL;
+       char *safeuid = NULL;
        int i;
 
+       if (!intrans) {
+               result = PQexec(dbconn, "BEGIN");
+               PQclear(result);
+       }
 
        /*
         * Delete the key if we already have it.
@@ -257,10 +291,9 @@ int store_key(struct openpgp_publickey *publickey)
         * of difference though - the largest chunk of data is the keydata and
         * it definitely needs updated.
         */
-       delete_key(get_keyid(publickey));
-
-       result = PQexec(dbconn, "BEGIN");
-       PQclear(result);
+       if (update) {
+               delete_key(get_keyid(publickey), true);
+       }
 
        next = publickey->next;
        publickey->next = NULL;
@@ -292,30 +325,29 @@ int store_key(struct openpgp_publickey *publickey)
        uids = keyuids(publickey, &primary);
        if (uids != NULL) {
                for (i = 0; uids[i] != NULL; i++) {
-                       /*
-                        * TODO: We really want to use PQescapeString, but this
-                        * isn't supported by the version of Postgresql in
-                        * Debian Stable. Roll on Woody and for now kludge it.
-                        */
-                       dodgychar = strchr(uids[i], '\'');
-                       while (dodgychar != NULL) {
-                               *dodgychar = ' ';
-                               dodgychar = strchr(uids[i], '\'');
+                       safeuid = malloc(strlen(uids[i]) * 2 + 1);
+                       if (safeuid != NULL) {
+                               memset(safeuid, 0, strlen(uids[i]) * 2 + 1);
+                               PQescapeString(safeuid, uids[i],
+                                               strlen(uids[i]));
+
+                               snprintf(statement, 1023,
+                                       "INSERT INTO onak_uids "
+                                       "(keyid, uid, pri) "
+                                       "VALUES ('%llX', '%s', '%c')",
+                                       get_keyid(publickey),
+                                       safeuid,
+                                       (uids[i] == primary) ? 't' : 'f');
+                               result = PQexec(dbconn, statement);
+
+                               free(safeuid);
+                               safeuid = NULL;
                        }
-                       dodgychar = strchr(uids[i], '\\');
-                               while (dodgychar != NULL) {
-                               *dodgychar = ' ';
-                               dodgychar = strchr(uids[i], '\\');
+                       if (uids[i] != NULL) {
+                               free(uids[i]);
+                               uids[i] = NULL;
                        }
 
-                       snprintf(statement, 1023,
-                               "INSERT INTO onak_uids (keyid, uid, pri) "
-                               "VALUES ('%llX', '%s', '%c')",
-                               get_keyid(publickey),
-                               uids[i],
-                               (uids[i] == primary) ? 't' : 'f');
-                       result = PQexec(dbconn, statement);
-
                        if (PQresultStatus(result) != PGRES_COMMAND_OK) {
                                fprintf(stderr, "Problem storing key in DB.\n");
                                fprintf(stderr, "%s\n",
@@ -326,10 +358,27 @@ int store_key(struct openpgp_publickey *publickey)
                         */
                        PQclear(result);
                }
+               free(uids);
+               uids = NULL;
        }
 
-       result = PQexec(dbconn, "COMMIT");
-       PQclear(result);
+       for (curuid = publickey->uids; curuid != NULL; curuid = curuid->next) {
+               for (packets = curuid->sigs; packets != NULL; 
+                               packets = packets->next) {
+                       snprintf(statement, 1023,
+                               "INSERT INTO onak_sigs (signer, signee) "
+                               "VALUES ('%llX', '%llX')",
+                               sig_keyid(packets->packet),
+                               get_keyid(publickey));
+                       result = PQexec(dbconn, statement);
+                       PQclear(result);
+               }
+       }
+
+       if (!intrans) {
+               result = PQexec(dbconn, "COMMIT");
+               PQclear(result);
+       }
        
        return 0;
 }
@@ -337,11 +386,12 @@ int store_key(struct openpgp_publickey *publickey)
 /**
  *     delete_key - Given a keyid delete the key from storage.
  *     @keyid: The keyid to delete.
+ *     @intrans: If we're already in a transaction.
  *
  *     This function deletes a public key from whatever storage mechanism we
  *     are using. Returns 0 if the key existed.
  */
-int delete_key(uint64_t keyid)
+int delete_key(uint64_t keyid, bool intrans)
 {
        PGresult *result = NULL;
        char *oids = NULL;
@@ -350,8 +400,10 @@ int delete_key(uint64_t keyid)
        int i;
        Oid key_oid;
 
-       result = PQexec(dbconn, "BEGIN");
-       PQclear(result);
+       if (!intrans) {
+               result = PQexec(dbconn, "BEGIN");
+               PQclear(result);
+       }
        
        snprintf(statement, 1023,
                        "SELECT keydata FROM onak_keys WHERE keyid = '%llX'",
@@ -375,6 +427,12 @@ int delete_key(uint64_t keyid)
                result = PQexec(dbconn, statement);
                PQclear(result);
 
+               snprintf(statement, 1023,
+                       "DELETE FROM onak_sigs WHERE signee = '%llX'",
+                       keyid);
+               result = PQexec(dbconn, statement);
+               PQclear(result);
+
                snprintf(statement, 1023,
                        "DELETE FROM onak_uids WHERE keyid = '%llX'",
                        keyid);
@@ -386,8 +444,10 @@ int delete_key(uint64_t keyid)
 
        PQclear(result);
 
-       result = PQexec(dbconn, "COMMIT");
-       PQclear(result);
+       if (!intrans) {
+               result = PQexec(dbconn, "COMMIT");
+               PQclear(result);
+       }
        return (found);
 }
 
@@ -426,8 +486,54 @@ char *keyid2uid(uint64_t keyid)
        return uid;
 }
 
+/**
+ *     getkeysigs - Gets a linked list of the signatures on a key.
+ *     @keyid: The keyid to get the sigs for.
+ *
+ *     This function gets the list of signatures on a key. Used for key 
+ *     indexing and doing stats bits.
+ */
+struct ll *getkeysigs(uint64_t keyid)
+{
+       struct ll *sigs = NULL;
+       PGresult *result = NULL;
+       uint64_t signer;
+       char statement[1024];
+       int i = 0;
+       int numsigs = 0;
+       bool intrans = false;
+
+       if (!intrans) {
+               result = PQexec(dbconn, "BEGIN");
+               PQclear(result);
+       }
+
+       snprintf(statement, 1023,
+               "SELECT signer FROM onak_sigs WHERE signee = '%llX'",
+               keyid);
+       result = PQexec(dbconn, statement);
+
+       if (PQresultStatus(result) == PGRES_TUPLES_OK) {
+               numsigs = PQntuples(result);
+               for (i = 0; i < numsigs;  i++) {
+                       signer = strtol(PQgetvalue(result, i, 0), NULL, 16);
+                       sigs = lladd(sigs, createandaddtohash(signer));
+               }
+       } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+               fprintf(stderr, "Problem retrieving key from DB.\n");
+       }
+
+       PQclear(result);
+
+       if (!intrans) {
+               result = PQexec(dbconn, "COMMIT");
+               PQclear(result);
+       }
+       return sigs;
+}
+
 /*
  * Include the basic keydb routines.
  */
-#define NEED_GETKEYSIGS 1
+#define NEED_GETFULLKEYID 1
 #include "keydb.c"