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                 free(*name);
746                 free(*description);
747                 free(*brief);
748                 free(*vendor);
749                 return false;
750             }
751 
752             return true; /* only one configItem allowed in the dtd */
753         }
754     }
755 
756     return false;
757 }
758 
759 static void
parse_model(struct rxkb_context * ctx,xmlNode * model,enum rxkb_popularity popularity)760 parse_model(struct rxkb_context *ctx, xmlNode *model,
761             enum rxkb_popularity popularity)
762 {
763     char *name, *description, *brief, *vendor;
764 
765     if (parse_config_item(ctx, model, &name, &description, &brief, &vendor)) {
766         struct rxkb_model *m;
767 
768         list_for_each(m, &ctx->models, base.link) {
769             if (streq(m->name, name)) {
770                 free(name);
771                 free(description);
772                 free(brief);
773                 free(vendor);
774                 return;
775             }
776         }
777 
778         /* new model */
779         m = rxkb_model_create(&ctx->base);
780         m->name = name;
781         m->description = description;
782         m->vendor = vendor;
783         m->popularity = popularity;
784         list_append(&ctx->models, &m->base.link);
785     }
786 }
787 
788 static void
parse_model_list(struct rxkb_context * ctx,xmlNode * model_list,enum rxkb_popularity popularity)789 parse_model_list(struct rxkb_context *ctx, xmlNode *model_list,
790                 enum rxkb_popularity popularity)
791 {
792     xmlNode *node = NULL;
793 
794     for (node = model_list->children; node; node = node->next) {
795         if (is_node(node, "model"))
796             parse_model(ctx, node, popularity);
797     }
798 }
799 
800 static void
parse_language_list(xmlNode * language_list,struct rxkb_layout * layout)801 parse_language_list(xmlNode *language_list, struct rxkb_layout *layout)
802 {
803     xmlNode *node = NULL;
804     struct rxkb_iso639_code *code;
805 
806     for (node = language_list->children; node; node = node->next) {
807         if (is_node(node, "iso639Id")) {
808             char *str = extract_text(node);
809             struct rxkb_object *parent;
810 
811             parent = &layout->base;
812             code = rxkb_iso639_code_create(parent);
813             code->code = str;
814             list_append(&layout->iso639s, &code->base.link);
815         }
816     }
817 }
818 
819 static void
parse_country_list(xmlNode * country_list,struct rxkb_layout * layout)820 parse_country_list(xmlNode *country_list, struct rxkb_layout *layout)
821 {
822     xmlNode *node = NULL;
823     struct rxkb_iso3166_code *code;
824 
825     for (node = country_list->children; node; node = node->next) {
826         if (is_node(node, "iso3166Id")) {
827             char *str = extract_text(node);
828             struct rxkb_object *parent;
829 
830             parent = &layout->base;
831             code = rxkb_iso3166_code_create(parent);
832             code->code = str;
833             list_append(&layout->iso3166s, &code->base.link);
834         }
835     }
836 }
837 
838 static void
parse_variant(struct rxkb_context * ctx,struct rxkb_layout * l,xmlNode * variant,enum rxkb_popularity popularity)839 parse_variant(struct rxkb_context *ctx, struct rxkb_layout *l,
840               xmlNode *variant, enum rxkb_popularity popularity)
841 {
842     xmlNode *ci;
843     char *name, *description, *brief, *vendor;
844 
845     if (parse_config_item(ctx, variant, &name, &description, &brief, &vendor)) {
846         struct rxkb_layout *v;
847         bool exists = false;
848 
849         list_for_each(v, &ctx->layouts, base.link) {
850             if (streq(v->name, name) && streq(v->name, l->name)) {
851                 exists = true;
852                 break;
853             }
854         }
855 
856         if (!exists) {
857             v = rxkb_layout_create(&ctx->base);
858             list_init(&v->iso639s);
859             list_init(&v->iso3166s);
860             v->name = strdup(l->name);
861             v->variant = name;
862             v->description = description;
863             v->brief = brief;
864             v->popularity = popularity;
865             list_append(&ctx->layouts, &v->base.link);
866 
867             for (ci = variant->children; ci; ci = ci->next) {
868                 xmlNode *node;
869 
870                 if (!is_node(ci, "configItem"))
871                     continue;
872 
873                 for (node = ci->children; node; node = node->next) {
874                     if (is_node(node, "languageList"))
875                         parse_language_list(node, v);
876                     if (is_node(node, "countryList"))
877                         parse_country_list(node, v);
878                 }
879             }
880         } else {
881             free(name);
882             free(description);
883             free(brief);
884             free(vendor);
885         }
886     }
887 }
888 
889 static void
parse_variant_list(struct rxkb_context * ctx,struct rxkb_layout * l,xmlNode * variant_list,enum rxkb_popularity popularity)890 parse_variant_list(struct rxkb_context *ctx, struct rxkb_layout *l,
891                    xmlNode *variant_list, enum rxkb_popularity popularity)
892 {
893     xmlNode *node = NULL;
894 
895     for (node = variant_list->children; node; node = node->next) {
896         if (is_node(node, "variant"))
897             parse_variant(ctx, l, node, popularity);
898     }
899 }
900 
901 static void
parse_layout(struct rxkb_context * ctx,xmlNode * layout,enum rxkb_popularity popularity)902 parse_layout(struct rxkb_context *ctx, xmlNode *layout,
903              enum rxkb_popularity popularity)
904 {
905     char *name, *description, *brief, *vendor;
906     struct rxkb_layout *l;
907     xmlNode *node = NULL;
908     bool exists = false;
909 
910     if (!parse_config_item(ctx, layout, &name, &description, &brief, &vendor))
911         return;
912 
913     list_for_each(l, &ctx->layouts, base.link) {
914         if (streq(l->name, name) && l->variant == NULL) {
915             exists = true;
916             break;
917         }
918     }
919 
920     if (!exists) {
921         l = rxkb_layout_create(&ctx->base);
922         list_init(&l->iso639s);
923         list_init(&l->iso3166s);
924         l->name = name;
925         l->variant = NULL;
926         l->description = description;
927         l->brief = brief;
928         l->popularity = popularity;
929         list_append(&ctx->layouts, &l->base.link);
930     } else {
931         free(name);
932         free(description);
933         free(brief);
934         free(vendor);
935     }
936 
937     for (node = layout->children; node; node = node->next) {
938         if (is_node(node, "variantList")) {
939             parse_variant_list(ctx, l, node, popularity);
940         }
941         if (!exists && is_node(node, "configItem")) {
942             xmlNode *ll;
943             for (ll = node->children; ll; ll = ll->next) {
944                 if (is_node(ll, "languageList"))
945                     parse_language_list(ll, l);
946                 if (is_node(ll, "countryList"))
947                     parse_country_list(ll, l);
948             }
949         }
950     }
951 }
952 
953 static void
parse_layout_list(struct rxkb_context * ctx,xmlNode * layout_list,enum rxkb_popularity popularity)954 parse_layout_list(struct rxkb_context *ctx, xmlNode *layout_list,
955                   enum rxkb_popularity popularity)
956 {
957     xmlNode *node = NULL;
958 
959     for (node = layout_list->children; node; node = node->next) {
960         if (is_node(node, "layout"))
961             parse_layout(ctx, node, popularity);
962     }
963 }
964 
965 static void
parse_option(struct rxkb_context * ctx,struct rxkb_option_group * group,xmlNode * option,enum rxkb_popularity popularity)966 parse_option(struct rxkb_context *ctx, struct rxkb_option_group *group,
967              xmlNode *option, enum rxkb_popularity popularity)
968 {
969     char *name, *description, *brief, *vendor;
970 
971     if (parse_config_item(ctx, option, &name, &description, &brief, &vendor)) {
972         struct rxkb_option *o;
973 
974         list_for_each(o, &group->options, base.link) {
975             if (streq(o->name, name)) {
976                 free(name);
977                 free(description);
978                 free(brief);
979                 free(vendor);
980                 return;
981             }
982         }
983 
984         o = rxkb_option_create(&group->base);
985         o->name = name;
986         o->description = description;
987         o->popularity = popularity;
988         list_append(&group->options, &o->base.link);
989     }
990 }
991 
992 static void
parse_group(struct rxkb_context * ctx,xmlNode * group,enum rxkb_popularity popularity)993 parse_group(struct rxkb_context *ctx, xmlNode *group,
994             enum rxkb_popularity popularity)
995 {
996     char *name, *description, *brief, *vendor;
997     struct rxkb_option_group *g;
998     xmlNode *node = NULL;
999     xmlChar *multiple;
1000     bool exists = false;
1001 
1002     if (!parse_config_item(ctx, group, &name, &description, &brief, &vendor))
1003         return;
1004 
1005     list_for_each(g, &ctx->option_groups, base.link) {
1006         if (streq(g->name, name)) {
1007             exists = true;
1008             break;
1009         }
1010     }
1011 
1012     if (!exists) {
1013         g = rxkb_option_group_create(&ctx->base);
1014         g->name = name;
1015         g->description = description;
1016         g->popularity = popularity;
1017 
1018         multiple = xmlGetProp(group, (const xmlChar*)"allowMultipleSelection");
1019         if (multiple && xmlStrEqual(multiple, (const xmlChar*)"true"))
1020             g->allow_multiple = true;
1021         xmlFree(multiple);
1022 
1023         list_init(&g->options);
1024         list_append(&ctx->option_groups, &g->base.link);
1025     } else {
1026         free(name);
1027         free(description);
1028         free(brief);
1029         free(vendor);
1030     }
1031 
1032     for (node = group->children; node; node = node->next) {
1033         if (is_node(node, "option"))
1034             parse_option(ctx, g, node, popularity);
1035     }
1036 }
1037 
1038 static void
parse_option_list(struct rxkb_context * ctx,xmlNode * option_list,enum rxkb_popularity popularity)1039 parse_option_list(struct rxkb_context *ctx, xmlNode *option_list,
1040                   enum rxkb_popularity popularity)
1041 {
1042     xmlNode *node = NULL;
1043 
1044     for (node = option_list->children; node; node = node->next) {
1045         if (is_node(node, "group"))
1046             parse_group(ctx, node, popularity);
1047     }
1048 }
1049 
1050 static void
parse_rules_xml(struct rxkb_context * ctx,xmlNode * root,enum rxkb_popularity popularity)1051 parse_rules_xml(struct rxkb_context *ctx, xmlNode *root,
1052                 enum rxkb_popularity popularity)
1053 {
1054     xmlNode *node = NULL;
1055 
1056     for (node = root->children; node; node = node->next) {
1057         if (is_node(node, "modelList"))
1058             parse_model_list(ctx, node, popularity);
1059         else if (is_node(node, "layoutList"))
1060             parse_layout_list(ctx, node, popularity);
1061         else if (is_node(node, "optionList"))
1062             parse_option_list(ctx, node, popularity);
1063     }
1064 }
1065 
1066 static void
1067 ATTR_PRINTF(2, 0)
xml_error_func(void * ctx,const char * msg,...)1068 xml_error_func(void *ctx, const char *msg, ...)
1069 {
1070     static char buf[PATH_MAX];
1071     static int slen = 0;
1072     va_list args;
1073     int rc;
1074 
1075     /* libxml2 prints IO errors from bad includes paths by
1076      * calling the error function once per word. So we get to
1077      * re-assemble the message here and print it when we get
1078      * the line break. My enthusiasm about this is indescribable.
1079      */
1080     va_start(args, msg);
1081     rc = vsnprintf(&buf[slen], sizeof(buf) - slen, msg, args);
1082     va_end(args);
1083 
1084     /* This shouldn't really happen */
1085     if (rc < 0) {
1086         log_err(ctx, "+++ out of cheese error. redo from start +++\n");
1087         slen = 0;
1088         memset(buf, 0, sizeof(buf));
1089         return;
1090     }
1091 
1092     slen += rc;
1093     if (slen >= (int)sizeof(buf)) {
1094         /* truncated, let's flush this */
1095         buf[sizeof(buf) - 1] = '\n';
1096         slen = sizeof(buf);
1097     }
1098 
1099     /* We're assuming here that the last character is \n. */
1100     if (buf[slen - 1] == '\n') {
1101         log_err(ctx, "%s", buf);
1102         memset(buf, 0, sizeof(buf));
1103         slen = 0;
1104     }
1105 }
1106 
1107 static bool
validate(struct rxkb_context * ctx,xmlDoc * doc)1108 validate(struct rxkb_context *ctx, xmlDoc *doc)
1109 {
1110     bool success = false;
1111     xmlValidCtxt *dtdvalid = NULL;
1112     xmlDtd *dtd = NULL;
1113     xmlParserInputBufferPtr buf = NULL;
1114     /* This is a modified version of the xkeyboard-config xkb.dtd. That one
1115      * requires modelList, layoutList and optionList, we
1116      * allow for any of those to be missing.
1117      */
1118     const char dtdstr[] =
1119         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1120         "<!ELEMENT xkbConfigRegistry (modelList?, layoutList?, optionList?)>\n"
1121         "<!ATTLIST xkbConfigRegistry version CDATA \"1.1\">\n"
1122         "<!ELEMENT modelList (model*)>\n"
1123         "<!ELEMENT model (configItem)>\n"
1124         "<!ELEMENT layoutList (layout*)>\n"
1125         "<!ELEMENT layout (configItem,  variantList?)>\n"
1126         "<!ELEMENT optionList (group*)>\n"
1127         "<!ELEMENT variantList (variant*)>\n"
1128         "<!ELEMENT variant (configItem)>\n"
1129         "<!ELEMENT group (configItem, option*)>\n"
1130         "<!ATTLIST group allowMultipleSelection (true|false) \"false\">\n"
1131         "<!ELEMENT option (configItem)>\n"
1132         "<!ELEMENT configItem (name, shortDescription?, description?, vendor?, countryList?, languageList?, hwList?)>\n"
1133         "<!ATTLIST configItem popularity (standard|exotic) \"standard\">\n"
1134         "<!ELEMENT name (#PCDATA)>\n"
1135         "<!ELEMENT shortDescription (#PCDATA)>\n"
1136         "<!ELEMENT description (#PCDATA)>\n"
1137         "<!ELEMENT vendor (#PCDATA)>\n"
1138         "<!ELEMENT countryList (iso3166Id+)>\n"
1139         "<!ELEMENT iso3166Id (#PCDATA)>\n"
1140         "<!ELEMENT languageList (iso639Id+)>\n"
1141         "<!ELEMENT iso639Id (#PCDATA)>\n"
1142         "<!ELEMENT hwList (hwId+)>\n"
1143         "<!ELEMENT hwId (#PCDATA)>\n";
1144 
1145     /* Note: do not use xmlParserInputBufferCreateStatic, it generates random
1146      * DTD validity errors for unknown reasons */
1147     buf = xmlParserInputBufferCreateMem(dtdstr, sizeof(dtdstr),
1148                                         XML_CHAR_ENCODING_UTF8);
1149     if (!buf)
1150         return false;
1151 
1152     dtd = xmlIOParseDTD(NULL, buf, XML_CHAR_ENCODING_UTF8);
1153     if (!dtd) {
1154         log_err(ctx, "Failed to load DTD\n");
1155         return false;
1156     }
1157 
1158     dtdvalid = xmlNewValidCtxt();
1159     if (xmlValidateDtd(dtdvalid, doc, dtd))
1160         success = true;
1161 
1162     if (dtd)
1163         xmlFreeDtd(dtd);
1164     if (dtdvalid)
1165         xmlFreeValidCtxt(dtdvalid);
1166 
1167     return success;
1168 }
1169 
1170 static bool
parse(struct rxkb_context * ctx,const char * path,enum rxkb_popularity popularity)1171 parse(struct rxkb_context *ctx, const char *path,
1172       enum rxkb_popularity popularity)
1173 {
1174     bool success = false;
1175     xmlDoc *doc = NULL;
1176     xmlNode *root = NULL;
1177 
1178     if (!check_eaccess(path, R_OK))
1179         return false;
1180 
1181     LIBXML_TEST_VERSION
1182 
1183     xmlSetGenericErrorFunc(ctx, xml_error_func);
1184 
1185     doc = xmlParseFile(path);
1186     if (!doc)
1187         return false;
1188 
1189     if (!validate(ctx, doc)) {
1190         log_err(ctx, "XML error: failed to validate document at %s\n", path);
1191         goto error;
1192     }
1193 
1194     root = xmlDocGetRootElement(doc);
1195     parse_rules_xml(ctx, root, popularity);
1196 
1197     success = true;
1198 error:
1199     xmlFreeDoc(doc);
1200     xmlCleanupParser();
1201 
1202     return success;
1203 }
1204