1 /* gpgconf.c - Configuration utility for GnuPG
2 * Copyright (C) 2003, 2007, 2009, 2011 Free Software Foundation, Inc.
3 * Copyright (C) 2016 g10 Code GmbH.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
31 #include "../common/init.h"
34 /* Constants to identify the commands and options. */
35 enum cmd_and_opt_values
68 /* The list of commands and options. */
69 static ARGPARSE_OPTS opts[] =
71 { 300, NULL, 0, N_("@Commands:\n ") },
73 { aListComponents, "list-components", 256, N_("list all components") },
74 { aCheckPrograms, "check-programs", 256, N_("check all programs") },
75 { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
76 { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
77 { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
78 { aApplyDefaults, "apply-defaults", 256,
79 N_("apply global default values") },
80 { aApplyProfile, "apply-profile", 256,
81 N_("|FILE|update configuration files using FILE") },
82 { aListDirs, "list-dirs", 256,
83 N_("get the configuration directories for @GPGCONF@") },
84 { aListConfig, "list-config", 256,
85 N_("list global configuration file") },
86 { aCheckConfig, "check-config", 256,
87 N_("check global configuration file") },
88 { aQuerySWDB, "query-swdb", 256,
89 N_("query the software version database") },
90 { aReload, "reload", 256, N_("reload all or a given component")},
91 { aLaunch, "launch", 256, N_("launch a given component")},
92 { aKill, "kill", 256, N_("kill a given component")},
93 { aCreateSocketDir, "create-socketdir", 256, "@"},
94 { aRemoveSocketDir, "remove-socketdir", 256, "@"},
96 { 301, NULL, 0, N_("@\nOptions:\n ") },
98 { oOutput, "output", 2, N_("use as output file") },
99 { oVerbose, "verbose", 0, N_("verbose") },
100 { oQuiet, "quiet", 0, N_("quiet") },
101 { oDryRun, "dry-run", 0, N_("do not make any changes") },
102 { oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") },
104 { oHomedir, "homedir", 2, "@" },
105 { oBuilddir, "build-prefix", 2, "@" },
106 { oNull, "null", 0, "@" },
107 { oNoVerbose, "no-verbose", 0, "@"},
112 /* Print usage information and and provide strings for help. */
114 my_strusage( int level )
120 case 11: p = "@GPGCONF@ (@GNUPG@)";
122 case 13: p = VERSION; break;
123 case 17: p = PRINTABLE_OS_NAME; break;
124 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
127 case 40: p = _("Usage: @GPGCONF@ [options] (-h for help)");
130 p = _("Syntax: @GPGCONF@ [options]\n"
131 "Manage configuration options for tools of the @GNUPG@ system\n");
134 default: p = NULL; break;
140 /* Return the fp for the output. This is usually stdout unless
141 --output has been used. In the latter case this function opens
144 get_outfp (estream_t *fp)
150 *fp = es_fopen (opt.outfile, "w");
152 gc_error (1, errno, "can not open '%s'", opt.outfile);
162 list_dirs (estream_t fp, char **names)
166 const char *(*fnc)(void);
169 { "sysconfdir", gnupg_sysconfdir, NULL },
170 { "bindir", gnupg_bindir, NULL },
171 { "libexecdir", gnupg_libexecdir, NULL },
172 { "libdir", gnupg_libdir, NULL },
173 { "datadir", gnupg_datadir, NULL },
174 { "localedir", gnupg_localedir, NULL },
175 { "socketdir", gnupg_socketdir, NULL },
176 { "dirmngr-socket", dirmngr_socket_name, NULL,},
177 { "agent-ssh-socket", gnupg_socketdir, GPG_AGENT_SSH_SOCK_NAME },
178 { "agent-extra-socket", gnupg_socketdir, GPG_AGENT_EXTRA_SOCK_NAME },
179 { "agent-browser-socket",gnupg_socketdir, GPG_AGENT_BROWSER_SOCK_NAME },
180 { "agent-socket", gnupg_socketdir, GPG_AGENT_SOCK_NAME },
181 { "homedir", gnupg_homedir, NULL }
188 for (idx = 0; idx < DIM (list); idx++)
190 s = list[idx].fnc ();
193 tmp = make_filename (s, list[idx].extra, NULL);
199 es_fprintf (fp, "%s:%s\n", list[idx].name, gc_percent_escape (s));
202 for (j=0; names[j]; j++)
203 if (!strcmp (names[j], list[idx].name))
206 es_putc (opt.null? '\0':'\n', fp);
216 /* Check whether NAME is valid argument for query_swdb(). Valid names
217 * start with a letter and contain only alphanumeric characters or an
220 valid_swdb_name_p (const char *name)
222 if (!name || !*name || !alphap (name))
225 for (name++; *name; name++)
226 if (!alnump (name) && *name != '_')
233 /* Query the SWDB file. If necessary and possible this functions asks
234 * the dirmngr to load an updated version of that file. The caller
235 * needs to provide the NAME to query (e.g. "gnupg", "libgcrypt") and
236 * optional the currently installed version in CURRENT_VERSION. The
237 * output written to OUT is a colon delimited line with these fields:
239 * name :: The name of the package
240 * curvers:: The installed version if given.
241 * status :: This value tells the status of the software package
242 * '-' :: No information available
243 * (error or CURRENT_VERSION not given)
244 * '?' :: Unknown NAME
245 * 'u' :: Update available
246 * 'c' :: The version is Current
247 * 'n' :: The current version is already Newer than the
249 * urgency :: If the value is greater than zero an urgent update is required.
250 * error :: 0 on success or an gpg_err_code_t
252 * GPG_ERR_TOO_OLD :: The SWDB file is to old to be used.
253 * GPG_ERR_ENOENT :: The SWDB file is not available.
254 * GPG_ERR_BAD_SIGNATURE :: Currupted SWDB file.
255 * filedate:: Date of the swdb file (yyyymmddThhmmss)
256 * verified:: Date we checked the validity of the file (yyyyymmddThhmmss)
257 * version :: The version string from the swdb.
258 * reldate :: Release date of that version (yyyymmddThhmmss)
259 * size :: Size of the package in bytes.
260 * hash :: SHA-2 hash of the package.
264 query_swdb (estream_t out, const char *name, const char *current_version)
267 const char *search_name;
271 char *self_version = NULL;
272 size_t length_of_line = 0;
277 gnupg_isotime_t filedate = {0};
278 gnupg_isotime_t verified = {0};
279 char *value_ver = NULL;
280 gnupg_isotime_t value_date = {0};
281 char *value_size = NULL;
282 char *value_sha2 = NULL;
283 unsigned long value_size_ul = 0;
287 if (!valid_swdb_name_p (name))
289 log_error ("error in package name '%s': %s\n",
290 name, gpg_strerror (GPG_ERR_INV_NAME));
293 if (!strcmp (name, "gnupg"))
294 search_name = "gnupg21";
295 else if (!strcmp (name, "gnupg1"))
296 search_name = "gnupg1";
300 if (!current_version && !strcmp (name, "gnupg"))
302 /* Use our own version but string a possible beta string. */
303 self_version = xstrdup (PACKAGE_VERSION);
304 p = strchr (self_version, '-');
307 current_version = self_version;
310 if (current_version && (strchr (current_version, ':')
311 || compare_version_strings (current_version, NULL)))
313 log_error ("error in version string '%s': %s\n",
314 current_version, gpg_strerror (GPG_ERR_INV_ARG));
318 fname = make_filename (gnupg_homedir (), "swdb.lst", NULL);
319 fp = es_fopen (fname, "r");
322 err = gpg_error_from_syserror ();
323 es_fprintf (out, "%s:%s:-::%u:::::::\n",
325 current_version? current_version : "",
327 if (gpg_err_code (err) != GPG_ERR_ENOENT)
328 log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
332 /* Note that the parser uses the first occurance of a matching
333 * values and ignores possible duplicated values. */
335 maxlen = 2048; /* Set limit. */
336 while ((len = es_read_line (fp, &line, &length_of_line, &maxlen)) > 0)
340 err = gpg_error (GPG_ERR_LINE_TOO_LONG);
341 log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
344 /* Strip newline and carriage return, if present. */
345 while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
348 if (split_fields (line, fields, DIM (fields)) < DIM(fields))
349 continue; /* Skip empty lines and names w/o a value. */
350 if (*fields[0] == '#')
351 continue; /* Skip comments. */
353 /* Record the meta data. */
354 if (!*filedate && !strcmp (fields[0], ".filedate"))
356 string2isotime (filedate, fields[1]);
359 if (!*verified && !strcmp (fields[0], ".verified"))
361 string2isotime (verified, fields[1]);
365 /* Tokenize the name. */
366 p = strrchr (fields[0], '_');
368 continue; /* Name w/o an underscore. */
371 /* Wait for the requested name. */
372 if (!strcmp (fields[0], search_name))
374 if (!strcmp (p, "ver") && !value_ver)
375 value_ver = xstrdup (fields[1]);
376 else if (!strcmp (p, "date") && !*value_date)
377 string2isotime (value_date, fields[1]);
378 else if (!strcmp (p, "size") && !value_size)
379 value_size = xstrdup (fields[1]);
380 else if (!strcmp (p, "sha2") && !value_sha2)
381 value_sha2 = xstrdup (fields[1]);
384 if (len < 0 || es_ferror (fp))
386 err = gpg_error_from_syserror ();
387 log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
391 if (!*filedate || !*verified)
393 err = gpg_error (GPG_ERR_INV_TIME);
394 es_fprintf (out, "%s:%s:-::%u:::::::\n",
396 current_version? current_version : "",
403 es_fprintf (out, "%s:%s:?:::::::::\n",
405 current_version? current_version : "");
411 gpg_err_set_errno (0);
412 value_size_ul = strtoul (value_size, &p, 10);
416 value_size_ul *= 1024;
421 if (compare_version_strings (value_ver, NULL))
422 err = gpg_error (GPG_ERR_INV_VALUE);
423 else if (!current_version)
425 else if (!(i = compare_version_strings (value_ver, current_version)))
432 es_fprintf (out, "%s:%s:%c::%d:%s:%s:%s:%s:%lu:%s:\n",
434 current_version? current_version : "",
442 value_sha2? value_sha2 : "");
451 xfree (self_version);
457 main (int argc, char **argv)
461 int no_more_options = 0;
462 enum cmd_and_opt_values cmd = 0;
463 estream_t outfp = NULL;
465 early_system_init ();
466 gnupg_reopen_std (GPGCONF_NAME);
467 set_strusage (my_strusage);
468 log_set_prefix (GPGCONF_NAME, GPGRT_LOG_WITH_PREFIX);
470 /* Make sure that our subsystems are ready. */
472 init_common_subsystems (&argc, &argv);
473 gc_components_init ();
475 /* Parse the command line. */
478 pargs.flags = 1; /* Do not remove the args. */
479 while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
483 case oOutput: opt.outfile = pargs.r.ret_str; break;
484 case oQuiet: opt.quiet = 1; break;
485 case oDryRun: opt.dry_run = 1; break;
489 case oVerbose: opt.verbose++; break;
490 case oNoVerbose: opt.verbose = 0; break;
491 case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
492 case oBuilddir: gnupg_set_builddir (pargs.r.ret_str); break;
493 case oNull: opt.null = 1; break;
496 case aListComponents:
509 case aCreateSocketDir:
510 case aRemoveSocketDir:
514 default: pargs.err = 2; break;
518 if (log_get_errorcount (0))
521 /* Print a warning if an argument looks like an option. */
522 if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
526 for (i=0; i < argc; i++)
527 if (argv[i][0] == '-' && argv[i][1] == '-')
528 log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
531 fname = argc ? *argv : NULL;
535 case aListComponents:
537 /* List all components. */
538 gc_component_list_components (get_outfp (&outfp));
542 /* Check all programs. */
543 gc_check_programs (get_outfp (&outfp));
551 es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
552 es_putc ('\n', es_stderr);
553 es_fputs (_("Need one component argument"), es_stderr);
554 es_putc ('\n', es_stderr);
559 int idx = gc_component_find (fname);
562 es_fputs (_("Component not found"), es_stderr);
563 es_putc ('\n', es_stderr);
566 if (cmd == aCheckOptions)
567 gc_component_check_options (idx, get_outfp (&outfp), NULL);
570 gc_component_retrieve_options (idx);
571 if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
573 if (cmd == aListOptions)
574 gc_component_list_options (idx, get_outfp (&outfp));
575 else if (cmd == aChangeOptions)
576 gc_component_change_options (idx, es_stdin,
577 get_outfp (&outfp), 0);
586 es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
587 es_putc ('\n', es_stderr);
588 es_fputs (_("Need one component argument"), es_stderr);
589 es_putc ('\n', es_stderr);
592 else if (!strcmp (fname, "all"))
596 if (gc_component_launch (-1))
601 gc_component_kill (-1);
606 /* Launch/Kill a given component. */
609 idx = gc_component_find (fname);
612 es_fputs (_("Component not found"), es_stderr);
613 es_putc ('\n', es_stderr);
616 else if (cmd == aLaunch)
618 if (gc_component_launch (idx))
623 /* We don't error out if the kill failed because this
624 command should do nothing if the component is not
626 gc_component_kill (idx);
632 if (!fname || !strcmp (fname, "all"))
635 gc_component_reload (-1);
639 /* Reload given component. */
642 idx = gc_component_find (fname);
645 es_fputs (_("Component not found"), es_stderr);
646 es_putc ('\n', es_stderr);
651 gc_component_reload (idx);
657 if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
662 if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
669 es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
670 es_putc ('\n', es_stderr);
671 es_fputs (_("No argument allowed"), es_stderr);
672 es_putc ('\n', es_stderr);
675 gc_component_retrieve_options (-1);
676 if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
681 gc_component_retrieve_options (-1);
682 if (gc_apply_profile (fname))
687 /* Show the system configuration directories for gpgconf. */
689 list_dirs (outfp, argc? argv : NULL);
693 /* Query the software version database. */
694 if (!fname || argc > 2)
696 es_fprintf (es_stderr, "usage: %s --query-swdb NAME [VERSION]\n",
701 query_swdb (outfp, fname, argc > 1? argv[1] : NULL);
704 case aCreateSocketDir:
709 /* Make sure that the top /run/user/UID/gnupg dir has been
713 /* Check the /var/run dir. */
714 socketdir = _gnupg_socketdir_internal (1, &flags);
715 if ((flags & 64) && !opt.dry_run)
717 /* No sub dir - create it. */
718 if (gnupg_mkdir (socketdir, "-rwx"))
719 gc_error (1, errno, "error creating '%s'", socketdir);
722 socketdir = _gnupg_socketdir_internal (1, &flags);
725 /* Give some info. */
726 if ( (flags & ~32) || opt.verbose || opt.dry_run)
728 log_info ("socketdir is '%s'\n", socketdir);
729 if ((flags & 1)) log_info ("\tgeneral error\n");
730 if ((flags & 2)) log_info ("\tno /run/user dir\n");
731 if ((flags & 4)) log_info ("\tbad permissions\n");
732 if ((flags & 8)) log_info ("\tbad permissions (subdir)\n");
733 if ((flags & 16)) log_info ("\tmkdir failed\n");
734 if ((flags & 32)) log_info ("\tnon-default homedir\n");
735 if ((flags & 64)) log_info ("\tno such subdir\n");
736 if ((flags & 128)) log_info ("\tusing homedir as fallback\n");
739 if ((flags & ~32) && !opt.dry_run)
740 gc_error (1, 0, "error creating socket directory");
746 case aRemoveSocketDir:
751 /* Check the /var/run dir. */
752 socketdir = _gnupg_socketdir_internal (1, &flags);
754 log_info ("ignoring request to remove non /run/user socket dir\n");
755 else if (opt.dry_run)
757 else if (rmdir (socketdir))
758 gc_error (1, errno, "error removing '%s'", socketdir);
766 if (outfp != es_stdout)
767 if (es_fclose (outfp))
768 gc_error (1, errno, "error closing '%s'", opt.outfile);