Fix up dynamic loading; we export a structure of functions now from
[onak.git] / keydb.c
1 /*
2  * keydb.c - Routines for DB access that just use store/fetch.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002-2004 Project Purple
7  */
8
9 /**
10  *      The routines in this file are meant to be used as an initial step when
11  *      adding a new db access module. They provide various functions required
12  *      of the db access module using only the store and fetch functions. As
13  *      they need to parse the actual OpenPGP data to work they are a lot
14  *      slower than custom functions however.
15  */
16
17 #include <stdio.h>
18
19 #include "decodekey.h"
20 #include "hash.h"
21 #include "keydb.h"
22 #include "keyid.h"
23 #include "keystructs.h"
24 #include "mem.h"
25 #include "merge.h"
26 #include "parsekey.h"
27 #include "sendsync.h"
28
29 #ifdef NEED_KEYID2UID
30 /**
31  *      keyid2uid - Takes a keyid and returns the primary UID for it.
32  *      @keyid: The keyid to lookup.
33  */
34 char *generic_keyid2uid(uint64_t keyid)
35 {
36         struct openpgp_publickey *publickey = NULL;
37         struct openpgp_signedpacket_list *curuid = NULL;
38         char buf[1024];
39
40         buf[0]=0;
41         if (config.dbbackend->fetch_key(keyid, &publickey, false) &&
42                         publickey != NULL) {
43                 curuid = publickey->uids;
44                 while (curuid != NULL && buf[0] == 0) {
45                         if (curuid->packet->tag == 13) {
46                                 snprintf(buf, 1023, "%.*s",
47                                                 (int) curuid->packet->length,
48                                                 curuid->packet->data);
49                         }
50                         curuid = curuid -> next;
51                 }
52                 free_publickey(publickey);
53         }
54
55         if (buf[0] == 0) {
56                 return NULL;
57         } else {
58                 return strdup(buf);
59         }
60 }
61 #endif
62
63 #ifdef NEED_GETKEYSIGS
64 /**
65  *      getkeysigs - Gets a linked list of the signatures on a key.
66  *      @keyid: The keyid to get the sigs for.
67  *      @revoked: Is the key revoked?
68  *
69  *      This function gets the list of signatures on a key. Used for key 
70  *      indexing and doing stats bits. If revoked is non-NULL then if the key
71  *      is revoked it's set to true.
72  */
73 struct ll *generic_getkeysigs(uint64_t keyid, bool *revoked)
74 {
75         struct ll *sigs = NULL;
76         struct openpgp_signedpacket_list *uids = NULL;
77         struct openpgp_publickey *publickey = NULL;
78
79         config.dbbackend->fetch_key(keyid, &publickey, false);
80         
81         if (publickey != NULL) {
82                 for (uids = publickey->uids; uids != NULL; uids = uids->next) {
83                         sigs = keysigs(sigs, uids->sigs);
84                 }
85                 if (revoked != NULL) {
86                         *revoked = publickey->revoked;
87                 }
88                 free_publickey(publickey);
89         }
90
91         return sigs;
92 }
93 #endif
94
95 /**
96  *      cached_getkeysigs - Gets the signatures on a key.
97  *      @keyid: The key we want the signatures for.
98  *      
99  *      This function gets the signatures on a key. It's the same as the
100  *      getkeysigs function above except we use the hash module to cache the
101  *      data so if we need it again it's already loaded.
102  */
103 struct ll *generic_cached_getkeysigs(uint64_t keyid)
104 {
105         struct stats_key *key = NULL;
106         struct stats_key *signedkey = NULL;
107         struct ll        *cursig = NULL;
108         bool              revoked = false;
109
110         if (keyid == 0)  {
111                 return NULL;
112         }
113
114         key = createandaddtohash(keyid);
115
116         if (key->gotsigs == false) {
117                 key->sigs = config.dbbackend->getkeysigs(key->keyid, &revoked);
118                 key->revoked = revoked;
119                 for (cursig = key->sigs; cursig != NULL;
120                                 cursig = cursig->next) {
121                         signedkey = (struct stats_key *) cursig->object;
122                         signedkey->signs = lladd(signedkey->signs, key);
123                 }
124                 key->gotsigs = true;
125         }
126
127         return key->sigs;
128 }
129
130 #ifdef NEED_GETFULLKEYID
131 /**
132  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
133  *      @keyid: The 32bit keyid.
134  *
135  *      This function maps a 32bit key id to the full 64bit one. It returns the
136  *      full keyid. If the key isn't found a keyid of 0 is returned.
137  */
138 uint64_t generic_getfullkeyid(uint64_t keyid)
139 {
140         struct openpgp_publickey *publickey = NULL;
141
142         if (keyid < 0x100000000LL) {
143                 config.dbbackend->fetch_key(keyid, &publickey, false);
144                 if (publickey != NULL) {
145                         keyid = get_keyid(publickey);
146                         free_publickey(publickey);
147                         publickey = NULL;
148                 } else {
149                         keyid = 0;
150                 }
151         }
152         
153         return keyid;
154 }
155 #endif
156
157 #ifdef NEED_UPDATEKEYS
158 /**
159  *      update_keys - Takes a list of public keys and updates them in the DB.
160  *      @keys: The keys to update in the DB.
161  *      @sendsync: Should we send a sync mail to our peers.
162  *
163  *      Takes a list of keys and adds them to the database, merging them with
164  *      the key in the database if it's already present there. The key list is
165  *      update to contain the minimum set of updates required to get from what
166  *      we had before to what we have now (ie the set of data that was added to
167  *      the DB). Returns the number of entirely new keys added.
168  */
169 int generic_update_keys(struct openpgp_publickey **keys, bool sendsync)
170 {
171         struct openpgp_publickey *curkey = NULL;
172         struct openpgp_publickey *oldkey = NULL;
173         struct openpgp_publickey *prev = NULL;
174         int newkeys = 0;
175         bool intrans;
176
177         for (curkey = *keys; curkey != NULL; curkey = curkey->next) {
178                 intrans = config.dbbackend->starttrans();
179                 logthing(LOGTHING_INFO,
180                         "Fetching key 0x%llX, result: %d",
181                         get_keyid(curkey),
182                         config.dbbackend->fetch_key(get_keyid(curkey), &oldkey,
183                                         intrans));
184
185                 /*
186                  * If we already have the key stored in the DB then merge it
187                  * with the new one that's been supplied. Otherwise the key
188                  * we've just got is the one that goes in the DB and also the
189                  * one that we send out.
190                  */
191                 if (oldkey != NULL) {
192                         merge_keys(oldkey, curkey);
193                         if (curkey->sigs == NULL &&
194                                         curkey->uids == NULL &&
195                                         curkey->subkeys == NULL) {
196                                 if (prev == NULL) {
197                                         *keys = curkey->next;
198                                 } else {
199                                         prev->next = curkey->next;
200                                         curkey->next = NULL;
201                                         free_publickey(curkey);
202                                         curkey = prev;
203                                 }
204                         } else {
205                                 prev = curkey;
206                                 logthing(LOGTHING_INFO,
207                                         "Merged key; storing updated key.");
208                                 store_key(oldkey, intrans, true);
209                         }
210                         free_publickey(oldkey);
211                         oldkey = NULL;
212                 } else {
213                         logthing(LOGTHING_INFO,
214                                 "Storing completely new key.");
215                         config.dbbackend->store_key(curkey, intrans, false);
216                         newkeys++;
217                 }
218                 config.dbbackend->endtrans();
219                 intrans = false;
220         }
221
222         if (sendsync && keys != NULL) {
223                 sendkeysync(*keys);
224         }
225
226         return newkeys;
227 }
228 #endif /* NEED_UPDATEKEYS */