-lots
[oweals/gnunet.git] / src / fs / fs_publish_ksk.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/fs_publish_ksk.c
23  * @brief publish a URI under a keyword in GNUnet
24  * @see https://gnunet.org/encoding
25  * @author Krista Bennett
26  * @author Christian Grothoff
27  */
28
29 #include "platform.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_fs_service.h"
34 #include "fs_api.h"
35 #include "fs_tree.h"
36
37
38 /**
39  * Maximum legal size for a kblock.
40  */
41 #define MAX_KBLOCK_SIZE (60 * 1024)
42
43
44 /**
45  * Context for the KSK publication.
46  */
47 struct GNUNET_FS_PublishKskContext
48 {
49
50   /**
51    * Keywords to use.
52    */
53   struct GNUNET_FS_Uri *ksk_uri;
54
55   /**
56    * Global FS context.
57    */
58   struct GNUNET_FS_Handle *h;
59
60   /**
61    * The master block that we are sending
62    * (in plaintext), has "mdsize+slen" more
63    * bytes than the struct would suggest.
64    */
65   struct KBlock *kb;
66
67   /**
68    * Buffer of the same size as "kb" for
69    * the encrypted version.
70    */
71   struct KBlock *cpy;
72
73   /**
74    * Handle to the datastore, NULL if we are just
75    * simulating.
76    */
77   struct GNUNET_DATASTORE_Handle *dsh;
78
79   /**
80    * Handle to datastore PUT request.
81    */
82   struct GNUNET_DATASTORE_QueueEntry *qre;
83
84   /**
85    * Current task.
86    */
87   GNUNET_SCHEDULER_TaskIdentifier ksk_task;
88
89   /**
90    * Function to call once we're done.
91    */
92   GNUNET_FS_PublishContinuation cont;
93
94   /**
95    * Closure for cont.
96    */
97   void *cont_cls;
98
99   /**
100    * When should the KBlocks expire?
101    */
102   struct GNUNET_FS_BlockOptions bo;
103
104   /**
105    * Size of the serialized metadata.
106    */
107   ssize_t mdsize;
108
109   /**
110    * Size of the (CHK) URI as a string.
111    */
112   size_t slen;
113
114   /**
115    * Keyword that we are currently processing.
116    */
117   unsigned int i;
118
119 };
120
121
122 /**
123  * Continuation of "GNUNET_FS_publish_ksk" that performs
124  * the actual publishing operation (iterating over all
125  * of the keywords).
126  *
127  * @param cls closure of type "struct PublishKskContext*"
128  * @param tc unused
129  */
130 static void
131 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
132
133
134 /**
135  * Function called by the datastore API with
136  * the result from the PUT request.
137  *
138  * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
139  * @param success GNUNET_OK on success
140  * @param min_expiration minimum expiration time required for content to be stored
141  * @param msg error message (or NULL)
142  */
143 static void
144 kb_put_cont (void *cls, int success, 
145              struct GNUNET_TIME_Absolute min_expiration,
146              const char *msg)
147 {
148   struct GNUNET_FS_PublishKskContext *pkc = cls;
149
150   pkc->qre = NULL;
151   if (GNUNET_OK != success)
152   {
153     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
154                 "KBlock PUT operation failed: %s\n", msg);
155     pkc->cont (pkc->cont_cls, NULL, msg);
156     GNUNET_FS_publish_ksk_cancel (pkc);
157     return;
158   }
159   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
160 }
161
162
163 /**
164  * Continuation of "GNUNET_FS_publish_ksk" that performs the actual
165  * publishing operation (iterating over all of the keywords).
166  *
167  * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
168  * @param tc unused
169  */
170 static void
171 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
172 {
173   struct GNUNET_FS_PublishKskContext *pkc = cls;
174   const char *keyword;
175   struct GNUNET_HashCode key;
176   struct GNUNET_HashCode query;
177   struct GNUNET_CRYPTO_AesSessionKey skey;
178   struct GNUNET_CRYPTO_AesInitializationVector iv;
179   struct GNUNET_CRYPTO_RsaPrivateKey *pk;
180
181   pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK;
182   if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh))
183   {
184     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n");
185     pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL);
186     GNUNET_FS_publish_ksk_cancel (pkc);
187     return;
188   }
189   keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
190   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n",
191               &keyword[1]);
192   /* first character of keyword indicates if it is
193    * mandatory or not -- ignore for hashing */
194   GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
195   GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
196   GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1], pkc->slen + pkc->mdsize, &skey, &iv,
197                              &pkc->cpy[1]);
198   pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
199   GNUNET_assert (NULL != pk);
200   GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace);
201   GNUNET_CRYPTO_hash (&pkc->cpy->keyspace,
202                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
203                       &query);
204   GNUNET_assert (GNUNET_OK ==
205                  GNUNET_CRYPTO_rsa_sign (pk, &pkc->cpy->purpose,
206                                          &pkc->cpy->signature));
207   GNUNET_CRYPTO_rsa_key_free (pk);
208   pkc->qre =
209       GNUNET_DATASTORE_put (pkc->dsh, 0, &query,
210                             pkc->mdsize + sizeof (struct KBlock) + pkc->slen,
211                             pkc->cpy, GNUNET_BLOCK_TYPE_FS_KBLOCK,
212                             pkc->bo.content_priority, pkc->bo.anonymity_level,
213                             pkc->bo.replication_level, pkc->bo.expiration_time,
214                             -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT,
215                             &kb_put_cont, pkc);
216 }
217
218
219 /**
220  * Publish a CHK under various keywords on GNUnet.
221  *
222  * @param h handle to the file sharing subsystem
223  * @param ksk_uri keywords to use
224  * @param meta metadata to use
225  * @param uri URI to refer to in the KBlock
226  * @param bo per-block options
227  * @param options publication options
228  * @param cont continuation
229  * @param cont_cls closure for cont
230  * @return NULL on error ('cont' will still be called)
231  */
232 struct GNUNET_FS_PublishKskContext *
233 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
234                        const struct GNUNET_FS_Uri *ksk_uri,
235                        const struct GNUNET_CONTAINER_MetaData *meta,
236                        const struct GNUNET_FS_Uri *uri,
237                        const struct GNUNET_FS_BlockOptions *bo,
238                        enum GNUNET_FS_PublishOptions options,
239                        GNUNET_FS_PublishContinuation cont, void *cont_cls)
240 {
241   struct GNUNET_FS_PublishKskContext *pkc;
242   char *uris;
243   size_t size;
244   char *kbe;
245   char *sptr;
246
247   GNUNET_assert (NULL != uri);
248   pkc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishKskContext));
249   pkc->h = h;
250   pkc->bo = *bo;
251   pkc->cont = cont;
252   pkc->cont_cls = cont_cls;
253   if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
254   {
255     pkc->dsh = GNUNET_DATASTORE_connect (h->cfg);
256     if (NULL == pkc->dsh)
257     {
258       cont (cont_cls, NULL, _("Could not connect to datastore."));
259       GNUNET_free (pkc);
260       return NULL;
261     }
262   }
263   if (meta == NULL)
264     pkc->mdsize = 0;
265   else
266     pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
267   GNUNET_assert (pkc->mdsize >= 0);
268   uris = GNUNET_FS_uri_to_string (uri);
269   pkc->slen = strlen (uris) + 1;
270   size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen;
271   if (size > MAX_KBLOCK_SIZE)
272   {
273     size = MAX_KBLOCK_SIZE;
274     pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen;
275   }
276   pkc->kb = GNUNET_malloc (size);
277   kbe = (char *) &pkc->kb[1];
278   memcpy (kbe, uris, pkc->slen);
279   GNUNET_free (uris);
280   sptr = &kbe[pkc->slen];
281   if (meta != NULL)
282     pkc->mdsize =
283         GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize,
284                                               GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
285   if (-1 == pkc->mdsize)
286   {
287     GNUNET_break (0);
288     GNUNET_free (pkc->kb);
289     if (pkc->dsh != NULL)
290     {
291       GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
292       pkc->dsh = NULL;
293     }
294     GNUNET_free (pkc);
295     cont (cont_cls, NULL, _("Internal error."));
296     return NULL;
297   }
298   size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize;
299
300   pkc->cpy = GNUNET_malloc (size);
301   pkc->cpy->purpose.size =
302       htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
303              sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
304              pkc->mdsize + pkc->slen);
305   pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK);
306   pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
307   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
308   return pkc;
309 }
310
311
312 /**
313  * Abort the KSK publishing operation.
314  *
315  * @param pkc context of the operation to abort.
316  */
317 void
318 GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc)
319 {
320   if (GNUNET_SCHEDULER_NO_TASK != pkc->ksk_task)
321   {
322     GNUNET_SCHEDULER_cancel (pkc->ksk_task);
323     pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK;
324   }
325   if (NULL != pkc->qre)
326   {
327     GNUNET_DATASTORE_cancel (pkc->qre);
328     pkc->qre = NULL;
329   }
330   if (NULL != pkc->dsh)
331   {
332     GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
333     pkc->dsh = NULL;
334   }
335   GNUNET_free (pkc->cpy);
336   GNUNET_free (pkc->kb);
337   GNUNET_FS_uri_destroy (pkc->ksk_uri);
338   GNUNET_free (pkc);
339 }
340
341
342 /* end of fs_publish_ksk.c */