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

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2014 Stef 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 "gkd-ssh-agent-preload.h"
      27              : #include "gkd-ssh-agent-util.h"
      28              : 
      29              : #include "egg/egg-file-tracker.h"
      30              : #include <string.h>
      31              : 
      32              : enum {
      33              :         PROP_0,
      34              :         PROP_PATH
      35              : };
      36              : 
      37              : struct _GkdSshAgentPreload
      38              : {
      39              :         GObject object;
      40              : 
      41              :         gchar *path;
      42              :         GHashTable *keys_by_public_filename;
      43              :         GHashTable *keys_by_public_key;
      44              :         EggFileTracker *file_tracker;
      45              :         GMutex lock;
      46              : };
      47              : 
      48            0 : G_DEFINE_TYPE (GkdSshAgentPreload, gkd_ssh_agent_preload, G_TYPE_OBJECT);
      49              : 
      50              : void
      51            0 : gkd_ssh_agent_key_info_free (gpointer boxed)
      52              : {
      53            0 :         GkdSshAgentKeyInfo *info = boxed;
      54            0 :         if (!info)
      55            0 :                 return;
      56            0 :         g_bytes_unref (info->public_key);
      57            0 :         g_free (info->comment);
      58            0 :         g_free (info->filename);
      59            0 :         g_free (info);
      60              : }
      61              : 
      62              : gpointer
      63            0 : gkd_ssh_agent_key_info_copy (gpointer boxed)
      64              : {
      65            0 :         GkdSshAgentKeyInfo *info = boxed;
      66            0 :         GkdSshAgentKeyInfo *copy = g_new0 (GkdSshAgentKeyInfo, 1);
      67            0 :         copy->public_key = g_bytes_ref (info->public_key);
      68            0 :         copy->comment = g_strdup (info->comment);
      69            0 :         copy->filename = g_strdup (info->filename);
      70            0 :         return copy;
      71              : }
      72              : 
      73              : static void file_load_inlock   (EggFileTracker *tracker,
      74              :                                 const gchar *path,
      75              :                                 gpointer user_data);
      76              : static void file_remove_inlock (EggFileTracker *tracker,
      77              :                                 const gchar *path,
      78              :                                 gpointer user_data);
      79              : 
      80              : static void
      81            0 : gkd_ssh_agent_preload_init (GkdSshAgentPreload *self)
      82              : {
      83            0 :         g_mutex_init (&self->lock);
      84            0 :         self->keys_by_public_filename = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
      85            0 :         self->keys_by_public_key = g_hash_table_new_full (g_bytes_hash, g_bytes_equal, NULL, gkd_ssh_agent_key_info_free);
      86            0 : }
      87              : 
      88              : static void
      89            0 : gkd_ssh_agent_preload_constructed (GObject *object)
      90              : {
      91            0 :         GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (object);
      92              : 
      93            0 :         self->file_tracker = egg_file_tracker_new (self->path, "*.pub", NULL);
      94            0 :         g_signal_connect (self->file_tracker, "file-added", G_CALLBACK (file_load_inlock), self);
      95            0 :         g_signal_connect (self->file_tracker, "file-removed", G_CALLBACK (file_remove_inlock), self);
      96            0 :         g_signal_connect (self->file_tracker, "file-changed", G_CALLBACK (file_load_inlock), self);
      97              : 
      98            0 :         G_OBJECT_CLASS (gkd_ssh_agent_preload_parent_class)->constructed (object);
      99            0 : }
     100              : 
     101              : static void
     102            0 : gkd_ssh_agent_preload_set_property (GObject *object,
     103              :                                     guint prop_id,
     104              :                                     const GValue *value,
     105              :                                     GParamSpec *pspec)
     106              : {
     107            0 :         GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (object);
     108              : 
     109            0 :         switch (prop_id) {
     110            0 :         case PROP_PATH:
     111            0 :                 self->path = g_value_dup_string (value);
     112            0 :                 break;
     113            0 :         default:
     114            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     115            0 :                 break;
     116              :         }
     117            0 : }
     118              : 
     119              : static void
     120            0 : gkd_ssh_agent_preload_finalize (GObject *object)
     121              : {
     122            0 :         GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (object);
     123              : 
     124            0 :         g_free (self->path);
     125            0 :         g_clear_pointer (&self->keys_by_public_key, (GDestroyNotify) g_hash_table_unref);
     126            0 :         g_clear_pointer (&self->keys_by_public_filename, (GDestroyNotify) g_hash_table_unref);
     127            0 :         g_clear_object (&self->file_tracker);
     128              : 
     129            0 :         g_mutex_clear (&self->lock);
     130              : 
     131            0 :         G_OBJECT_CLASS (gkd_ssh_agent_preload_parent_class)->finalize (object);
     132            0 : }
     133              : 
     134              : static void
     135            0 : gkd_ssh_agent_preload_class_init (GkdSshAgentPreloadClass *klass)
     136              : {
     137            0 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     138            0 :         gobject_class->constructed = gkd_ssh_agent_preload_constructed;
     139            0 :         gobject_class->set_property = gkd_ssh_agent_preload_set_property;
     140            0 :         gobject_class->finalize = gkd_ssh_agent_preload_finalize;
     141            0 :         g_object_class_install_property (gobject_class, PROP_PATH,
     142              :                  g_param_spec_string ("path", "Path", "Path",
     143              :                                       "",
     144              :                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
     145            0 : }
     146              : 
     147              : static gchar *
     148            0 : private_path_for_public (const gchar *public_path)
     149              : {
     150            0 :         if (g_str_has_suffix (public_path, ".pub"))
     151            0 :                 return g_strndup (public_path, strlen (public_path) - 4);
     152              : 
     153            0 :         return NULL;
     154              : }
     155              : 
     156              : static GBytes *
     157            0 : file_get_contents (const gchar *path,
     158              :                    gboolean must_be_present)
     159              : {
     160            0 :         GError *error = NULL;
     161              :         gchar *contents;
     162              :         gsize length;
     163              : 
     164            0 :         if (!g_file_get_contents (path, &contents, &length, &error)) {
     165            0 :                 if (must_be_present || error->code != G_FILE_ERROR_NOENT)
     166            0 :                         g_message ("couldn't read file: %s: %s", path, error->message);
     167            0 :                 g_error_free (error);
     168            0 :                 return NULL;
     169              :         }
     170              : 
     171            0 :         return g_bytes_new_take (contents, length);
     172              : }
     173              : 
     174              : static void
     175            0 : file_remove_inlock (EggFileTracker *tracker,
     176              :                     const gchar *path,
     177              :                     gpointer user_data)
     178              : {
     179            0 :         GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (user_data);
     180              :         GkdSshAgentKeyInfo *info;
     181              : 
     182            0 :         info = g_hash_table_lookup (self->keys_by_public_filename, path);
     183            0 :         if (info) {
     184            0 :                 g_hash_table_remove (self->keys_by_public_filename, path);
     185            0 :                 g_hash_table_remove (self->keys_by_public_key, info->public_key);
     186              :         }
     187            0 : }
     188              : 
     189              : static void
     190            0 : file_load_inlock (EggFileTracker *tracker,
     191              :                   const gchar *path,
     192              :                   gpointer user_data)
     193              : {
     194            0 :         GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (user_data);
     195              :         gchar *private_path;
     196              :         GBytes *private_bytes;
     197              :         GBytes *public_bytes;
     198              :         GBytes *public_key;
     199              :         GkdSshAgentKeyInfo *info;
     200              :         gchar *comment;
     201              : 
     202            0 :         file_remove_inlock (tracker, path, user_data);
     203              : 
     204            0 :         private_path = private_path_for_public (path);
     205              : 
     206            0 :         private_bytes = file_get_contents (private_path, FALSE);
     207            0 :         if (!private_bytes) {
     208            0 :                 g_debug ("no private key present for public key: %s", path);
     209            0 :                 g_free (private_path);
     210            0 :                 return;
     211              :         }
     212              : 
     213            0 :         public_bytes = file_get_contents (path, TRUE);
     214            0 :         if (public_bytes) {
     215            0 :                 public_key = _gkd_ssh_agent_parse_public_key (public_bytes, &comment);
     216            0 :                 if (public_key) {
     217            0 :                         info = g_new0 (GkdSshAgentKeyInfo, 1);
     218            0 :                         info->filename = private_path;
     219            0 :                         private_path = NULL;
     220            0 :                         info->public_key = public_key;
     221            0 :                         info->comment = comment;
     222            0 :                         g_hash_table_replace (self->keys_by_public_filename, g_strdup (path), info);
     223            0 :                         g_hash_table_replace (self->keys_by_public_key, info->public_key, info);
     224              :                 } else {
     225            0 :                         g_message ("failed to parse ssh public key: %s", path);
     226              :                 }
     227              : 
     228            0 :                 g_bytes_unref (public_bytes);
     229              :         }
     230              : 
     231            0 :         g_bytes_unref (private_bytes);
     232            0 :         g_free (private_path);
     233              : }
     234              : 
     235              : GkdSshAgentPreload *
     236            0 : gkd_ssh_agent_preload_new (const gchar *path)
     237              : {
     238            0 :         g_return_val_if_fail (path, NULL);
     239              : 
     240            0 :         return g_object_new (GKD_TYPE_SSH_AGENT_PRELOAD, "path", path, NULL);
     241              : }
     242              : 
     243              : GList *
     244            0 : gkd_ssh_agent_preload_get_keys (GkdSshAgentPreload *self)
     245              : {
     246            0 :         GList *keys = NULL;
     247              :         GHashTableIter iter;
     248              :         GkdSshAgentKeyInfo *info;
     249              : 
     250            0 :         g_mutex_lock (&self->lock);
     251              : 
     252            0 :         egg_file_tracker_refresh (self->file_tracker, FALSE);
     253              : 
     254            0 :         g_hash_table_iter_init (&iter, self->keys_by_public_key);
     255            0 :         while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&info))
     256            0 :                 keys = g_list_prepend (keys, gkd_ssh_agent_key_info_copy (info));
     257              : 
     258            0 :         g_mutex_unlock (&self->lock);
     259              : 
     260            0 :         return keys;
     261              : }
     262              : 
     263              : GkdSshAgentKeyInfo *
     264            0 : gkd_ssh_agent_preload_lookup_by_public_key (GkdSshAgentPreload *self,
     265              :                                             GBytes *public_key)
     266              : {
     267              :         GkdSshAgentKeyInfo *info;
     268              : 
     269            0 :         g_mutex_lock (&self->lock);
     270              : 
     271            0 :         egg_file_tracker_refresh (self->file_tracker, FALSE);
     272              : 
     273            0 :         info = g_hash_table_lookup (self->keys_by_public_key, public_key);
     274            0 :         if (info)
     275            0 :                 info = gkd_ssh_agent_key_info_copy (info);
     276              : 
     277            0 :         g_mutex_unlock (&self->lock);
     278              : 
     279            0 :         return info;
     280              : }
        

Generated by: LCOV version 2.0-1