1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2017, Intel Corporation
4  * All rights reserved.
5  */
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <glib.h>
9 #include <inttypes.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include "connection.h"
15 #include "connection-manager.h"
16 #include "command-source.h"
17 #include "source-interface.h"
18 #include "tpm2-command.h"
19 #include "tpm2-header.h"
20 #include "util.h"
21 
22 #ifndef G_SOURCE_FUNC
23 #define G_SOURCE_FUNC(x) ((GSourceFunc)(void*)x)
24 #endif
25 
26 enum {
27     PROP_0,
28     PROP_COMMAND_ATTRS,
29     PROP_CONNECTION_MANAGER,
30     PROP_SINK,
31     N_PROPERTIES
32 };
33 static GParamSpec *obj_properties [N_PROPERTIES] = { NULL, };
34 
35 /**
36  * Function implementing the Source interface. Adds a sink for the source
37  * to pass data to.
38  */
39 void
command_source_add_sink(Source * self,Sink * sink)40 command_source_add_sink (Source      *self,
41                          Sink        *sink)
42 {
43     CommandSource *src = COMMAND_SOURCE (self);
44     GValue value = G_VALUE_INIT;
45 
46     g_debug (__func__);
47     g_value_init (&value, G_TYPE_OBJECT);
48     g_value_set_object (&value, sink);
49     g_object_set_property (G_OBJECT (src), "sink", &value);
50     g_value_unset (&value);
51 }
52 /*
53  * This function initializes the SourceInterface. This is just registering
54  * a function pointer with the interface.
55  */
56 static void
command_source_source_interface_init(gpointer g_iface)57 command_source_source_interface_init (gpointer g_iface)
58 {
59     SourceInterface *source = (SourceInterface*)g_iface;
60     source->add_sink = command_source_add_sink;
61 }
62 /*
63  * This is a callback function used to clean up memory used by the
64  * source_data_t structure. It's called by the GHashTable when removing
65  * source_data_t values.
66  */
67 static void
source_data_free(gpointer data)68 source_data_free (gpointer data)
69 {
70     source_data_t *source_data = (source_data_t*)data;
71     g_object_unref (source_data->cancellable);
72     g_source_unref (source_data->source);
73     g_free (source_data);
74 }
75 /*
76  * Initialize a CommandSource instance.
77  */
78 static void
command_source_init(CommandSource * source)79 command_source_init (CommandSource *source)
80 {
81     source->main_context = g_main_context_new ();
82     source->main_loop = g_main_loop_new (source->main_context, FALSE);
83     /*
84      * GHashTable mapping a GSocket to an instance of the source_data_t
85      * structure. The socket is the I/O mechanism for communicating with a
86      * client (from Connection object), and the source_data_t instance is
87      * a collection of data that we use to manage callbacks for I/O events
88      * from the main loop.
89      * The hash table owns a reference to the socket (key) and it owns
90      * the structure held in the value (it will be freed when removed).
91      */
92     source->istream_to_source_data_map =
93         g_hash_table_new_full (g_direct_hash,
94                                g_direct_equal,
95                                g_object_unref,
96                                source_data_free);
97 }
98 
99 G_DEFINE_TYPE_WITH_CODE (
100     CommandSource,
101     command_source,
102     TYPE_THREAD,
103     G_IMPLEMENT_INTERFACE (TYPE_SOURCE,
104                            command_source_source_interface_init)
105     );
106 
107 static void
command_source_set_property(GObject * object,guint property_id,GValue const * value,GParamSpec * pspec)108 command_source_set_property (GObject       *object,
109                               guint          property_id,
110                               GValue const  *value,
111                               GParamSpec    *pspec)
112 {
113     CommandSource *self = COMMAND_SOURCE (object);
114 
115     g_debug (__func__);
116     switch (property_id) {
117     case PROP_COMMAND_ATTRS:
118         self->command_attrs = COMMAND_ATTRS (g_value_dup_object (value));
119         break;
120     case PROP_CONNECTION_MANAGER:
121         self->connection_manager = CONNECTION_MANAGER (g_value_get_object (value));
122         break;
123     case PROP_SINK:
124         /* be rigid initially, add flexiblity later if we need it */
125         if (self->sink != NULL) {
126             g_warning ("  sink already set");
127             break;
128         }
129         self->sink = SINK (g_value_get_object (value));
130         g_object_ref (self->sink);
131         break;
132     default:
133         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
134         break;
135     }
136 }
137 
138 static void
command_source_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)139 command_source_get_property (GObject      *object,
140                               guint         property_id,
141                               GValue       *value,
142                               GParamSpec   *pspec)
143 {
144     CommandSource *self = COMMAND_SOURCE (object);
145 
146     g_debug (__func__);
147     switch (property_id) {
148     case PROP_COMMAND_ATTRS:
149         g_value_set_object (value, self->command_attrs);
150         break;
151     case PROP_CONNECTION_MANAGER:
152         g_value_set_object (value, self->connection_manager);
153         break;
154     case PROP_SINK:
155         g_value_set_object (value, self->sink);
156         break;
157     default:
158         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
159         break;
160     }
161 }
162 /*
163  * This function is invoked by the GMainLoop thread when a client GSocket has
164  * data ready. This is what makes the CommandSource a source (of Tpm2Commands).
165  * Here we take the GSocket, extract the command body from the it and
166  * transform it to a Tpm2Command. Most of the details are handled by utility
167  * functions further down the stack.
168  *
169  * If an error occurs while getting the command from the GSocket the connection
170  * with the client will be closed and removed from the ConnectionManager.
171  * Additionally the function will return FALSE and the GSource will no longer
172  * monitor the GSocket for the G_IO_IN condition.
173  */
174 gboolean
command_source_on_input_ready(GInputStream * istream,gpointer user_data)175 command_source_on_input_ready (GInputStream *istream,
176                                gpointer      user_data)
177 {
178     source_data_t *data = (source_data_t*)user_data;
179     Connection    *connection;
180     Tpm2Command   *command;
181     TPMA_CC        attributes = { 0 };
182     uint8_t       *buf;
183     size_t         buf_size;
184 
185     g_debug (__func__);
186     connection =
187         connection_manager_lookup_istream (data->self->connection_manager,
188                                            istream);
189     if (connection == NULL) {
190         g_error ("%s: failed to get connection associated with istream",
191                  __func__);
192     }
193     buf = read_tpm_buffer_alloc (istream, &buf_size);
194     if (buf == NULL) {
195         goto fail_out;
196     }
197     attributes = command_attrs_from_cc (data->self->command_attrs,
198                                         get_command_code (buf));
199     command = tpm2_command_new (connection, buf, buf_size, attributes);
200     if (command != NULL) {
201         sink_enqueue (data->self->sink, G_OBJECT (command));
202         /* the sink now owns this message */
203         g_object_unref (command);
204     } else {
205         goto fail_out;
206     }
207     g_object_unref (connection);
208     return G_SOURCE_CONTINUE;
209 fail_out:
210     if (buf != NULL) {
211         g_free (buf);
212     }
213     g_debug ("%s: removing connection from connection_manager", __func__);
214     connection_manager_remove (data->self->connection_manager,
215                                connection);
216     ControlMessage *msg =
217         control_message_new_with_object (CONNECTION_REMOVED,
218                                          G_OBJECT (connection));
219     sink_enqueue (data->self->sink, G_OBJECT (msg));
220     g_object_unref (msg);
221     g_object_unref (connection);
222     /*
223      * Remove data from hash table which includes the GCancellable associated
224      * with the G_IN_IO condition source. Don't call the cancellable though
225      * since we're letting this source die at the end of this function
226      * (returning FALSE).
227      */
228     g_debug ("%s: removing GCancellable", __func__);
229     g_hash_table_remove (data->self->istream_to_source_data_map, istream);
230     return G_SOURCE_REMOVE;
231 }
232 /*
233  * This is a callback function invoked by the ConnectionManager when a new
234  * Connection object is added to it. It creates and sets up the GIO
235  * machinery needed to monitor the Connection for I/O events.
236  */
237 gint
command_source_on_new_connection(ConnectionManager * connection_manager,Connection * connection,CommandSource * self)238 command_source_on_new_connection (ConnectionManager   *connection_manager,
239                                   Connection          *connection,
240                                   CommandSource       *self)
241 {
242     GIOStream *iostream;
243     GPollableInputStream *istream;
244     source_data_t *data;
245     UNUSED_PARAM(connection_manager);
246 
247     g_info ("%s: adding new connection", __func__);
248     /*
249      * Take reference to socket, will be freed when the source_data_t
250      * structure is freed
251      */
252     iostream = connection_get_iostream (connection);
253     istream = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (iostream));
254     g_object_ref (istream);
255     data = g_malloc0 (sizeof (source_data_t));
256     data->cancellable = g_cancellable_new ();
257     data->source = g_pollable_input_stream_create_source (istream,
258                                                           data->cancellable);
259     /* we ignore the ID returned since we keep a reference to the source around */
260     g_source_attach (data->source, self->main_context);
261     data->self = self;
262     g_source_set_callback (data->source,
263                            G_SOURCE_FUNC (command_source_on_input_ready),
264                            data,
265                            NULL);
266     /*
267      * To stop watching this socket for G_IO_IN condition use this GHashTable
268      * to look up the GCancellable object. The hash table takes ownership of
269      * the reference to the istream and the source_data_t pointer.
270      */
271     g_hash_table_insert (self->istream_to_source_data_map, istream, data);
272 
273     return 0;
274 }
275 /*
276  * callback for iterating over objects in the member socket_to_source_data_map
277  * GHashMap to kill off the GSource. This requires cancelling it, and then
278  * calling the GSource destroy function. This should only happen when the
279  * CommandSource object is destroyed.
280  */
281 static void
command_source_source_cancel(gpointer key,gpointer value,gpointer user_data)282 command_source_source_cancel (gpointer key,
283                               gpointer value,
284                               gpointer user_data)
285 {
286     UNUSED_PARAM(key);
287     UNUSED_PARAM(user_data);
288     g_debug ("%s", __func__);
289     source_data_t *data = (source_data_t*)value;
290 
291     g_debug ("%s: canceling cancellable and destroying source", __func__);
292     g_cancellable_cancel (data->cancellable);
293 }
294 /*
295  * GObject dispose function. It's used to unref / release all GObjects held
296  * by the CommandSource before chaining up to the parent.
297  */
298 static void
command_source_dispose(GObject * object)299 command_source_dispose (GObject *object) {
300     CommandSource *self = COMMAND_SOURCE (object);
301 
302     g_clear_object (&self->sink);
303     g_clear_object (&self->connection_manager);
304     g_clear_object (&self->command_attrs);
305     /* cancel all outstanding G_IO_IN condition GSources and destroy them */
306     if (self->istream_to_source_data_map != NULL) {
307         g_hash_table_foreach (self->istream_to_source_data_map,
308                               command_source_source_cancel,
309                               NULL);
310     }
311     g_clear_pointer (&self->istream_to_source_data_map, g_hash_table_unref);
312     if (self->main_loop != NULL && g_main_loop_is_running (self->main_loop)) {
313         g_main_loop_quit (self->main_loop);
314     }
315     g_clear_pointer (&self->main_loop, g_main_loop_unref);
316     g_clear_pointer (&self->main_context, g_main_context_unref);
317     G_OBJECT_CLASS (command_source_parent_class)->dispose (object);
318 }
319 
320 /*
321  * GObject finalize function releases all resources not freed in 'dispose'
322  * & chain up to parent.
323  */
324 static void
command_source_finalize(GObject * object)325 command_source_finalize (GObject  *object)
326 {
327     G_OBJECT_CLASS (command_source_parent_class)->finalize (object);
328 }
329 /*
330  * Cause the GMainLoop to stop monitoring whatever GSources are attached to
331  * it and return
332  */
333 static void
command_source_unblock(Thread * self)334 command_source_unblock (Thread *self)
335 {
336     CommandSource *source = COMMAND_SOURCE (self);
337     g_main_loop_quit (source->main_loop);
338 }
339 /*
340  * This function creates it's very own GMainLoop thread. This is used to
341  * monitor client connections for incoming data (TPM2 command buffers).
342  */
343 void*
command_source_thread(void * data)344 command_source_thread (void *data)
345 {
346     CommandSource *source;
347 
348     g_assert (data != NULL);
349     source = COMMAND_SOURCE (data);
350     g_assert (source->main_loop != NULL);
351 
352     if (!g_main_loop_is_running (source->main_loop)) {
353         g_main_loop_run (source->main_loop);
354     }
355 
356     return NULL;
357 }
358 
359 static void
command_source_class_init(CommandSourceClass * klass)360 command_source_class_init (CommandSourceClass *klass)
361 {
362     GObjectClass *object_class = G_OBJECT_CLASS (klass);
363     ThreadClass  *thread_class = THREAD_CLASS (klass);
364 
365     g_debug ("command_source_class_init");
366     if (command_source_parent_class == NULL)
367         command_source_parent_class = g_type_class_peek_parent (klass);
368 
369     object_class->dispose      = command_source_dispose;
370     object_class->finalize     = command_source_finalize;
371     object_class->get_property = command_source_get_property;
372     object_class->set_property = command_source_set_property;
373     thread_class->thread_run   = command_source_thread;
374     thread_class->thread_unblock = command_source_unblock;
375 
376     obj_properties [PROP_COMMAND_ATTRS] =
377         g_param_spec_object ("command-attrs",
378                              "CommandAttrs object",
379                              "CommandAttrs instance.",
380                              TYPE_COMMAND_ATTRS,
381                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
382     obj_properties [PROP_CONNECTION_MANAGER] =
383         g_param_spec_object ("connection-manager",
384                              "ConnectionManager object",
385                              "ConnectionManager instance.",
386                              TYPE_CONNECTION_MANAGER,
387                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
388     obj_properties [PROP_SINK] =
389         g_param_spec_object ("sink",
390                              "Sink",
391                              "Reference to a Sink object.",
392                              G_TYPE_OBJECT,
393                              G_PARAM_READWRITE);
394     g_object_class_install_properties (object_class,
395                                        N_PROPERTIES,
396                                        obj_properties);
397 }
398 CommandSource*
command_source_new(ConnectionManager * connection_manager,CommandAttrs * command_attrs)399 command_source_new (ConnectionManager    *connection_manager,
400                     CommandAttrs         *command_attrs)
401 {
402     CommandSource *source;
403 
404     if (connection_manager == NULL)
405         g_error ("command_source_new passed NULL ConnectionManager");
406     g_object_ref (connection_manager);
407     source = COMMAND_SOURCE (g_object_new (TYPE_COMMAND_SOURCE,
408                                              "command-attrs", command_attrs,
409                                              "connection-manager", connection_manager,
410                                              NULL));
411     g_signal_connect (connection_manager,
412                       "new-connection",
413                       (GCallback) command_source_on_new_connection,
414                       source);
415     return source;
416 }
417