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