- Fix coverity 10602
[oweals/gnunet.git] / src / regex / plugin_block_regex.c
1 /*
2      This file is part of GNUnet
3      (C) 2013 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 regex/plugin_block_regex.c
23  * @brief blocks used for regex storage and search
24  * @author Bartlomiej Polot
25  */
26
27 #include "platform.h"
28 #include "gnunet_block_plugin.h"
29 #include "block_regex.h"
30 #include "regex_block_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_signatures.h"
33
34
35 /**
36  * Function called to validate a reply or a request of type
37  * GNUNET_BLOCK_TYPE_REGEX.
38  * For request evaluation, pass "NULL" for the reply_block.
39  * Note that it is assumed that the reply has already been
40  * matched to the key (and signatures checked) as it would
41  * be done with the "get_key" function.
42  *
43  * @param cls closure
44  * @param type block type
45  * @param query original query (hash)
46  * @param bf pointer to bloom filter associated with query; possibly updated (!)
47  * @param bf_mutator mutation value for bf
48  * @param xquery extrended query data (can be NULL, depending on type)
49  * @param xquery_size number of bytes in xquery
50  * @param reply_block response to validate
51  * @param reply_block_size number of bytes in reply block
52  * @return characterization of result
53  */
54 static enum GNUNET_BLOCK_EvaluationResult
55 evaluate_block_regex (void *cls, enum GNUNET_BLOCK_Type type,
56                       const struct GNUNET_HashCode *query,
57                       struct GNUNET_CONTAINER_BloomFilter **bf,
58                       int32_t bf_mutator, const void *xquery,
59                       size_t xquery_size, const void *reply_block,
60                       size_t reply_block_size)
61 {
62   if (NULL == reply_block)
63     {
64       if (0 != xquery_size)
65         {
66           const char *s;  
67           
68           s = (const char *) xquery;
69           if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
70             {
71               GNUNET_break_op (0);
72               return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
73             }
74         }
75       return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
76     }
77   if (0 != xquery_size)
78   {
79     const char *query;
80
81     query = (const char *) xquery;
82     if ('\0' != query[xquery_size - 1]) /* must be valid 0-terminated string */
83     {
84       GNUNET_break_op (0);
85       return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
86     }
87   }
88   else 
89   {
90     /* xquery is required for regex, at least an empty string */
91     GNUNET_break_op (0);
92     return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
93   }
94   switch (REGEX_BLOCK_check (reply_block,
95                              reply_block_size,
96                              query,
97                              xquery))
98   {
99     case GNUNET_SYSERR:
100       GNUNET_break_op(0);
101       return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
102     case GNUNET_NO:
103       /* xquery missmatch, can happen */
104       return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
105     default:
106       break;
107   }
108   if (NULL != bf)
109   {
110     struct GNUNET_HashCode chash;
111     struct GNUNET_HashCode mhash;
112
113     GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
114     GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
115     if (NULL != *bf)
116     {
117       if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
118         return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
119     }
120     else
121     {
122       *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
123     }
124     GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
125   }
126   return GNUNET_BLOCK_EVALUATION_OK_MORE;
127 }
128
129
130 /**
131  * Function called to validate a reply or a request of type
132  * GNUNET_BLOCK_TYPE_REGEX_ACCEPT.
133  * For request evaluation, pass "NULL" for the reply_block.
134  * Note that it is assumed that the reply has already been
135  * matched to the key (and signatures checked) as it would
136  * be done with the "get_key" function.
137  *
138  * @param cls closure
139  * @param type block type
140  * @param query original query (hash)
141  * @param bf pointer to bloom filter associated with query; possibly updated (!)
142  * @param bf_mutator mutation value for bf
143  * @param xquery extrended query data (can be NULL, depending on type)
144  * @param xquery_size number of bytes in xquery
145  * @param reply_block response to validate
146  * @param reply_block_size number of bytes in reply block
147  * @return characterization of result
148  */
149 static enum GNUNET_BLOCK_EvaluationResult
150 evaluate_block_regex_accept (void *cls, enum GNUNET_BLOCK_Type type,
151                              const struct GNUNET_HashCode * query,
152                              struct GNUNET_CONTAINER_BloomFilter **bf,
153                              int32_t bf_mutator, const void *xquery,
154                              size_t xquery_size, const void *reply_block,
155                              size_t reply_block_size)
156 {
157   const struct RegexAcceptBlock *rba;
158
159   if (0 != xquery_size)
160   {
161     GNUNET_break_op (0);
162     return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
163   }
164   if (NULL == reply_block)
165     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
166   if (sizeof (struct RegexAcceptBlock) != reply_block_size)
167   {
168     GNUNET_break_op(0);
169     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
170   }
171   rba = reply_block;
172   if (ntohl (rba->purpose.size) !=
173       sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
174       sizeof (struct GNUNET_TIME_AbsoluteNBO) +
175       sizeof (struct GNUNET_HashCode)) 
176   {
177     GNUNET_break_op(0);
178     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
179   }
180   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (rba->expiration_time)).rel_value)
181   {
182     /* technically invalid, but can happen without an error, so
183        we're nice by reporting it as a 'duplicate' */
184     return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
185   }  
186   if (GNUNET_OK !=
187       GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT,
188                                 &rba->purpose,
189                                 &rba->signature,
190                                 &rba->public_key))
191   {
192     GNUNET_break_op(0);
193     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
194   }
195   if (NULL != bf)
196   {
197     struct GNUNET_HashCode chash;
198     struct GNUNET_HashCode mhash;
199
200     GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
201     GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
202     if (NULL != *bf)
203     {
204       if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
205         return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
206     }
207     else
208     {
209       *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
210     }
211     GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
212   }
213   return GNUNET_BLOCK_EVALUATION_OK_MORE;
214 }
215
216
217 /**
218  * Function called to validate a reply or a request.  For
219  * request evaluation, simply pass "NULL" for the reply_block.
220  * Note that it is assumed that the reply has already been
221  * matched to the key (and signatures checked) as it would
222  * be done with the "get_key" function.
223  *
224  * @param cls closure
225  * @param type block type
226  * @param query original query (hash)
227  * @param bf pointer to bloom filter associated with query; possibly updated (!)
228  * @param bf_mutator mutation value for bf
229  * @param xquery extrended query data (can be NULL, depending on type)
230  * @param xquery_size number of bytes in xquery
231  * @param reply_block response to validate
232  * @param reply_block_size number of bytes in reply block
233  * @return characterization of result
234  */
235 static enum GNUNET_BLOCK_EvaluationResult
236 block_plugin_regex_evaluate (void *cls, enum GNUNET_BLOCK_Type type,
237                              const struct GNUNET_HashCode * query,
238                              struct GNUNET_CONTAINER_BloomFilter **bf,
239                              int32_t bf_mutator, const void *xquery,
240                              size_t xquery_size, const void *reply_block,
241                              size_t reply_block_size)
242 {
243   enum GNUNET_BLOCK_EvaluationResult result;
244
245   switch (type)
246   {
247     case GNUNET_BLOCK_TYPE_REGEX:
248       result = evaluate_block_regex (cls, type, query, bf, bf_mutator,
249                                      xquery, xquery_size,
250                                      reply_block, reply_block_size);
251       break;
252     case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
253       result = evaluate_block_regex_accept (cls, type, query, bf, bf_mutator,
254                                             xquery, xquery_size,
255                                             reply_block, reply_block_size);
256       break;
257
258     default:
259       result = GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
260   }
261   return result;
262 }
263
264
265 /**
266  * Function called to obtain the key for a block.
267  *
268  * @param cls closure
269  * @param type block type
270  * @param block block to get the key for
271  * @param block_size number of bytes in block
272  * @param key set to the key (query) for the given block
273  * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported
274  *         (or if extracting a key from a block of this type does not work)
275  */
276 static int
277 block_plugin_regex_get_key (void *cls, enum GNUNET_BLOCK_Type type,
278                             const void *block, size_t block_size,
279                             struct GNUNET_HashCode * key)
280 {
281   switch (type)
282   {
283     case GNUNET_BLOCK_TYPE_REGEX:
284       if (GNUNET_OK !=
285           REGEX_BLOCK_get_key (block, block_size,
286                                key))
287       {
288         GNUNET_break_op (0);
289         return GNUNET_NO;
290       }
291       return GNUNET_OK;
292     case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
293       if (sizeof (struct RegexAcceptBlock) != block_size)
294       {
295         GNUNET_break_op (0);
296         return GNUNET_NO;
297       }
298       *key = ((struct RegexAcceptBlock *) block)->key;
299       return GNUNET_OK;
300     default:
301       GNUNET_break (0);
302       return GNUNET_SYSERR;
303   }
304 }
305
306
307 /**
308  * Entry point for the plugin.
309  */
310 void *
311 libgnunet_plugin_block_regex_init (void *cls)
312 {
313   static enum GNUNET_BLOCK_Type types[] =
314   {
315     GNUNET_BLOCK_TYPE_REGEX,
316     GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
317     GNUNET_BLOCK_TYPE_ANY       /* end of list */
318   };
319   struct GNUNET_BLOCK_PluginFunctions *api;
320
321   api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions));
322   api->evaluate = &block_plugin_regex_evaluate;
323   api->get_key = &block_plugin_regex_get_key;
324   api->types = types;
325   return api;
326 }
327
328
329 /**
330  * Exit point from the plugin.
331  */
332 void *
333 libgnunet_plugin_block_regex_done (void *cls)
334 {
335   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
336
337   GNUNET_free (api);
338   return NULL;
339 }
340
341 /* end of plugin_block_regex.c */