Commit | Line | Data |
---|---|---|
ffc92d69 JH |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
5 | /* Copyright (c) Jeremy Harris 2019 */ | |
6 | /* See the file NOTICE for conditions of use and distribution. */ | |
7 | ||
8 | #include "../exim.h" | |
9 | #include "lf_functions.h" | |
10 | #include <jansson.h> | |
11 | ||
12 | ||
13 | ||
14 | /* All use of allocations will be done against the POOL_SEARCH memory, | |
15 | which is freed once by search_tidyup(). Make the free call a dummy. | |
16 | This burns some 300kB in handling a 37kB JSON file, for the benefit of | |
17 | a fast free. The alternative of staying with malloc is nearly as bad, | |
18 | eyeballing the activity there are 20% the number of free vs. alloc | |
f3ebb786 JH |
19 | calls (before the big bunch at the end). |
20 | ||
21 | Assume that the file is trusted, so no tainting */ | |
ffc92d69 JH |
22 | |
23 | static void * | |
24 | json_malloc(size_t nbytes) | |
25 | { | |
f3ebb786 | 26 | void * p = store_get((int)nbytes, FALSE); |
ffc92d69 JH |
27 | /* debug_printf("%s %d: %p\n", __FUNCTION__, (int)nbytes, p); */ |
28 | return p; | |
29 | } | |
30 | static void | |
31 | json_free(void * p) | |
32 | { | |
33 | /* debug_printf("%s: %p\n", __FUNCTION__, p); */ | |
34 | } | |
35 | ||
36 | /************************************************* | |
37 | * Open entry point * | |
38 | *************************************************/ | |
39 | ||
40 | /* See local README for interface description */ | |
41 | ||
42 | static void * | |
43 | json_open(uschar *filename, uschar **errmsg) | |
44 | { | |
45 | FILE * f; | |
46 | ||
47 | json_set_alloc_funcs(json_malloc, json_free); | |
48 | ||
49 | if (!(f = Ufopen(filename, "rb"))) | |
50 | { | |
51 | int save_errno = errno; | |
52 | *errmsg = string_open_failed(errno, "%s for json search", filename); | |
53 | errno = save_errno; | |
54 | return NULL; | |
55 | } | |
56 | return f; | |
57 | } | |
58 | ||
59 | ||
60 | ||
61 | /************************************************* | |
62 | * Check entry point * | |
63 | *************************************************/ | |
64 | ||
65 | static BOOL | |
66 | json_check(void *handle, uschar *filename, int modemask, uid_t *owners, | |
67 | gid_t *owngroups, uschar **errmsg) | |
68 | { | |
69 | return lf_check_file(fileno((FILE *)handle), filename, S_IFREG, modemask, | |
70 | owners, owngroups, "json", errmsg) == 0; | |
71 | } | |
72 | ||
73 | ||
74 | ||
75 | /************************************************* | |
76 | * Find entry point for lsearch * | |
77 | *************************************************/ | |
78 | ||
79 | /* See local README for interface description */ | |
80 | ||
81 | static int | |
82 | json_find(void *handle, uschar *filename, const uschar *keystring, int length, | |
83 | uschar **result, uschar **errmsg, uint *do_cache) | |
84 | { | |
85 | FILE * f = handle; | |
86 | json_t * j, * j0; | |
87 | json_error_t jerr; | |
88 | uschar * key; | |
89 | int sep = 0; | |
90 | ||
91 | length = length; /* Keep picky compilers happy */ | |
92 | do_cache = do_cache; /* Keep picky compilers happy */ | |
93 | ||
94 | rewind(f); | |
95 | if (!(j = json_loadf(f, 0, &jerr))) | |
96 | { | |
97 | *errmsg = string_sprintf("json error on open: %.*s\n", | |
98 | JSON_ERROR_TEXT_LENGTH, jerr.text); | |
99 | return FAIL; | |
100 | } | |
101 | j0 = j; | |
102 | ||
103 | for (int k = 1; (key = string_nextinlist(&keystring, &sep, NULL, 0)); k++) | |
104 | { | |
105 | BOOL numeric = TRUE; | |
106 | for (uschar * s = key; *s; s++) if (!isdigit(*s)) { numeric = FALSE; break; } | |
107 | ||
108 | if (!(j = numeric | |
109 | ? json_array_get(j, (size_t) strtoul(CS key, NULL, 10)) | |
110 | : json_object_get(j, CCS key) | |
111 | ) ) | |
112 | { | |
42c7f0b4 | 113 | DEBUG(D_lookup) debug_printf_indent("%s, for key %d: '%s'\n", |
ffc92d69 JH |
114 | numeric |
115 | ? US"bad index, or not json array" | |
116 | : US"no such key, or not json object", | |
117 | k, key); | |
118 | json_decref(j0); | |
119 | return FAIL; | |
120 | } | |
121 | } | |
122 | ||
123 | switch (json_typeof(j)) | |
124 | { | |
125 | case JSON_STRING: | |
126 | *result = string_copyn(CUS json_string_value(j), json_string_length(j)); | |
127 | break; | |
128 | case JSON_INTEGER: | |
129 | *result = string_sprintf("%" JSON_INTEGER_FORMAT, json_integer_value(j)); | |
130 | break; | |
131 | case JSON_REAL: | |
132 | *result = string_sprintf("%f", json_real_value(j)); | |
133 | break; | |
134 | case JSON_TRUE: *result = US"true"; break; | |
135 | case JSON_FALSE: *result = US"false"; break; | |
136 | case JSON_NULL: *result = NULL; break; | |
137 | default: *result = US json_dumps(j, 0); break; | |
138 | } | |
139 | json_decref(j0); | |
140 | return OK; | |
141 | } | |
142 | ||
143 | ||
144 | ||
145 | /************************************************* | |
146 | * Close entry point * | |
147 | *************************************************/ | |
148 | ||
149 | /* See local README for interface description */ | |
150 | ||
151 | static void | |
152 | json_close(void *handle) | |
153 | { | |
154 | (void)fclose((FILE *)handle); | |
155 | } | |
156 | ||
157 | ||
158 | ||
159 | /************************************************* | |
160 | * Version reporting entry point * | |
161 | *************************************************/ | |
162 | ||
163 | /* See local README for interface description. */ | |
164 | ||
165 | #include "../version.h" | |
166 | ||
167 | void | |
168 | json_version_report(FILE *f) | |
169 | { | |
170 | fprintf(f, "Library version: json: Jansonn version %s\n", JANSSON_VERSION); | |
171 | } | |
172 | ||
173 | ||
174 | static lookup_info json_lookup_info = { | |
175 | US"json", /* lookup name */ | |
176 | lookup_absfile, /* uses absolute file name */ | |
177 | json_open, /* open function */ | |
178 | json_check, /* check function */ | |
179 | json_find, /* find function */ | |
180 | json_close, /* close function */ | |
181 | NULL, /* no tidy function */ | |
182 | NULL, /* no quoting function */ | |
183 | json_version_report /* version reporting */ | |
184 | }; | |
185 | ||
186 | ||
187 | #ifdef DYNLOOKUP | |
188 | #define json_lookup_module_info _lookup_module_info | |
189 | #endif | |
190 | ||
191 | static lookup_info *_lookup_list[] = { &json_lookup_info }; | |
192 | lookup_module_info json_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; | |
193 | ||
194 | /* End of lookups/json.c */ |