Update Debian Vcs-* fields to point to git repository
[onak.git] / keydb_hkp.c
1 /*
2  * keydb_hkp.c - Routines to store and fetch keys from another keyserver.
3  *
4  * Copyright 2013 Jonathan McDowell <noodles@earth.li>
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <curl/curl.h>
25
26 #include "armor.h"
27 #include "charfuncs.h"
28 #include "keydb.h"
29 #include "keystructs.h"
30 #include "log.h"
31 #include "mem.h"
32 #include "onak-conf.h"
33 #include "parsekey.h"
34
35 static CURL *curl = NULL;
36
37 /**
38  *      initdb - Initialize the key database.
39  *
40  *      We initialize CURL here.
41  */
42 static void hkp_initdb(bool readonly)
43 {
44         curl_global_init(CURL_GLOBAL_DEFAULT);
45         curl = curl_easy_init();
46 }
47
48 /**
49  *      cleanupdb - De-initialize the key database.
50  *
51  *      We cleanup CURL here.
52  */
53 static void hkp_cleanupdb(void)
54 {
55         if (curl) {
56                 curl_easy_cleanup(curl);
57                 curl = NULL;
58         }
59         curl_global_cleanup();
60 }
61
62 /**
63  *      Receive data from a CURL request and process it into a buffer context.
64  */
65 static size_t hkp_curl_recv_data(void *buffer, size_t size, size_t nmemb,
66                 void *ctx)
67 {
68         buffer_putchar(ctx, nmemb * size, buffer);
69
70         return (nmemb * size);
71 }
72
73 /**
74  *      fetch_key - Given a keyid fetch the key from storage.
75  *      @keyid: The keyid to fetch.
76  *      @publickey: A pointer to a structure to return the key in.
77  *      @intrans: If we're already in a transaction.
78  *
79  *      We use the hex representation of the keyid as the filename to fetch the
80  *      key from. The key is stored in the file as a binary OpenPGP stream of
81  *      packets, so we can just use read_openpgp_stream() to read the packets
82  *      in and then parse_keys() to parse the packets into a publickey
83  *      structure.
84  */
85 static int hkp_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
86                 bool intrans)
87 {
88         struct openpgp_packet_list *packets = NULL;
89         char keyurl[1024];
90         CURLcode res;
91         struct buffer_ctx buf;
92
93         buf.offset = 0;
94         buf.size = 8192;
95         buf.buffer = malloc(8192);
96
97         snprintf(keyurl, sizeof(keyurl),
98                         "http://%s:11371/pks/lookup?op=get&search=0x%08" PRIX64,
99                         config.db_dir, keyid);
100
101         curl_easy_setopt(curl, CURLOPT_URL, keyurl);
102         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
103                         hkp_curl_recv_data);
104         curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
105         res = curl_easy_perform(curl);
106
107         if (res == 0) {
108                 buf.offset = 0;
109                 dearmor_openpgp_stream(buffer_fetchchar, &buf, &packets);
110                 parse_keys(packets, publickey);
111                 free_packet_list(packets);
112                 packets = NULL;
113         } else {
114                 logthing(LOGTHING_ERROR, "Couldn't find key: %s (%d)",
115                         curl_easy_strerror(res), res);
116         }
117
118         free(buf.buffer);
119         buf.offset = buf.size = 0;
120         buf.buffer = NULL;
121
122         return (res == 0) ? 1 : 0;
123 }
124
125 /**
126  *      fetch_key_text - Tries to find the keys that contain the supplied text.
127  *      @search: The text to search for.
128  *      @publickey: A pointer to a structure to return the key in.
129  *
130  *      This function searches for the supplied text and returns the keys that
131  *      contain it.
132  *
133  *      TODO: Write for flat file access. Some sort of grep?
134  */
135 static int hkp_fetch_key_text(const char *search,
136                 struct openpgp_publickey **publickey)
137 {
138         struct openpgp_packet_list *packets = NULL;
139         char keyurl[1024];
140         CURLcode res;
141         struct buffer_ctx buf;
142         int count = 0;
143
144         buf.offset = 0;
145         buf.size = 8192;
146         buf.buffer = malloc(8192);
147
148         snprintf(keyurl, sizeof(keyurl),
149                         "http://%s:11371/pks/lookup?op=get&search=%s",
150                         config.db_dir, search);
151
152         curl_easy_setopt(curl, CURLOPT_URL, keyurl);
153         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
154                         hkp_curl_recv_data);
155         curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
156         res = curl_easy_perform(curl);
157
158         if (res == 0) {
159                 buf.offset = 0;
160                 dearmor_openpgp_stream(buffer_fetchchar, &buf, &packets);
161                 count = parse_keys(packets, publickey);
162                 free_packet_list(packets);
163                 packets = NULL;
164         } else {
165                 logthing(LOGTHING_ERROR, "Couldn't find key: %s (%d)",
166                         curl_easy_strerror(res), res);
167         }
168
169         free(buf.buffer);
170         buf.offset = buf.size = 0;
171         buf.buffer = NULL;
172
173         return count;
174 }
175
176 /**
177  *      store_key - Takes a key and stores it.
178  *      @publickey: A pointer to the public key to store.
179  *      @intrans: If we're already in a transaction.
180  *      @update: If true the key exists and should be updated.
181  *
182  */
183 static int hkp_store_key(struct openpgp_publickey *publickey, bool intrans,
184                 bool update)
185 {
186         struct openpgp_packet_list *packets = NULL;
187         struct openpgp_packet_list *list_end = NULL;
188         char keyurl[1024];
189         CURLcode res;
190         struct buffer_ctx buf;
191         char *addform;
192
193         buf.offset = 0;
194         buf.size = 8192;
195         buf.buffer = malloc(8192);
196         buf.offset = snprintf(buf.buffer, buf.size, "keytextz");
197
198         flatten_publickey(publickey, &packets, &list_end);
199         armor_openpgp_stream(buffer_putchar, &buf, packets);
200         addform = curl_easy_escape(curl, buf.buffer, buf.offset);
201         addform[7] = '=';
202
203         snprintf(keyurl, sizeof(keyurl),
204                         "http://%s:11371/pks/add",
205                         config.db_dir);
206
207         curl_easy_setopt(curl, CURLOPT_URL, keyurl);
208         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, addform);
209         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
210                         hkp_curl_recv_data);
211         buf.offset = 0;
212         curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
213         res = curl_easy_perform(curl);
214
215         if (res != 0) {
216                 logthing(LOGTHING_ERROR, "Couldn't send key: %s (%d)",
217                         curl_easy_strerror(res), res);
218         }
219
220         curl_free(addform);
221
222         /* TODO: buf has any response text we might want to parse. */
223         free(buf.buffer);
224         buf.offset = buf.size = 0;
225         buf.buffer = NULL;
226
227         return (res == 0) ? 1 : 0;
228 }
229
230 /**
231  *      delete_key - Given a keyid delete the key from storage.
232  *      @keyid: The keyid to delete.
233  *      @intrans: If we're already in a transaction.
234  *
235  *      No op for HKP.
236  */
237 static int hkp_delete_key(uint64_t keyid, bool intrans)
238 {
239         return -1;
240 }
241
242 /**
243  *      iterate_keys - call a function once for each key in the db.
244  *      @iterfunc: The function to call.
245  *      @ctx: A context pointer
246  *
247  *      Not applicable for HKP backend.
248  */
249 static int hkp_iterate_keys(void (*iterfunc)(void *ctx,
250                 struct openpgp_publickey *key), void *ctx)
251 {
252         return 0;
253 }
254
255 /**
256  *      starttrans - Start a transaction.
257  *
258  *      This is just a no-op for HKP access.
259  */
260 static bool hkp_starttrans(void)
261 {
262         return true;
263 }
264
265 /**
266  *      endtrans - End a transaction.
267  *
268  *      This is just a no-op for HKP access.
269  */
270 static void hkp_endtrans(void)
271 {
272         return;
273 }
274
275 /*
276  * Include the basic keydb routines.
277  */
278 #define NEED_KEYID2UID 1
279 #define NEED_GETKEYSIGS 1
280 #define NEED_GETFULLKEYID 1
281 #define NEED_UPDATEKEYS 1
282 #include "keydb.c"
283
284 struct dbfuncs keydb_hkp_funcs = {
285         .initdb                 = hkp_initdb,
286         .cleanupdb              = hkp_cleanupdb,
287         .starttrans             = hkp_starttrans,
288         .endtrans               = hkp_endtrans,
289         .fetch_key              = hkp_fetch_key,
290         .fetch_key_text         = hkp_fetch_key_text,
291         .store_key              = hkp_store_key,
292         .update_keys            = generic_update_keys,
293         .delete_key             = hkp_delete_key,
294         .getkeysigs             = generic_getkeysigs,
295         .cached_getkeysigs      = generic_cached_getkeysigs,
296         .keyid2uid              = generic_keyid2uid,
297         .getfullkeyid           = generic_getfullkeyid,
298         .iterate_keys           = hkp_iterate_keys,
299 };