1 /*
2  * Copyright © 2020 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "config.h"
25 
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include <libxml/parser.h>
33 
34 #include "xkbcommon/xkbregistry.h"
35 #include "utils.h"
36 #include "util-list.h"
37 
38 struct rxkb_object;
39 
40 typedef void (*destroy_func_t)(struct rxkb_object *object);
41 
42 /**
43  * All our objects are refcounted and are linked to iterate through them.
44  * Abstract those bits away into a shared parent class so we can generate
45  * most of the functions through macros.
46  */
47 struct rxkb_object {
48     struct rxkb_object *parent;
49     uint32_t refcount;
50     struct list link;
51     destroy_func_t destroy;
52 };
53 
54 struct rxkb_iso639_code {
55     struct rxkb_object base;
56     char *code;
57 };
58 
59 struct rxkb_iso3166_code {
60     struct rxkb_object base;
61     char *code;
62 };
63 
64 enum context_state {
65     CONTEXT_NEW,
66     CONTEXT_PARSED,
67     CONTEXT_FAILED,
68 };
69 
70 struct rxkb_context {
71     struct rxkb_object base;
72     enum context_state context_state;
73 
74     bool load_extra_rules_files;
75 
76     struct list models;         /* list of struct rxkb_models */
77     struct list layouts;        /* list of struct rxkb_layouts */
78     struct list option_groups;  /* list of struct rxkb_option_group */
79 
80     darray(char *) includes;
81 
82 
83     ATTR_PRINTF(3, 0) void (*log_fn)(struct rxkb_context *ctx,
84                                      enum rxkb_log_level level,
85                                      const char *fmt, va_list args);
86     enum rxkb_log_level log_level;
87 
88     void *userdata;
89 };
90 
91 struct rxkb_model {
92     struct rxkb_object base;
93 
94     char *name;
95     char *vendor;
96     char *description;
97     enum rxkb_popularity popularity;
98 };
99 
100 struct rxkb_layout {
101     struct rxkb_object base;
102 
103     char *name;
104     char *brief;
105     char *description;
106     char *variant;
107     enum rxkb_popularity popularity;
108 
109     struct list iso639s;  /* list of struct rxkb_iso639_code */
110     struct list iso3166s; /* list of struct rxkb_iso3166_code */
111 };
112 
113 struct rxkb_option_group {
114     struct rxkb_object base;
115 
116     bool allow_multiple;
117     struct list options; /* list of struct rxkb_options */
118     char *name;
119     char *description;
120     enum rxkb_popularity popularity;
121 };
122 
123 struct rxkb_option {
124     struct rxkb_object base;
125 
126     char *name;
127     char *brief;
128     char *description;
129     enum rxkb_popularity popularity;
130 };
131 
132 static bool
133 parse(struct rxkb_context *ctx, const char *path,
134       enum rxkb_popularity popularity);
135 
136 ATTR_PRINTF(3, 4)
137 static void
rxkb_log(struct rxkb_context * ctx,enum rxkb_log_level level,const char * fmt,...)138 rxkb_log(struct rxkb_context *ctx, enum rxkb_log_level level,
139          const char *fmt, ...)
140 {
141     va_list args;
142 
143     if (ctx->log_level < level)
144         return;
145 
146     va_start(args, fmt);
147     ctx->log_fn(ctx, level, fmt, args);
148     va_end(args);
149 }
150 
151 /*
152  * The format is not part of the argument list in order to avoid the
153  * "ISO C99 requires rest arguments to be used" warning when only the
154  * format is supplied without arguments. Not supplying it would still
155  * result in an error, though.
156  */
157 #define log_dbg(ctx, ...) \
158     rxkb_log((ctx), RXKB_LOG_LEVEL_DEBUG, __VA_ARGS__)
159 #define log_info(ctx, ...) \
160     rxkb_log((ctx), RXKB_LOG_LEVEL_INFO, __VA_ARGS__)
161 #define log_warn(ctx, ...) \
162     rxkb_log((ctx), RXKB_LOG_LEVEL_WARNING,  __VA_ARGS__)
163 #define log_err(ctx, ...) \
164     rxkb_log((ctx), RXKB_LOG_LEVEL_ERROR,  __VA_ARGS__)
165 #define log_wsgo(ctx, ...) \
166     rxkb_log((ctx), RXKB_LOG_LEVEL_CRITICAL, __VA_ARGS__)
167 
168 
169 #define DECLARE_REF_UNREF_FOR_TYPE(type_) \
170 XKB_EXPORT struct type_ * type_##_ref(struct type_ *object) { \
171     rxkb_object_ref(&object->base); \
172     return object; \
173 } \
174 XKB_EXPORT struct type_ * type_##_unref(struct type_ *object) { \
175     if (!object) return NULL; \
176     return rxkb_object_unref(&object->base); \
177 }
178 
179 #define DECLARE_CREATE_FOR_TYPE(type_) \
180 static inline struct type_ * type_##_create(struct rxkb_object *parent) { \
181     struct type_ *t = calloc(1, sizeof *t); \
182     if (t) \
183         rxkb_object_init(&t->base, parent, (destroy_func_t)type_##_destroy); \
184     return t; \
185 }
186 
187 #define DECLARE_TYPED_GETTER_FOR_TYPE(type_, field_, rtype_) \
188 XKB_EXPORT rtype_ type_##_get_##field_(struct type_ *object) { \
189     return object->field_; \
190 }
191 
192 #define DECLARE_GETTER_FOR_TYPE(type_, field_) \
193    DECLARE_TYPED_GETTER_FOR_TYPE(type_, field_, const char*)
194 
195 #define DECLARE_FIRST_NEXT_FOR_TYPE(type_, parent_type_, parent_field_) \
196 XKB_EXPORT struct type_ * type_##_first(struct parent_type_ *parent) { \
197     struct type_ *o = NULL; \
198     if (!list_empty(&parent->parent_field_)) \
199         o = list_first_entry(&parent->parent_field_, o, base.link); \
200     return o; \
201 } \
202 XKB_EXPORT struct type_ * \
203 type_##_next(struct type_ *o) \
204 { \
205     struct parent_type_ *parent; \
206     struct type_ *next; \
207     parent = container_of(o->base.parent, struct parent_type_, base); \
208     next = list_first_entry(&o->base.link, o, base.link); \
209     if (list_is_last(&parent->parent_field_, &o->base.link)) \
210         return NULL; \
211     return next; \
212 }
213 
214 static void
rxkb_object_init(struct rxkb_object * object,struct rxkb_object * parent,destroy_func_t destroy)215 rxkb_object_init(struct rxkb_object *object, struct rxkb_object *parent, destroy_func_t destroy)
216 {
217     object->refcount = 1;
218     object->destroy = destroy;
219     object->parent = parent;
220     list_init(&object->link);
221 }
222 
223 static void
rxkb_object_destroy(struct rxkb_object * object)224 rxkb_object_destroy(struct rxkb_object *object)
225 {
226     if (object->destroy)
227         object->destroy(object);
228     list_remove(&object->link);
229     free(object);
230 }
231 
232 static void *
rxkb_object_ref(struct rxkb_object * object)233 rxkb_object_ref(struct rxkb_object *object)
234 {
235     assert(object->refcount >= 1);
236     ++object->refcount;
237     return object;
238 }
239 
240 static void *
rxkb_object_unref(struct rxkb_object * object)241 rxkb_object_unref(struct rxkb_object *object)
242 {
243     assert(object->refcount >= 1);
244     if (--object->refcount == 0)
245         rxkb_object_destroy(object);
246     return NULL;
247 }
248 
249 static void
rxkb_iso639_code_destroy(struct rxkb_iso639_code * code)250 rxkb_iso639_code_destroy(struct rxkb_iso639_code *code)
251 {
252     free(code->code);
253 }
254 
255 XKB_EXPORT struct rxkb_iso639_code *
rxkb_layout_get_iso639_first(struct rxkb_layout * layout)256 rxkb_layout_get_iso639_first(struct rxkb_layout *layout)
257 {
258     struct rxkb_iso639_code *code = NULL;
259 
260     if (!list_empty(&layout->iso639s))
261         code = list_first_entry(&layout->iso639s, code, base.link);
262 
263     return code;
264 }
265 
266 XKB_EXPORT struct rxkb_iso639_code *
rxkb_iso639_code_next(struct rxkb_iso639_code * code)267 rxkb_iso639_code_next(struct rxkb_iso639_code *code)
268 {
269     struct rxkb_iso639_code *next = NULL;
270     struct rxkb_layout *layout;
271 
272     layout = container_of(code->base.parent, struct rxkb_layout, base);
273 
274     if (list_is_last(&layout->iso639s, &code->base.link))
275         return NULL;
276 
277     next = list_first_entry(&code->base.link, code, base.link);
278 
279     return next;
280 }
281 
282 DECLARE_REF_UNREF_FOR_TYPE(rxkb_iso639_code);
283 DECLARE_CREATE_FOR_TYPE(rxkb_iso639_code);
284 DECLARE_GETTER_FOR_TYPE(rxkb_iso639_code, code);
285 
286 static void
rxkb_iso3166_code_destroy(struct rxkb_iso3166_code * code)287 rxkb_iso3166_code_destroy(struct rxkb_iso3166_code *code)
288 {
289     free(code->code);
290 }
291 
292 XKB_EXPORT struct rxkb_iso3166_code *
rxkb_layout_get_iso3166_first(struct rxkb_layout * layout)293 rxkb_layout_get_iso3166_first(struct rxkb_layout *layout)
294 {
295     struct rxkb_iso3166_code *code = NULL;
296 
297     if (!list_empty(&layout->iso3166s))
298         code = list_first_entry(&layout->iso3166s, code, base.link);
299 
300     return code;
301 }
302 
303 XKB_EXPORT struct rxkb_iso3166_code *
rxkb_iso3166_code_next(struct rxkb_iso3166_code * code)304 rxkb_iso3166_code_next(struct rxkb_iso3166_code *code)
305 {
306     struct rxkb_iso3166_code *next = NULL;
307     struct rxkb_layout *layout;
308 
309     layout = container_of(code->base.parent, struct rxkb_layout, base);
310 
311     if (list_is_last(&layout->iso3166s, &code->base.link))
312         return NULL;
313 
314     next = list_first_entry(&code->base.link, code, base.link);
315 
316     return next;
317 }
318 
319 DECLARE_REF_UNREF_FOR_TYPE(rxkb_iso3166_code);
320 DECLARE_CREATE_FOR_TYPE(rxkb_iso3166_code);
321 DECLARE_GETTER_FOR_TYPE(rxkb_iso3166_code, code);
322 
323 static void
rxkb_option_destroy(struct rxkb_option * o)324 rxkb_option_destroy(struct rxkb_option *o)
325 {
326     free(o->name);
327     free(o->brief);
328     free(o->description);
329 }
330 
331 DECLARE_REF_UNREF_FOR_TYPE(rxkb_option);
332 DECLARE_CREATE_FOR_TYPE(rxkb_option);
333 DECLARE_GETTER_FOR_TYPE(rxkb_option, name);
334 DECLARE_GETTER_FOR_TYPE(rxkb_option, brief);
335 DECLARE_GETTER_FOR_TYPE(rxkb_option, description);
336 DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_option, popularity, enum rxkb_popularity);
337 DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_option, rxkb_option_group, options);
338 
339 static void
rxkb_layout_destroy(struct rxkb_layout * l)340 rxkb_layout_destroy(struct rxkb_layout *l)
341 {
342     struct rxkb_iso639_code *iso639, *tmp_639;
343     struct rxkb_iso3166_code *iso3166, *tmp_3166;
344 
345     free(l->name);
346     free(l->brief);
347     free(l->description);
348     free(l->variant);
349 
350     list_for_each_safe(iso639, tmp_639, &l->iso639s, base.link) {
351         rxkb_iso639_code_unref(iso639);
352     }
353     list_for_each_safe(iso3166, tmp_3166, &l->iso3166s, base.link) {
354         rxkb_iso3166_code_unref(iso3166);
355     }
356 }
357 
358 DECLARE_REF_UNREF_FOR_TYPE(rxkb_layout);
359 DECLARE_CREATE_FOR_TYPE(rxkb_layout);
360 DECLARE_GETTER_FOR_TYPE(rxkb_layout, name);
361 DECLARE_GETTER_FOR_TYPE(rxkb_layout, brief);
362 DECLARE_GETTER_FOR_TYPE(rxkb_layout, description);
363 DECLARE_GETTER_FOR_TYPE(rxkb_layout, variant);
364 DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_layout, popularity, enum rxkb_popularity);
365 DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_layout, rxkb_context, layouts);
366 
367 static void
rxkb_model_destroy(struct rxkb_model * m)368 rxkb_model_destroy(struct rxkb_model *m)
369 {
370     free(m->name);
371     free(m->vendor);
372     free(m->description);
373 }
374 
375 DECLARE_REF_UNREF_FOR_TYPE(rxkb_model);
376 DECLARE_CREATE_FOR_TYPE(rxkb_model);
377 DECLARE_GETTER_FOR_TYPE(rxkb_model, name);
378 DECLARE_GETTER_FOR_TYPE(rxkb_model, vendor);
379 DECLARE_GETTER_FOR_TYPE(rxkb_model, description);
380 DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_model, popularity, enum rxkb_popularity);
381 DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_model, rxkb_context, models);
382 
383 static void
rxkb_option_group_destroy(struct rxkb_option_group * og)384 rxkb_option_group_destroy(struct rxkb_option_group *og)
385 {
386     struct rxkb_option *o, *otmp;
387 
388     free(og->name);
389     free(og->description);
390 
391     list_for_each_safe(o, otmp, &og->options, base.link) {
392         rxkb_option_unref(o);
393     }
394 }
395 
396 XKB_EXPORT bool
rxkb_option_group_allows_multiple(struct rxkb_option_group * g)397 rxkb_option_group_allows_multiple(struct rxkb_option_group *g)
398 {
399     return g->allow_multiple;
400 }
401 
402 DECLARE_REF_UNREF_FOR_TYPE(rxkb_option_group);
403 DECLARE_CREATE_FOR_TYPE(rxkb_option_group);
404 DECLARE_GETTER_FOR_TYPE(rxkb_option_group, name);
405 DECLARE_GETTER_FOR_TYPE(rxkb_option_group, description);
406 DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_option_group, popularity, enum rxkb_popularity);
407 DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_option_group, rxkb_context, option_groups);
408 
409 static void
rxkb_context_destroy(struct rxkb_context * ctx)410 rxkb_context_destroy(struct rxkb_context *ctx)
411 {
412     struct rxkb_model *m, *mtmp;
413     struct rxkb_layout *l, *ltmp;
414     struct rxkb_option_group *og, *ogtmp;
415     char **path;
416 
417     list_for_each_safe(m, mtmp, &ctx->models, base.link)
418         rxkb_model_unref(m);
419     assert(list_empty(&ctx->models));
420 
421     list_for_each_safe(l, ltmp, &ctx->layouts, base.link)
422         rxkb_layout_unref(l);
423     assert(list_empty(&ctx->layouts));
424 
425     list_for_each_safe(og, ogtmp, &ctx->option_groups, base.link)
426         rxkb_option_group_unref(og);
427     assert(list_empty(&ctx->option_groups));
428 
429     darray_foreach(path, ctx->includes)
430         free(*path);
431     darray_free(ctx->includes);
432 
433     assert(darray_empty(ctx->includes));
434 }
435 
436 DECLARE_REF_UNREF_FOR_TYPE(rxkb_context);
437 DECLARE_CREATE_FOR_TYPE(rxkb_context);
438 DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_context, log_level, enum rxkb_log_level);
439 
440 XKB_EXPORT void
rxkb_context_set_log_level(struct rxkb_context * ctx,enum rxkb_log_level level)441 rxkb_context_set_log_level(struct rxkb_context *ctx,
442                            enum rxkb_log_level level)
443 {
444     ctx->log_level = level;
445 }
446 
447 static const char *
log_level_to_prefix(enum rxkb_log_level level)448 log_level_to_prefix(enum rxkb_log_level level)
449 {
450     switch (level) {
451     case RXKB_LOG_LEVEL_DEBUG:
452         return "xkbregistry: DEBUG: ";
453     case RXKB_LOG_LEVEL_INFO:
454         return "xkbregistry: INFO: ";
455     case RXKB_LOG_LEVEL_WARNING:
456         return "xkbregistry: WARNING: ";
457     case RXKB_LOG_LEVEL_ERROR:
458         return "xkbregistry: ERROR: ";
459     case RXKB_LOG_LEVEL_CRITICAL:
460         return "xkbregistry: CRITICAL: ";
461     default:
462         return NULL;
463     }
464 }
465 
466 ATTR_PRINTF(3, 0) static void
default_log_fn(struct rxkb_context * ctx,enum rxkb_log_level level,const char * fmt,va_list args)467 default_log_fn(struct rxkb_context *ctx, enum rxkb_log_level level,
468                const char *fmt, va_list args)
469 {
470     const char *prefix = log_level_to_prefix(level);
471 
472     if (prefix)
473         fprintf(stderr, "%s", prefix);
474     vfprintf(stderr, fmt, args);
475 }
476 
477 static enum rxkb_log_level
log_level(const char * level)478 log_level(const char *level) {
479     char *endptr;
480     enum rxkb_log_level lvl;
481 
482     errno = 0;
483     lvl = strtol(level, &endptr, 10);
484     if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0])))
485         return lvl;
486     if (istreq_prefix("crit", level))
487         return RXKB_LOG_LEVEL_CRITICAL;
488     if (istreq_prefix("err", level))
489         return RXKB_LOG_LEVEL_ERROR;
490     if (istreq_prefix("warn", level))
491         return RXKB_LOG_LEVEL_WARNING;
492     if (istreq_prefix("info", level))
493         return RXKB_LOG_LEVEL_INFO;
494     if (istreq_prefix("debug", level) || istreq_prefix("dbg", level))
495         return RXKB_LOG_LEVEL_DEBUG;
496 
497     return RXKB_LOG_LEVEL_ERROR;
498 }
499 
500 XKB_EXPORT struct rxkb_context *
rxkb_context_new(enum rxkb_context_flags flags)501 rxkb_context_new(enum rxkb_context_flags flags)
502 {
503     struct rxkb_context *ctx = rxkb_context_create(NULL);
504     const char *env;
505 
506     if (!ctx)
507         return NULL;
508 
509     ctx->context_state = CONTEXT_NEW;
510     ctx->load_extra_rules_files = flags & RXKB_CONTEXT_LOAD_EXOTIC_RULES;
511     ctx->log_fn = default_log_fn;
512     ctx->log_level = RXKB_LOG_LEVEL_ERROR;
513 
514     /* Environment overwrites defaults. */
515     env = secure_getenv("RXKB_LOG_LEVEL");
516     if (env)
517         rxkb_context_set_log_level(ctx, log_level(env));
518 
519     list_init(&ctx->models);
520     list_init(&ctx->layouts);
521     list_init(&ctx->option_groups);
522 
523     if (!(flags & RXKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
524         !rxkb_context_include_path_append_default(ctx)) {
525         rxkb_context_unref(ctx);
526         return NULL;
527     }
528 
529     return ctx;
530 }
531 
532 XKB_EXPORT void
rxkb_context_set_log_fn(struct rxkb_context * ctx,void (* log_fn)(struct rxkb_context * ctx,enum rxkb_log_level level,const char * fmt,va_list args))533 rxkb_context_set_log_fn(struct rxkb_context *ctx,
534                         void (*log_fn)(struct rxkb_context *ctx,
535                                        enum rxkb_log_level level,
536                                        const char *fmt, va_list args))
537 {
538     ctx->log_fn = (log_fn ? log_fn : default_log_fn);
539 }
540 
541 XKB_EXPORT bool
rxkb_context_include_path_append(struct rxkb_context * ctx,const char * path)542 rxkb_context_include_path_append(struct rxkb_context *ctx, const char *path)
543 {
544     struct stat stat_buf;
545     int err;
546     char *tmp = NULL;
547     char rules[PATH_MAX];
548 
549     if (ctx->context_state != CONTEXT_NEW) {
550         log_err(ctx, "include paths can only be appended to a new context\n");
551         return false;
552     }
553 
554     tmp = strdup(path);
555     if (!tmp)
556         goto err;
557 
558     err = stat(path, &stat_buf);
559     if (err != 0)
560         goto err;
561     if (!S_ISDIR(stat_buf.st_mode))
562         goto err;
563 
564     if (!check_eaccess(path, R_OK | X_OK))
565         goto err;
566 
567     /* Pre-filter for the 99.9% case - if we can't assemble the default ruleset
568      * path, complain here instead of during parsing later. The niche cases
569      * where this is the wrong behaviour aren't worth worrying about.
570      */
571     if (!snprintf_safe(rules, sizeof(rules), "%s/rules/%s.xml",
572                        path, DEFAULT_XKB_RULES))
573         goto err;
574 
575     darray_append(ctx->includes, tmp);
576 
577     return true;
578 
579 err:
580     free(tmp);
581     return false;
582 }
583 
584 XKB_EXPORT bool
rxkb_context_include_path_append_default(struct rxkb_context * ctx)585 rxkb_context_include_path_append_default(struct rxkb_context *ctx)
586 {
587     const char *home, *xdg, *root, *extra;
588     char *user_path;
589     bool ret = false;
590 
591     if (ctx->context_state != CONTEXT_NEW) {
592         log_err(ctx, "include paths can only be appended to a new context\n");
593         return false;
594     }
595 
596     home = secure_getenv("HOME");
597 
598     xdg = secure_getenv("XDG_CONFIG_HOME");
599     if (xdg != NULL) {
600         user_path = asprintf_safe("%s/xkb", xdg);
601         if (user_path) {
602             ret |= rxkb_context_include_path_append(ctx, user_path);
603             free(user_path);
604         }
605     } else if (home != NULL) {
606         /* XDG_CONFIG_HOME fallback is $HOME/.config/ */
607         user_path = asprintf_safe("%s/.config/xkb", home);
608         if (user_path) {
609             ret |= rxkb_context_include_path_append(ctx, user_path);
610             free(user_path);
611         }
612     }
613 
614     if (home != NULL) {
615         user_path = asprintf_safe("%s/.xkb", home);
616         if (user_path) {
617             ret |= rxkb_context_include_path_append(ctx, user_path);
618             free(user_path);
619         }
620     }
621 
622     extra = secure_getenv("XKB_CONFIG_EXTRA_PATH");
623     if (extra != NULL)
624         ret |= rxkb_context_include_path_append(ctx, extra);
625     else
626         ret |= rxkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_EXTRA_PATH);
627 
628     root = secure_getenv("XKB_CONFIG_ROOT");
629     if (root != NULL)
630         ret |= rxkb_context_include_path_append(ctx, root);
631     else
632         ret |= rxkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
633 
634     return ret;
635 }
636 
637 XKB_EXPORT bool
rxkb_context_parse_default_ruleset(struct rxkb_context * ctx)638 rxkb_context_parse_default_ruleset(struct rxkb_context *ctx)
639 {
640     return rxkb_context_parse(ctx, DEFAULT_XKB_RULES);
641 }
642 
643 XKB_EXPORT bool
rxkb_context_parse(struct rxkb_context * ctx,const char * ruleset)644 rxkb_context_parse(struct rxkb_context *ctx, const char *ruleset)
645 {
646     char **path;
647     bool success = false;
648 
649     if (ctx->context_state != CONTEXT_NEW) {
650         log_err(ctx, "parse must only be called on a new context\n");
651         return false;
652     }
653 
654     darray_foreach_reverse(path, ctx->includes) {
655         char rules[PATH_MAX];
656 
657         if (snprintf_safe(rules, sizeof(rules), "%s/rules/%s.xml",
658                            *path, ruleset)) {
659             log_dbg(ctx, "Parsing %s\n", rules);
660             if (parse(ctx, rules, RXKB_POPULARITY_STANDARD))
661                 success = true;
662         }
663 
664         if (ctx->load_extra_rules_files &&
665             snprintf_safe(rules, sizeof(rules), "%s/rules/%s.extras.xml",
666                           *path, ruleset)) {
667             log_dbg(ctx, "Parsing %s\n", rules);
668             if (parse(ctx, rules, RXKB_POPULARITY_EXOTIC))
669                 success = true;
670         }
671     }
672 
673     ctx->context_state = success ? CONTEXT_PARSED : CONTEXT_FAILED;
674 
675     return success;
676 }
677 
678 
679 XKB_EXPORT void
rxkb_context_set_user_data(struct rxkb_context * ctx,void * userdata)680 rxkb_context_set_user_data(struct rxkb_context *ctx, void *userdata)
681 {
682     ctx->userdata = userdata;
683 }
684 
685 XKB_EXPORT void *
rxkb_context_get_user_data(struct rxkb_context * ctx)686 rxkb_context_get_user_data(struct rxkb_context *ctx)
687 {
688     return ctx->userdata;
689 }
690 
691 static inline bool
is_node(xmlNode * node,const char * name)692 is_node(xmlNode *node, const char *name)
693 {
694     return node->type == XML_ELEMENT_NODE &&
695         xmlStrEqual(node->name, (const xmlChar*)name);
696 }
697 
698 /* return a copy of the text content from the first text node of this node */
699 static char *
extract_text(xmlNode * node)700 extract_text(xmlNode *node)
701 {
702     xmlNode *n;
703 
704     for (n = node->children; n; n = n->next) {
705         if (n->type == XML_TEXT_NODE)
706             return (char *)xmlStrdup(n->content);
707     }
708     return NULL;
709 }
710 
711 static bool
parse_config_item(struct rxkb_context * ctx,xmlNode * parent,char ** name,char ** description,char ** brief,char ** vendor)712 parse_config_item(struct rxkb_context *ctx,
713                   xmlNode *parent,
714                   char **name,
715                   char **description,
716                   char **brief,
717                   char **vendor)
718 {
719     xmlNode *node = NULL;
720     xmlNode *ci = NULL;
721 
722     for (ci = parent->children; ci; ci = ci->next) {
723         if (is_node(ci, "configItem")) {
724             *name = NULL;
725             *description = NULL;
726             *brief = NULL;
727             *vendor = NULL;
728 
729             for (node = ci->children; node; node = node->next) {
730                 if (is_node(node, "name"))
731                     *name = extract_text(node);
732                 else if (is_node(node, "description"))
733                     *description = extract_text(node);
734                 else if (is_node(node, "shortDescription"))
735                     *brief = extract_text(node);
736                 else if (is_node(node, "vendor"))
737                     *vendor = extract_text(node);
738                 /* Note: the DTD allows for vendor + brief but models only use
739                  * vendor and everything else only uses shortDescription */
740             }
741 
742             if (!*name || !strlen(*name))  {
743                 log_err(ctx, "xml:%d: missing required element 'name'\n",
744                         ci->line);
745                 return false;
746             }
747 
748             return true; /* only one configItem allowed in the dtd */
749         }
750     }
751 
752     return false;
753 }
754 
755 static void
parse_model(struct rxkb_context * ctx,xmlNode * model,enum rxkb_popularity popularity)756 parse_model(struct rxkb_context *ctx, xmlNode *model,
757             enum rxkb_popularity popularity)
758 {
759     char *name, *description, *brief, *vendor;
760 
761     if (parse_config_item(ctx, model, &name, &description, &brief, &vendor)) {
762         struct rxkb_model *m;
763 
764         list_for_each(m, &ctx->models, base.link) {
765             if (streq(m->name, name)) {
766                 free(name);
767                 free(description);
768                 free(brief);
769                 free(vendor);
770                 return;
771             }
772         }
773 
774         /* new model */
775         m = rxkb_model_create(&ctx->base);
776         m->name = name;
777         m->description = description;
778         m->vendor = vendor;
779         m->popularity = popularity;
780         list_append(&ctx->models, &m->base.link);
781     }
782 }
783 
784 static void
parse_model_list(struct rxkb_context * ctx,xmlNode * model_list,enum rxkb_popularity popularity)785 parse_model_list(struct rxkb_context *ctx, xmlNode *model_list,
786                 enum rxkb_popularity popularity)
787 {
788     xmlNode *node = NULL;
789 
790     for (node = model_list->children; node; node = node->next) {
791         if (is_node(node, "model"))
792             parse_model(ctx, node, popularity);
793     }
794 }
795 
796 static void
parse_language_list(xmlNode * language_list,struct rxkb_layout * layout)797 parse_language_list(xmlNode *language_list, struct rxkb_layout *layout)
798 {
799     xmlNode *node = NULL;
800     struct rxkb_iso639_code *code;
801 
802     for (node = language_list->children; node; node = node->next) {
803         if (is_node(node, "iso639Id")) {
804             char *str = extract_text(node);
805             struct rxkb_object *parent;
806 
807             parent = &layout->base;
808             code = rxkb_iso639_code_create(parent);
809             code->code = str;
810             list_append(&layout->iso639s, &code->base.link);
811         }
812     }
813 }
814 
815 static void
parse_country_list(xmlNode * country_list,struct rxkb_layout * layout)816 parse_country_list(xmlNode *country_list, struct rxkb_layout *layout)
817 {
818     xmlNode *node = NULL;
819     struct rxkb_iso3166_code *code;
820 
821     for (node = country_list->children; node; node = node->next) {
822         if (is_node(node, "iso3166Id")) {
823             char *str = extract_text(node);
824             struct rxkb_object *parent;
825 
826             parent = &layout->base;
827             code = rxkb_iso3166_code_create(parent);
828             code->code = str;
829             list_append(&layout->iso3166s, &code->base.link);
830         }
831     }
832 }
833 
834 static void
parse_variant(struct rxkb_context * ctx,struct rxkb_layout * l,xmlNode * variant,enum rxkb_popularity popularity)835 parse_variant(struct rxkb_context *ctx, struct rxkb_layout *l,
836               xmlNode *variant, enum rxkb_popularity popularity)
837 {
838     xmlNode *ci;
839     char *name, *description, *brief, *vendor;
840 
841     if (parse_config_item(ctx, variant, &name, &description, &brief, &vendor)) {
842         struct rxkb_layout *v;
843         bool exists = false;
844 
845         list_for_each(v, &ctx->layouts, base.link) {
846             if (streq(v->name, name) && streq(v->name, l->name)) {
847                 exists = true;
848                 break;
849             }
850         }
851 
852         if (!exists) {
853             v = rxkb_layout_create(&ctx->base);
854             list_init(&v->iso639s);
855             list_init(&v->iso3166s);
856             v->name = strdup(l->name);
857             v->variant = name;
858             v->description = description;
859             v->brief = brief;
860             v->popularity = popularity;
861             list_append(&ctx->layouts, &v->base.link);
862 
863             for (ci = variant->children; ci; ci = ci->next) {
864                 xmlNode *node;
865 
866                 if (!is_node(ci, "configItem"))
867                     continue;
868 
869                 for (node = ci->children; node; node = node->next) {
870                     if (is_node(node, "languageList"))
871                         parse_language_list(node, v);
872                     if (is_node(node, "countryList"))
873                         parse_country_list(node, v);
874                 }
875             }
876         } else {
877             free(name);
878             free(description);
879             free(brief);
880             free(vendor);
881         }
882     }
883 }
884 
885 static void
parse_variant_list(struct rxkb_context * ctx,struct rxkb_layout * l,xmlNode * variant_list,enum rxkb_popularity popularity)886 parse_variant_list(struct rxkb_context *ctx, struct rxkb_layout *l,
887                    xmlNode *variant_list, enum rxkb_popularity popularity)
888 {
889     xmlNode *node = NULL;
890 
891     for (node = variant_list->children; node; node = node->next) {
892         if (is_node(node, "variant"))
893             parse_variant(ctx, l, node, popularity);
894     }
895 }
896 
897 static void
parse_layout(struct rxkb_context * ctx,xmlNode * layout,enum rxkb_popularity popularity)898 parse_layout(struct rxkb_context *ctx, xmlNode *layout,
899              enum rxkb_popularity popularity)
900 {
901     char *name, *description, *brief, *vendor;
902     struct rxkb_layout *l;
903     xmlNode *node = NULL;
904     bool exists = false;
905 
906     if (!parse_config_item(ctx, layout, &name, &description, &brief, &vendor))
907         return;
908 
909     list_for_each(l, &ctx->layouts, base.link) {
910         if (streq(l->name, name) && l->variant == NULL) {
911             exists = true;
912             break;
913         }
914     }
915 
916     if (!exists) {
917         l = rxkb_layout_create(&ctx->base);
918         list_init(&l->iso639s);
919         list_init(&l->iso3166s);
920         l->name = name;
921         l->variant = NULL;
922         l->description = description;
923         l->brief = brief;
924         l->popularity = popularity;
925         list_append(&ctx->layouts, &l->base.link);
926     } else {
927         free(name);
928         free(description);
929         free(brief);
930         free(vendor);
931     }
932 
933     for (node = layout->children; node; node = node->next) {
934         if (is_node(node, "variantList")) {
935             parse_variant_list(ctx, l, node, popularity);
936         }
937         if (!exists && is_node(node, "configItem")) {
938             xmlNode *ll;
939             for (ll = node->children; ll; ll = ll->next) {
940                 if (is_node(ll, "languageList"))
941                     parse_language_list(ll, l);
942                 if (is_node(ll, "countryList"))
943                     parse_country_list(ll, l);
944             }
945         }
946     }
947 }
948 
949 static void
parse_layout_list(struct rxkb_context * ctx,xmlNode * layout_list,enum rxkb_popularity popularity)950 parse_layout_list(struct rxkb_context *ctx, xmlNode *layout_list,
951                   enum rxkb_popularity popularity)
952 {
953     xmlNode *node = NULL;
954 
955     for (node = layout_list->children; node; node = node->next) {
956         if (is_node(node, "layout"))
957             parse_layout(ctx, node, popularity);
958     }
959 }
960 
961 static void
parse_option(struct rxkb_context * ctx,struct rxkb_option_group * group,xmlNode * option,enum rxkb_popularity popularity)962 parse_option(struct rxkb_context *ctx, struct rxkb_option_group *group,
963              xmlNode *option, enum rxkb_popularity popularity)
964 {
965     char *name, *description, *brief, *vendor;
966 
967     if (parse_config_item(ctx, option, &name, &description, &brief, &vendor)) {
968         struct rxkb_option *o;
969 
970         list_for_each(o, &group->options, base.link) {
971             if (streq(o->name, name)) {
972                 free(name);
973                 free(description);
974                 free(brief);
975                 free(vendor);
976                 return;
977             }
978         }
979 
980         o = rxkb_option_create(&group->base);
981         o->name = name;
982         o->description = description;
983         o->popularity = popularity;
984         list_append(&group->options, &o->base.link);
985     }
986 }
987 
988 static void
parse_group(struct rxkb_context * ctx,xmlNode * group,enum rxkb_popularity popularity)989 parse_group(struct rxkb_context *ctx, xmlNode *group,
990             enum rxkb_popularity popularity)
991 {
992     char *name, *description, *brief, *vendor;
993     struct rxkb_option_group *g;
994     xmlNode *node = NULL;
995     xmlChar *multiple;
996     bool exists = false;
997 
998     if (!parse_config_item(ctx, group, &name, &description, &brief, &vendor))
999         return;
1000 
1001     list_for_each(g, &ctx->option_groups, base.link) {
1002         if (streq(g->name, name)) {
1003             exists = true;
1004             break;
1005         }
1006     }
1007 
1008     if (!exists) {
1009         g = rxkb_option_group_create(&ctx->base);
1010         g->name = name;
1011         g->description = description;
1012         g->popularity = popularity;
1013 
1014         multiple = xmlGetProp(group, (const xmlChar*)"allowMultipleSelection");
1015         if (multiple && xmlStrEqual(multiple, (const xmlChar*)"true"))
1016             g->allow_multiple = true;
1017         xmlFree(multiple);
1018 
1019         list_init(&g->options);
1020         list_append(&ctx->option_groups, &g->base.link);
1021     } else {
1022         free(name);
1023         free(description);
1024         free(brief);
1025         free(vendor);
1026     }
1027 
1028     for (node = group->children; node; node = node->next) {
1029         if (is_node(node, "option"))
1030             parse_option(ctx, g, node, popularity);
1031     }
1032 }
1033 
1034 static void
parse_option_list(struct rxkb_context * ctx,xmlNode * option_list,enum rxkb_popularity popularity)1035 parse_option_list(struct rxkb_context *ctx, xmlNode *option_list,
1036                   enum rxkb_popularity popularity)
1037 {
1038     xmlNode *node = NULL;
1039 
1040     for (node = option_list->children; node; node = node->next) {
1041         if (is_node(node, "group"))
1042             parse_group(ctx, node, popularity);
1043     }
1044 }
1045 
1046 static void
parse_rules_xml(struct rxkb_context * ctx,xmlNode * root,enum rxkb_popularity popularity)1047 parse_rules_xml(struct rxkb_context *ctx, xmlNode *root,
1048                 enum rxkb_popularity popularity)
1049 {
1050     xmlNode *node = NULL;
1051 
1052     for (node = root->children; node; node = node->next) {
1053         if (is_node(node, "modelList"))
1054             parse_model_list(ctx, node, popularity);
1055         else if (is_node(node, "layoutList"))
1056             parse_layout_list(ctx, node, popularity);
1057         else if (is_node(node, "optionList"))
1058             parse_option_list(ctx, node, popularity);
1059     }
1060 }
1061 
1062 static void
1063 ATTR_PRINTF(2, 0)
xml_error_func(void * ctx,const char * msg,...)1064 xml_error_func(void *ctx, const char *msg, ...)
1065 {
1066     static char buf[PATH_MAX];
1067     static int slen = 0;
1068     va_list args;
1069     int rc;
1070 
1071     /* libxml2 prints IO errors from bad includes paths by
1072      * calling the error function once per word. So we get to
1073      * re-assemble the message here and print it when we get
1074      * the line break. My enthusiasm about this is indescribable.
1075      */
1076     va_start(args, msg);
1077     rc = vsnprintf(&buf[slen], sizeof(buf) - slen, msg, args);
1078     va_end(args);
1079 
1080     /* This shouldn't really happen */
1081     if (rc < 0) {
1082         log_err(ctx, "+++ out of cheese error. redo from start +++\n");
1083         slen = 0;
1084         memset(buf, 0, sizeof(buf));
1085         return;
1086     }
1087 
1088     slen += rc;
1089     if (slen >= (int)sizeof(buf)) {
1090         /* truncated, let's flush this */
1091         buf[sizeof(buf) - 1] = '\n';
1092         slen = sizeof(buf);
1093     }
1094 
1095     /* We're assuming here that the last character is \n. */
1096     if (buf[slen - 1] == '\n') {
1097         log_err(ctx, "%s", buf);
1098         memset(buf, 0, sizeof(buf));
1099         slen = 0;
1100     }
1101 }
1102 
1103 static bool
validate(struct rxkb_context * ctx,xmlDoc * doc)1104 validate(struct rxkb_context *ctx, xmlDoc *doc)
1105 {
1106     bool success = false;
1107     xmlValidCtxt *dtdvalid = NULL;
1108     xmlDtd *dtd = NULL;
1109     xmlParserInputBufferPtr buf = NULL;
1110     /* This is a modified version of the xkeyboard-config xkb.dtd. That one
1111      * requires modelList, layoutList and optionList, we
1112      * allow for any of those to be missing.
1113      */
1114     const char dtdstr[] =
1115         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1116         "<!ELEMENT xkbConfigRegistry (modelList?, layoutList?, optionList?)>\n"
1117         "<!ATTLIST xkbConfigRegistry version CDATA \"1.1\">\n"
1118         "<!ELEMENT modelList (model*)>\n"
1119         "<!ELEMENT model (configItem)>\n"
1120         "<!ELEMENT layoutList (layout*)>\n"
1121         "<!ELEMENT layout (configItem,  variantList?)>\n"
1122         "<!ELEMENT optionList (group*)>\n"
1123         "<!ELEMENT variantList (variant*)>\n"
1124         "<!ELEMENT variant (configItem)>\n"
1125         "<!ELEMENT group (configItem, option*)>\n"
1126         "<!ATTLIST group allowMultipleSelection (true|false) \"false\">\n"
1127         "<!ELEMENT option (configItem)>\n"
1128         "<!ELEMENT configItem (name, shortDescription?, description?, vendor?, countryList?, languageList?, hwList?)>\n"
1129         "<!ATTLIST configItem popularity (standard|exotic) \"standard\">\n"
1130         "<!ELEMENT name (#PCDATA)>\n"
1131         "<!ELEMENT shortDescription (#PCDATA)>\n"
1132         "<!ELEMENT description (#PCDATA)>\n"
1133         "<!ELEMENT vendor (#PCDATA)>\n"
1134         "<!ELEMENT countryList (iso3166Id+)>\n"
1135         "<!ELEMENT iso3166Id (#PCDATA)>\n"
1136         "<!ELEMENT languageList (iso639Id+)>\n"
1137         "<!ELEMENT iso639Id (#PCDATA)>\n"
1138         "<!ELEMENT hwList (hwId+)>\n"
1139         "<!ELEMENT hwId (#PCDATA)>\n";
1140 
1141     /* Note: do not use xmlParserInputBufferCreateStatic, it generates random
1142      * DTD validity errors for unknown reasons */
1143     buf = xmlParserInputBufferCreateMem(dtdstr, sizeof(dtdstr),
1144                                         XML_CHAR_ENCODING_UTF8);
1145     if (!buf)
1146         return false;
1147 
1148     dtd = xmlIOParseDTD(NULL, buf, XML_CHAR_ENCODING_UTF8);
1149     if (!dtd) {
1150         log_err(ctx, "Failed to load DTD\n");
1151         return false;
1152     }
1153 
1154     dtdvalid = xmlNewValidCtxt();
1155     if (xmlValidateDtd(dtdvalid, doc, dtd))
1156         success = true;
1157 
1158     if (dtd)
1159         xmlFreeDtd(dtd);
1160     if (dtdvalid)
1161         xmlFreeValidCtxt(dtdvalid);
1162 
1163     return success;
1164 }
1165 
1166 static bool
parse(struct rxkb_context * ctx,const char * path,enum rxkb_popularity popularity)1167 parse(struct rxkb_context *ctx, const char *path,
1168       enum rxkb_popularity popularity)
1169 {
1170     bool success = false;
1171     xmlDoc *doc = NULL;
1172     xmlNode *root = NULL;
1173 
1174     if (!check_eaccess(path, R_OK))
1175         return false;
1176 
1177     LIBXML_TEST_VERSION
1178 
1179     xmlSetGenericErrorFunc(ctx, xml_error_func);
1180 
1181     doc = xmlParseFile(path);
1182     if (!doc)
1183         return false;
1184 
1185     if (!validate(ctx, doc)) {
1186         log_err(ctx, "XML error: failed to validate document at %s\n", path);
1187         goto error;
1188     }
1189 
1190     root = xmlDocGetRootElement(doc);
1191     parse_rules_xml(ctx, root, popularity);
1192 
1193     success = true;
1194 error:
1195     xmlFreeDoc(doc);
1196     xmlCleanupParser();
1197 
1198     return success;
1199 }
1200