OSDN Git Service

Add options for disabling weak encryption methods.
[ffftp/ffftp.git] / putty / CONF.C
1 /*\r
2  * conf.c: implementation of the internal storage format used for\r
3  * the configuration of a PuTTY session.\r
4  */\r
5 \r
6 #include <stdio.h>\r
7 #include <stddef.h>\r
8 #include <assert.h>\r
9 \r
10 #include "tree234.h"\r
11 #include "putty.h"\r
12 \r
13 /*\r
14  * Enumeration of types used in keys and values.\r
15  */\r
16 typedef enum { TYPE_NONE, TYPE_INT, TYPE_STR, TYPE_FILENAME, TYPE_FONT } Type;\r
17 \r
18 /*\r
19  * Arrays which allow us to look up the subkey and value types for a\r
20  * given primary key id.\r
21  */\r
22 #define CONF_SUBKEYTYPE_DEF(valtype, keytype, keyword) TYPE_ ## keytype,\r
23 static int subkeytypes[] = { CONFIG_OPTIONS(CONF_SUBKEYTYPE_DEF) };\r
24 #define CONF_VALUETYPE_DEF(valtype, keytype, keyword) TYPE_ ## valtype,\r
25 static int valuetypes[] = { CONFIG_OPTIONS(CONF_VALUETYPE_DEF) };\r
26 \r
27 /*\r
28  * Configuration keys are primarily integers (big enum of all the\r
29  * different configurable options); some keys have string-designated\r
30  * subkeys, such as the list of environment variables (subkeys\r
31  * defined by the variable names); some have integer-designated\r
32  * subkeys (wordness, colours, preference lists).\r
33  */\r
34 struct key {\r
35     int primary;\r
36     union {\r
37         int i;\r
38         char *s;\r
39     } secondary;\r
40 };\r
41 \r
42 struct value {\r
43     union {\r
44         int intval;\r
45         char *stringval;\r
46         Filename *fileval;\r
47         FontSpec *fontval;\r
48     } u;\r
49 };\r
50 \r
51 struct conf_entry {\r
52     struct key key;\r
53     struct value value;\r
54 };\r
55 \r
56 struct conf_tag {\r
57     tree234 *tree;\r
58 };\r
59 \r
60 /*\r
61  * Because 'struct key' is the first element in 'struct conf_entry',\r
62  * it's safe (guaranteed by the C standard) to cast arbitrarily back\r
63  * and forth between the two types. Therefore, we only need one\r
64  * comparison function, which can double as a main sort function for\r
65  * the tree (comparing two conf_entry structures with each other)\r
66  * and a search function (looking up an externally supplied key).\r
67  */\r
68 static int conf_cmp(void *av, void *bv)\r
69 {\r
70     struct key *a = (struct key *)av;\r
71     struct key *b = (struct key *)bv;\r
72 \r
73     if (a->primary < b->primary)\r
74         return -1;\r
75     else if (a->primary > b->primary)\r
76         return +1;\r
77     switch (subkeytypes[a->primary]) {\r
78       case TYPE_INT:\r
79         if (a->secondary.i < b->secondary.i)\r
80             return -1;\r
81         else if (a->secondary.i > b->secondary.i)\r
82             return +1;\r
83         return 0;\r
84       case TYPE_STR:\r
85         return strcmp(a->secondary.s, b->secondary.s);\r
86       default:\r
87         return 0;\r
88     }\r
89 }\r
90 \r
91 /*\r
92  * Free any dynamic data items pointed to by a 'struct key'. We\r
93  * don't free the structure itself, since it's probably part of a\r
94  * larger allocated block.\r
95  */\r
96 static void free_key(struct key *key)\r
97 {\r
98     if (subkeytypes[key->primary] == TYPE_STR)\r
99         sfree(key->secondary.s);\r
100 }\r
101 \r
102 /*\r
103  * Copy a 'struct key' into another one, copying its dynamic data\r
104  * if necessary.\r
105  */\r
106 static void copy_key(struct key *to, struct key *from)\r
107 {\r
108     to->primary = from->primary;\r
109     switch (subkeytypes[to->primary]) {\r
110       case TYPE_INT:\r
111         to->secondary.i = from->secondary.i;\r
112         break;\r
113       case TYPE_STR:\r
114         to->secondary.s = dupstr(from->secondary.s);\r
115         break;\r
116     }\r
117 }\r
118 \r
119 /*\r
120  * Free any dynamic data items pointed to by a 'struct value'. We\r
121  * don't free the value itself, since it's probably part of a larger\r
122  * allocated block.\r
123  */\r
124 static void free_value(struct value *val, int type)\r
125 {\r
126     if (type == TYPE_STR)\r
127         sfree(val->u.stringval);\r
128     else if (type == TYPE_FILENAME)\r
129         filename_free(val->u.fileval);\r
130     else if (type == TYPE_FONT)\r
131         fontspec_free(val->u.fontval);\r
132 }\r
133 \r
134 /*\r
135  * Copy a 'struct value' into another one, copying its dynamic data\r
136  * if necessary.\r
137  */\r
138 static void copy_value(struct value *to, struct value *from, int type)\r
139 {\r
140     switch (type) {\r
141       case TYPE_INT:\r
142         to->u.intval = from->u.intval;\r
143         break;\r
144       case TYPE_STR:\r
145         to->u.stringval = dupstr(from->u.stringval);\r
146         break;\r
147       case TYPE_FILENAME:\r
148         to->u.fileval = filename_copy(from->u.fileval);\r
149         break;\r
150       case TYPE_FONT:\r
151         to->u.fontval = fontspec_copy(from->u.fontval);\r
152         break;\r
153     }\r
154 }\r
155 \r
156 /*\r
157  * Free an entire 'struct conf_entry' and its dynamic data.\r
158  */\r
159 static void free_entry(struct conf_entry *entry)\r
160 {\r
161     free_key(&entry->key);\r
162     free_value(&entry->value, valuetypes[entry->key.primary]);\r
163     sfree(entry);\r
164 }\r
165 \r
166 Conf *conf_new(void)\r
167 {\r
168     Conf *conf = snew(struct conf_tag);\r
169 \r
170     conf->tree = newtree234(conf_cmp);\r
171 \r
172     return conf;\r
173 }\r
174 \r
175 static void conf_clear(Conf *conf)\r
176 {\r
177     struct conf_entry *entry;\r
178 \r
179     while ((entry = delpos234(conf->tree, 0)) != NULL)\r
180         free_entry(entry);\r
181 }\r
182 \r
183 void conf_free(Conf *conf)\r
184 {\r
185     conf_clear(conf);\r
186     freetree234(conf->tree);\r
187     sfree(conf);\r
188 }\r
189 \r
190 static void conf_insert(Conf *conf, struct conf_entry *entry)\r
191 {\r
192     struct conf_entry *oldentry = add234(conf->tree, entry);\r
193     if (oldentry && oldentry != entry) {\r
194         del234(conf->tree, oldentry);\r
195         free_entry(oldentry);\r
196         oldentry = add234(conf->tree, entry);\r
197         assert(oldentry == entry);\r
198     }\r
199 }\r
200 \r
201 void conf_copy_into(Conf *newconf, Conf *oldconf)\r
202 {\r
203     struct conf_entry *entry, *entry2;\r
204     int i;\r
205 \r
206     conf_clear(newconf);\r
207 \r
208     for (i = 0; (entry = index234(oldconf->tree, i)) != NULL; i++) {\r
209         entry2 = snew(struct conf_entry);\r
210         copy_key(&entry2->key, &entry->key);\r
211         copy_value(&entry2->value, &entry->value,\r
212                    valuetypes[entry->key.primary]);\r
213         add234(newconf->tree, entry2);\r
214     }\r
215 }\r
216 \r
217 Conf *conf_copy(Conf *oldconf)\r
218 {\r
219     Conf *newconf = conf_new();\r
220 \r
221     conf_copy_into(newconf, oldconf);\r
222 \r
223     return newconf;\r
224 }\r
225 \r
226 int conf_get_int(Conf *conf, int primary)\r
227 {\r
228     struct key key;\r
229     struct conf_entry *entry;\r
230 \r
231     assert(subkeytypes[primary] == TYPE_NONE);\r
232     assert(valuetypes[primary] == TYPE_INT);\r
233     key.primary = primary;\r
234     entry = find234(conf->tree, &key, NULL);\r
235     assert(entry);\r
236     return entry->value.u.intval;\r
237 }\r
238 \r
239 int conf_get_int_int(Conf *conf, int primary, int secondary)\r
240 {\r
241     struct key key;\r
242     struct conf_entry *entry;\r
243 \r
244     assert(subkeytypes[primary] == TYPE_INT);\r
245     assert(valuetypes[primary] == TYPE_INT);\r
246     key.primary = primary;\r
247     key.secondary.i = secondary;\r
248     entry = find234(conf->tree, &key, NULL);\r
249     assert(entry);\r
250     return entry->value.u.intval;\r
251 }\r
252 \r
253 char *conf_get_str(Conf *conf, int primary)\r
254 {\r
255     struct key key;\r
256     struct conf_entry *entry;\r
257 \r
258     assert(subkeytypes[primary] == TYPE_NONE);\r
259     assert(valuetypes[primary] == TYPE_STR);\r
260     key.primary = primary;\r
261     entry = find234(conf->tree, &key, NULL);\r
262     assert(entry);\r
263     return entry->value.u.stringval;\r
264 }\r
265 \r
266 char *conf_get_str_str_opt(Conf *conf, int primary, const char *secondary)\r
267 {\r
268     struct key key;\r
269     struct conf_entry *entry;\r
270 \r
271     assert(subkeytypes[primary] == TYPE_STR);\r
272     assert(valuetypes[primary] == TYPE_STR);\r
273     key.primary = primary;\r
274     key.secondary.s = (char *)secondary;\r
275     entry = find234(conf->tree, &key, NULL);\r
276     return entry ? entry->value.u.stringval : NULL;\r
277 }\r
278 \r
279 char *conf_get_str_str(Conf *conf, int primary, const char *secondary)\r
280 {\r
281     char *ret = conf_get_str_str_opt(conf, primary, secondary);\r
282     assert(ret);\r
283     return ret;\r
284 }\r
285 \r
286 char *conf_get_str_strs(Conf *conf, int primary,\r
287                        char *subkeyin, char **subkeyout)\r
288 {\r
289     struct key key;\r
290     struct conf_entry *entry;\r
291 \r
292     assert(subkeytypes[primary] == TYPE_STR);\r
293     assert(valuetypes[primary] == TYPE_STR);\r
294     key.primary = primary;\r
295     if (subkeyin) {\r
296         key.secondary.s = subkeyin;\r
297         entry = findrel234(conf->tree, &key, NULL, REL234_GT);\r
298     } else {\r
299         key.secondary.s = "";\r
300         entry = findrel234(conf->tree, &key, NULL, REL234_GE);\r
301     }\r
302     if (!entry || entry->key.primary != primary)\r
303         return NULL;\r
304     *subkeyout = entry->key.secondary.s;\r
305     return entry->value.u.stringval;\r
306 }\r
307 \r
308 char *conf_get_str_nthstrkey(Conf *conf, int primary, int n)\r
309 {\r
310     struct key key;\r
311     struct conf_entry *entry;\r
312     int index;\r
313 \r
314     assert(subkeytypes[primary] == TYPE_STR);\r
315     assert(valuetypes[primary] == TYPE_STR);\r
316     key.primary = primary;\r
317     key.secondary.s = "";\r
318     entry = findrelpos234(conf->tree, &key, NULL, REL234_GE, &index);\r
319     if (!entry || entry->key.primary != primary)\r
320         return NULL;\r
321     entry = index234(conf->tree, index + n);\r
322     if (!entry || entry->key.primary != primary)\r
323         return NULL;\r
324     return entry->key.secondary.s;\r
325 }\r
326 \r
327 Filename *conf_get_filename(Conf *conf, int primary)\r
328 {\r
329     struct key key;\r
330     struct conf_entry *entry;\r
331 \r
332     assert(subkeytypes[primary] == TYPE_NONE);\r
333     assert(valuetypes[primary] == TYPE_FILENAME);\r
334     key.primary = primary;\r
335     entry = find234(conf->tree, &key, NULL);\r
336     assert(entry);\r
337     return entry->value.u.fileval;\r
338 }\r
339 \r
340 FontSpec *conf_get_fontspec(Conf *conf, int primary)\r
341 {\r
342     struct key key;\r
343     struct conf_entry *entry;\r
344 \r
345     assert(subkeytypes[primary] == TYPE_NONE);\r
346     assert(valuetypes[primary] == TYPE_FONT);\r
347     key.primary = primary;\r
348     entry = find234(conf->tree, &key, NULL);\r
349     assert(entry);\r
350     return entry->value.u.fontval;\r
351 }\r
352 \r
353 void conf_set_int(Conf *conf, int primary, int value)\r
354 {\r
355     struct conf_entry *entry = snew(struct conf_entry);\r
356 \r
357     assert(subkeytypes[primary] == TYPE_NONE);\r
358     assert(valuetypes[primary] == TYPE_INT);\r
359     entry->key.primary = primary;\r
360     entry->value.u.intval = value; \r
361     conf_insert(conf, entry);\r
362 }\r
363 \r
364 void conf_set_int_int(Conf *conf, int primary, int secondary, int value)\r
365 {\r
366     struct conf_entry *entry = snew(struct conf_entry);\r
367 \r
368     assert(subkeytypes[primary] == TYPE_INT);\r
369     assert(valuetypes[primary] == TYPE_INT);\r
370     entry->key.primary = primary;\r
371     entry->key.secondary.i = secondary;\r
372     entry->value.u.intval = value;\r
373     conf_insert(conf, entry);\r
374 }\r
375 \r
376 void conf_set_str(Conf *conf, int primary, const char *value)\r
377 {\r
378     struct conf_entry *entry = snew(struct conf_entry);\r
379 \r
380     assert(subkeytypes[primary] == TYPE_NONE);\r
381     assert(valuetypes[primary] == TYPE_STR);\r
382     entry->key.primary = primary;\r
383     entry->value.u.stringval = dupstr(value);\r
384     conf_insert(conf, entry);\r
385 }\r
386 \r
387 void conf_set_str_str(Conf *conf, int primary, const char *secondary,\r
388                       const char *value)\r
389 {\r
390     struct conf_entry *entry = snew(struct conf_entry);\r
391 \r
392     assert(subkeytypes[primary] == TYPE_STR);\r
393     assert(valuetypes[primary] == TYPE_STR);\r
394     entry->key.primary = primary;\r
395     entry->key.secondary.s = dupstr(secondary);\r
396     entry->value.u.stringval = dupstr(value);\r
397     conf_insert(conf, entry);\r
398 }\r
399 \r
400 void conf_del_str_str(Conf *conf, int primary, const char *secondary)\r
401 {\r
402     struct key key;\r
403     struct conf_entry *entry;\r
404 \r
405     assert(subkeytypes[primary] == TYPE_STR);\r
406     assert(valuetypes[primary] == TYPE_STR);\r
407     key.primary = primary;\r
408     key.secondary.s = (char *)secondary;\r
409     entry = find234(conf->tree, &key, NULL);\r
410     if (entry) {\r
411         del234(conf->tree, entry);\r
412         free_entry(entry);\r
413     }\r
414  }\r
415 \r
416 void conf_set_filename(Conf *conf, int primary, const Filename *value)\r
417 {\r
418     struct conf_entry *entry = snew(struct conf_entry);\r
419 \r
420     assert(subkeytypes[primary] == TYPE_NONE);\r
421     assert(valuetypes[primary] == TYPE_FILENAME);\r
422     entry->key.primary = primary;\r
423     entry->value.u.fileval = filename_copy(value);\r
424     conf_insert(conf, entry);\r
425 }\r
426 \r
427 void conf_set_fontspec(Conf *conf, int primary, const FontSpec *value)\r
428 {\r
429     struct conf_entry *entry = snew(struct conf_entry);\r
430 \r
431     assert(subkeytypes[primary] == TYPE_NONE);\r
432     assert(valuetypes[primary] == TYPE_FONT);\r
433     entry->key.primary = primary;\r
434     entry->value.u.fontval = fontspec_copy(value);\r
435     conf_insert(conf, entry);\r
436 }\r
437 \r
438 int conf_serialised_size(Conf *conf)\r
439 {\r
440     int i;\r
441     struct conf_entry *entry;\r
442     int size = 0;\r
443 \r
444     for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) {\r
445         size += 4;   /* primary key */\r
446         switch (subkeytypes[entry->key.primary]) {\r
447           case TYPE_INT:\r
448             size += 4;\r
449             break;\r
450           case TYPE_STR:\r
451             size += 1 + strlen(entry->key.secondary.s);\r
452             break;\r
453         }\r
454         switch (valuetypes[entry->key.primary]) {\r
455           case TYPE_INT:\r
456             size += 4;\r
457             break;\r
458           case TYPE_STR:\r
459             size += 1 + strlen(entry->value.u.stringval);\r
460             break;\r
461           case TYPE_FILENAME:\r
462             size += filename_serialise(entry->value.u.fileval, NULL);\r
463             break;\r
464           case TYPE_FONT:\r
465             size += fontspec_serialise(entry->value.u.fontval, NULL);\r
466             break;\r
467         }\r
468     }\r
469 \r
470     size += 4;                         /* terminator value */\r
471 \r
472     return size;\r
473 }\r
474 \r
475 void conf_serialise(Conf *conf, void *vdata)\r
476 {\r
477     unsigned char *data = (unsigned char *)vdata;\r
478     int i, len;\r
479     struct conf_entry *entry;\r
480 \r
481     for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) {\r
482         PUT_32BIT_MSB_FIRST(data, entry->key.primary);\r
483         data += 4;\r
484 \r
485         switch (subkeytypes[entry->key.primary]) {\r
486           case TYPE_INT:\r
487             PUT_32BIT_MSB_FIRST(data, entry->key.secondary.i);\r
488             data += 4;\r
489             break;\r
490           case TYPE_STR:\r
491             len = strlen(entry->key.secondary.s);\r
492             memcpy(data, entry->key.secondary.s, len);\r
493             data += len;\r
494             *data++ = 0;\r
495             break;\r
496         }\r
497         switch (valuetypes[entry->key.primary]) {\r
498           case TYPE_INT:\r
499             PUT_32BIT_MSB_FIRST(data, entry->value.u.intval);\r
500             data += 4;\r
501             break;\r
502           case TYPE_STR:\r
503             len = strlen(entry->value.u.stringval);\r
504             memcpy(data, entry->value.u.stringval, len);\r
505             data += len;\r
506             *data++ = 0;\r
507             break;\r
508           case TYPE_FILENAME:\r
509             data += filename_serialise(entry->value.u.fileval, data);\r
510             break;\r
511           case TYPE_FONT:\r
512             data += fontspec_serialise(entry->value.u.fontval, data);\r
513             break;\r
514         }\r
515     }\r
516 \r
517     PUT_32BIT_MSB_FIRST(data, 0xFFFFFFFFU);\r
518 }\r
519 \r
520 int conf_deserialise(Conf *conf, void *vdata, int maxsize)\r
521 {\r
522     unsigned char *data = (unsigned char *)vdata;\r
523     unsigned char *start = data;\r
524     struct conf_entry *entry;\r
525     unsigned primary;\r
526     int used;\r
527     unsigned char *zero;\r
528 \r
529     while (maxsize >= 4) {\r
530         primary = GET_32BIT_MSB_FIRST(data);\r
531         data += 4, maxsize -= 4;\r
532 \r
533         if (primary >= N_CONFIG_OPTIONS)\r
534             break;\r
535 \r
536         entry = snew(struct conf_entry);\r
537         entry->key.primary = primary;\r
538 \r
539         switch (subkeytypes[entry->key.primary]) {\r
540           case TYPE_INT:\r
541             if (maxsize < 4) {\r
542                 sfree(entry);\r
543                 goto done;\r
544             }\r
545             entry->key.secondary.i = toint(GET_32BIT_MSB_FIRST(data));\r
546             data += 4, maxsize -= 4;\r
547             break;\r
548           case TYPE_STR:\r
549             zero = memchr(data, 0, maxsize);\r
550             if (!zero) {\r
551                 sfree(entry);\r
552                 goto done;\r
553             }\r
554             entry->key.secondary.s = dupstr((char *)data);\r
555             maxsize -= (zero + 1 - data);\r
556             data = zero + 1;\r
557             break;\r
558         }\r
559 \r
560         switch (valuetypes[entry->key.primary]) {\r
561           case TYPE_INT:\r
562             if (maxsize < 4) {\r
563                 if (subkeytypes[entry->key.primary] == TYPE_STR)\r
564                     sfree(entry->key.secondary.s);\r
565                 sfree(entry);\r
566                 goto done;\r
567             }\r
568             entry->value.u.intval = toint(GET_32BIT_MSB_FIRST(data));\r
569             data += 4, maxsize -= 4;\r
570             break;\r
571           case TYPE_STR:\r
572             zero = memchr(data, 0, maxsize);\r
573             if (!zero) {\r
574                 if (subkeytypes[entry->key.primary] == TYPE_STR)\r
575                     sfree(entry->key.secondary.s);\r
576                 sfree(entry);\r
577                 goto done;\r
578             }\r
579             entry->value.u.stringval = dupstr((char *)data);\r
580             maxsize -= (zero + 1 - data);\r
581             data = zero + 1;\r
582             break;\r
583           case TYPE_FILENAME:\r
584             entry->value.u.fileval =\r
585                 filename_deserialise(data, maxsize, &used);\r
586             if (!entry->value.u.fileval) {\r
587                 if (subkeytypes[entry->key.primary] == TYPE_STR)\r
588                     sfree(entry->key.secondary.s);\r
589                 sfree(entry);\r
590                 goto done;\r
591             }\r
592             data += used;\r
593             maxsize -= used;\r
594             break;\r
595           case TYPE_FONT:\r
596             entry->value.u.fontval =\r
597                 fontspec_deserialise(data, maxsize, &used);\r
598             if (!entry->value.u.fontval) {\r
599                 if (subkeytypes[entry->key.primary] == TYPE_STR)\r
600                     sfree(entry->key.secondary.s);\r
601                 sfree(entry);\r
602                 goto done;\r
603             }\r
604             data += used;\r
605             maxsize -= used;\r
606             break;\r
607         }\r
608         conf_insert(conf, entry);\r
609     }\r
610 \r
611     done:\r
612     return (int)(data - start);\r
613 }\r