LCOV - code coverage report
Current view: top level - daemon - gkd-main.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 39.5 % 413 163
Test Date: 2024-04-08 13:24:42 Functions: 47.1 % 34 16

            Line data    Source code
       1              : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
       2              : /* gnome-keyring-daemon.c - main keyring daemon code.
       3              : 
       4              :    Copyright (C) 2003 Red Hat, Inc
       5              : 
       6              :    Gnome keyring is free software; you can redistribute it and/or
       7              :    modify it under the terms of the GNU General Public License as
       8              :    published by the Free Software Foundation; either version 2 of the
       9              :    License, or (at your option) any later version.
      10              : 
      11              :    Gnome keyring is distributed in the hope that it will be useful,
      12              :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :    General Public License for more details.
      15              : 
      16              :    You should have received a copy of the GNU General Public License
      17              :    along with this program; if not, write to the Free Software
      18              :    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      19              : 
      20              :    Author: Alexander Larsson <alexl@redhat.com>
      21              :    Author: Stef Walter <stef@memberwebs.com>
      22              : */
      23              : 
      24              : #include "config.h"
      25              : 
      26              : #include "gkd-glue.h"
      27              : #include "gkd-main.h"
      28              : #include "gkd-capability.h"
      29              : #include "gkd-pkcs11.h"
      30              : #include "gkd-util.h"
      31              : 
      32              : #include "control/gkd-control.h"
      33              : 
      34              : #include "dbus/gkd-dbus.h"
      35              : 
      36              : #include "egg/egg-cleanup.h"
      37              : #include "egg/egg-error.h"
      38              : #include "egg/egg-libgcrypt.h"
      39              : #include "egg/egg-secure-memory.h"
      40              : #include "egg/egg-unix-credentials.h"
      41              : 
      42              : #include "login/gkd-login.h"
      43              : 
      44              : #include <errno.h>
      45              : #include <fcntl.h>
      46              : #include <pthread.h>
      47              : #include <stdlib.h>
      48              : #include <stdio.h>
      49              : #include <string.h>
      50              : #include <signal.h>
      51              : #include <locale.h>
      52              : #include <syslog.h>
      53              : #include <unistd.h>
      54              : 
      55              : #include <sys/types.h>
      56              : #include <sys/socket.h>
      57              : #include <sys/un.h>
      58              : #include <sys/stat.h>
      59              : #include <sys/wait.h>
      60              : 
      61              : #include <gio/gunixinputstream.h>
      62              : #include <gio/gunixoutputstream.h>
      63              : #include <glib.h>
      64              : #include <glib/gi18n.h>
      65              : #include <glib-object.h>
      66              : #include <glib-unix.h>
      67              : 
      68              : #include <gcrypt.h>
      69              : 
      70              : /* preset file descriptors */
      71              : #define  STDIN   0
      72              : #define  STDOUT  1
      73              : #define  STDERR  2
      74              : 
      75              : #ifndef HAVE_SOCKLEN_T
      76              : typedef int socklen_t;
      77              : #endif
      78              : 
      79              : #define GKD_COMP_KEYRING    "keyring"
      80              : #define GKD_COMP_PKCS11     "pkcs11"
      81              : #define GKD_COMP_SECRETS    "secrets"
      82              : #define GKD_COMP_SSH        "ssh"
      83              : 
      84            0 : EGG_SECURE_DECLARE (daemon_main);
      85              : 
      86              : /* -----------------------------------------------------------------------------
      87              :  * COMMAND LINE
      88              :  */
      89              : 
      90              : /* All the components to run on startup if not specified on command line */
      91              : #ifdef WITH_SSH
      92              : #       ifdef WITH_GPG
      93              : #               define DEFAULT_COMPONENTS  GKD_COMP_PKCS11 "," GKD_COMP_SECRETS "," GKD_COMP_SSH "," GKD_COMP_GPG
      94              : #       else
      95              : #               define DEFAULT_COMPONENTS  GKD_COMP_PKCS11 "," GKD_COMP_SECRETS "," GKD_COMP_SSH
      96              : #       endif
      97              : #else
      98              : #       ifdef WITH_GPG
      99              : #               define DEFAULT_COMPONENTS  GKD_COMP_PKCS11 "," GKD_COMP_SECRETS  "," GKD_COMP_GPG
     100              : #       else
     101              : #               define DEFAULT_COMPONENTS  GKD_COMP_PKCS11 "," GKD_COMP_SECRETS
     102              : #       endif
     103              : #endif
     104              : 
     105              : /*
     106              :  * If --login is used and then daemon is not initialized within LOGIN_TIMEOUT
     107              :  * seconds, then we exit. See on_login_timeout() below.
     108              :  */
     109              : 
     110              : #define LOGIN_TIMEOUT 120
     111              : 
     112              : static gchar* run_components = DEFAULT_COMPONENTS;
     113              : static gboolean pkcs11_started = FALSE;
     114              : static gboolean secrets_started = FALSE;
     115              : static gboolean dbus_started = FALSE;
     116              : 
     117              : static gboolean run_foreground = FALSE;
     118              : static gboolean run_daemonized = FALSE;
     119              : static gboolean run_version = FALSE;
     120              : static gboolean run_for_login = FALSE;
     121              : static gboolean perform_unlock = FALSE;
     122              : static gboolean run_for_start = FALSE;
     123              : static gboolean run_for_replace = FALSE;
     124              : static gchar* login_password = NULL;
     125              : static gchar* control_directory = NULL;
     126              : static guint timeout_id = 0;
     127              : static gboolean initialization_completed = FALSE;
     128              : static GMainLoop *loop = NULL;
     129              : static int parent_wakeup_fd = -1;
     130              : static GDBusConnection *system_bus_connection = NULL;
     131              : 
     132              : static GOptionEntry option_entries[] = {
     133              :         { "start", 's', 0, G_OPTION_ARG_NONE, &run_for_start,
     134              :           "Start a dameon or initialize an already running daemon." },
     135              :         { "replace", 'r', 0, G_OPTION_ARG_NONE, &run_for_replace,
     136              :           "Replace the daemon for this desktop login environment." },
     137              :         { "foreground", 'f', 0, G_OPTION_ARG_NONE, &run_foreground,
     138              :           "Run in the foreground", NULL },
     139              :         { "daemonize", 'd', 0, G_OPTION_ARG_NONE, &run_daemonized,
     140              :           "Run as a daemon", NULL },
     141              :         { "login", 'l', 0, G_OPTION_ARG_NONE, &run_for_login,
     142              :           "Run by PAM for a user login. Read login password from stdin", NULL },
     143              :         { "unlock", 0, 0, G_OPTION_ARG_NONE, &perform_unlock,
     144              :           "Prompt for login keyring password, or read from stdin", NULL },
     145              :         { "components", 'c', 0, G_OPTION_ARG_STRING, &run_components,
     146              :           "The optional components to run", DEFAULT_COMPONENTS },
     147              :         { "control-directory", 'C', 0, G_OPTION_ARG_FILENAME, &control_directory,
     148              :           "The directory for sockets and control data", NULL },
     149              :         { "version", 'V', 0, G_OPTION_ARG_NONE, &run_version,
     150              :           "Show the version number and exit.", NULL },
     151              :         { NULL }
     152              : };
     153              : 
     154              : static void
     155           27 : parse_arguments (int *argc, char** argv[])
     156              : {
     157           27 :         GError *err = NULL;
     158              :         GOptionContext *context;
     159              : 
     160           27 :         context = g_option_context_new ("- The Gnome Keyring Daemon");
     161           27 :         g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
     162              : 
     163           27 :         if (!g_option_context_parse (context, argc, argv, &err)) {
     164            0 :                 g_printerr ("gnome-keyring-daemon: %s\n", egg_error_message (err));
     165            0 :                 g_clear_error (&err);
     166              :         }
     167              : 
     168           27 :         if (!run_components || !run_components[0]) {
     169            7 :                 run_components = DEFAULT_COMPONENTS;
     170              :         } else {
     171           20 :                 run_components = g_strdup (run_components);
     172           20 :                 egg_cleanup_register (g_free, run_components);
     173              :         }
     174              : 
     175              :         /* Check the arguments */
     176           27 :         if (run_for_login && run_for_start) {
     177            0 :                 g_printerr ("gnome-keyring-daemon: The --start option is incompatible with --login\n");
     178            0 :                 run_for_login = FALSE;
     179              :         }
     180              : 
     181           27 :         if (run_for_login && run_for_replace) {
     182            0 :                 g_printerr ("gnome-keyring-daemon: The --replace option is incompatible with --login\n");
     183            0 :                 run_for_login = FALSE;
     184              :         }
     185              : 
     186           27 :         if (run_for_start && run_for_replace) {
     187            0 :                 g_printerr ("gnome-keyring-daemon: The --replace option is incompatible with --start\n");
     188            0 :                 run_for_start = FALSE;
     189              :         }
     190              : 
     191           27 :         if (run_for_start && perform_unlock) {
     192            0 :                 g_printerr ("gnome-keyring-daemon: The --start option is incompatible with --unlock");
     193            0 :                 perform_unlock = FALSE;
     194              :         }
     195              : 
     196           27 :         if (run_for_login)
     197            0 :                 perform_unlock = TRUE;
     198              : 
     199           27 :         g_option_context_free (context);
     200           27 : }
     201              : 
     202              : /* -----------------------------------------------------------------------------
     203              :  * MEMORY
     204              :  */
     205              : 
     206              : static gboolean do_warning = TRUE;
     207              : #define WARNING  "couldn't allocate secure memory to keep passwords " \
     208              :                  "and or keys from being written to the disk"
     209              : 
     210              : #define ABORTMSG "The GNOME_KEYRING_PARANOID environment variable was set. " \
     211              :                  "Exiting..."
     212              : 
     213              : 
     214              : /*
     215              :  * These are called from gkr-secure-memory.c to provide appropriate
     216              :  * locking for memory between threads
     217              :  */
     218              : 
     219              : G_LOCK_DEFINE_STATIC (memory_mutex);
     220              : 
     221              : static void
     222         2017 : egg_memory_lock (void)
     223              : {
     224         2017 :         G_LOCK (memory_mutex);
     225         2017 : }
     226              : 
     227              : static void
     228         2017 : egg_memory_unlock (void)
     229              : {
     230         2017 :         G_UNLOCK (memory_mutex);
     231         2017 : }
     232              : 
     233              : static void *
     234          357 : egg_memory_fallback (void *p, size_t sz)
     235              : {
     236              :         const gchar *env;
     237              : 
     238              :         /* We were asked to free memory */
     239          357 :         if (!sz) {
     240          354 :                 g_free (p);
     241          354 :                 return NULL;
     242              :         }
     243              : 
     244              :         /* We were asked to allocate */
     245            3 :         if (!p) {
     246            0 :                 if (do_warning) {
     247            0 :                         g_message (WARNING);
     248            0 :                         do_warning = FALSE;
     249              :                 }
     250              : 
     251            0 :                 env = g_getenv ("GNOME_KEYRING_PARANOID");
     252            0 :                 if (env && *env)
     253            0 :                         g_error (ABORTMSG);
     254              : 
     255            0 :                 return g_malloc0 (sz);
     256              :         }
     257              : 
     258              :         /*
     259              :          * Reallocation is a bit of a gray area, as we can be asked
     260              :          * by external libraries (like libgcrypt) to reallocate a
     261              :          * non-secure block into secure memory. We cannot satisfy
     262              :          * this request (as we don't know the size of the original
     263              :          * block) so we just try our best here.
     264              :          */
     265              : 
     266            3 :         return g_realloc (p, sz);
     267              : }
     268              : 
     269              : EGG_SECURE_DEFINE_GLOBALS (egg_memory_lock, egg_memory_unlock, egg_memory_fallback);
     270              : 
     271              : /* -----------------------------------------------------------------------------
     272              :  * LOGS
     273              :  */
     274              : 
     275              : static void
     276          427 : log_handler (const gchar *log_domain, GLogLevelFlags log_level,
     277              :              const gchar *message, gpointer user_data)
     278              : {
     279              :         int level;
     280              : 
     281              :         /* Note that crit and err are the other way around in syslog */
     282              : 
     283          427 :         switch (G_LOG_LEVEL_MASK & log_level) {
     284            0 :         case G_LOG_LEVEL_ERROR:
     285            0 :                 level = LOG_CRIT;
     286            0 :                 break;
     287            0 :         case G_LOG_LEVEL_CRITICAL:
     288            0 :                 level = LOG_ERR;
     289            0 :                 break;
     290            0 :         case G_LOG_LEVEL_WARNING:
     291            0 :                 level = LOG_WARNING;
     292            0 :                 break;
     293            4 :         case G_LOG_LEVEL_MESSAGE:
     294            4 :                 level = LOG_NOTICE;
     295            4 :                 break;
     296            0 :         case G_LOG_LEVEL_INFO:
     297            0 :                 level = LOG_INFO;
     298            0 :                 break;
     299          423 :         case G_LOG_LEVEL_DEBUG:
     300          423 :                 level = -1;
     301          423 :                 break;
     302            0 :         default:
     303            0 :                 level = LOG_ERR;
     304            0 :                 break;
     305              :         }
     306              : 
     307              :         /* Log to syslog first */
     308          427 :         if (level != -1) {
     309            4 :                 if (log_domain)
     310            0 :                         syslog (level, "%s: %s", log_domain, message);
     311              :                 else
     312            4 :                         syslog (level, "%s", message);
     313              :         }
     314              : 
     315              :         /* And then to default handler for aborting and stuff like that */
     316          427 :         g_log_default_handler (log_domain, log_level, message, user_data);
     317          427 : }
     318              : 
     319              : static void
     320            1 : printerr_handler (const gchar *string)
     321              : {
     322              :         /* Print to syslog and stderr */
     323            1 :         syslog (LOG_WARNING, "%s", string);
     324            1 :         fprintf (stderr, "%s", string);
     325            1 : }
     326              : 
     327              : static void
     328           54 : prepare_logging ()
     329              : {
     330           54 :         GLogLevelFlags flags = G_LOG_FLAG_FATAL | G_LOG_LEVEL_ERROR |
     331              :                                G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING |
     332              :                                G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO;
     333              : 
     334           54 :         openlog ("gnome-keyring-daemon", LOG_PID, LOG_AUTH);
     335              : 
     336           54 :         g_log_set_handler (NULL, flags, log_handler, NULL);
     337           54 :         g_log_set_handler ("Glib", flags, log_handler, NULL);
     338           54 :         g_log_set_handler ("Gtk", flags, log_handler, NULL);
     339           54 :         g_log_set_handler ("Gnome", flags, log_handler, NULL);
     340           54 :         g_log_set_default_handler (log_handler, NULL);
     341           54 :         g_set_printerr_handler (printerr_handler);
     342           54 : }
     343              : 
     344              : #ifdef WITH_DEBUG
     345              : 
     346              : static void
     347            0 : dump_diagnostics (void)
     348              : {
     349              :         egg_secure_rec *records;
     350              :         egg_secure_rec *rec;
     351              :         unsigned int count, i;
     352              :         GHashTable *table;
     353              :         GHashTableIter iter;
     354            0 :         gsize request = 0;
     355            0 :         gsize block = 0;
     356              : 
     357            0 :         g_printerr ("------------------- Secure Memory --------------------\n");
     358            0 :         g_printerr (" Tag                          Used            Space\n");
     359            0 :         g_printerr ("------------------------------------------------------\n");
     360              : 
     361            0 :         records = egg_secure_records (&count);
     362            0 :         table = g_hash_table_new (g_str_hash, g_str_equal);
     363            0 :         for (i = 0; i < count; i++) {
     364            0 :                 if (!records[i].tag)
     365            0 :                         records[i].tag = "<unused>";
     366            0 :                 rec = g_hash_table_lookup (table, records[i].tag);
     367            0 :                 if (rec == NULL)
     368            0 :                         g_hash_table_insert (table, (gchar *)records[i].tag, &records[i]);
     369              :                 else {
     370            0 :                         rec->block_length += records[i].block_length;
     371            0 :                         rec->request_length += records[i].request_length;
     372              :                 }
     373            0 :                 block += records[i].block_length;
     374            0 :                 request += records[i].request_length;
     375              :         }
     376              : 
     377            0 :         g_hash_table_iter_init (&iter, table);
     378            0 :         while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&rec))
     379            0 :                 g_printerr (" %-20s %12lu %16lu\n", rec->tag,
     380            0 :                             (unsigned long)rec->request_length,
     381            0 :                             (unsigned long)rec->block_length);
     382              : 
     383            0 :         if (count > 0)
     384            0 :                 g_printerr ("------------------------------------------------------\n");
     385              : 
     386            0 :         g_printerr (" %-20s %12lu %16lu\n", "Total",
     387              :                     (unsigned long)request, (unsigned long)block);
     388            0 :         g_printerr ("------------------------------------------------------\n");
     389              : 
     390            0 :         g_hash_table_destroy (table);
     391            0 :         free (records);
     392            0 : }
     393              : 
     394              : #endif /* WITH_DEBUG */
     395              : 
     396              : /* -----------------------------------------------------------------------------
     397              :  * SIGNALS
     398              :  */
     399              : 
     400              : void
     401           27 : gkd_main_quit (void)
     402              : {
     403              :         /* Always stop accepting control connections immediately */
     404           27 :         gkd_control_stop ();
     405           27 :         g_main_loop_quit (loop);
     406           27 : }
     407              : 
     408              : static gboolean
     409           23 : on_signal_term (gpointer user_data)
     410              : {
     411           23 :         gkd_main_quit ();
     412           23 :         g_debug ("received signal, terminating");
     413           23 :         return FALSE;
     414              : }
     415              : 
     416              : static gboolean
     417            0 : on_signal_usr1 (gpointer user_data)
     418              : {
     419              : #ifdef WITH_DEBUG
     420            0 :         dump_diagnostics ();
     421              : #endif
     422            0 :         return TRUE;
     423              : }
     424              : 
     425              : /* -----------------------------------------------------------------------------
     426              :  * STARTUP
     427              :  */
     428              : 
     429              : static int
     430            0 : sane_dup2 (int fd1, int fd2)
     431              : {
     432              :         int ret;
     433              : 
     434            0 :  retry:
     435            0 :         ret = dup2 (fd1, fd2);
     436            0 :         if (ret < 0 && errno == EINTR)
     437            0 :                 goto retry;
     438              : 
     439            0 :         return ret;
     440              : }
     441              : 
     442              : static gchar*
     443            0 : read_login_password (int fd)
     444              : {
     445              :         /* We only accept a max of 8K as the login password */
     446              :         #define MAX_LENGTH 8192
     447              :         #define MAX_BLOCK 256
     448              : 
     449              :         /*
     450              :          * When --login is specified then the login password is passed
     451              :          * in on stdin. All data (including newlines) are part of the
     452              :          * password. A zero length password is no password.
     453              :          */
     454              : 
     455            0 :         gchar *buf = egg_secure_alloc (MAX_BLOCK);
     456            0 :         gchar *ret = NULL;
     457            0 :         int r, len = 0;
     458              : 
     459              :         for (;;) {
     460            0 :                 r = read (fd, buf, MAX_BLOCK);
     461            0 :                 if (r < 0) {
     462            0 :                         if (errno == EAGAIN)
     463            0 :                                 continue;
     464            0 :                         egg_secure_free (ret);
     465            0 :                         egg_secure_free (buf);
     466            0 :                         return NULL;
     467              : 
     468            0 :                 } else if (r == 0 || len > MAX_LENGTH) {
     469              :                         break;
     470              : 
     471              :                 } else {
     472            0 :                         ret = egg_secure_realloc (ret, len + r + 1);
     473            0 :                         memset (ret + len, 0, r + 1);
     474            0 :                         len = len + r;
     475            0 :                         strncat (ret, buf, r);
     476              :                 }
     477              :         }
     478              : 
     479            0 :         egg_secure_free (buf);
     480            0 :         return ret;
     481              : }
     482              : 
     483              : static void
     484            0 : cleanup_and_exit (int code)
     485              : {
     486            0 :         egg_cleanup_perform ();
     487            0 :         exit (code);
     488              : }
     489              : 
     490              : static void
     491            0 : clear_login_password (void)
     492              : {
     493            0 :         if(login_password)
     494            0 :                 egg_secure_strfree (login_password);
     495            0 :         login_password = NULL;
     496            0 : }
     497              : 
     498              : static void
     499           27 : print_environment (void)
     500              : {
     501              :         const gchar **env;
     502           49 :         for (env = gkd_util_get_environment (); *env; ++env)
     503           22 :                 printf ("%s\n", *env);
     504           27 :         fflush (stdout);
     505           27 : }
     506              : 
     507              : static gboolean
     508            0 : initialize_daemon_at (const gchar *directory)
     509              : {
     510              :         gchar **ourenv, **daemonenv, **e;
     511              : 
     512              :         /* Exchange environment variables, and try to initialize daemon */
     513            0 :         ourenv = gkd_util_build_environment (GKD_UTIL_IN_ENVIRONMENT);
     514            0 :         daemonenv = gkd_control_initialize (directory, run_components,
     515              :                                             (const gchar**)ourenv);
     516            0 :         g_strfreev (ourenv);
     517              : 
     518              :         /* Initialization failed, start this process up as a daemon */
     519            0 :         if (!daemonenv)
     520            0 :                 return FALSE;
     521              : 
     522              :         /* Setup all the environment variables we were passed */
     523            0 :         for (e = daemonenv; *e; ++e)
     524            0 :                 gkd_util_push_environment_full (*e);
     525            0 :         g_strfreev (daemonenv);
     526              : 
     527            0 :         return TRUE;
     528              : }
     529              : 
     530              : static gboolean
     531            1 : replace_daemon_at (const gchar *directory)
     532              : {
     533              :         gboolean ret;
     534              : 
     535              :         /*
     536              :          * The first control_directory is the environment one, always
     537              :          * prefer that since it's the one that ssh will connect to
     538              :          */
     539            1 :         if (control_directory == NULL)
     540            1 :                 control_directory = g_strdup (directory);
     541              : 
     542            1 :         ret = gkd_control_quit (directory, GKD_CONTROL_QUIET_IF_NO_PEER);
     543              : 
     544              :         /*
     545              :          * If we quit, wait a short time before initializing so the other
     546              :          * daemon can quit completely
     547              :          */
     548            1 :         if (ret == TRUE)
     549            1 :                 g_usleep (200 * 1000); /* 200 ms in us */
     550              : 
     551              :         /*
     552              :          * Note that we don't return TRUE, since we want to quit all the
     553              :          * running daemons (for this session) that may have been started
     554              :          * by dbus or elsewhere.
     555              :          */
     556              : 
     557            1 :         return FALSE;
     558              : }
     559              : 
     560              : typedef gboolean (*DiscoverFunc) (const gchar *control_directory);
     561              : 
     562              : static gboolean
     563            1 : discover_other_daemon (DiscoverFunc callback, gboolean acquire)
     564              : {
     565              :         const gchar *control_env;
     566            1 :         gchar *control = NULL;
     567            1 :         gboolean acquired = FALSE;
     568              :         gboolean ret;
     569              : 
     570              :         /* A pre-specified directory to control at, don't try anything else */
     571            1 :         if (control_directory)
     572            0 :                 return (callback) (control_directory);
     573              : 
     574              :         /* An environment variable from an already running daemon */
     575            1 :         control_env = g_getenv (GKD_UTIL_ENV_CONTROL);
     576            1 :         if (control_env && control_env[0]) {
     577            0 :                 if ((callback)(control_env))
     578            0 :                         return TRUE;
     579              :         }
     580              : 
     581              :         /* Or the default location when no evironment variable */
     582            1 :         control_env = g_getenv ("XDG_RUNTIME_DIR");
     583            1 :         if (control_env) {
     584            1 :                 control = g_build_filename (control_env, "keyring", NULL);
     585            1 :                 ret = (callback) (control);
     586            1 :                 g_free (control);
     587            1 :                 g_printerr ("discover_other_daemon: %d", ret);
     588            1 :                 if (ret == TRUE)
     589            0 :                         return TRUE;
     590              :         }
     591              : 
     592              :         /* See if we can contact a daemon running, that didn't set an env variable */
     593            1 :         if (acquire && !gkd_dbus_singleton_acquire (&acquired))
     594            0 :                 return FALSE;
     595              : 
     596              :         /* We're the main daemon */
     597            1 :         if (acquired)
     598            0 :                 return FALSE;
     599              : 
     600            1 :         control = gkd_dbus_singleton_control ();
     601            1 :         if (control) {
     602            0 :                 ret = (callback) (control);
     603            0 :                 g_free (control);
     604            0 :                 if (ret == TRUE)
     605            0 :                         return TRUE;
     606              :         }
     607              : 
     608            1 :         return FALSE;
     609              : }
     610              : 
     611              : static void
     612            0 : redirect_fds_after_fork (void)
     613              : {
     614              :         int fd, i;
     615              : 
     616            0 :         for (i = 0; i < 3; ++i) {
     617            0 :                 fd = open ("/dev/null", O_RDONLY);
     618            0 :                 sane_dup2 (fd, i);
     619            0 :                 close (fd);
     620              :         }
     621            0 : }
     622              : 
     623              : static void
     624            0 : block_on_fd (int fd)
     625              : {
     626              :         unsigned char dummy;
     627            0 :         read (fd, &dummy, 1);
     628            0 : }
     629              : 
     630              : static int
     631           27 : fork_and_print_environment (void)
     632              : {
     633              :         int status;
     634              :         pid_t pid;
     635           27 :         int wakeup_fds[2] = { -1, -1 };
     636              : 
     637           27 :         if (run_foreground) {
     638           27 :                 return -1;
     639              :         }
     640              : 
     641            0 :         if (!g_unix_open_pipe (wakeup_fds, FD_CLOEXEC, NULL))
     642            0 :                 exit (1);
     643              : 
     644            0 :         pid = fork ();
     645              : 
     646            0 :         if (pid != 0) {
     647              :                 /* Here we are in the initial process */
     648            0 :                 close (wakeup_fds[1]);
     649              : 
     650            0 :                 if (run_daemonized) {
     651              : 
     652              :                         /* Initial process, waits for intermediate child */
     653            0 :                         if (pid == -1)
     654            0 :                                 exit (1);
     655              : 
     656            0 :                         waitpid (pid, &status, 0);
     657            0 :                         if (WEXITSTATUS (status) != 0)
     658            0 :                                 exit (WEXITSTATUS (status));
     659              : 
     660              :                 } else {
     661              :                         /* Not double forking, wait for child */
     662            0 :                         block_on_fd (wakeup_fds[0]);
     663              :                 }
     664              : 
     665              :                 /* The initial process exits successfully */
     666            0 :                 exit (0);
     667              :         }
     668              : 
     669            0 :         if (run_daemonized) {
     670              : 
     671              :                 /*
     672              :                  * Become session leader of a new session, process group leader of a new
     673              :                  * process group, and detach from the controlling TTY, so that SIGHUP is
     674              :                  * not sent to this process when the previous session leader dies
     675              :                  */
     676            0 :                 setsid ();
     677              : 
     678              :                 /* Double fork if need to daemonize properly */
     679            0 :                 pid = fork ();
     680              : 
     681            0 :                 if (pid != 0) {
     682            0 :                         close (wakeup_fds[1]);
     683              : 
     684              :                         /* Here we are in the intermediate child process */
     685              : 
     686              :                         /*
     687              :                          * This process exits, so that the final child will inherit
     688              :                          * init as parent to avoid zombies
     689              :                          */
     690            0 :                         if (pid == -1)
     691            0 :                                 exit (1);
     692              : 
     693              :                         /* We've done two forks. */
     694            0 :                         block_on_fd (wakeup_fds[0]);
     695              : 
     696              :                         /* The intermediate child exits */
     697            0 :                         exit (0);
     698              :                 }
     699              : 
     700              :         }
     701              : 
     702              :         /* Here we are in the resulting daemon or background process. */
     703            0 :         return wakeup_fds[1];
     704              : }
     705              : 
     706              : static gboolean
     707           27 : gkr_daemon_startup_steps (const gchar *components)
     708              : {
     709           27 :         g_assert (components);
     710              : 
     711              :         /*
     712              :          * Startup that must run before forking.
     713              :          * Note that we set initialized flags early so that two
     714              :          * initializations don't overlap
     715              :          */
     716              : 
     717              : #ifdef WITH_SSH
     718              :         static gboolean ssh_started = FALSE;
     719              : 
     720              :         if (strstr (components, GKD_COMP_SSH)) {
     721              :                 if (ssh_started) {
     722              :                         g_message ("The SSH agent was already initialized");
     723              :                 } else {
     724              :                         ssh_started = TRUE;
     725              :                         if (!gkd_daemon_startup_ssh ()) {
     726              :                                 ssh_started = FALSE;
     727              :                                 return FALSE;
     728              :                         }
     729              :                 }
     730              :         }
     731              : #endif
     732              : 
     733           27 :         return TRUE;
     734              : }
     735              : 
     736              : static gboolean
     737           27 : gkr_daemon_initialize_steps (const gchar *components)
     738              : {
     739           27 :         g_assert (components);
     740              : 
     741              :         /*
     742              :          * Startup that can run after forking.
     743              :          * Note that we set initialized flags early so that two
     744              :          * initializations don't overlap
     745              :          */
     746              : 
     747           27 :         if (!initialization_completed) {
     748              : 
     749              :                 /* The LANG environment variable may have changed */
     750           27 :                 setlocale (LC_ALL, "");
     751              : 
     752           27 :                 initialization_completed = TRUE;
     753           27 :                 if (timeout_id)
     754            0 :                         g_source_remove (timeout_id);
     755              : 
     756              :                 /* Initialize new style PKCS#11 components */
     757           27 :                 if (!gkd_pkcs11_initialize ())
     758            0 :                         return FALSE;
     759              : 
     760              :                 /*
     761              :                  * Unlock the login keyring if we were given a password on STDIN.
     762              :                  * If it does not exist. We create it.
     763              :                  */
     764           27 :                 if (login_password) {
     765            0 :                         if (!gkd_login_unlock (login_password))
     766            0 :                                 g_message ("failed to unlock login keyring on startup");
     767            0 :                         egg_secure_strclear (login_password);
     768              :                 }
     769              : 
     770           27 :                 dbus_started = TRUE;
     771           27 :                 if (!gkd_dbus_setup ())
     772            0 :                         dbus_started = FALSE;
     773              :         }
     774              : 
     775              :         /* The Secret Service API */
     776           27 :         if (strstr (components, GKD_COMP_SECRETS) || strstr (components, GKD_COMP_KEYRING)) {
     777           25 :                 if (secrets_started) {
     778            0 :                         g_message ("The Secret Service was already initialized");
     779              :                 } else {
     780           25 :                         if (!dbus_started) {
     781            0 :                                 dbus_started = TRUE;
     782            0 :                                 if (!gkd_dbus_setup ())
     783            0 :                                         dbus_started = FALSE;
     784              :                         }
     785           25 :                         if (dbus_started) {
     786           25 :                                 secrets_started = TRUE;
     787           25 :                                 if (!gkd_dbus_secrets_startup ()) {
     788            0 :                                         secrets_started = FALSE;
     789            0 :                                         return FALSE;
     790              :                                 }
     791              :                         }
     792              :                 }
     793              :         }
     794              : 
     795              :         /* The PKCS#11 remoting */
     796           27 :         if (strstr (components, GKD_COMP_PKCS11)) {
     797           11 :                 if (pkcs11_started) {
     798            0 :                         g_message ("The PKCS#11 component was already initialized");
     799              :                 } else {
     800           11 :                         pkcs11_started = TRUE;
     801           11 :                         if (!gkd_pkcs11_startup_pkcs11 ()) {
     802            0 :                                 pkcs11_started = FALSE;
     803            0 :                                 return FALSE;
     804              :                         }
     805              :                 }
     806              :         }
     807              : 
     808           27 :         return TRUE;
     809              : }
     810              : 
     811              : void
     812            0 : gkd_main_complete_initialization (const gchar *components)
     813              : {
     814            0 :         g_assert (components);
     815              : 
     816              :         /*
     817              :          * Sometimes we don't initialize the full daemon right on
     818              :          * startup. When run with --login is one such case.
     819              :          */
     820              : 
     821            0 :         gkr_daemon_startup_steps (components);
     822            0 :         gkr_daemon_initialize_steps (components);
     823            0 : }
     824              : 
     825              : static gboolean
     826            0 : on_login_timeout (gpointer data)
     827              : {
     828            0 :         if (!initialization_completed)
     829            0 :                 cleanup_and_exit (0);
     830            0 :         return FALSE;
     831              : }
     832              : 
     833              : static void
     834            0 : on_vanished_quit_loop (GDBusConnection *connection,
     835              :                        const gchar *name,
     836              :                        gpointer user_data)
     837              : {
     838            0 :         g_main_loop_quit (user_data);
     839            0 : }
     840              : 
     841            0 : static void on_logind_session_property_get (GObject *connection,
     842              :                                             GAsyncResult *res,
     843              :                                             gpointer user_data G_GNUC_UNUSED)
     844              : {
     845            0 :         GError *error = NULL;
     846              :         GVariant *result, *resultv;
     847              :         const gchar *state;
     848              :         gboolean should_quit;
     849              : 
     850            0 :         result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (connection), res, &error);
     851              : 
     852            0 :         if (error) {
     853            0 :                 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     854            0 :                         g_critical ("%s Couldn't get session state: %s", G_STRLOC, error->message);
     855            0 :                 g_error_free (error);
     856            0 :                 return;
     857              :         }
     858              : 
     859            0 :         g_variant_get (result, "(v)", &resultv, NULL);
     860            0 :         state = g_variant_get_string (resultv, NULL);
     861              : 
     862            0 :         should_quit = g_strcmp0 (state, "closing") == 0;
     863              : 
     864            0 :         g_clear_pointer (&result, g_variant_unref);
     865            0 :         g_clear_pointer (&resultv, g_variant_unref);
     866              : 
     867              :         /* yes, the session is closing, so we'll quit now */
     868            0 :         if (should_quit)
     869            0 :                 cleanup_and_exit (0);
     870              : }
     871              : 
     872            0 : static void on_logind_session_properties_changed (GDBusConnection *connection,
     873              :                                                   const gchar *sender_name G_GNUC_UNUSED,
     874              :                                                   const gchar *object_path,
     875              :                                                   const gchar *interface_name G_GNUC_UNUSED,
     876              :                                                   const gchar *signal_name G_GNUC_UNUSED,
     877              :                                                   GVariant *parameters,
     878              :                                                   gpointer user_data G_GNUC_UNUSED)
     879              : {
     880              :         const gchar *prop_iface;
     881              :         gboolean active;
     882              :         GVariant* changed_properties;
     883              : 
     884            0 :         g_variant_get (parameters, "(&s@a{sv}^as)", &prop_iface, &changed_properties, NULL);
     885              : 
     886            0 :         if (g_variant_lookup (changed_properties, "Active", "b", &active, NULL)) {
     887            0 :                 if (!active) {
     888              :                         /* ok, the session went inactive, let's see if that is because
     889              :                          * it is closing */
     890            0 :                         g_dbus_connection_call (
     891              :                                 connection,
     892              :                                 "org.freedesktop.login1",
     893              :                                 object_path,
     894              :                                 "org.freedesktop.DBus.Properties",
     895              :                                 "Get",
     896              :                                 g_variant_new ("(ss)", prop_iface, "State"),
     897              :                                 G_VARIANT_TYPE ("(v)"),
     898              :                                 G_DBUS_CALL_FLAGS_NONE,
     899              :                                 -1,
     900              :                                 NULL,
     901              :                                 on_logind_session_property_get,
     902              :                                 NULL
     903              :                         );
     904              :                 }
     905              :         }
     906              : 
     907            0 :         g_variant_unref (changed_properties);
     908            0 : }
     909              : 
     910              : static void
     911            0 : on_logind_object_path_get (GObject *connection,
     912              :                            GAsyncResult *res,
     913              :                            gpointer user_data G_GNUC_UNUSED)
     914              : {
     915            0 :         GError *error = NULL;
     916              :         GVariant *result;
     917              :         const gchar *object_path;
     918              :         gchar *remote_error;
     919              :         gboolean is_cancelled, is_name_has_no_owner;
     920              : 
     921            0 :         result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (connection), res, &error);
     922              : 
     923              :         /* If there's an error we always want to quit - but we only tell the
     924              :          * user about it if something went wrong. Cancelling the operation or
     925              :          * not having logind available are okay. */
     926            0 :         if (error) {
     927            0 :                 is_cancelled = g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
     928              : 
     929            0 :                 remote_error = g_dbus_error_get_remote_error (error);
     930            0 :                 is_name_has_no_owner = g_strcmp0 (remote_error, "org.freedesktop.DBus.Error.NameHasNoOwner") == 0;
     931              : 
     932            0 :                 if (!is_cancelled && !is_name_has_no_owner)
     933            0 :                         g_critical ("%s Couldn't get object path: %s", G_STRLOC, error->message);
     934              : 
     935            0 :                 g_free (remote_error);
     936            0 :                 g_error_free (error);
     937            0 :                 return;
     938              :         }
     939              : 
     940              :         /* now we know which object path to look on, watch for
     941              :          * PropertiesChanged. Note that, per logind's documentation, we only
     942              :          * get notified for 'Active' changing */
     943            0 :         g_variant_get (result, "(&o)", &object_path, NULL);
     944              : 
     945            0 :         g_dbus_connection_signal_subscribe (
     946            0 :                 G_DBUS_CONNECTION (connection),
     947              :                 "org.freedesktop.login1",
     948              :                 "org.freedesktop.DBus.Properties",
     949              :                 "PropertiesChanged",
     950              :                 object_path,
     951              :                 NULL,
     952              :                 G_DBUS_SIGNAL_FLAGS_NONE,
     953              :                 on_logind_session_properties_changed,
     954              :                 NULL,
     955              :                 NULL
     956              :         );
     957              : 
     958            0 :         g_clear_pointer (&result, g_variant_unref);
     959              : }
     960              : 
     961              : static void
     962            0 : start_watching_logind_for_session_closure ()
     963              : {
     964            0 :         g_return_if_fail (system_bus_connection != NULL);
     965              : 
     966              :         const gchar *xdg_session_id;
     967              : 
     968            0 :         xdg_session_id = g_getenv ("XDG_SESSION_ID");
     969              : 
     970            0 :         if (!xdg_session_id)
     971            0 :                 return;
     972              : 
     973              :         /* get the right object path */
     974            0 :         g_dbus_connection_call (
     975              :                 system_bus_connection,
     976              :                 "org.freedesktop.login1",
     977              :                 "/org/freedesktop/login1",
     978              :                 "org.freedesktop.login1.Manager",
     979              :                 "GetSession",
     980              :                 g_variant_new ("(s)", xdg_session_id, NULL),
     981              :                 G_VARIANT_TYPE ("(o)"),
     982              :                 G_DBUS_CALL_FLAGS_NO_AUTO_START,
     983              :                 -1,
     984              :                 NULL,
     985              :                 on_logind_object_path_get,
     986              :                 NULL
     987              :         );
     988              : }
     989              : 
     990              : int
     991           27 : main (int argc, char *argv[])
     992              : {
     993              :         /*
     994              :          * The gnome-keyring startup is not as simple as I wish it could be.
     995              :          *
     996              :          * It's often started in the primordial stages of a session, where
     997              :          * there's no DBus, and no proper X display. This is the strange world
     998              :          * of PAM.
     999              :          *
    1000              :          * When started with the --login option, we do as little initialization
    1001              :          * as possible. We expect a login password on the stdin, and unlock
    1002              :          * or create the login keyring.
    1003              :          *
    1004              :          * Then later we expect gnome-keyring-dameon to be run again with the
    1005              :          * --start option. This second gnome-keyring-daemon will hook the
    1006              :          * original daemon up with environment variables necessary to initialize
    1007              :          * itself and bring it into the session. This second daemon usually exits.
    1008              :          *
    1009              :          * Without either of these options, we follow a more boring and
    1010              :          * predictable startup.
    1011              :          */
    1012              : 
    1013           27 :         GDBusConnection *connection = NULL;
    1014           27 :         GError *error = NULL;
    1015              : 
    1016              :         /*
    1017              :          * Before we do ANYTHING, we drop privileges so we don't become
    1018              :          * a security issue ourselves.
    1019              :          */
    1020           27 :         gkd_capability_obtain_capability_and_drop_privileges ();
    1021              : 
    1022              : #ifdef WITH_STRICT
    1023              :         g_setenv ("DBUS_FATAL_WARNINGS", "1", FALSE);
    1024              :         if (!g_getenv ("G_DEBUG"))
    1025              :                 g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
    1026              : #endif
    1027              : 
    1028              : #if !GLIB_CHECK_VERSION(2,35,0)
    1029              :         g_type_init ();
    1030              : #endif
    1031              : 
    1032              :         /* internationalisation */
    1033           27 :         setlocale (LC_ALL, "");
    1034              : 
    1035              : #ifdef HAVE_GETTEXT
    1036           27 :         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
    1037           27 :         textdomain (GETTEXT_PACKAGE);
    1038           27 :         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
    1039              : #endif
    1040              : 
    1041           27 :         egg_libgcrypt_initialize ();
    1042              : 
    1043              :         /* Send all warning or error messages to syslog */
    1044           27 :         prepare_logging ();
    1045              : 
    1046           27 :         parse_arguments (&argc, &argv);
    1047              : 
    1048              :         /* The --version option. This is machine parseable output */
    1049           27 :         if (run_version) {
    1050            0 :                 g_print ("gnome-keyring-daemon: %s\n", VERSION);
    1051            0 :                 g_print ("testing: %s\n",
    1052              : #ifdef WITH_DEBUG
    1053              :                          "enabled");
    1054              : #else
    1055              :                          "disabled");
    1056              : #endif
    1057            0 :                 exit (0);
    1058              :         }
    1059              : 
    1060           27 :         if (perform_unlock) {
    1061            0 :                 login_password = read_login_password (STDIN);
    1062            0 :                 atexit (clear_login_password);
    1063              :         }
    1064              : 
    1065              :         /* The whole forking and daemonizing dance starts here. */
    1066           27 :         parent_wakeup_fd = fork_and_print_environment();
    1067              : 
    1068              :         /* The --start option */
    1069           27 :         if (run_for_start) {
    1070            0 :                 if (discover_other_daemon (initialize_daemon_at, TRUE)) {
    1071              :                         /*
    1072              :                          * Another daemon was initialized, print out environment,
    1073              :                          * tell parent we're done, and quit or go comatose.
    1074              :                          */
    1075            0 :                         print_environment ();
    1076            0 :                         close (parent_wakeup_fd);
    1077            0 :                         if (run_foreground) {
    1078            0 :                                 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
    1079            0 :                                 if (error) {
    1080            0 :                                         g_warning ("Couldn't connect to session bus: %s", error->message);
    1081            0 :                                         g_clear_error (&error);
    1082              :                                 }
    1083            0 :                                 loop = g_main_loop_new (NULL, FALSE);
    1084            0 :                                 g_bus_watch_name (G_BUS_TYPE_SESSION, "org.gnome.keyring",
    1085              :                                                   G_BUS_NAME_WATCHER_FLAGS_NONE,
    1086              :                                                   NULL, on_vanished_quit_loop, loop, NULL);
    1087            0 :                                 g_main_loop_run (loop);
    1088            0 :                                 g_clear_pointer (&loop, g_main_loop_unref);
    1089            0 :                                 g_clear_object (&connection);
    1090              :                         }
    1091            0 :                         cleanup_and_exit (0);
    1092              :                 }
    1093              : 
    1094              :         /* The --replace option */
    1095           27 :         } else if (run_for_replace) {
    1096            1 :                 discover_other_daemon (replace_daemon_at, FALSE);
    1097            1 :                 if (control_directory)
    1098            1 :                         g_message ("Replacing daemon, using directory: %s", control_directory);
    1099              :                 else
    1100            0 :                         g_message ("Could not find daemon to replace, staring normally");
    1101              :         }
    1102              : 
    1103              :         /* Initialize the main directory */
    1104           27 :         gkd_util_init_master_directory (control_directory);
    1105              : 
    1106              :         /* Initialize our daemon main loop and threading */
    1107           27 :         loop = g_main_loop_new (NULL, FALSE);
    1108              : 
    1109              :         /* Initialize our control socket */
    1110           27 :         if (!gkd_control_listen ())
    1111            0 :                 return FALSE;
    1112              : 
    1113              :         /* The --login option. Delayed initialization */
    1114           27 :         if (run_for_login) {
    1115            0 :                 timeout_id = g_timeout_add_seconds (LOGIN_TIMEOUT, (GSourceFunc) on_login_timeout, NULL);
    1116              : 
    1117              :         /* Not a login daemon. Startup stuff now.*/
    1118              :         } else {
    1119              :                 /* These are things that can run before forking */
    1120           27 :                 if (!gkr_daemon_startup_steps (run_components))
    1121            0 :                         cleanup_and_exit (1);
    1122              :         }
    1123              : 
    1124              :         /* if we can get a connection to the system bus, watch it and then kill
    1125              :          * ourselves when our session closes */
    1126              : 
    1127           27 :         system_bus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
    1128              : 
    1129           27 :         if (system_bus_connection)
    1130            0 :                 start_watching_logind_for_session_closure ();
    1131              : 
    1132           27 :         signal (SIGPIPE, SIG_IGN);
    1133              : 
    1134              :         /* Print the environment and tell the parent we're done */
    1135           27 :         print_environment ();
    1136              : 
    1137           27 :         if (!run_foreground) {
    1138            0 :                 close (parent_wakeup_fd);
    1139            0 :                 redirect_fds_after_fork ();
    1140              :         }
    1141              : 
    1142           27 :         g_unix_signal_add (SIGTERM, on_signal_term, loop);
    1143           27 :         g_unix_signal_add (SIGHUP, on_signal_term, loop);
    1144           27 :         g_unix_signal_add (SIGUSR1, on_signal_usr1, loop);
    1145              : 
    1146              :         /* Prepare logging a second time, since we may be in a different process */
    1147           27 :         prepare_logging();
    1148              : 
    1149              :         /* Remainder initialization after forking, if initialization not delayed */
    1150           27 :         if (!run_for_login) {
    1151           27 :                 gkr_daemon_initialize_steps (run_components);
    1152              : 
    1153              :                 /*
    1154              :                  * Close stdout and so that the caller knows that we're
    1155              :                  * all initialized, (when run in foreground mode).
    1156              :                  *
    1157              :                  * However since some logging goes to stdout, redirect that
    1158              :                  * to stderr. We don't want the caller confusing that with
    1159              :                  * valid output anyway.
    1160              :                  */
    1161           27 :                 if (dup2 (2, 1) < 1)
    1162            0 :                         g_warning ("couldn't redirect stdout to stderr");
    1163              : 
    1164           27 :                 g_debug ("initialization complete");
    1165              :         }
    1166              : 
    1167           27 :         g_main_loop_run (loop);
    1168              : 
    1169              :         /* This wraps everything up in order */
    1170           27 :         egg_cleanup_perform ();
    1171              : 
    1172           27 :         g_free (control_directory);
    1173              : 
    1174           27 :         g_debug ("exiting cleanly");
    1175           27 :         return 0;
    1176              : }
        

Generated by: LCOV version 2.0-1