Line data Source code
1 : /*
2 : * Trivial smb.conf parsing code
3 : * iniparser compatibility layer.
4 : *
5 : * Copyright Jeremy Allison <jra@samba.org> 2014
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, and the entire permission notice in its entirety,
12 : * including the disclaimer of warranties.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. The name of the author may not be used to endorse or promote
17 : * products derived from this software without specific prior
18 : * written permission.
19 : *
20 : * ALTERNATIVELY, this product may be distributed under the terms of
21 : * the GNU Public License Version 3 or later, in which case the provisions
22 : * of the GPL are required INSTEAD OF the above restrictions. (This clause is
23 : * necessary due to a potential bad interaction between the GPL and
24 : * the restrictions contained in a BSD-style copyright.)
25 : *
26 : * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
27 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 : * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
36 : * OF THE POSSIBILITY OF SUCH DAMAGE.
37 : */
38 :
39 : #include <stdio.h>
40 : #include <stdlib.h>
41 : #include <stdbool.h>
42 : #include <ctype.h>
43 : #include <errno.h>
44 : #include <string.h>
45 : #include <stddef.h>
46 : #include "tini.h"
47 : #include "tiniparser.h"
48 :
49 : struct tiniparser_entry {
50 : struct tiniparser_entry *next_entry;
51 : char *key;
52 : char *value;
53 : };
54 :
55 : struct tiniparser_section {
56 : struct tiniparser_section *next_section;
57 : struct tiniparser_entry *entry_list;
58 : char section_name[];
59 : };
60 :
61 : struct tiniparser_dictionary {
62 : struct tiniparser_section *section_list;
63 : };
64 :
65 : /*
66 : * Find a section from a given key.
67 : * Also return start of subkey.
68 : * Return NULL if section name can't be found,
69 : * if no section name given, or no subkey given.
70 : */
71 :
72 0 : static struct tiniparser_section *find_section(struct tiniparser_dictionary *d,
73 : const char *key,
74 : const char **subkey)
75 : {
76 0 : struct tiniparser_section *curr_section;
77 0 : const char *p;
78 0 : size_t section_len;
79 :
80 0 : if (key == NULL) {
81 0 : return NULL;
82 : }
83 0 : p = strchr(key, ':');
84 0 : if (p == NULL) {
85 : /* No section. */
86 0 : return NULL;
87 : }
88 :
89 0 : section_len = p - key;
90 : /* Ensure we have at least one character of section name. */
91 0 : if (section_len == 0) {
92 0 : return NULL;
93 : }
94 : /* Ensure we have at least one character of subkey. */
95 0 : if (p[1] == '\0') {
96 0 : return NULL;
97 : }
98 :
99 0 : for (curr_section = d->section_list;
100 0 : curr_section;
101 0 : curr_section = curr_section->next_section) {
102 : /*
103 : * Check if the key section matches the
104 : * section name *exactly* (with terminating
105 : * null after section_len characters.
106 : */
107 0 : if ((strncasecmp(key, curr_section->section_name, section_len) == 0) &&
108 0 : (curr_section->section_name[section_len] == '\0')) {
109 0 : *subkey = p+1;
110 0 : return curr_section;
111 : }
112 : }
113 0 : return NULL;
114 : }
115 :
116 0 : static struct tiniparser_entry *find_entry(struct tiniparser_section *section,
117 : const char *key)
118 : {
119 0 : struct tiniparser_entry *curr_entry;
120 :
121 0 : for (curr_entry = section->entry_list;
122 0 : curr_entry;
123 0 : curr_entry = curr_entry->next_entry) {
124 0 : if (strcasecmp(key,
125 0 : curr_entry->key) == 0) {
126 0 : return curr_entry;
127 : }
128 : }
129 0 : return NULL;
130 : }
131 :
132 0 : const char *tiniparser_getstring(struct tiniparser_dictionary *d,
133 : const char *key,
134 : const char *default_value)
135 : {
136 0 : struct tiniparser_section *section;
137 0 : struct tiniparser_entry *entry;
138 0 : const char *subkey;
139 :
140 0 : section = find_section(d, key, &subkey);
141 0 : if (section == NULL) {
142 0 : return default_value;
143 : }
144 :
145 0 : entry = find_entry(section, subkey);
146 0 : if (entry == NULL) {
147 0 : return default_value;
148 : }
149 :
150 0 : return entry->value;
151 : }
152 :
153 :
154 0 : bool tiniparser_getboolean(struct tiniparser_dictionary *d,
155 : const char *key,
156 : bool default_value)
157 : {
158 0 : const char *value = tiniparser_getstring(d, key, NULL);
159 :
160 0 : if (value == NULL) {
161 0 : return default_value;
162 : }
163 :
164 0 : switch(value[0]) {
165 0 : case '1':
166 : case 'T':
167 : case 't':
168 : case 'y':
169 : case 'Y':
170 0 : return true;
171 0 : case '0':
172 : case 'F':
173 : case 'f':
174 : case 'n':
175 : case 'N':
176 0 : return false;
177 0 : default:
178 0 : break;
179 : }
180 :
181 0 : return default_value;
182 : }
183 :
184 0 : int tiniparser_getint(struct tiniparser_dictionary *d,
185 : const char *key,
186 : int default_value)
187 : {
188 0 : const char *value = tiniparser_getstring(d, key, NULL);
189 :
190 0 : if (value == NULL) {
191 0 : return default_value;
192 : }
193 :
194 0 : return (int)strtol(value, NULL, 0);
195 : }
196 :
197 0 : static bool value_parser(const char *key,
198 : const char *value,
199 : void *private_data)
200 : {
201 0 : struct tiniparser_dictionary *d =
202 : (struct tiniparser_dictionary *)private_data;
203 0 : struct tiniparser_section *section = d->section_list;
204 0 : struct tiniparser_entry *entry = NULL;
205 0 : size_t val_len;
206 0 : size_t key_len;
207 :
208 0 : if (section == NULL) {
209 0 : return false;
210 : }
211 0 : if (key == NULL) {
212 0 : return false;
213 : }
214 0 : if (value == NULL) {
215 0 : return false;
216 : }
217 :
218 0 : key_len = strlen(key) + 1;
219 0 : val_len = strlen(value) + 1;
220 :
221 0 : entry = find_entry(section, key);
222 0 : if (entry) {
223 : /* Replace current value. */
224 0 : char *new_val = malloc(val_len);
225 0 : if (new_val == NULL) {
226 0 : return false;
227 : }
228 0 : memcpy(new_val, value, val_len);
229 0 : free(entry->value);
230 0 : entry->value = new_val;
231 0 : return true;
232 : }
233 :
234 : /* Create a new entry. */
235 0 : entry = malloc(sizeof(struct tiniparser_entry));
236 0 : if (entry == NULL) {
237 0 : return false;
238 : }
239 0 : entry->key = malloc(key_len);
240 0 : if (entry->key == NULL) {
241 0 : free(entry);
242 0 : return false;
243 : }
244 0 : memcpy(entry->key, key, key_len);
245 :
246 0 : entry->value = malloc(val_len);
247 0 : if (entry->value == NULL) {
248 0 : free(entry->key);
249 0 : free(entry);
250 0 : return false;
251 : }
252 0 : memcpy(entry->value, value, val_len);
253 :
254 0 : entry->next_entry = section->entry_list;
255 0 : section->entry_list = entry;
256 0 : return true;
257 : }
258 :
259 0 : static bool section_parser(const char *section_name,
260 : void *private_data)
261 : {
262 0 : struct tiniparser_section **pp_section;
263 0 : struct tiniparser_section *new_section;
264 0 : struct tiniparser_dictionary *d =
265 : (struct tiniparser_dictionary *)private_data;
266 0 : size_t section_name_len;
267 :
268 0 : if (section_name == NULL) {
269 0 : return false;
270 : }
271 :
272 : /* Section names can't contain ':' */
273 0 : if (strchr(section_name, ':') != NULL) {
274 0 : return false;
275 : }
276 :
277 : /* Do we already have this section ? */
278 0 : for (pp_section = &d->section_list;
279 0 : *pp_section;
280 0 : pp_section = &(*pp_section)->next_section) {
281 0 : if (strcasecmp(section_name,
282 0 : (*pp_section)->section_name) == 0) {
283 : /*
284 : * Move to the front of the list for
285 : * value_parser() to find it.
286 : */
287 :
288 : /* First save current entry. */
289 0 : struct tiniparser_section *curr_section = *pp_section;
290 :
291 : /* Now unlink current entry from list. */
292 0 : *pp_section = curr_section->next_section;
293 :
294 : /* Make current entry next point to whole list. */
295 0 : curr_section->next_section = d->section_list;
296 :
297 : /* And replace list with current entry at start. */
298 0 : d->section_list = curr_section;
299 :
300 0 : return true;
301 : }
302 : }
303 :
304 0 : section_name_len = strlen(section_name) + 1;
305 :
306 : /* Create new section. */
307 0 : new_section = malloc(
308 : offsetof(struct tiniparser_section, section_name) +
309 : section_name_len);
310 0 : if (new_section == NULL) {
311 0 : return false;
312 : }
313 :
314 0 : memcpy(new_section->section_name, section_name, section_name_len);
315 :
316 0 : new_section->entry_list = NULL;
317 :
318 : /* Add it to the head of the singly linked list. */
319 0 : new_section->next_section = d->section_list;
320 0 : d->section_list = new_section;
321 0 : return true;
322 : }
323 :
324 0 : struct tiniparser_dictionary *tiniparser_load_stream(FILE *fp)
325 : {
326 0 : bool ret;
327 0 : struct tiniparser_dictionary *d = NULL;
328 :
329 0 : d = malloc(sizeof(struct tiniparser_dictionary));
330 0 : if (d == NULL) {
331 0 : return NULL;
332 : }
333 0 : d->section_list = NULL;
334 :
335 0 : ret = tini_parse(fp,
336 : false,
337 : section_parser,
338 : value_parser,
339 : d);
340 0 : if (ret == false) {
341 0 : tiniparser_freedict(d);
342 0 : d = NULL;
343 : }
344 0 : return d;
345 : }
346 :
347 468 : struct tiniparser_dictionary *tiniparser_load(const char *filename)
348 : {
349 0 : struct tiniparser_dictionary *d;
350 468 : FILE *fp = fopen(filename, "r");
351 :
352 468 : if (fp == NULL) {
353 468 : return NULL;
354 : }
355 :
356 0 : d = tiniparser_load_stream(fp);
357 :
358 0 : fclose(fp);
359 :
360 0 : return d;
361 : }
362 :
363 0 : void tiniparser_freedict(struct tiniparser_dictionary *d)
364 : {
365 0 : struct tiniparser_section *curr_section, *next_section;
366 :
367 0 : if (d == NULL) {
368 0 : return;
369 : }
370 :
371 0 : for (curr_section = d->section_list;
372 0 : curr_section;
373 0 : curr_section = next_section) {
374 0 : struct tiniparser_entry *curr_entry, *next_entry;
375 :
376 0 : next_section = curr_section->next_section;
377 :
378 0 : for (curr_entry = curr_section->entry_list;
379 0 : curr_entry;
380 0 : curr_entry = next_entry) {
381 0 : next_entry = curr_entry->next_entry;
382 :
383 0 : free(curr_entry->key);
384 0 : free(curr_entry->value);
385 0 : free(curr_entry);
386 : }
387 0 : free(curr_section);
388 : }
389 0 : free(d);
390 : }
|