LCOV - code coverage report
Current view: top level - daemon/ssh-agent - gkd-ssh-agent-service.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 268 0
Test Date: 2024-04-08 13:24:42 Functions: 0.0 % 29 0

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2007 Stefan Walter
       5              :  * Copyright (C) 2018 Red Hat, Inc.
       6              :  *
       7              :  * This program is free software; you can redistribute it and/or modify
       8              :  * it under the terms of the GNU Lesser General Public License as
       9              :  * published by the Free Software Foundation; either version 2.1 of
      10              :  * the License, or (at your option) any later version.
      11              :  *
      12              :  * This program is distributed in the hope that it will be useful, but
      13              :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              :  * Lesser General Public License for more details.
      16              :  *
      17              :  * You should have received a copy of the GNU Lesser General Public
      18              :  * License along with this program; if not, see
      19              :  * <http://www.gnu.org/licenses/>.
      20              :  *
      21              :  * Author: Stef Walter <stef@thewalter.net>, Daiki Ueno
      22              :  */
      23              : 
      24              : #include "config.h"
      25              : 
      26              : #include <gio/gunixsocketaddress.h>
      27              : #include <glib/gstdio.h>
      28              : 
      29              : #include <gcr/gcr-base.h>
      30              : 
      31              : #include "gkd-ssh-agent-service.h"
      32              : #include "gkd-ssh-agent-preload.h"
      33              : #include "gkd-ssh-agent-private.h"
      34              : #include "gkd-ssh-agent-process.h"
      35              : #include "gkd-ssh-agent-util.h"
      36              : #include "daemon/login/gkd-login-interaction.h"
      37              : 
      38              : #include "egg/egg-buffer.h"
      39              : #include "egg/egg-error.h"
      40              : #include "egg/egg-secure-memory.h"
      41              : 
      42              : #include <glib/gi18n-lib.h>
      43              : 
      44            0 : EGG_SECURE_DECLARE (ssh_agent);
      45              : 
      46              : typedef gboolean (*GkdSshAgentOperation) (GkdSshAgentService *agent, GSocketConnection *connection, EggBuffer *req, EggBuffer *resp, GCancellable *cancellable, GError **error);
      47              : static const GkdSshAgentOperation operations[GKD_SSH_OP_MAX];
      48              : 
      49              : enum {
      50              :         PROP_0,
      51              :         PROP_PATH,
      52              :         PROP_INTERACTION,
      53              :         PROP_PRELOAD
      54              : };
      55              : 
      56              : struct _GkdSshAgentService
      57              : {
      58              :         GObject object;
      59              :         gchar *path;
      60              :         GTlsInteraction *interaction;
      61              :         GkdSshAgentPreload *preload;
      62              :         GkdSshAgentProcess *process;
      63              :         GSocketAddress *address;
      64              :         GSocketListener *listener;
      65              :         GHashTable *keys;
      66              :         GMutex lock;
      67              :         GCancellable *cancellable;
      68              : };
      69              : 
      70            0 : G_DEFINE_TYPE (GkdSshAgentService, gkd_ssh_agent_service, G_TYPE_OBJECT);
      71              : 
      72              : static void
      73            0 : gkd_ssh_agent_service_init (GkdSshAgentService *self)
      74              : {
      75            0 :         self->keys = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
      76              :                                             (GDestroyNotify)g_bytes_unref, NULL);
      77            0 :         g_mutex_init (&self->lock);
      78            0 : }
      79              : 
      80              : static void
      81            0 : gkd_ssh_agent_service_constructed (GObject *object)
      82              : {
      83            0 :         GkdSshAgentService *self = GKD_SSH_AGENT_SERVICE (object);
      84              :         gchar *path;
      85              : 
      86            0 :         path = g_strdup_printf ("%s/.ssh", self->path);
      87            0 :         self->process = gkd_ssh_agent_process_new (path);
      88            0 :         g_free (path);
      89              : 
      90            0 :         self->listener = G_SOCKET_LISTENER (g_threaded_socket_service_new (-1));
      91            0 :         self->cancellable = g_cancellable_new ();
      92              : 
      93            0 :         G_OBJECT_CLASS (gkd_ssh_agent_service_parent_class)->constructed (object);
      94            0 : }
      95              : 
      96              : static void
      97            0 : gkd_ssh_agent_service_set_property (GObject *object,
      98              :                             guint prop_id,
      99              :                             const GValue *value,
     100              :                             GParamSpec *pspec)
     101              : {
     102            0 :         GkdSshAgentService *self = GKD_SSH_AGENT_SERVICE (object);
     103              : 
     104            0 :         switch (prop_id) {
     105            0 :         case PROP_PATH:
     106            0 :                 self->path = g_value_dup_string (value);
     107            0 :                 break;
     108            0 :         case PROP_INTERACTION:
     109            0 :                 self->interaction = g_value_dup_object (value);
     110            0 :                 break;
     111            0 :         case PROP_PRELOAD:
     112            0 :                 self->preload = g_value_dup_object (value);
     113            0 :                 break;
     114            0 :         default:
     115            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     116            0 :                 break;
     117              :         }
     118            0 : }
     119              : 
     120              : static void
     121            0 : gkd_ssh_agent_service_finalize (GObject *object)
     122              : {
     123            0 :         GkdSshAgentService *self = GKD_SSH_AGENT_SERVICE (object);
     124              : 
     125            0 :         g_free (self->path);
     126            0 :         g_object_unref (self->interaction);
     127            0 :         g_object_unref (self->preload);
     128              : 
     129            0 :         g_object_unref (self->process);
     130            0 :         g_object_unref (self->listener);
     131            0 :         g_clear_object (&self->address);
     132            0 :         g_mutex_clear (&self->lock);
     133            0 :         g_hash_table_unref (self->keys);
     134            0 :         g_object_unref (self->cancellable);
     135              : 
     136            0 :         G_OBJECT_CLASS (gkd_ssh_agent_service_parent_class)->finalize (object);
     137            0 : }
     138              : 
     139              : static void
     140            0 : gkd_ssh_agent_service_class_init (GkdSshAgentServiceClass *klass)
     141              : {
     142            0 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     143            0 :         gobject_class->constructed = gkd_ssh_agent_service_constructed;
     144            0 :         gobject_class->set_property = gkd_ssh_agent_service_set_property;
     145            0 :         gobject_class->finalize = gkd_ssh_agent_service_finalize;
     146            0 :         g_object_class_install_property (gobject_class, PROP_PATH,
     147              :                  g_param_spec_string ("path", "Path", "Path",
     148              :                                       "",
     149              :                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
     150            0 :         g_object_class_install_property (gobject_class, PROP_INTERACTION,
     151              :                  g_param_spec_object ("interaction", "Interaction", "Interaction",
     152              :                                       G_TYPE_TLS_INTERACTION,
     153              :                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
     154            0 :         g_object_class_install_property (gobject_class, PROP_PRELOAD,
     155              :                  g_param_spec_object ("preload", "Preload", "Preload",
     156              :                                       GKD_TYPE_SSH_AGENT_PRELOAD,
     157              :                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
     158            0 : }
     159              : 
     160              : static gboolean
     161            0 : relay_request (GkdSshAgentService *self,
     162              :                GSocketConnection *connection,
     163              :                EggBuffer *req,
     164              :                EggBuffer *resp,
     165              :                GCancellable *cancellable,
     166              :                GError **error)
     167              : {
     168            0 :         return _gkd_ssh_agent_call (connection, req, resp, cancellable, error);
     169              : }
     170              : 
     171              : static gboolean
     172            0 : handle_request (GkdSshAgentService *self,
     173              :                 GSocketConnection *connection,
     174              :                 EggBuffer *req,
     175              :                 EggBuffer *resp,
     176              :                 GCancellable *cancellable,
     177              :                 GError **error)
     178              : {
     179              :         GkdSshAgentOperation func;
     180              :         guchar op;
     181              : 
     182            0 :         egg_buffer_reset (resp);
     183            0 :         egg_buffer_add_uint32 (resp, 0);
     184              : 
     185              :         /* Decode the operation; on failure, just pass through */
     186            0 :         if (egg_buffer_get_byte (req, 4, NULL, &op) &&
     187            0 :             op < GKD_SSH_OP_MAX && operations[op] != NULL)
     188            0 :                 func = operations[op];
     189              :         else
     190            0 :                 func = relay_request;
     191              : 
     192            0 :         return func (self, connection, req, resp, cancellable, error);
     193              : }
     194              : 
     195              : static void
     196            0 : add_key (GkdSshAgentService *self,
     197              :          GBytes *key)
     198              : {
     199            0 :         g_mutex_lock (&self->lock);
     200            0 :         g_hash_table_add (self->keys, g_bytes_ref (key));
     201            0 :         g_mutex_unlock (&self->lock);
     202            0 : }
     203              : 
     204              : static void
     205            0 : remove_key (GkdSshAgentService *self,
     206              :             GBytes *key)
     207              : {
     208            0 :         g_mutex_lock (&self->lock);
     209            0 :         g_hash_table_remove (self->keys, key);
     210            0 :         g_mutex_unlock (&self->lock);
     211            0 : }
     212              : 
     213              : static void
     214            0 : clear_keys (GkdSshAgentService *self)
     215              : {
     216            0 :         g_mutex_lock (&self->lock);
     217            0 :         g_hash_table_remove_all (self->keys);
     218            0 :         g_mutex_unlock (&self->lock);
     219            0 : }
     220              : 
     221              : static void
     222            0 : ensure_key (GkdSshAgentService *self,
     223              :                           GBytes *key)
     224              : {
     225              :         GcrSshAskpass *askpass;
     226            0 :         GError *error = NULL;
     227              :         gint status;
     228              :         GkdSshAgentKeyInfo *info;
     229              :         gchar *unique;
     230              :         const gchar *label;
     231              :         GHashTable *fields;
     232              :         GTlsInteraction *interaction;
     233              :         gchar *standard_error;
     234              : 
     235            0 :         gchar *argv[] = {
     236              :                 SSH_ADD,
     237              :                 NULL,
     238              :                 NULL
     239              :         };
     240              : 
     241            0 :         if (gkd_ssh_agent_service_lookup_key (self, key))
     242            0 :                 return;
     243              : 
     244            0 :         info = gkd_ssh_agent_preload_lookup_by_public_key (self->preload, key);
     245            0 :         if (!info)
     246            0 :                 return;
     247              : 
     248            0 :         argv[1] = info->filename;
     249              : 
     250            0 :         fields = g_hash_table_new (g_str_hash, g_str_equal);
     251            0 :         unique = g_strdup_printf ("ssh-store:%s", info->filename);
     252            0 :         g_hash_table_insert (fields, "unique", unique);
     253              : 
     254            0 :         label = info->comment[0] != '\0' ? info->comment : _("Unnamed");
     255              : 
     256            0 :         interaction = gkd_login_interaction_new (self->interaction, NULL, label, fields);
     257            0 :         askpass = gcr_ssh_askpass_new (interaction);
     258            0 :         g_object_unref (interaction);
     259              : 
     260            0 :         if (!g_spawn_sync (NULL, argv, NULL,
     261              :                            G_SPAWN_STDOUT_TO_DEV_NULL,
     262              :                            gcr_ssh_askpass_child_setup, askpass,
     263              :                            NULL, &standard_error, &status, &error)) {
     264            0 :                 g_warning ("couldn't run %s: %s", argv[0], error->message);
     265            0 :                 g_error_free (error);
     266            0 :         } else if (!g_spawn_check_exit_status (status, &error)) {
     267            0 :                 g_message ("the %s command failed: %s", argv[0], error->message);
     268            0 :                 g_printerr ("%s", _gkd_ssh_agent_canon_error (standard_error));
     269            0 :                 g_free (standard_error);
     270              :         } else {
     271            0 :                 add_key (self, key);
     272              :         }
     273              : 
     274            0 :         g_hash_table_unref (fields);
     275            0 :         g_free (unique);
     276            0 :         gkd_ssh_agent_key_info_free (info);
     277            0 :         g_object_unref (askpass);
     278              : }
     279              : 
     280              : static gboolean
     281            0 : on_run (GThreadedSocketService *service,
     282              :         GSocketConnection *connection,
     283              :         GObject *source_object,
     284              :         gpointer user_data)
     285              : {
     286            0 :         GkdSshAgentService *self = g_object_ref (GKD_SSH_AGENT_SERVICE (user_data));
     287              :         EggBuffer req;
     288              :         EggBuffer resp;
     289              :         GError *error;
     290              :         GSocketConnection *agent_connection;
     291              :         gboolean ret;
     292              : 
     293            0 :         egg_buffer_init_full (&req, 128, egg_secure_realloc);
     294            0 :         egg_buffer_init_full (&resp, 128, (EggBufferAllocator)g_realloc);
     295              : 
     296            0 :         error = NULL;
     297            0 :         agent_connection = gkd_ssh_agent_process_connect (self->process, self->cancellable, &error);
     298            0 :         if (!agent_connection) {
     299            0 :                 g_warning ("couldn't connect to ssh-agent: %s", error->message);
     300            0 :                 g_error_free (error);
     301            0 :                 goto out;
     302              :         }
     303              : 
     304              :         while (TRUE) {
     305              :                 /* Read in the request */
     306            0 :                 error = NULL;
     307            0 :                 if (!_gkd_ssh_agent_read_packet (connection, &req, self->cancellable, &error)) {
     308            0 :                         if (error->code != G_IO_ERROR_CANCELLED &&
     309            0 :                             error->code != G_IO_ERROR_CONNECTION_CLOSED)
     310            0 :                                 g_message ("couldn't read from client: %s", error->message);
     311            0 :                         g_error_free (error);
     312            0 :                         break;
     313              :                 }
     314              : 
     315              :                 /* Handle the request */
     316            0 :                 error = NULL;
     317            0 :                 while (!(ret = handle_request (self, agent_connection, &req, &resp, self->cancellable, &error))) {
     318            0 :                         if (gkd_ssh_agent_process_get_pid (self->process) != 0) {
     319            0 :                                 if (error->code != G_IO_ERROR_CANCELLED)
     320            0 :                                         g_message ("couldn't handle client request: %s", error->message);
     321            0 :                                 g_error_free (error);
     322            0 :                                 goto out;
     323              :                         }
     324              : 
     325              :                         /* Reconnect to the ssh-agent */
     326            0 :                         g_clear_object (&agent_connection);
     327            0 :                         g_clear_error (&error);
     328            0 :                         agent_connection = gkd_ssh_agent_process_connect (self->process, self->cancellable, &error);
     329            0 :                         if (!agent_connection) {
     330            0 :                                 if (error->code != G_IO_ERROR_CANCELLED)
     331            0 :                                         g_message ("couldn't connect to ssh-agent: %s", error->message);
     332            0 :                                 g_error_free (error);
     333            0 :                                 goto out;
     334              :                         }
     335              :                 }
     336              : 
     337              :                 /* Write the reply back out */
     338            0 :                 error = NULL;
     339            0 :                 if (!_gkd_ssh_agent_write_packet (connection, &resp, self->cancellable, &error)) {
     340            0 :                         if (error->code != G_IO_ERROR_CANCELLED)
     341            0 :                                 g_message ("couldn't write to client: %s", error->message);
     342            0 :                         g_error_free (error);
     343            0 :                         break;
     344              :                 }
     345              :         }
     346              : 
     347            0 :  out:
     348            0 :         egg_buffer_uninit (&req);
     349            0 :         egg_buffer_uninit (&resp);
     350              : 
     351            0 :         g_object_unref (agent_connection);
     352            0 :         g_object_unref (self);
     353              : 
     354            0 :         return TRUE;
     355              : }
     356              : 
     357              : static void
     358            0 : on_closed (GkdSshAgentProcess *process,
     359              :            gpointer user_data)
     360              : {
     361            0 :         GkdSshAgentService *self = GKD_SSH_AGENT_SERVICE (user_data);
     362            0 :         clear_keys (self);
     363            0 : }
     364              : 
     365              : gboolean
     366            0 : gkd_ssh_agent_service_start (GkdSshAgentService *self)
     367              : {
     368              :         gchar *path;
     369              :         GError *error;
     370              : 
     371            0 :         path = g_strdup_printf ("%s/ssh", self->path);
     372            0 :         g_unlink (path);
     373            0 :         self->address = g_unix_socket_address_new (path);
     374            0 :         g_free (path);
     375              : 
     376            0 :         error = NULL;
     377            0 :         if (!g_socket_listener_add_address (self->listener,
     378              :                                             self->address,
     379              :                                             G_SOCKET_TYPE_STREAM,
     380              :                                             G_SOCKET_PROTOCOL_DEFAULT,
     381              :                                             NULL,
     382              :                                             NULL,
     383              :                                             &error)) {
     384            0 :                 g_warning ("couldn't listen on %s: %s",
     385              :                            g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (self->address)),
     386              :                            error->message);
     387            0 :                 g_error_free (error);
     388            0 :                 return FALSE;
     389              :         }
     390              : 
     391            0 :         g_signal_connect (self->listener, "run", G_CALLBACK (on_run), self);
     392            0 :         g_signal_connect (self->process, "closed", G_CALLBACK (on_closed), self);
     393              : 
     394            0 :         g_setenv ("SSH_AUTH_SOCK", g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (self->address)), TRUE);
     395              : 
     396            0 :         g_socket_service_start (G_SOCKET_SERVICE (self->listener));
     397              : 
     398            0 :         return TRUE;
     399              : }
     400              : 
     401              : void
     402            0 : gkd_ssh_agent_service_stop (GkdSshAgentService *self)
     403              : {
     404            0 :         if (self->address)
     405            0 :                 g_unlink (g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (self->address)));
     406              : 
     407            0 :         g_cancellable_cancel (self->cancellable);
     408            0 :         g_socket_service_stop (G_SOCKET_SERVICE (self->listener));
     409            0 : }
     410              : 
     411              : GkdSshAgentService *
     412            0 : gkd_ssh_agent_service_new (const gchar *path,
     413              :                    GTlsInteraction *interaction,
     414              :                    GkdSshAgentPreload *preload)
     415              : {
     416            0 :         g_return_val_if_fail (path, NULL);
     417            0 :         g_return_val_if_fail (interaction, NULL);
     418            0 :         g_return_val_if_fail (preload, NULL);
     419              : 
     420            0 :         return g_object_new (GKD_TYPE_SSH_AGENT_SERVICE,
     421              :                              "path", path,
     422              :                              "interaction", interaction,
     423              :                              "preload", preload,
     424              :                              NULL);
     425              : }
     426              : 
     427              : GkdSshAgentPreload *
     428            0 : gkd_ssh_agent_service_get_preload (GkdSshAgentService *self)
     429              : {
     430            0 :         return self->preload;
     431              : }
     432              : 
     433              : GkdSshAgentProcess *
     434            0 : gkd_ssh_agent_service_get_process (GkdSshAgentService *self)
     435              : {
     436            0 :         return self->process;
     437              : }
     438              : 
     439              : gboolean
     440            0 : gkd_ssh_agent_service_lookup_key (GkdSshAgentService *self,
     441              :                           GBytes *key)
     442              : {
     443              :         gboolean ret;
     444            0 :         g_mutex_lock (&self->lock);
     445            0 :         ret = g_hash_table_contains (self->keys, key);
     446            0 :         g_mutex_unlock (&self->lock);
     447            0 :         return ret;
     448              : }
     449              : 
     450              : /* ---------------------------------------------------------------------------- */
     451              : 
     452              : static gboolean
     453            0 : op_add_identity (GkdSshAgentService *self,
     454              :                  GSocketConnection *connection,
     455              :                  EggBuffer *req,
     456              :                  EggBuffer *resp,
     457              :                  GCancellable *cancellable,
     458              :                  GError **error)
     459              : {
     460              :         const guchar *blob;
     461            0 :         gsize offset = 5;
     462              :         gsize length;
     463            0 :         GBytes *key = NULL;
     464              :         gboolean ret;
     465              : 
     466              :         /* If parsing the request fails, just pass through */
     467            0 :         ret = egg_buffer_get_byte_array (req, offset, &offset, &blob, &length);
     468            0 :         if (ret)
     469            0 :                 key = g_bytes_new (blob, length);
     470              :         else
     471            0 :                 g_message ("got unparseable add identity request for ssh-agent");
     472              : 
     473            0 :         ret = relay_request (self, connection, req, resp, cancellable, error);
     474            0 :         if (key) {
     475            0 :                 if (ret)
     476            0 :                         add_key (self, key);
     477            0 :                 g_bytes_unref (key);
     478              :         }
     479              : 
     480            0 :         return ret;
     481              : }
     482              : 
     483              : static GHashTable *
     484            0 : parse_identities_answer (EggBuffer *resp)
     485              : {
     486              :         GHashTable *answer;
     487              :         const guchar *blob;
     488              :         gchar *comment;
     489              :         gsize length;
     490            0 :         gsize offset = 4;
     491              :         guint32 count;
     492              :         guchar op;
     493              :         guint32 i;
     494              : 
     495            0 :         if (!egg_buffer_get_byte (resp, offset, &offset, &op) ||
     496            0 :             op != GKD_SSH_RES_IDENTITIES_ANSWER ||
     497            0 :             !egg_buffer_get_uint32 (resp, offset, &offset, &count)) {
     498            0 :                 g_message ("got unexpected response back from ssh-agent when requesting identities");
     499            0 :                 return NULL;
     500              :         }
     501              : 
     502            0 :         answer = g_hash_table_new_full (g_bytes_hash, g_bytes_equal, (GDestroyNotify)g_bytes_unref, g_free);
     503              : 
     504            0 :         for (i = 0; i < count; i++) {
     505            0 :                 if (!egg_buffer_get_byte_array (resp, offset, &offset, &blob, &length) ||
     506            0 :                     !egg_buffer_get_string (resp, offset, &offset, &comment, g_realloc)) {
     507            0 :                         g_message ("got unparseable response back from ssh-agent when requesting identities");
     508            0 :                         g_hash_table_unref (answer);
     509            0 :                         return NULL;
     510              :                 }
     511            0 :                 g_hash_table_insert (answer, g_bytes_new (blob, length), comment);
     512              :         }
     513              : 
     514            0 :         return answer;
     515              : }
     516              : 
     517              : 
     518              : static gboolean
     519            0 : op_request_identities (GkdSshAgentService *self,
     520              :                        GSocketConnection *connection,
     521              :                        EggBuffer *req,
     522              :                        EggBuffer *resp,
     523              :                        GCancellable *cancellable,
     524              :                        GError **error)
     525              : {
     526              :         GHashTable *answer;
     527              :         GHashTableIter iter;
     528              :         gsize length;
     529              :         guint32 added;
     530              :         GBytes *key;
     531              :         GList *keys;
     532              :         GList *l;
     533              :         GkdSshAgentPreload *preload;
     534              : 
     535            0 :         if (!relay_request (self, connection, req, resp, cancellable, error))
     536            0 :                 return FALSE;
     537              : 
     538              :         /* Parse all the keys, and if it fails, just fall through */
     539            0 :         answer = parse_identities_answer (resp);
     540            0 :         if (!answer)
     541            0 :                 return TRUE;
     542              : 
     543            0 :         g_hash_table_iter_init (&iter, answer);
     544            0 :         while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
     545            0 :                 add_key (self, key);
     546              : 
     547            0 :         added = 0;
     548              : 
     549              :         /* Add any preloaded keys not already in answer */
     550            0 :         preload = gkd_ssh_agent_service_get_preload (self);
     551            0 :         keys = gkd_ssh_agent_preload_get_keys (preload);
     552            0 :         for (l = keys; l != NULL; l = g_list_next (l)) {
     553            0 :                 GkdSshAgentKeyInfo *info = l->data;
     554            0 :                 if (!g_hash_table_contains (answer, info->public_key)) {
     555            0 :                         const guchar *blob = g_bytes_get_data (info->public_key, &length);
     556            0 :                         egg_buffer_add_byte_array (resp, blob, length);
     557            0 :                         egg_buffer_add_string (resp, info->comment);
     558            0 :                         added++;
     559              :                 }
     560              :         }
     561              : 
     562            0 :         g_list_free_full (keys, (GDestroyNotify)gkd_ssh_agent_key_info_free);
     563              : 
     564              :         /* Set the correct amount of keys including the ones we added */
     565            0 :         egg_buffer_set_uint32 (resp, 5, added + g_hash_table_size (answer));
     566            0 :         g_hash_table_unref (answer);
     567              : 
     568              :         /* Set the correct total size of the payload */
     569            0 :         egg_buffer_set_uint32 (resp, 0, resp->len - 4);
     570              : 
     571            0 :         return TRUE;
     572              : }
     573              : 
     574              : static gboolean
     575            0 : op_sign_request (GkdSshAgentService *self,
     576              :                  GSocketConnection *connection,
     577              :                  EggBuffer *req,
     578              :                  EggBuffer *resp,
     579              :                  GCancellable *cancellable,
     580              :                  GError **error)
     581              : {
     582              :         const guchar *blob;
     583              :         gsize length;
     584            0 :         gsize offset = 5;
     585              :         GBytes *key;
     586              : 
     587              :         /* If parsing the request fails, just pass through */
     588            0 :         if (egg_buffer_get_byte_array (req, offset, &offset, &blob, &length)) {
     589            0 :                 key = g_bytes_new (blob, length);
     590            0 :                 ensure_key (self, key);
     591            0 :                 g_bytes_unref (key);
     592              :         } else {
     593            0 :                 g_message ("got unparseable sign request for ssh-agent");
     594              :         }
     595              : 
     596            0 :         return relay_request (self, connection, req, resp, cancellable, error);
     597              : }
     598              : 
     599              : static gboolean
     600            0 : op_remove_identity (GkdSshAgentService *self,
     601              :                     GSocketConnection *connection,
     602              :                     EggBuffer *req,
     603              :                     EggBuffer *resp,
     604              :                     GCancellable *cancellable,
     605              :                     GError **error)
     606              : {
     607              :         const guchar *blob;
     608              :         gsize length;
     609            0 :         gsize offset = 5;
     610            0 :         GBytes *key = NULL;
     611              :         gboolean ret;
     612              : 
     613              :         /* If parsing the request fails, just pass through */
     614            0 :         ret = egg_buffer_get_byte_array (req, offset, &offset, &blob, &length);
     615            0 :         if (ret)
     616            0 :                 key = g_bytes_new (blob, length);
     617              :         else
     618            0 :                 g_message ("got unparseable remove request for ssh-agent");
     619              : 
     620              :         /* Call out ssh-agent anyway to make sure that the key is removed */
     621            0 :         ret = relay_request (self, connection, req, resp, cancellable, error);
     622            0 :         if (key) {
     623            0 :                 if (ret)
     624            0 :                         remove_key (self, key);
     625            0 :                 g_bytes_unref (key);
     626              :         }
     627            0 :         return ret;
     628              : }
     629              : 
     630              : static gboolean
     631            0 : op_remove_all_identities (GkdSshAgentService *self,
     632              :                           GSocketConnection *connection,
     633              :                           EggBuffer *req,
     634              :                           EggBuffer *resp,
     635              :                           GCancellable *cancellable,
     636              :                           GError **error)
     637              : {
     638              :         gboolean ret;
     639              : 
     640            0 :         ret = relay_request (self, connection, req, resp, cancellable, error);
     641            0 :         if (ret)
     642            0 :                 clear_keys (self);
     643              : 
     644            0 :         return ret;
     645              : }
     646              : 
     647              : static const GkdSshAgentOperation operations[GKD_SSH_OP_MAX] = {
     648              :         NULL,                                 /* 0 */
     649              :         NULL,                                 /* GKR_SSH_OP_REQUEST_RSA_IDENTITIES */
     650              :         NULL,                                 /* 2 */
     651              :         NULL,                                 /* GKR_SSH_OP_RSA_CHALLENGE */
     652              :         NULL,                                 /* 4 */
     653              :         NULL,                                 /* 5 */
     654              :         NULL,                                 /* 6 */
     655              :         NULL,                                 /* GKR_SSH_OP_ADD_RSA_IDENTITY */
     656              :         NULL,                                 /* GKR_SSH_OP_REMOVE_RSA_IDENTITY */
     657              :         NULL,                                 /* GKR_SSH_OP_REMOVE_ALL_RSA_IDENTITIES */
     658              :         NULL,                                 /* 10 */
     659              :         op_request_identities,                /* GKR_SSH_OP_REQUEST_IDENTITIES */
     660              :         NULL,                                 /* 12 */
     661              :         op_sign_request,                      /* GKR_SSH_OP_SIGN_REQUEST */
     662              :         NULL,                                 /* 14 */
     663              :         NULL,                                 /* 15 */
     664              :         NULL,                                 /* 16 */
     665              :         op_add_identity,                      /* GKR_SSH_OP_ADD_IDENTITY */
     666              :         op_remove_identity,                   /* GKR_SSH_OP_REMOVE_IDENTITY */
     667              :         op_remove_all_identities,             /* GKR_SSH_OP_REMOVE_ALL_IDENTITIES */
     668              :         NULL,                                 /* GKR_SSH_OP_ADD_SMARTCARD_KEY */
     669              :         NULL,                                 /* GKR_SSH_OP_REMOVE_SMARTCARD_KEY */
     670              :         NULL,                                 /* GKR_SSH_OP_LOCK */
     671              :         NULL,                                 /* GKR_SSH_OP_UNLOCK */
     672              :         NULL,                                 /* GKR_SSH_OP_ADD_RSA_ID_CONSTRAINED */
     673              :         op_add_identity,                      /* GKR_SSH_OP_ADD_ID_CONSTRAINED */
     674              :         NULL,                                 /* GKR_SSH_OP_ADD_SMARTCARD_KEY_CONSTRAINED */
     675              : };
        

Generated by: LCOV version 2.0-1