]> git.sommitrealweird.co.uk Git - onak.git/blobdiff - keydb_pg.c
Fix replyto email address bug.
[onak.git] / keydb_pg.c
index 76129fa0b1565be42a39d46de3176e4cb097828b..5933c91381647f4fb837c3de4ea859aafb9d59f9 100644 (file)
@@ -3,14 +3,12 @@
  *
  * Jonathan McDowell <noodles@earth.li>
  *
- * Copyright 2002 Project Purple
+ * Copyright 2002-2004 Project Purple
  */
 
 #include <postgresql/libpq-fe.h>
 #include <postgresql/libpq/libpq-fs.h>
 
-//#include <libpq-fe.h>
-//#include <libpq/libpq-fs.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <errno.h>
@@ -23,8 +21,9 @@
 #include "hash.h"
 #include "keydb.h"
 #include "keyid.h"
-#include "keyindex.h"
+#include "decodekey.h"
 #include "keystructs.h"
+#include "log.h"
 #include "mem.h"
 #include "onak-conf.h"
 #include "parsekey.h"
@@ -39,7 +38,7 @@ static PGconn *dbconn = NULL;
  */
 static int keydb_fetchchar(void *fd, size_t count, unsigned char *c)
 {
-       return (!lo_read(dbconn, *(int *) fd, c, count));
+       return (!lo_read(dbconn, *(int *) fd, (char *) c, count));
 }
 
 /**
@@ -47,7 +46,7 @@ static int keydb_fetchchar(void *fd, size_t count, unsigned char *c)
  */
 static int keydb_putchar(void *fd, size_t count, unsigned char *c)
 {
-       return !(lo_write(dbconn, *(int *) fd, c, count));
+       return !(lo_write(dbconn, *(int *) fd, (char *) c, count));
 }
 
 /**
@@ -57,7 +56,7 @@ static int keydb_putchar(void *fd, size_t count, unsigned char *c)
  *     this file are called in order to allow the DB to be initialized ready
  *     for access.
  */
-void initdb(void)
+void initdb(bool readonly)
 {
        dbconn = PQsetdbLogin(config.pg_dbhost, // host
                        NULL, // port
@@ -68,8 +67,8 @@ void initdb(void)
                        config.pg_dbpass); // password
 
        if (PQstatus(dbconn) == CONNECTION_BAD) {
-               fprintf(stderr, "Connection to database failed.\n");
-               fprintf(stderr, "%s\n", PQerrorMessage(dbconn));
+               logthing(LOGTHING_CRITICAL, "Connection to database failed.");
+               logthing(LOGTHING_CRITICAL, "%s", PQerrorMessage(dbconn));
                PQfinish(dbconn);
                dbconn = NULL;
                exit(1);
@@ -132,7 +131,8 @@ void endtrans(void)
  *     in and then parse_keys() to parse the packets into a publickey
  *     structure.
  */
-int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey, bool intrans)
+int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+               bool intrans)
 {
        struct openpgp_packet_list *packets = NULL;
        PGresult *result = NULL;
@@ -168,16 +168,19 @@ int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey, bool intrans
 
                        fd = lo_open(dbconn, key_oid, INV_READ);
                        if (fd < 0) {
-                               fprintf(stderr, "Can't open large object.\n");
+                               logthing(LOGTHING_ERROR,
+                                               "Can't open large object.");
                        } else {
                                read_openpgp_stream(keydb_fetchchar, &fd,
-                                               &packets);
+                                               &packets, 0);
                                parse_keys(packets, publickey);
                                lo_close(dbconn, fd);
+                               free_packet_list(packets);
+                               packets = NULL;
                        }
                }
        } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
-               fprintf(stderr, "Problem retrieving key from DB.\n");
+               logthing(LOGTHING_ERROR, "Problem retrieving key from DB.");
        }
 
        PQclear(result);
@@ -232,16 +235,20 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 
                        fd = lo_open(dbconn, key_oid, INV_READ);
                        if (fd < 0) {
-                               fprintf(stderr, "Can't open large object.\n");
+                               logthing(LOGTHING_ERROR,
+                                               "Can't open large object.");
                        } else {
                                read_openpgp_stream(keydb_fetchchar, &fd,
-                                               &packets);
+                                               &packets,
+                                               0);
                                parse_keys(packets, publickey);
                                lo_close(dbconn, fd);
+                               free_packet_list(packets);
+                               packets = NULL;
                        }
                }
        } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
-               fprintf(stderr, "Problem retrieving key from DB.\n");
+               logthing(LOGTHING_ERROR, "Problem retrieving key from DB.");
        }
 
        PQclear(result);
@@ -302,12 +309,14 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
                
        key_oid = lo_creat(dbconn, INV_READ | INV_WRITE);
        if (key_oid == 0) {
-               fprintf(stderr, "Can't create key OID\n");
+               logthing(LOGTHING_ERROR, "Can't create key OID");
        } else {
                fd = lo_open(dbconn, key_oid, INV_WRITE);
                write_openpgp_stream(keydb_putchar, &fd, packets);
                lo_close(dbconn, fd);
        }
