|
24 | 24 | #include <config.h>
|
25 | 25 | #endif
|
26 | 26 |
|
| 27 | +#include <math.h> |
27 | 28 | #include <errno.h>
|
| 29 | +#include <pcre.h> |
28 | 30 | #include <yaml.h>
|
29 | 31 | #include <yaml-path.h>
|
30 | 32 |
|
|
35 | 37 | #include "list.h"
|
36 | 38 | #include "probe/probe.h"
|
37 | 39 |
|
| 40 | +#define OSCAP_YAML_STRING_TAG "tag:yaml.org,2002:str" |
| 41 | +#define OSCAP_YAML_BOOL_TAG "tag:yaml.org,2002:bool" |
| 42 | +#define OSCAP_YAML_FLOAT_TAG "tag:yaml.org,2002:float" |
| 43 | +#define OSCAP_YAML_INT_TAG "tag:yaml.org,2002:int" |
| 44 | + |
| 45 | +#define OVECCOUNT 30 /* should be a multiple of 3 */ |
| 46 | + |
38 | 47 | int yamlfilecontent_probe_offline_mode_supported()
|
39 | 48 | {
|
40 | 49 | return PROBE_OFFLINE_OWN;
|
41 | 50 | }
|
42 | 51 |
|
| 52 | +static bool match_regex(const char *pattern, const char *value) |
| 53 | +{ |
| 54 | + const char *errptr; |
| 55 | + int erroroffset; |
| 56 | + pcre *re = pcre_compile(pattern, 0, &errptr, &erroroffset, NULL); |
| 57 | + if (re == NULL) { |
| 58 | + dE("pcre_compile failed on pattern '%s': %s at %d", pattern, |
| 59 | + errptr, erroroffset); |
| 60 | + return false; |
| 61 | + } |
| 62 | + int ovector[OVECCOUNT]; |
| 63 | + int rc = pcre_exec(re, NULL, value, strlen(value), 0, 0, ovector, OVECCOUNT); |
| 64 | + if (rc > 0) { |
| 65 | + return true; |
| 66 | + } |
| 67 | + return false; |
| 68 | +} |
| 69 | + |
| 70 | +static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t event) |
| 71 | +{ |
| 72 | + char *tag = (char *) event.data.scalar.tag; |
| 73 | + char *value = (char *) event.data.scalar.value; |
| 74 | + |
| 75 | + /* nodes lacking an explicit tag are given a non-specific tag: |
| 76 | + * “!” for non-plain scalars, and “?” for all other nodes |
| 77 | + */ |
| 78 | + if (tag == NULL) { |
| 79 | + if (event.data.scalar.style != YAML_PLAIN_SCALAR_STYLE) { |
| 80 | + tag = "!"; |
| 81 | + } else { |
| 82 | + tag = "?"; |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + /* Nodes with "!" tag can be sequences, maps or strings, but we process |
| 87 | + * only scalars in this functions, so they can only be strings. */ |
| 88 | + if (!strcmp(tag, "!")) { |
| 89 | + tag = OSCAP_YAML_STRING_TAG; |
| 90 | + } |
| 91 | + |
| 92 | + bool question = !strcmp(tag, "?"); |
| 93 | + |
| 94 | + /* Regular expressions based on https://yaml.org/spec/1.2/spec.html#id2804923 */ |
| 95 | + |
| 96 | + if (question || !strcmp(tag, OSCAP_YAML_BOOL_TAG)) { |
| 97 | + if (match_regex("^true|True|TRUE$", value)) { |
| 98 | + return SEXP_number_newb(true); |
| 99 | + } else if (match_regex("^false|False|FALSE$", value)) { |
| 100 | + return SEXP_number_newb(false); |
| 101 | + } else if (!question) { |
| 102 | + return NULL; |
| 103 | + } |
| 104 | + } |
| 105 | + if (question || !strcmp(tag, OSCAP_YAML_INT_TAG)) { |
| 106 | + if (match_regex("^[+-]?[0-9]+$", value)) { |
| 107 | + int int_value = strtol(value, NULL, 10); |
| 108 | + return SEXP_number_newi(int_value); |
| 109 | + } else if (match_regex("^0o[0-7]+$", value)) { |
| 110 | + /* strtol doesn't understand 0o as octal prefix, it wants 0 */ |
| 111 | + int int_value = strtol(value + 2, NULL, 8); |
| 112 | + return SEXP_number_newi(int_value); |
| 113 | + } else if (match_regex("^0x[0-9a-fA-F]+$", value)) { |
| 114 | + int int_value = strtol(value, NULL, 16); |
| 115 | + return SEXP_number_newi(int_value); |
| 116 | + } else if (!question) { |
| 117 | + return NULL; |
| 118 | + } |
| 119 | + } |
| 120 | + if (question || !strcmp(tag, OSCAP_YAML_FLOAT_TAG)) { |
| 121 | + if (match_regex("^[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$", value)) { |
| 122 | + double double_value = strtod(value, NULL); |
| 123 | + return SEXP_number_newf(double_value); |
| 124 | + } else if (match_regex("^[-+]?(\\.inf|\\.Inf|\\.INF)$", value)) { |
| 125 | + double double_value = INFINITY; |
| 126 | + if (value[0] == '-') { |
| 127 | + double_value = -INFINITY; |
| 128 | + } |
| 129 | + return SEXP_number_newf(double_value); |
| 130 | + } else if (match_regex("^\\.nan|\\.NaN|\\.NAN$", value)) { |
| 131 | + double double_value = NAN; |
| 132 | + return SEXP_number_newf(double_value); |
| 133 | + } else if (!question) { |
| 134 | + return NULL; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + return SEXP_string_new(value, strlen(value)); |
| 139 | +} |
| 140 | + |
43 | 141 | static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx)
|
44 | 142 | {
|
45 | 143 | int ret = 0;
|
@@ -118,7 +216,17 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str
|
118 | 216 | }
|
119 | 217 | }
|
120 | 218 | if (event.type == YAML_SCALAR_EVENT) {
|
121 |
| - oscap_list_add(values, (void *) strdup((const char *) event.data.scalar.value)); |
| 219 | + SEXP_t *sexp = yaml_scalar_event_to_sexp(event); |
| 220 | + if (sexp == NULL) { |
| 221 | + SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, |
| 222 | + "Can't convert '%s' to SEXP", event.data.scalar.tag); |
| 223 | + probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); |
| 224 | + SEXP_free(msg); |
| 225 | + probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); |
| 226 | + ret = -1; |
| 227 | + goto cleanup; |
| 228 | + } |
| 229 | + oscap_list_add(values, sexp); |
122 | 230 | }
|
123 | 231 | } while (event.type != YAML_STREAM_END_EVENT);
|
124 | 232 |
|
@@ -157,18 +265,15 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f
|
157 | 265 | NULL
|
158 | 266 | );
|
159 | 267 | while (oscap_iterator_has_more(values_it)) {
|
160 |
| - char *value = oscap_iterator_next(values_it); |
161 |
| - /* TODO: type conversion of 'value' data */ |
162 |
| - SEXP_t *value_sexp = SEXP_string_new(value, strlen(value)); |
| 268 | + SEXP_t *value_sexp = oscap_iterator_next(values_it); |
163 | 269 | probe_item_ent_add(item, "value_of", NULL, value_sexp);
|
164 |
| - SEXP_free(value_sexp); |
165 | 270 | }
|
166 | 271 | probe_item_collect(ctx, item);
|
167 | 272 | }
|
168 | 273 | oscap_iterator_free(values_it);
|
169 | 274 |
|
170 | 275 | cleanup:
|
171 |
| - oscap_list_free(values, free); |
| 276 | + oscap_list_free(values, (oscap_destruct_func) SEXP_free); |
172 | 277 | free(filepath_with_prefix);
|
173 | 278 | free(filepath);
|
174 | 279 | return ret;
|
|
0 commit comments