server: handle pcre2 now returning -1 for "no match"
[rb-79.git] / tripcodes.c
blob73aa0ee4e1ad17b1a478cbcdbd55e1ec7c5632c0
1 /*
2 * Copyright (c) 2017-2020, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include <sodium.h>
25 #include "macros.h"
26 #include "rb79.h"
28 /* Global configuration */
29 static const struct configuration *conf;
31 /* Characters for Base64 */
32 static const char *base64_elts =
33 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
35 /* This should be a multiple of 3, so that base64 gives no '=' */
36 #define OUT_HASH_LEN (3 * 3)
39 * Initialize any static elements needed for this file
41 * Preconditions:
43 * - setup_tripcodes() was not invoked more recently than
44 * clean_tripcodes().
46 * Postconditions (success):
48 * - Any other function in this file may be safely called.
50 int
51 setup_tripcodes(const struct configuration *in_conf)
53 conf = in_conf;
55 return 0;
59 * Base64 encode in to *out.
61 * Preconditions:
63 * - in is an array of memory of length in_len (it need not be a string).
65 * - in_len is a multiple of 3.
67 * - out and out_len are not 0.
69 * - overwriting *out shall not cause a memory leak.
71 * Postconditions (success):
73 * - *out is a string of length *out_len.
75 * - The contents of *out are the base64 encoding of the first
76 * in_len bytes of in.
78 static int
79 base64_encode(const unsigned char *in, size_t in_len, char **out,
80 size_t *out_len)
82 int ret = -1;
83 size_t built_len = in_len * 4 / 3 + 3;
84 size_t out_idx = 0;
85 char *built = 0;
87 if ((in_len * 4) / in_len != 4 ||
88 (in_len * 4 / 3) + 3 < (in_len * 4 / 3)) {
89 ERROR_MESSAGE("overflow (in_len = %zu)", in_len);
90 goto done;
93 if (!(built = malloc(built_len))) {
94 PERROR_MESSAGE("malloc");
95 goto done;
98 for (size_t in_idx = 0; in_idx + 2 < in_len; in_idx += 3) {
99 unsigned char i1 = in[in_idx + 0];
100 unsigned char i2 = in[in_idx + 1];
101 unsigned char i3 = in[in_idx + 2];
102 size_t j1 = i1 >> 2;
103 size_t j2 = ((i1 & 0x03) << 4) | (i2 >> 4);
104 size_t j3 = ((i2 & 0x0F) << 2) | ((i3 & 0xC0) >> 6);
105 size_t j4 = (i3 & 0x3F);
107 built[out_idx++] = base64_elts[j1];
108 built[out_idx++] = base64_elts[j2];
109 built[out_idx++] = base64_elts[j3];
110 built[out_idx++] = base64_elts[j4];
113 built[out_idx] = '\0';
114 *out = built;
115 *out_len = out_idx;
116 ret = 0;
117 done:
119 return ret;
123 * Calculate (raw) tripcode from (raw) name, if necessary. Name is
124 * truncated to hide the input. This assumes p->raw.tripcode is
125 * empty.
127 * Preconditions:
129 * - p is not 0.
131 * - p->raw.name is either 0, or is a string of length p->raw.name_len.
133 * - Overwriting p->raw.tripcode shall not cause a memory leak.
135 * Postconditions (success):
137 * - If p->raw.name was of the form "foo#bar", it is now of the
138 * form "foo". p->raw.name_len has been adjusted accordingly.
140 * - If p->raw.name was of the form "foo#bar", p->raw.tripcode is
141 * determined by the key "bar". p->raw.tripcode_len is appropriate.
144 tripcodes_calculate(struct post_cmd *p)
146 int ret = -1;
147 char *trip_phrase_start = 0;
148 unsigned char out_buf[OUT_HASH_LEN];
150 /* do not initialize this - unknown if struct or scalar */
151 crypto_generichash_state cg_state;
153 if (!p->raw.name_len) {
154 goto success;
157 /* XXX: The string length operations could be tightened */
158 trip_phrase_start = strchr(p->raw.name, '#');
160 if (!trip_phrase_start) {
161 goto success;
164 *trip_phrase_start = '\0';
165 p->raw.name_len = strlen(p->raw.name);
166 trip_phrase_start++;
168 if (!*trip_phrase_start) {
169 goto success;
172 if (crypto_generichash_init(&cg_state, 0, 0, OUT_HASH_LEN) < 0) {
173 PERROR_MESSAGE("crypto_generichash_init");
174 goto done;
177 if (crypto_generichash_update(&cg_state, (const unsigned
178 char *) trip_phrase_start,
179 strlen(trip_phrase_start)) < 0) {
180 LOG("Failed to update hash with \"%s\"", trip_phrase_start);
181 PERROR_MESSAGE("crypto_generichash_update");
182 goto done;
185 if (crypto_generichash_update(&cg_state, (const unsigned
186 char *) conf->trip_salt,
187 conf->trip_salt_len) < 0) {
188 LOG("Failed to update hash with \"%s\"", conf->trip_salt);
189 PERROR_MESSAGE("crypto_generichash_update");
190 goto done;
193 if (crypto_generichash_final(&cg_state, out_buf, OUT_HASH_LEN) < 0) {
194 PERROR_MESSAGE("crypto_generichash_final");
195 goto done;
198 if (base64_encode(out_buf, OUT_HASH_LEN, &p->raw.tripcode,
199 &p->raw.tripcode_len) < 0) {
200 goto done;
203 success:
204 ret = 0;
205 done:
207 return ret;
211 * Clean any memory from this file
213 * Postconditions (success):
215 * - Valgrind won't report any memory leaks from this file.
217 * - setup_tripcodes() can be safely called again.
220 clean_tripcodes(void)
222 conf = 0;
224 return 0;