+       free_packet_list(packets);
+       packets = NULL;
 
        snprintf(statement, 1023, 
                        "INSERT INTO onak_keys (keyid, keydata) VALUES "
@@ -317,8 +326,8 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
        result = PQexec(dbconn, statement);
 
        if (PQresultStatus(result) != PGRES_COMMAND_OK) {
-               fprintf(stderr, "Problem storing key in DB.\n");
-               fprintf(stderr, "%s\n", PQresultErrorMessage(result));
+               logthing(LOGTHING_ERROR, "Problem storing key in DB.");
+               logthing(LOGTHING_ERROR, "%s", PQresultErrorMessage(result));
        }
        PQclear(result);
 
@@ -349,8 +358,9 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
                        }
 
                        if (PQresultStatus(result) != PGRES_COMMAND_OK) {
-                               fprintf(stderr, "Problem storing key in DB.\n");
-                               fprintf(stderr, "%s\n",
+                               logthing(LOGTHING_ERROR,
+                                               "Problem storing key in DB.");
+                               logthing(LOGTHING_ERROR, "%s",
                                                PQresultErrorMessage(result));
                        }
                        /*
@@ -438,7 +448,8 @@ int delete_key(uint64_t keyid, bool intrans)
                        keyid);
                result = PQexec(dbconn, statement);
        } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
-               fprintf(stderr, "Problem retrieving key (%llX) from DB.\n",
+               logthing(LOGTHING_ERROR,
+                               "Problem retrieving key (%llX) from DB.",
                                keyid);
        }
 
@@ -477,7 +488,8 @@ char *keyid2uid(uint64_t keyid)
                        PQntuples(result) >= 1) {
                uid = strdup(PQgetvalue(result, 0, 0));
        } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
-               fprintf(stderr, "Problem retrieving key (%llX) from DB.\n",
+               logthing(LOGTHING_ERROR,
+                               "Problem retrieving key (%llX) from DB.",
                                keyid);
        }
 
@@ -489,19 +501,21 @@ char *keyid2uid(uint64_t keyid)
 /**
  *     getkeysigs - Gets a linked list of the signatures on a key.
  *     @keyid: The keyid to get the sigs for.
+ *     @revoked: If the key is revoked.
  *
  *     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 *getkeysigs(uint64_t keyid, bool *revoked)
 {
        struct ll *sigs = NULL;
        PGresult *result = NULL;
        uint64_t signer;
        char statement[1024];
-       int i = 0;
+       int i, j;
        int numsigs = 0;
        bool intrans = false;
+       char *str;
 
        if (!intrans) {
                result = PQexec(dbconn, "BEGIN");
@@ -509,18 +523,29 @@ struct ll *getkeysigs(uint64_t keyid)
        }
 
        snprintf(statement, 1023,
-               "SELECT signer FROM onak_sigs WHERE signee = '%llX'",
+               "SELECT DISTINCT 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);
+                       j = 0;
+                       signer = 0;
+                       str = PQgetvalue(result, i, 0);
+                       while (str[j] != 0) {
+                               signer <<= 4;
+                               if (str[j] >= '0' && str[j] <= '9') {
+                                       signer += str[j] - '0';
+                               } else {
+                                       signer += str[j] - 'A' + 10;
+                               }
+                               j++;
+                       }
                        sigs = lladd(sigs, createandaddtohash(signer));
                }
        } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
-               fprintf(stderr, "Problem retrieving key from DB.\n");
+               logthing(LOGTHING_ERROR, "Problem retrieving key from DB.");
        }
 
        PQclear(result);
@@ -529,11 +554,81 @@ struct ll *getkeysigs(uint64_t keyid)
                result = PQexec(dbconn, "COMMIT");
                PQclear(result);
        }
+
+       /*
+        * TODO: What do we do about revocations? We don't have the details
+        * stored in a separate table, so we'd have to grab the key and decode
+        * it, which we're trying to avoid by having a signers table.
+        */
+       if (revoked != NULL) {
+               *revoked = false;
+       }
+       
        return sigs;
 }
 
+/**
+ *     iterate_keys - call a function once for each key in the db.
+ *     @iterfunc: The function to call.
+ *     @ctx: A context pointer
+ *
+ *     Calls iterfunc once for each key in the database. ctx is passed
+ *     unaltered to iterfunc. This function is intended to aid database dumps
+ *     and statistic calculations.
+ *
+ *     Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+               void *ctx)
+{
+       struct openpgp_packet_list *packets = NULL;
+       struct openpgp_publickey *key = NULL;
+       PGresult *result = NULL;
+       char *oids = NULL;
+       char statement[1024];
+       int fd = -1;
+       int i = 0;
+       int numkeys = 0;
+       Oid key_oid;
+
+       result = PQexec(dbconn, "SELECT keydata FROM onak_keys;");
+
+       if (PQresultStatus(result) == PGRES_TUPLES_OK) {
+               numkeys = PQntuples(result);
+               for (i = 0; i < numkeys; i++) {
+                       oids = PQgetvalue(result, i, 0);
+                       key_oid = (Oid) atoi(oids);
+
+                       fd = lo_open(dbconn, key_oid, INV_READ);
+                       if (fd < 0) {
+                               logthing(LOGTHING_ERROR,
+                                               "Can't open large object.");
+                       } else {
+                               read_openpgp_stream(keydb_fetchchar, &fd,
+                                               &packets, 0);
+                               parse_keys(packets, key);
+                               lo_close(dbconn, fd);
+
+                               iterfunc(ctx, key);
+                                       
+                               free_publickey(key);
+                               key = NULL;
+                               free_packet_list(packets);
+                               packets = NULL;
+                       }
+               }
+       } else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+               logthing(LOGTHING_ERROR, "Problem retrieving key from DB.");
+       }
+
+       PQclear(result);
+
+       return (numkeys);
+}
+
 /*
  * Include the basic keydb routines.
  */
 #define NEED_GETFULLKEYID 1
+#define NEED_UPDATEKEYS 1
 #include "keydb.c"