]> git.ozlabs.org Git - ccan/blob - ccan/rune/rune.c
19d55c5490fb60a28f05d1819ec0acb9b32ff4bb
[ccan] / ccan / rune / rune.c
1 /* MIT (BSD) license - see LICENSE file for details */
2 #include "config.h"
3 #include <assert.h>
4 #include <errno.h>
5 #include <inttypes.h>
6 #include <stdio.h>
7 #include <ccan/endian/endian.h>
8 #include <ccan/tal/str/str.h>
9 #include <ccan/rune/rune.h>
10 #include <ccan/rune/internal.h>
11
12 /* Helper to produce an id field */
13 static struct rune_restr *unique_id_restr(const tal_t *ctx,
14                                           const char *unique_id,
15                                           const char *version)
16 {
17         const char *id;
18         struct rune_restr *restr;
19
20         assert(!strchr(unique_id, '-'));
21         if (version)
22                 id = tal_fmt(NULL, "%s-%s", unique_id, version);
23         else
24                 id = tal_strdup(NULL, unique_id);
25
26         restr = rune_restr_new(ctx);
27         /* We use the empty field for this, since it's always present. */
28         rune_restr_add_altern(restr,
29                               take(rune_altern_new(NULL, "", '=', take(id))));
30         return restr;
31 }
32
33 /* We pad between fields with something identical to the SHA end marker */
34 void rune_sha256_endmarker(struct sha256_ctx *shactx)
35 {
36         static const unsigned char pad[64] = {0x80};
37         be64 sizedesc;
38
39         sizedesc = cpu_to_be64((uint64_t)shactx->bytes << 3);
40         /* Add '1' bit to terminate, then all 0 bits, up to next block - 8. */
41         sha256_update(shactx, pad, 1 + ((128 - 8 - (shactx->bytes % 64) - 1) % 64));
42         /* Add number of bits of data (big endian) */
43         sha256_update(shactx, &sizedesc, 8);
44 }
45
46 struct rune *rune_new(const tal_t *ctx, const u8 *secret, size_t secret_len,
47                       const char *version)
48 {
49         struct rune *rune = tal(ctx, struct rune);
50         assert(secret_len + 1 + 8 <= 64);
51
52         if (version)
53                 rune->version = tal_strdup(rune, version);
54         else
55                 rune->version = NULL;
56         rune->unique_id = NULL;
57         sha256_init(&rune->shactx);
58         sha256_update(&rune->shactx, secret, secret_len);
59         rune_sha256_endmarker(&rune->shactx);
60         rune->restrs = tal_arr(rune, struct rune_restr *, 0);
61         return rune;
62 }
63
64 struct rune *rune_dup(const tal_t *ctx, const struct rune *rune TAKES)
65 {
66         struct rune *dup;
67
68         if (taken(rune))
69                 return tal_steal(ctx, (struct rune *)rune);
70
71         dup = tal_dup(ctx, struct rune, rune);
72         dup->restrs = tal_arr(dup, struct rune_restr *, tal_count(rune->restrs));
73         for (size_t i = 0; i < tal_count(rune->restrs); i++) {
74                 dup->restrs[i] = rune_restr_dup(dup->restrs,
75                                                 rune->restrs[i]);
76         }
77         return dup;
78 }
79
80 struct rune *rune_derive_start(const tal_t *ctx,
81                                const struct rune *master,
82                                const char *unique_id TAKES)
83 {
84         struct rune *rune = rune_dup(ctx, master);
85
86         /* If they provide a unique_id, it goes first. */
87         if (unique_id) {
88                 if (taken(unique_id))
89                         rune->unique_id = tal_steal(rune, unique_id);
90                 else
91                         rune->unique_id = tal_strdup(rune, unique_id);
92                 
93                 rune_add_restr(rune, take(unique_id_restr(NULL,
94                                                           rune->unique_id,
95                                                           rune->version)));
96         } else {
97                 assert(!rune->version);
98         }
99         return rune;
100 }
101
102 struct rune_altern *rune_altern_new(const tal_t *ctx,
103                                     const char *fieldname TAKES,
104                                     enum rune_condition condition,
105                                     const char *value TAKES)
106 {
107         struct rune_altern *altern = tal(ctx, struct rune_altern);
108         altern->condition = condition;
109         altern->fieldname = tal_strdup(altern, fieldname);
110         altern->value = tal_strdup(altern, value);
111         return altern;
112 }
113
114 struct rune_altern *rune_altern_dup(const tal_t *ctx,
115                                     const struct rune_altern *altern TAKES)
116 {
117         struct rune_altern *dup;
118
119         if (taken(altern))
120                 return tal_steal(ctx, (struct rune_altern *)altern);
121         dup = tal(ctx, struct rune_altern);
122         dup->condition = altern->condition;
123         dup->fieldname = tal_strdup(dup, altern->fieldname);
124         dup->value = tal_strdup(dup, altern->value);
125         return dup;
126 }
127
128 struct rune_restr *rune_restr_dup(const tal_t *ctx,
129                                   const struct rune_restr *restr TAKES)
130 {
131         struct rune_restr *dup;
132         size_t num_altern;
133
134         if (taken(restr))
135                 return tal_steal(ctx, (struct rune_restr *)restr);
136
137         num_altern = tal_count(restr->alterns);
138         dup = tal(ctx, struct rune_restr);
139         dup->alterns = tal_arr(dup, struct rune_altern *, num_altern);
140         for (size_t i = 0; i < num_altern; i++) {
141                 dup->alterns[i] = rune_altern_dup(dup->alterns,
142                                                   restr->alterns[i]);
143         }
144         return dup;
145 }
146
147 struct rune_restr *rune_restr_new(const tal_t *ctx)
148 {
149         struct rune_restr *restr = tal(ctx, struct rune_restr);
150         restr->alterns = tal_arr(restr, struct rune_altern *, 0);
151         return restr;
152 }
153
154 void rune_restr_add_altern(struct rune_restr *restr,
155                            const struct rune_altern *alt TAKES)
156 {
157         size_t num = tal_count(restr->alterns);
158
159         tal_resize(&restr->alterns, num+1);
160         restr->alterns[num] = rune_altern_dup(restr->alterns, alt);
161 }
162
163 static bool is_unique_id(const struct rune_altern *alt)
164 {
165         return streq(alt->fieldname, "");
166 }
167         
168 /* Return unique_id if valid, and sets *version */
169 static const char *extract_unique_id(const tal_t *ctx,
170                                      const struct rune_altern *alt,
171                                      const char **version)
172 {
173         size_t len;
174         /* Condition must be '='! */
175         if (alt->condition != '=')
176                 return NULL;
177
178         len = strcspn(alt->value, "-");
179         if (alt->value[len])
180                 *version = tal_strdup(ctx, alt->value + len + 1);
181         else
182                 *version = NULL;
183         return tal_strndup(ctx, alt->value, len);
184 }
185
186 bool rune_add_restr(struct rune *rune,
187                     const struct rune_restr *restr TAKES)
188 {
189         size_t num = tal_count(rune->restrs);
190
191         /* An empty fieldname is additional correctness checks */
192         for (size_t i = 0; i < tal_count(restr->alterns); i++) {
193                 if (!is_unique_id(restr->alterns[i]))
194                         continue;
195
196                 /* Must be the only alternative */
197                 if (tal_count(restr->alterns) != 1)
198                         goto fail;
199                 /* Must be the first restriction */
200                 if (num != 0)
201                         goto fail;
202
203                 rune->unique_id = extract_unique_id(rune,
204                                                     restr->alterns[i],
205                                                     &rune->version);
206                 if (!rune->unique_id)
207                         goto fail;
208         }
209
210         tal_resize(&rune->restrs, num+1);
211         rune->restrs[num] = rune_restr_dup(rune->restrs, restr);
212
213         rune_sha256_add_restr(&rune->shactx, rune->restrs[num]);
214         return true;
215
216 fail:
217         if (taken(restr))
218                 tal_free(restr);
219         return false;
220 }
221
222 static const char *rune_restr_test(const tal_t *ctx,
223                                    const struct rune *rune,
224                                    const struct rune_restr *restr,
225                                    const char *(*check)(const tal_t *ctx,
226                                                         const struct rune *rune,
227                                                         const struct rune_altern *alt,
228                                                         void *arg),
229                                    void *arg)
230 {
231         size_t num = tal_count(restr->alterns);
232         const char **errs = tal_arr(NULL, const char *, num);
233         char *err;
234
235         /* Only one alternative has to pass! */
236         for (size_t i = 0; i < num; i++) {
237                 errs[i] = check(errs, rune, restr->alterns[i], arg);
238                 if (!errs[i]) {
239                         tal_free(errs);
240                         return NULL;
241                 }
242         }
243
244         err = tal_fmt(ctx, "%s", errs[0]);
245         for (size_t i = 1; i < num; i++)
246                 tal_append_fmt(&err, " AND %s", errs[i]);
247         tal_free(errs);
248         return err;
249 }
250
251 static const char *cond_test(const tal_t *ctx,
252                              const struct rune_altern *alt,
253                              const char *complaint,
254                              bool cond)
255 {
256         if (cond)
257                 return NULL;
258
259         return tal_fmt(ctx, "%s %s %s", alt->fieldname, complaint, alt->value);
260 }
261
262 static const char *integer_compare_valid(const tal_t *ctx,
263                                          const s64 *fieldval_int,
264                                          const struct rune_altern *alt,
265                                          s64 *runeval_int)
266 {
267         long l;
268         char *p;
269
270         if (!fieldval_int)
271                 return tal_fmt(ctx, "%s is not an integer field",
272                                alt->fieldname);
273
274         errno = 0;
275         l = strtol(alt->value, &p, 10);
276         if (p == alt->value
277             || *p
278             || ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE))
279                 return tal_fmt(ctx, "%s is not a valid integer", alt->value);
280
281         *runeval_int = l;
282         return NULL;
283 }
284
285 const char *rune_alt_single(const tal_t *ctx,
286                             const struct rune_altern *alt,
287                             const char *fieldval_str,
288                             const s64 *fieldval_int)
289 {
290         char strfield[STR_MAX_CHARS(s64) + 1];
291         s64 runeval_int;
292         const char *err;
293         
294         /* Caller can't set both! */
295         if (fieldval_int) {
296                 assert(!fieldval_str);
297                 sprintf(strfield, "%"PRIi64, *fieldval_int);
298                 fieldval_str = strfield;
299         }
300
301         switch (alt->condition) {
302         case RUNE_COND_IF_MISSING:
303                 if (!fieldval_str)
304                         return NULL;
305                 return tal_fmt(ctx, "%s is present", alt->fieldname);
306         case RUNE_COND_EQUAL:
307                 if (!fieldval_str)
308                         return tal_fmt(ctx, "%s not present", alt->fieldname);
309                 return cond_test(ctx, alt, "is not equal to",
310                                  streq(fieldval_str, alt->value));
311         case RUNE_COND_NOT_EQUAL:
312                 if (!fieldval_str)
313                         return tal_fmt(ctx, "%s not present", alt->fieldname);
314                 return cond_test(ctx, alt, "is equal to",
315                                  !streq(fieldval_str, alt->value));
316         case RUNE_COND_BEGINS:
317                 if (!fieldval_str)
318                         return tal_fmt(ctx, "%s not present", alt->fieldname);
319                 return cond_test(ctx, alt, "does not start with",
320                                  strstarts(fieldval_str, alt->value));
321         case RUNE_COND_ENDS:
322                 if (!fieldval_str)
323                         return tal_fmt(ctx, "%s not present", alt->fieldname);
324                 return cond_test(ctx, alt, "does not end with",
325                                  strends(fieldval_str, alt->value));
326         case RUNE_COND_CONTAINS:
327                 if (!fieldval_str)
328                         return tal_fmt(ctx, "%s not present", alt->fieldname);
329                 return cond_test(ctx, alt, "does not contain",
330                                  strstr(fieldval_str, alt->value));
331         case RUNE_COND_INT_LESS:
332                 err = integer_compare_valid(ctx, fieldval_int,
333                                             alt, &runeval_int);
334                 if (err)
335                         return err;
336                 return cond_test(ctx, alt, "is greater or equal to",
337                                  *fieldval_int < runeval_int);
338         case RUNE_COND_INT_GREATER:
339                 err = integer_compare_valid(ctx, fieldval_int,
340                                             alt, &runeval_int);
341                 if (err)
342                         return err;
343                 return cond_test(ctx, alt, "is less or equal to",
344                                  *fieldval_int > runeval_int);
345         case RUNE_COND_LEXO_BEFORE:
346                 if (!fieldval_str)
347                         return tal_fmt(ctx, "%s not present", alt->fieldname);
348                 return cond_test(ctx, alt, "is equal to or ordered after",
349                                  strcmp(fieldval_str, alt->value) < 0);
350         case RUNE_COND_LEXO_AFTER:
351                 if (!fieldval_str)
352                         return tal_fmt(ctx, "%s not present", alt->fieldname);
353                 return cond_test(ctx, alt, "is equal to or ordered before",
354                                  strcmp(fieldval_str, alt->value) > 0);
355         case RUNE_COND_COMMENT:
356                 return NULL;
357         }
358         /* We should never create any other values! */
359         abort();
360 }
361
362 const char *rune_meets_criteria_(const tal_t *ctx,
363                                  const struct rune *rune,
364                                  const char *(*check)(const tal_t *ctx,
365                                                       const struct rune *rune,
366                                                       const struct rune_altern *alt,
367                                                       void *arg),
368                                  void *arg)
369 {
370         for (size_t i = 0; i < tal_count(rune->restrs); i++) {
371                 const char *err;
372
373                 /* Don't "check" unique id */
374                 if (i == 0 && is_unique_id(rune->restrs[i]->alterns[0]))
375                         continue;
376                 
377                 err = rune_restr_test(ctx, rune, rune->restrs[i], check, arg);
378                 if (err)
379                         return err;
380         }
381         return NULL;
382 }
383
384 const char *rune_test_(const tal_t *ctx,
385                        const struct rune *master,
386                        const struct rune *rune,
387                        const char *(*check)(const tal_t *ctx,
388                                             const struct rune *rune,
389                                             const struct rune_altern *alt,
390                                             void *arg),
391                        void *arg)
392 {
393         const char *err;
394
395         err = rune_is_derived(master, rune);
396         if (err)
397                 return err;
398         return rune_meets_criteria_(ctx, rune, check, arg);
399 }
400
401 bool rune_altern_eq(const struct rune_altern *alt1,
402                     const struct rune_altern *alt2)
403 {
404         return alt1->condition == alt2->condition
405                 && streq(alt1->fieldname, alt2->fieldname)
406                 && streq(alt1->value, alt2->value);
407 }
408
409 bool rune_restr_eq(const struct rune_restr *rest1,
410                    const struct rune_restr *rest2)
411 {
412         if (tal_count(rest1->alterns) != tal_count(rest2->alterns))
413                 return false;
414
415         for (size_t i = 0; i < tal_count(rest1->alterns); i++)
416                 if (!rune_altern_eq(rest1->alterns[i], rest2->alterns[i]))
417                         return false;
418         return true;
419 }
420
421 /* Equal, as in both NULL, or both non-NULL and matching */
422 bool runestr_eq(const char *a, const char *b)
423 {
424         if (a) {
425                 if (!b)
426                         return false;
427                 return streq(a, b);
428         } else
429                 return b == NULL;
430 }
431
432 bool rune_eq(const struct rune *rune1, const struct rune *rune2)
433 {
434         if (!runestr_eq(rune1->unique_id, rune2->unique_id))
435                 return false;
436         if (!runestr_eq(rune1->version, rune2->version))
437                 return false;
438
439         if (memcmp(rune1->shactx.s, rune2->shactx.s, sizeof(rune1->shactx.s)))
440                 return false;
441         if (rune1->shactx.bytes != rune2->shactx.bytes)
442                 return false;
443         if (memcmp(rune1->shactx.buf.u8, rune2->shactx.buf.u8,
444                    rune1->shactx.bytes % 64))
445                 return false;
446
447         if (tal_count(rune1->restrs) != tal_count(rune2->restrs))
448                 return false;
449
450         for (size_t i = 0; i < tal_count(rune1->restrs); i++)
451                 if (!rune_restr_eq(rune1->restrs[i], rune2->restrs[i]))
452                         return false;
453         return true;
454 }