1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2013-2014 Intel Corporation.
8 * Contact: Imran Zaman <imran.zaman@intel.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 #include "gsignond/gsignond-log.h"
29 #include "gsignond/gsignond-error.h"
30 #include "gsignond/gsignond-plugin-interface.h"
31 #include "common/gsignond-pipe-stream.h"
32 #include "daemon/dbus/gsignond-dbus.h"
33 #include "gsignond-plugin-remote-private.h"
34 #include "gsignond-plugin-remote.h"
45 gsignond_plugin_remote_interface_init (
46 GSignondPluginInterface *iface);
48 G_DEFINE_TYPE_WITH_CODE (GSignondPluginRemote, gsignond_plugin_remote,
49 G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GSIGNOND_TYPE_PLUGIN,
50 gsignond_plugin_remote_interface_init));
52 #define GSIGNOND_PLUGIN_REMOTE_GET_PRIV(obj) \
53 G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_PLUGIN_REMOTE, \
54 GSignondPluginRemotePrivate)
62 g_spawn_close_pid (pid);
64 GSignondPluginRemote *plugin = GSIGNOND_PLUGIN_REMOTE (data);
66 DBG ("Plugind(%p) with pid (%d) closed with status %d", plugin, pid,
69 plugin->priv->is_plugind_up = FALSE;
74 gsignond_plugin_remote_set_property (
80 switch (property_id) {
82 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
87 gsignond_plugin_remote_get_property (
93 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (object);
95 switch (property_id) {
97 g_value_set_string (value,
98 gsignond_dbus_remote_plugin_v1_get_method(self->priv->dbus_plugin_proxy));
101 case PROP_MECHANISMS: {
102 g_value_set_boxed (value,
103 gsignond_dbus_remote_plugin_v1_get_mechanisms(self->priv->dbus_plugin_proxy));
107 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
112 static gboolean _check_child_exited(GSignondPluginRemote *self)
114 if (kill (self->priv->cpid, 0) == 0) {
115 WARN ("Plugind has to be killed with SIGKILL");
116 kill (self->priv->cpid, SIGKILL);
122 gsignond_plugin_remote_dispose (GObject *object)
124 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (object);
126 if (self->priv->cpid > 0 && self->priv->is_plugind_up) {
127 DBG ("Send SIGTERM to Plugind");
128 kill (self->priv->cpid, SIGTERM);
129 guint check_id = g_timeout_add(1000, (GSourceFunc)_check_child_exited, self);
130 while (self->priv->is_plugind_up)
131 g_main_context_iteration(NULL, TRUE);
132 g_source_remove(check_id);
133 DBG ("Plugind DESTROYED");
135 self->priv->cpid = 0;
137 if (self->priv->child_watch_id > 0) {
138 g_source_remove (self->priv->child_watch_id);
139 self->priv->child_watch_id = 0;
142 if (self->priv->connection) {
143 g_object_unref (self->priv->connection);
144 self->priv->connection = NULL;
147 if (self->priv->dbus_plugin_proxy) {
148 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
149 self->priv->signal_response);
150 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
151 self->priv->signal_response_final);
152 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
153 self->priv->signal_store);
154 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
155 self->priv->signal_error);
156 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
157 self->priv->signal_user_action_required);
158 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
159 self->priv->signal_refreshed);
160 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
161 self->priv->signal_status_changed);
162 g_object_unref (self->priv->dbus_plugin_proxy);
163 self->priv->dbus_plugin_proxy = NULL;
166 G_OBJECT_CLASS (gsignond_plugin_remote_parent_class)->dispose (object);
170 gsignond_plugin_remote_finalize (GObject *object)
172 //GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (object);
174 G_OBJECT_CLASS (gsignond_plugin_remote_parent_class)->finalize (object);
178 gsignond_plugin_remote_class_init (GSignondPluginRemoteClass *klass)
180 GObjectClass* object_class = G_OBJECT_CLASS (klass);
182 g_type_class_add_private (object_class,
183 sizeof (GSignondPluginRemotePrivate));
185 object_class->get_property = gsignond_plugin_remote_get_property;
186 object_class->set_property = gsignond_plugin_remote_set_property;
187 object_class->dispose = gsignond_plugin_remote_dispose;
188 object_class->finalize = gsignond_plugin_remote_finalize;
190 g_object_class_override_property (object_class, PROP_TYPE, "type");
191 g_object_class_override_property (object_class, PROP_MECHANISMS,
197 gsignond_plugin_remote_init (GSignondPluginRemote *self)
199 self->priv = GSIGNOND_PLUGIN_REMOTE_GET_PRIV(self);
201 self->priv->connection = NULL;
202 self->priv->dbus_plugin_proxy = NULL;
203 self->priv->cpid = 0;
205 self->priv->child_watch_id = 0;
207 self->priv->is_plugind_up = FALSE;
216 GError *error = NULL;
217 GSignondDbusRemotePluginV1 *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN_V1 (object);
218 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
220 gsignond_dbus_remote_plugin_v1_call_cancel_finish (proxy, res, &error);
222 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
223 g_error_free (error);
228 gsignond_plugin_remote_cancel (
229 GSignondPlugin *plugin)
231 g_return_if_fail (plugin && GSIGNOND_IS_PLUGIN_REMOTE (plugin));
232 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
234 gsignond_dbus_remote_plugin_v1_call_cancel (
235 self->priv->dbus_plugin_proxy, NULL, _cancel_async_cb, self);
239 _request_initial_async_cb (
244 GError *error = NULL;
245 GSignondDbusRemotePluginV1 *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN_V1 (object);
246 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
247 gsignond_dbus_remote_plugin_v1_call_request_initial_finish (proxy,
250 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
251 g_error_free (error);
256 gsignond_plugin_remote_request_initial (
257 GSignondPlugin *plugin,
258 GSignondSessionData *session_data,
259 GSignondDictionary *identity_method_cache,
260 const gchar *mechanism)
262 g_return_if_fail (session_data && plugin &&
263 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
264 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
266 GVariant *data = gsignond_dictionary_to_variant (session_data);
268 if (identity_method_cache)
269 cache = gsignond_dictionary_to_variant (identity_method_cache);
271 GSignondDictionary* empty_cache = gsignond_dictionary_new();
272 cache = gsignond_dictionary_to_variant (empty_cache);
273 gsignond_dictionary_unref(empty_cache);
275 gsignond_dbus_remote_plugin_v1_call_request_initial (
276 self->priv->dbus_plugin_proxy, data, cache, mechanism, NULL,
277 _request_initial_async_cb, self);
286 GError *error = NULL;
287 GSignondDbusRemotePluginV1 *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN_V1 (object);
288 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
290 gsignond_dbus_remote_plugin_v1_call_request_finish (proxy, res, &error);
292 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
293 g_error_free (error);
298 gsignond_plugin_remote_request (
299 GSignondPlugin *plugin,
300 GSignondSessionData *session_data)
302 g_return_if_fail (session_data && plugin &&
303 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
304 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
306 GVariant *data = gsignond_dictionary_to_variant (session_data);
307 gsignond_dbus_remote_plugin_v1_call_request (
308 self->priv->dbus_plugin_proxy, data, NULL, _request_async_cb, self);
312 _user_action_finished_async_cb (
317 GError *error = NULL;
318 GSignondDbusRemotePluginV1 *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN_V1 (object);
319 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
321 gsignond_dbus_remote_plugin_v1_call_user_action_finished_finish (proxy,
324 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
325 g_error_free (error);
330 gsignond_plugin_remote_user_action_finished (
331 GSignondPlugin *plugin,
332 GSignondSignonuiData *signonui_data)
334 g_return_if_fail (signonui_data && plugin &&
335 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
336 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
338 GVariant *data = gsignond_dictionary_to_variant (signonui_data);
339 gsignond_dbus_remote_plugin_v1_call_user_action_finished (
340 self->priv->dbus_plugin_proxy, data, NULL,
341 _user_action_finished_async_cb, self);
350 GError *error = NULL;
351 GSignondDbusRemotePluginV1 *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN_V1 (object);
352 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
354 gsignond_dbus_remote_plugin_v1_call_refresh_finish (proxy, res, &error);
356 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
357 g_error_free (error);
362 gsignond_plugin_remote_refresh (
363 GSignondPlugin *plugin,
364 GSignondSignonuiData *signonui_data)
366 g_return_if_fail (signonui_data && plugin &&
367 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
368 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
370 GVariant *data = gsignond_dictionary_to_variant (signonui_data);
371 gsignond_dbus_remote_plugin_v1_call_refresh (
372 self->priv->dbus_plugin_proxy, data, NULL, _refresh_async_cb, self);
376 gsignond_plugin_remote_interface_init (GSignondPluginInterface *iface)
378 iface->cancel = gsignond_plugin_remote_cancel;
379 iface->request_initial = gsignond_plugin_remote_request_initial;
380 iface->request = gsignond_plugin_remote_request;
381 iface->user_action_finished = gsignond_plugin_remote_user_action_finished;
382 iface->refresh = gsignond_plugin_remote_refresh;
387 GSignondPluginRemote *self,
388 GVariant *session_data,
391 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
393 GSignondSessionData *data = (GSignondSessionData *)
394 gsignond_dictionary_new_from_variant (session_data);
395 gsignond_plugin_response (GSIGNOND_PLUGIN(self), data);
396 gsignond_dictionary_unref (data);
401 GSignondPluginRemote *self,
402 GVariant *session_data,
405 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
407 GSignondSessionData *data = (GSignondSessionData *)
408 gsignond_dictionary_new_from_variant (session_data);
409 gsignond_plugin_response_final (GSIGNOND_PLUGIN(self), data);
410 gsignond_dictionary_unref (data);
415 GSignondPluginRemote *self,
416 GVariant *session_data,
419 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
421 GSignondSessionData *data = (GSignondSessionData *)
422 gsignond_dictionary_new_from_variant (session_data);
423 gsignond_plugin_store (GSIGNOND_PLUGIN(self), data);
424 gsignond_dictionary_unref (data);
429 GSignondPluginRemote *self,
433 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
434 GError *gerror = gsignond_error_new_from_variant (error);
435 gsignond_plugin_error (GSIGNOND_PLUGIN(self), gerror);
436 g_error_free (gerror);
440 _user_action_required_cb (
441 GSignondPluginRemote *self,
445 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
447 GSignondSignonuiData *data = (GSignondSignonuiData *)
448 gsignond_dictionary_new_from_variant (ui_data);
449 gsignond_plugin_user_action_required (GSIGNOND_PLUGIN(self), data);
450 gsignond_dictionary_unref (data);
455 GSignondPluginRemote *self,
459 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
461 GSignondSignonuiData *data = (GSignondSignonuiData *)
462 gsignond_dictionary_new_from_variant (ui_data);
463 gsignond_plugin_refreshed (GSIGNOND_PLUGIN(self), data);
464 gsignond_dictionary_unref (data);
469 GSignondPluginRemote *self,
474 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
476 gsignond_plugin_status_changed (GSIGNOND_PLUGIN(self),
477 (GSignondPluginState)status, message);
480 GSignondPluginRemote *
481 gsignond_plugin_remote_new (
482 const gchar *loader_path,
483 const gchar *plugin_type)
485 GError *error = NULL;
488 gint cin_fd, cout_fd;
489 GSignondPluginRemote *plugin = NULL;
490 GSignondPipeStream *stream = NULL;
491 gboolean ret = FALSE;
493 /* This guarantees that writes to a pipe will never cause
494 * a process terminanation via SIGPIPE, and instead a proper
495 * error will be returned */
496 signal(SIGPIPE, SIG_IGN);
498 /* Spawn child process */
499 argv = g_new0 (gchar *, 2 + 1);
500 argv[0] = g_strdup(loader_path);
501 argv[1] = g_strdup_printf("--load-plugin=%s",plugin_type);
502 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
503 G_SPAWN_DO_NOT_REAP_CHILD, NULL,
504 NULL, &cpid, &cin_fd, &cout_fd, NULL, &error);
506 if (ret == FALSE || (kill(cpid, 0) != 0)) {
507 DBG ("failed to start plugind: error %s(%d)",
508 error ? error->message : "(null)", ret);
509 if (error) g_error_free (error);
513 /* Create dbus plugin object */
514 plugin = GSIGNOND_PLUGIN_REMOTE (g_object_new (GSIGNOND_TYPE_PLUGIN_REMOTE,
517 plugin->priv->child_watch_id = g_child_watch_add (cpid,
518 (GChildWatchFunc)_on_child_down_cb, plugin);
519 plugin->priv->cpid = cpid;
520 plugin->priv->is_plugind_up = TRUE;
522 /* Create dbus connection */
523 stream = gsignond_pipe_stream_new (cout_fd, cin_fd, TRUE);
524 plugin->priv->connection = g_dbus_connection_new_sync (G_IO_STREAM (stream),
525 NULL, G_DBUS_CONNECTION_FLAGS_NONE, NULL, NULL, NULL);
526 g_object_unref (stream);
528 /* Create dbus proxy */
529 plugin->priv->dbus_plugin_proxy =
530 gsignond_dbus_remote_plugin_v1_proxy_new_sync (
531 plugin->priv->connection,
532 G_DBUS_PROXY_FLAGS_NONE,
534 GSIGNOND_PLUGIN_OBJECTPATH,
538 DBG ("Failed to register object: %s", error->message);
539 g_error_free (error);
540 g_object_unref (plugin);
543 DBG("'%s' object exported(%p)", GSIGNOND_PLUGIN_OBJECTPATH, plugin);
545 plugin->priv->signal_response = g_signal_connect_swapped (
546 plugin->priv->dbus_plugin_proxy, "response",
547 G_CALLBACK (_response_cb), plugin);
548 plugin->priv->signal_response_final = g_signal_connect_swapped (
549 plugin->priv->dbus_plugin_proxy, "response-final",
550 G_CALLBACK(_response_final_cb), plugin);
551 plugin->priv->signal_store = g_signal_connect_swapped (
552 plugin->priv->dbus_plugin_proxy, "store",
553 G_CALLBACK(_store_cb), plugin);
554 plugin->priv->signal_error = g_signal_connect_swapped (
555 plugin->priv->dbus_plugin_proxy, "error",
556 G_CALLBACK(_error_cb), plugin);
557 plugin->priv->signal_user_action_required = g_signal_connect_swapped (
558 plugin->priv->dbus_plugin_proxy, "user-action-required",
559 G_CALLBACK(_user_action_required_cb), plugin);
560 plugin->priv->signal_refreshed = g_signal_connect_swapped (
561 plugin->priv->dbus_plugin_proxy, "refreshed",
562 G_CALLBACK(_refreshed_cb), plugin);
563 plugin->priv->signal_status_changed = g_signal_connect_swapped (
564 plugin->priv->dbus_plugin_proxy, "status-changed",
565 G_CALLBACK(_status_changed_cb), plugin);