bincookie
Loading...
Searching...
No Matches
bincookie.h
Go to the documentation of this file.
1
8#ifndef _BINCOOKIE_H
9#define _BINCOOKIE_H
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
16// https://github.com/nodejs/http-parser/blob/master/http_parser.h#L32
17#include <sys/types.h>
18#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER < 1600) && \
19 !defined(__WINE__)
20#include <BaseTsd.h>
21#include <stddef.h>
22typedef unsigned __int32 uint32_t;
23typedef unsigned __int8 bool;
24#else
25#include <stdbool.h>
26#include <stdint.h>
27#endif
28#include <errno.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <time.h>
34
37
40#define bincookie_is_secure(cookie_ptr) (cookie_ptr->flags & secure)
42
45#define bincookie_domain_access_full(cookie_ptr) \
46 (((char *)cookie_ptr + cookie_ptr->domain_offset)[0] == '.')
48
51#define bincookie_iter_state_init(s) \
52 s.page_offset = 0; \
53 s.page_index = 0;
55
58#define bincookie_domain(c) ((char *)c + c->domain_offset)
60
63#define bincookie_path(c) \
64 ((char *)c + \
65 c->path_offset)
68
71#define bincookie_name(c) \
72 ((char *)c + \
73 c->name_offset)
76
79#define bincookie_value(c) ((char *)c + c->value_offset)
81#define APPLE_EPOCH_OFFSET 978307200
83
86#define bincookie_expiration_time(c) \
87 (c->expiry_date_epoch + APPLE_EPOCH_OFFSET)
89
92#define bincookie_creation_time(c) \
93 (c->create_date_epoch + APPLE_EPOCH_OFFSET)
96
98typedef enum {
99 secure = 1,
100 http_only = 1 << 2,
104typedef struct {
105 uint32_t page_offset;
106 uint32_t page_index;
110typedef struct {
111 uint32_t size;
112 unsigned char unk1[4];
114 unsigned char unk2[4];
116 uint32_t domain_offset;
117 uint32_t name_offset;
118 uint32_t path_offset;
119 uint32_t value_offset;
121 unsigned char unk[8];
123 double expiry_date_epoch;
124 double create_date_epoch;
128typedef struct {
129 unsigned char unk1[4];
131 uint32_t num_cookies;
132 uint32_t cookie_offsets[];
134
136typedef struct {
137 unsigned char magic[4];
138 uint32_t num_pages;
139 uint32_t page_sizes[];
144
153static inline bool bincookie_validate_pages(const bincookie_t *bc, size_t num_bytes) {
154 size_t page_offset = sizeof(bincookie_t) + (size_t)bc->num_pages * sizeof(uint32_t);
155 for (uint32_t i = 0; i < bc->num_pages; i++) {
156 if (page_offset > num_bytes || num_bytes - page_offset < sizeof(bincookie_page_t)) {
157 return false;
158 }
159 const bincookie_page_t *page = (const bincookie_page_t *)((const char *)bc + page_offset);
160 size_t offsets_room = num_bytes - page_offset - sizeof(bincookie_page_t);
161 if (offsets_room / sizeof(uint32_t) < page->num_cookies) {
162 return false;
163 }
164 for (uint32_t j = 0; j < page->num_cookies; j++) {
165 uint32_t cookie_offset = page->cookie_offsets[j];
166 if (cookie_offset > num_bytes - page_offset ||
167 num_bytes - page_offset - cookie_offset < sizeof(bincookie_cookie_t)) {
168 return false;
169 }
170 const bincookie_cookie_t *cookie =
171 (const bincookie_cookie_t *)((const char *)page + cookie_offset);
172 size_t cookie_pos = page_offset + cookie_offset;
173 uint32_t string_offsets[] = {cookie->domain_offset,
174 cookie->name_offset,
175 cookie->path_offset,
176 cookie->value_offset};
177 for (size_t k = 0; k < sizeof(string_offsets) / sizeof(string_offsets[0]); k++) {
178 if (string_offsets[k] >= num_bytes - cookie_pos) {
179 return false;
180 }
181 }
182 }
183 page_offset += bc->page_sizes[i];
184 }
185 return true;
186}
188
192static inline bincookie_t *const bincookie_init_file(FILE *fin) {
193 const long last_pos = ftell(fin);
194 rewind(fin);
195 char magic[4];
196 bincookie_t *cook = NULL;
197 size_t read = fread(magic, sizeof(magic), 1, fin);
198 bool is_cook = magic[0] == 'c' && magic[1] == 'o' && magic[2] == 'o' && magic[3] == 'k';
199 if (read != 1 || !is_cook) {
200 errno = EIO;
201 goto done;
202 }
203 // Read entire file
204 fseek(fin, 0, SEEK_END);
205 size_t num_bytes = (size_t)ftell(fin);
206 // The fixed header, made up of the magic and num_pages, must be present before any
207 // file-derived field is dereferenced.
208 if (num_bytes < sizeof(bincookie_t)) {
209 errno = EIO;
210 goto done;
211 }
212 cook = (bincookie_t *)malloc(num_bytes);
213 // LCOV_EXCL_START
214 if (cook == NULL) {
215 goto done;
216 } // LCOV_EXCL_STOP
217 memset(cook, 0, num_bytes);
218 rewind(fin);
219 // LCOV_EXCL_START
220 if (fread(cook, num_bytes, 1, fin) != 1) {
221 free(cook);
222 cook = NULL;
223 goto done;
224 } // LCOV_EXCL_STOP
225 cook->num_pages = __builtin_bswap32(cook->num_pages);
226 // num_pages comes straight from the file; reject any value whose page size table cannot fit
227 // within the bytes actually read from disk before the table is dereferenced.
228 if (cook->num_pages > (num_bytes - sizeof(bincookie_t)) / sizeof(uint32_t)) {
229 free(cook);
230 cook = NULL;
231 errno = EIO;
232 goto done;
233 }
234 // Fix page size numbers
235 for (uint32_t i = 0; i < cook->num_pages; i++) {
236 *(cook->page_sizes + i) = __builtin_bswap32(*(cook->page_sizes + i));
237 }
238 // Every page, cookie offset table, and cookie offset is also file-controlled, so reject the
239 // file unless the whole structure stays within bounds.
240 if (!bincookie_validate_pages(cook, num_bytes)) {
241 free(cook);
242 cook = NULL;
243 errno = EIO;
244 goto done;
245 }
246done:
247 fseek(fin, last_pos, SEEK_SET);
248 return cook;
249}
251
255static inline bincookie_t *const bincookie_init_path(const char *file_path) {
256 FILE *binary_file = fopen(file_path, "rb");
257 if (!binary_file) {
258 return NULL;
259 }
260 bincookie_t *ret = bincookie_init_file(binary_file);
261 fclose(binary_file);
262 return ret;
263}
265
270static inline bincookie_page_t *const bincookie_iter_pages(const bincookie_t *bc,
271 bincookie_iter_state_t *const state) {
272 if (state->page_offset == 0) {
273 state->page_offset = (uint32_t)(4 + sizeof(uint32_t) + (sizeof(uint32_t) * bc->num_pages));
274 }
275 if (state->page_index < bc->num_pages) {
276 bincookie_page_t *page = (bincookie_page_t *)((char *)bc + state->page_offset);
277 state->page_offset += bc->page_sizes[state->page_index];
278 state->page_index++;
279 return page;
280 }
281 return NULL;
282}
284
289static inline bincookie_cookie_t *const bincookie_iter_cookies(const bincookie_page_t *page,
290 unsigned int *i) {
291 if (*i < page->num_cookies) {
292 bincookie_cookie_t *ptr = (bincookie_cookie_t *)((char *)page + page->cookie_offsets[*i]);
293 (*i)++;
294 return ptr;
295 }
296 return NULL;
297}
299#ifdef __cplusplus
300}
301#endif
302
303#endif // _BINCOOKIE_H
static bincookie_page_t *const bincookie_iter_pages(const bincookie_t *bc, bincookie_iter_state_t *const state)
Iterate pages of a binarycookies file.
Definition bincookie.h:279
static bincookie_t *const bincookie_init_file(FILE *fin)
Read a binarycookies file.
Definition bincookie.h:201
static bincookie_t *const bincookie_init_path(const char *file_path)
Read a binarycookies file.
Definition bincookie.h:264
static bool bincookie_validate_pages(const bincookie_t *bc, size_t num_bytes)
Definition bincookie.h:162
static bincookie_cookie_t *const bincookie_iter_cookies(const bincookie_page_t *page, unsigned int *i)
Iterate cookies of a page.
Definition bincookie.h:298
bincookie_flag
Security enabled for a cookie.
Definition bincookie.h:107
@ http_only
Definition bincookie.h:109
@ secure
Definition bincookie.h:108
Keeps track of iteration state when iterating cookie file pages.
Definition bincookie.h:113
uint32_t page_offset
Definition bincookie.h:114
uint32_t page_index
Definition bincookie.h:115
Cookie page structure. A page can consist of 1 or more cookies.
Definition bincookie.h:137
uint32_t cookie_offsets[]
Definition bincookie.h:141
uint32_t num_cookies
Definition bincookie.h:140
bincookie file structure.
Definition bincookie.h:145
uint32_t num_pages
Definition bincookie.h:147
uint32_t page_sizes[]
Definition bincookie.h:148