2727#include <gnutls/abstract.h>
2828
2929#include <glib.h>
30+ #include <yaml.h>
3031
3132#include "tlshd.h"
3233
34+ /* --- libyaml helpers --- */
35+
36+ /* This depends on the yaml_event_type_t enum being densely packed */
37+ static const char * show_yaml_event_type (const yaml_event_t * event )
38+ {
39+ static const char * labels [] = {
40+ [YAML_NO_EVENT ] = "YAML_NO_EVENT" ,
41+ [YAML_STREAM_START_EVENT ] = "YAML_STREAM_START_EVENT" ,
42+ [YAML_STREAM_END_EVENT ] = "YAML_STREAM_END_EVENT" ,
43+ [YAML_DOCUMENT_START_EVENT ] = "YAML_DOCUMENT_START_EVENT" ,
44+ [YAML_DOCUMENT_END_EVENT ] = "YAML_DOCUMENT_END_EVENT" ,
45+ [YAML_ALIAS_EVENT ] = "YAML_ALIAS_EVENT" ,
46+ [YAML_SCALAR_EVENT ] = "YAML_SCALAR_EVENT" ,
47+ [YAML_SEQUENCE_START_EVENT ] = "YAML_SEQUENCE_START_EVENT" ,
48+ [YAML_SEQUENCE_END_EVENT ] = "YAML_SEQUENCE_END_EVENT" ,
49+ [YAML_MAPPING_START_EVENT ] = "YAML_MAPPING_START_EVENT" ,
50+ [YAML_MAPPING_END_EVENT ] = "YAML_MAPPING_END_EVENT" ,
51+ };
52+
53+ if (event -> type > YAML_MAPPING_END_EVENT )
54+ return "invalid YAML event" ;
55+ return labels [event -> type ];
56+ }
57+
58+ /* --- Tag configuration file parsing --- */
59+
60+ enum tlshd_tags_fsm_state_index {
61+ PS_STOP ,
62+ PS_START ,
63+ PS_STREAM ,
64+ PS_DOCUMENT ,
65+ PS_TOP_LEVEL ,
66+
67+ PS_UNEXPECTED_INPUT_TOKEN ,
68+ PS_FAILURE ,
69+ };
70+
3371struct tlshd_tags_filter ;
3472
3573struct tlshd_tags_filter_type {
@@ -41,6 +79,212 @@ struct tlshd_tags_filter_type {
4179
4280static GHashTable * tlshd_tags_filter_type_hash ;
4381
82+ struct tlshd_tags_parser_state {
83+ yaml_event_t ps_yaml_event ;
84+
85+ enum tlshd_tags_fsm_state_index ps_fsm_state ;
86+ };
87+
88+ static enum tlshd_tags_fsm_state_index
89+ tlshd_tags_top_level (struct tlshd_tags_parser_state * current )
90+ {
91+ const yaml_event_t * event = & current -> ps_yaml_event ;
92+ const char * mapping = (const char * )event -> data .scalar .value ;
93+
94+ tlshd_log_error ("Unexpected mapping name: %s\n" , mapping );
95+ return PS_UNEXPECTED_INPUT_TOKEN ;
96+ }
97+
98+ /* --- FSM states --- */
99+
100+ typedef enum tlshd_tags_fsm_state_index
101+ (* tlshd_tags_action_fn )(struct tlshd_tags_parser_state * current );
102+
103+ struct tlshd_tags_fsm_transition {
104+ yaml_event_type_t pt_yaml_event ;
105+ enum tlshd_tags_fsm_state_index pt_next_state ;
106+ tlshd_tags_action_fn pt_action ;
107+ };
108+
109+ #define NEXT_STATE (event , state ) \
110+ { \
111+ .pt_yaml_event = event, \
112+ .pt_next_state = state, \
113+ }
114+
115+ #define NEXT_ACTION (event , action ) \
116+ { \
117+ .pt_yaml_event = event, \
118+ .pt_action = action, \
119+ }
120+
121+ static const struct tlshd_tags_fsm_transition tlshd_tags_transitions_start [] = {
122+ NEXT_STATE (YAML_STREAM_START_EVENT , PS_STREAM ),
123+ };
124+
125+ static const struct tlshd_tags_fsm_transition tlshd_tags_transitions_stream [] = {
126+ NEXT_STATE (YAML_DOCUMENT_START_EVENT , PS_DOCUMENT ),
127+ NEXT_STATE (YAML_STREAM_END_EVENT , PS_STOP ),
128+ };
129+
130+ static const struct tlshd_tags_fsm_transition tlshd_tags_transitions_document [] = {
131+ NEXT_STATE (YAML_MAPPING_START_EVENT , PS_TOP_LEVEL ),
132+ NEXT_STATE (YAML_DOCUMENT_END_EVENT , PS_STREAM ),
133+ };
134+
135+ static const struct tlshd_tags_fsm_transition tlshd_tags_transitions_top_level [] = {
136+ NEXT_ACTION (YAML_SCALAR_EVENT , tlshd_tags_top_level ),
137+ NEXT_STATE (YAML_MAPPING_END_EVENT , PS_DOCUMENT ),
138+ };
139+
140+ struct tlshd_tags_fsm_state {
141+ const char * ts_name ;
142+ const struct tlshd_tags_fsm_transition * ts_transitions ;
143+ size_t ts_transition_count ;
144+ };
145+
146+ #define FSM_STATE (name , array ) \
147+ [name] = { \
148+ .ts_name = #name, \
149+ .ts_transitions = array, \
150+ .ts_transition_count = ARRAY_SIZE(array), \
151+ }
152+
153+ #define TERMINAL_STATE (name ) \
154+ [name] = { \
155+ .ts_name = #name, \
156+ .ts_transition_count = 0, \
157+ }
158+
159+ static const struct tlshd_tags_fsm_state tlshd_tags_fsm_state_table [] = {
160+ TERMINAL_STATE (PS_STOP ),
161+ FSM_STATE (PS_START , tlshd_tags_transitions_start ),
162+ FSM_STATE (PS_STREAM , tlshd_tags_transitions_stream ),
163+ FSM_STATE (PS_DOCUMENT , tlshd_tags_transitions_document ),
164+ FSM_STATE (PS_TOP_LEVEL , tlshd_tags_transitions_top_level ),
165+ TERMINAL_STATE (PS_UNEXPECTED_INPUT_TOKEN ),
166+ TERMINAL_STATE (PS_FAILURE ),
167+ };
168+
169+ /*
170+ * Each libyaml event produces zero or one input tokens.
171+ *
172+ * tlshd_tags_process_yaml_event() evaluates the event token based on
173+ * the current parser state, then advances to the next FSM state.
174+ */
175+ static void
176+ tlshd_tags_process_yaml_event (struct tlshd_tags_parser_state * current )
177+ {
178+ const struct tlshd_tags_fsm_state * fsm_state =
179+ & tlshd_tags_fsm_state_table [current -> ps_fsm_state ];
180+ const yaml_event_t * event = & current -> ps_yaml_event ;
181+ const struct tlshd_tags_fsm_transition * transition ;
182+ size_t i ;
183+
184+ if (fsm_state -> ts_transition_count == 0 )
185+ return ;
186+
187+ transition = NULL ;
188+ for (i = 0 ; i < fsm_state -> ts_transition_count ; ++ i ) {
189+ if (fsm_state -> ts_transitions [i ].pt_yaml_event == event -> type ) {
190+ transition = & fsm_state -> ts_transitions [i ];
191+ break ;
192+ }
193+ }
194+ if (transition == NULL ) {
195+ tlshd_log_debug ("ps_state=%s, unexpected event: %s\n" ,
196+ fsm_state -> ts_name ,
197+ show_yaml_event_type (event ));
198+ current -> ps_fsm_state = PS_FAILURE ;
199+ return ;
200+ }
201+
202+ if (tlshd_debug > 3 )
203+ tlshd_log_debug ("ps_state=%s yaml event=%s" ,
204+ fsm_state -> ts_name ,
205+ show_yaml_event_type (event ));
206+
207+ if (transition -> pt_action )
208+ current -> ps_fsm_state = transition -> pt_action (current );
209+ else
210+ current -> ps_fsm_state = transition -> pt_next_state ;
211+ }
212+
213+ static void tlshd_tags_parse_file (const char * filename )
214+ {
215+ struct tlshd_tags_parser_state current ;
216+ yaml_parser_t parser ;
217+ FILE * fh ;
218+
219+ if (!yaml_parser_initialize (& parser )) {
220+ tlshd_log_error ("Failed to initialize parser!\n" );
221+ return ;
222+ }
223+
224+ fh = fopen (filename , "r" );
225+ if (!fh ) {
226+ tlshd_log_perror ("fopen" );
227+ yaml_parser_delete (& parser );
228+ return ;
229+ }
230+ yaml_parser_set_input_file (& parser , fh );
231+
232+ tlshd_log_debug ("Parsing tags config file '%s'" , filename );
233+
234+ current .ps_fsm_state = PS_START ;
235+ do {
236+ if (!yaml_parser_parse (& parser , & current .ps_yaml_event )) {
237+ tlshd_log_error ("Parser error %d\n" ,
238+ parser .error );
239+ break ;
240+ }
241+ tlshd_tags_process_yaml_event (& current );
242+ yaml_event_delete (& current .ps_yaml_event );
243+
244+ if (current .ps_fsm_state == PS_FAILURE ||
245+ current .ps_fsm_state == PS_UNEXPECTED_INPUT_TOKEN ) {
246+ tlshd_log_error ("Tag parsing failed, line: %zu column: %zu file: %s\n" ,
247+ parser .mark .line + 1 ,
248+ parser .mark .column ,
249+ filename );
250+ break ;
251+ }
252+ } while (current .ps_fsm_state != PS_STOP );
253+
254+ yaml_parser_delete (& parser );
255+ fclose (fh );
256+ }
257+
258+ static bool tlshd_tags_read_directory (const char * tagsdir )
259+ {
260+ const gchar * filename ;
261+ GError * error ;
262+ GDir * dir ;
263+
264+ error = NULL ;
265+ dir = g_dir_open (tagsdir , 0 , & error );
266+ if (!dir ) {
267+ tlshd_log_gerror ("Failed to open the tags directory" , error );
268+ g_error_free (error );
269+ return false;
270+ }
271+
272+ while ((filename = g_dir_read_name (dir )) != NULL ) {
273+ gchar * pathname ;
274+
275+ if (!g_str_has_suffix (filename , ".yml" ) &&
276+ !g_str_has_suffix (filename , ".yaml" ))
277+ continue ;
278+ pathname = g_build_filename (tagsdir , filename , NULL );
279+
280+ tlshd_tags_parse_file (pathname );
281+ g_free (pathname );
282+ }
283+
284+ g_dir_close (dir );
285+ return true;
286+ }
287+
44288/* --- Filter Types --- */
45289
46290static const struct tlshd_tags_filter_type tlshd_tags_static_filter_types [] = {
@@ -148,9 +392,20 @@ static bool tlshd_tags_filter_type_hash_init(void)
148392 * @tagsdir: pathname of directory containing files that define tags
149393 *
150394 */
151- bool tlshd_tags_config_init (__attribute__ (( unused )) const char * tagsdir )
395+ bool tlshd_tags_config_init (const char * tagsdir )
152396{
153- return tlshd_tags_filter_type_hash_init ();
397+ if (!tlshd_tags_filter_type_hash_init ())
398+ goto out ;
399+
400+ if (!tlshd_tags_read_directory (tagsdir ))
401+ goto filter_type_hash ;
402+
403+ return true;
404+
405+ filter_type_hash :
406+ tlshd_tags_filter_type_hash_destroy ();
407+ out :
408+ return false;
154409}
155410
156411/**
0 commit comments