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.
4 *
5 * This file is part of GnuPG.
6 *
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.
11 *
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.
16 *
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/>.
19 * SPDX-License-Identifier: GPL-3.0-or-later
20 */
21
22 #include <config.h>
23
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #define INCLUDED_BY_MAIN_MODULE 1
31 #include "gpgconf.h"
32 #include "../common/i18n.h"
33 #include "../common/sysutils.h"
34 #include "../common/init.h"
35 #include "../common/status.h"
36 #include "../common/exechelp.h"
37
38
39 /* Constants to identify the commands and options. */
40 enum cmd_and_opt_values
41 {
42 aNull = 0,
43 oDryRun = 'n',
44 oOutput = 'o',
45 oQuiet = 'q',
46 oVerbose = 'v',
47 oRuntime = 'r',
48 oComponent = 'c',
49 oNull = '0',
50 oNoVerbose = 500,
51 oHomedir,
52 oBuilddir,
53 oStatusFD,
54 oShowSocket,
55 oChUid,
56
57 aListComponents,
58 aCheckPrograms,
59 aListOptions,
60 aChangeOptions,
61 aCheckOptions,
62 aApplyDefaults,
63 aListConfig,
64 aCheckConfig,
65 aQuerySWDB,
66 aListDirs,
67 aLaunch,
68 aKill,
69 aCreateSocketDir,
70 aRemoveSocketDir,
71 aApplyProfile,
72 aReload,
73 aShowVersions,
74 aShowCodepages
75 };
76
77
78 /* The list of commands and options. */
79 static gpgrt_opt_t opts[] =
80 {
81 { 300, NULL, 0, N_("@Commands:\n ") },
82
83 { aListComponents, "list-components", 256, N_("list all components") },
84 { aCheckPrograms, "check-programs", 256, N_("check all programs") },
85 { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
86 { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
87 { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
88 { aApplyDefaults, "apply-defaults", 256,
89 N_("apply global default values") },
90 { aApplyProfile, "apply-profile", 256,
91 N_("|FILE|update configuration files using FILE") },
92 { aListDirs, "list-dirs", 256,
93 N_("get the configuration directories for @GPGCONF@") },
94 { aListConfig, "list-config", 256,
95 N_("list global configuration file") },
96 { aCheckConfig, "check-config", 256,
97 N_("check global configuration file") },
98 { aQuerySWDB, "query-swdb", 256,
99 N_("query the software version database") },
100 { aReload, "reload", 256, N_("reload all or a given component")},
101 { aLaunch, "launch", 256, N_("launch a given component")},
102 { aKill, "kill", 256, N_("kill a given component")},
103 { aCreateSocketDir, "create-socketdir", 256, "@"},
104 { aRemoveSocketDir, "remove-socketdir", 256, "@"},
105 ARGPARSE_c (aShowVersions, "show-versions", "@"),
106 ARGPARSE_c (aShowCodepages, "show-codepages", "@"),
107
108 { 301, NULL, 0, N_("@\nOptions:\n ") },
109
110 { oOutput, "output", 2, N_("use as output file") },
111 { oVerbose, "verbose", 0, N_("verbose") },
112 { oQuiet, "quiet", 0, N_("quiet") },
113 { oDryRun, "dry-run", 0, N_("do not make any changes") },
114 { oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") },
115 ARGPARSE_s_i (oStatusFD, "status-fd",
116 N_("|FD|write status info to this FD")),
117 /* hidden options */
118 { oHomedir, "homedir", 2, "@" },
119 { oBuilddir, "build-prefix", 2, "@" },
120 { oNull, "null", 0, "@" },
121 { oNoVerbose, "no-verbose", 0, "@"},
122 ARGPARSE_s_n (oShowSocket, "show-socket", "@"),
123 ARGPARSE_s_s (oChUid, "chuid", "@"),
124
125 ARGPARSE_end(),
126 };
127
128
129 /* The stream to output the status information. Status Output is disabled if
130 * this is NULL. */
131 static estream_t statusfp;
132
133 static void show_versions (estream_t fp);
134
135
136
137 /* Print usage information and provide strings for help. */
138 static const char *
my_strusage(int level)139 my_strusage( int level )
140 {
141 const char *p;
142
143 switch (level)
144 {
145 case 9: p = "GPL-3.0-or-later"; break;
146 case 11: p = "@GPGCONF@ (@GNUPG@)";
147 break;
148 case 13: p = VERSION; break;
149 case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
150 case 17: p = PRINTABLE_OS_NAME; break;
151 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
152
153 case 1:
154 case 40: p = _("Usage: @GPGCONF@ [options] (-h for help)");
155 break;
156 case 41:
157 p = _("Syntax: @GPGCONF@ [options]\n"
158 "Manage configuration options for tools of the @GNUPG@ system\n");
159 break;
160
161 default: p = NULL; break;
162 }
163 return p;
164 }
165
166
167 /* Return the fp for the output. This is usually stdout unless
168 --output has been used. In the latter case this function opens
169 that file. */
170 static estream_t
get_outfp(estream_t * fp)171 get_outfp (estream_t *fp)
172 {
173 if (!*fp)
174 {
175 if (opt.outfile)
176 {
177 *fp = es_fopen (opt.outfile, "w");
178 if (!*fp)
179 gc_error (1, errno, "can not open '%s'", opt.outfile);
180 }
181 else
182 *fp = es_stdout;
183 }
184 return *fp;
185 }
186
187
188 /* Set the status FD. */
189 static void
set_status_fd(int fd)190 set_status_fd (int fd)
191 {
192 static int last_fd = -1;
193
194 if (fd != -1 && last_fd == fd)
195 return;
196
197 if (statusfp && statusfp != es_stdout && statusfp != es_stderr)
198 es_fclose (statusfp);
199 statusfp = NULL;
200 if (fd == -1)
201 return;
202
203 if (fd == 1)
204 statusfp = es_stdout;
205 else if (fd == 2)
206 statusfp = es_stderr;
207 else
208 statusfp = es_fdopen (fd, "w");
209 if (!statusfp)
210 {
211 log_fatal ("can't open fd %d for status output: %s\n",
212 fd, gpg_strerror (gpg_error_from_syserror ()));
213 }
214 last_fd = fd;
215 }
216
217
218 /* Write a status line with code NO followed by the output of the
219 * printf style FORMAT. The caller needs to make sure that LFs and
220 * CRs are not printed. */
221 void
gpgconf_write_status(int no,const char * format,...)222 gpgconf_write_status (int no, const char *format, ...)
223 {
224 va_list arg_ptr;
225
226 if (!statusfp)
227 return; /* Not enabled. */
228
229 es_fputs ("[GNUPG:] ", statusfp);
230 es_fputs (get_status_string (no), statusfp);
231 if (format)
232 {
233 es_putc (' ', statusfp);
234 va_start (arg_ptr, format);
235 es_vfprintf (statusfp, format, arg_ptr);
236 va_end (arg_ptr);
237 }
238 es_putc ('\n', statusfp);
239 }
240
241
242 static void
list_dirs(estream_t fp,char ** names)243 list_dirs (estream_t fp, char **names)
244 {
245 static struct {
246 const char *name;
247 const char *(*fnc)(void);
248 const char *extra;
249 } list[] = {
250 { "sysconfdir", gnupg_sysconfdir, NULL },
251 { "bindir", gnupg_bindir, NULL },
252 { "libexecdir", gnupg_libexecdir, NULL },
253 { "libdir", gnupg_libdir, NULL },
254 { "datadir", gnupg_datadir, NULL },
255 { "localedir", gnupg_localedir, NULL },
256 { "socketdir", gnupg_socketdir, NULL },
257 { "dirmngr-socket", dirmngr_socket_name, NULL,},
258 { "keyboxd-socket", keyboxd_socket_name, NULL,},
259 { "agent-ssh-socket", gnupg_socketdir, GPG_AGENT_SSH_SOCK_NAME },
260 { "agent-extra-socket", gnupg_socketdir, GPG_AGENT_EXTRA_SOCK_NAME },
261 { "agent-browser-socket",gnupg_socketdir, GPG_AGENT_BROWSER_SOCK_NAME },
262 { "agent-socket", gnupg_socketdir, GPG_AGENT_SOCK_NAME },
263 { "homedir", gnupg_homedir, NULL }
264 };
265 int idx, j;
266 char *tmp;
267 const char *s;
268
269
270 for (idx = 0; idx < DIM (list); idx++)
271 {
272 s = list[idx].fnc ();
273 if (list[idx].extra)
274 {
275 tmp = make_filename (s, list[idx].extra, NULL);
276 s = tmp;
277 }
278 else
279 tmp = NULL;
280 if (!names)
281 es_fprintf (fp, "%s:%s\n", list[idx].name, gc_percent_escape (s));
282 else
283 {
284 for (j=0; names[j]; j++)
285 if (!strcmp (names[j], list[idx].name))
286 {
287 es_fputs (s, fp);
288 es_putc (opt.null? '\0':'\n', fp);
289 }
290 }
291
292 xfree (tmp);
293 }
294
295
296 #ifdef HAVE_W32_SYSTEM
297 tmp = read_w32_registry_string (NULL,
298 GNUPG_REGISTRY_DIR,
299 "HomeDir");
300 if (tmp)
301 {
302 int hkcu = 0;
303 int hklm = 0;
304
305 xfree (tmp);
306 if ((tmp = read_w32_registry_string ("HKEY_CURRENT_USER",
307 GNUPG_REGISTRY_DIR,
308 "HomeDir")))
309 {
310 xfree (tmp);
311 hkcu = 1;
312 }
313 if ((tmp = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
314 GNUPG_REGISTRY_DIR,
315 "HomeDir")))
316 {
317 xfree (tmp);
318 hklm = 1;
319 }
320
321 es_fflush (fp);
322 log_info ("Warning: homedir taken from registry key (%s:%s) in%s%s\n",
323 GNUPG_REGISTRY_DIR, "HomeDir",
324 hkcu?" HKCU":"",
325 hklm?" HKLM":"");
326
327
328
329 }
330 else if ((tmp = read_w32_registry_string (NULL,
331 GNUPG_REGISTRY_DIR,
332 NULL)))
333 {
334 xfree (tmp);
335 es_fflush (fp);
336 log_info ("Warning: registry key (%s) without value in HKCU or HKLM\n",
337 GNUPG_REGISTRY_DIR);
338 }
339
340
341 #endif /*HAVE_W32_SYSTEM*/
342 }
343
344
345
346 /* Check whether NAME is valid argument for query_swdb(). Valid names
347 * start with a letter and contain only alphanumeric characters or an
348 * underscore. */
349 static int
valid_swdb_name_p(const char * name)350 valid_swdb_name_p (const char *name)
351 {
352 if (!name || !*name || !alphap (name))
353 return 0;
354
355 for (name++; *name; name++)
356 if (!alnump (name) && *name != '_')
357 return 0;
358
359 return 1;
360 }
361
362
363 /* Query the SWDB file. If necessary and possible this functions asks
364 * the dirmngr to load an updated version of that file. The caller
365 * needs to provide the NAME to query (e.g. "gnupg", "libgcrypt") and
366 * optional the currently installed version in CURRENT_VERSION. The
367 * output written to OUT is a colon delimited line with these fields:
368 *
369 * name :: The name of the package
370 * curvers:: The installed version if given.
371 * status :: This value tells the status of the software package
372 * '-' :: No information available
373 * (error or CURRENT_VERSION not given)
374 * '?' :: Unknown NAME
375 * 'u' :: Update available
376 * 'c' :: The version is Current
377 * 'n' :: The current version is already Newer than the
378 * available one.
379 * urgency :: If the value is greater than zero an urgent update is required.
380 * error :: 0 on success or an gpg_err_code_t
381 * Common codes seen:
382 * GPG_ERR_TOO_OLD :: The SWDB file is to old to be used.
383 * GPG_ERR_ENOENT :: The SWDB file is not available.
384 * GPG_ERR_BAD_SIGNATURE :: Corrupted SWDB file.
385 * filedate:: Date of the swdb file (yyyymmddThhmmss)
386 * verified:: Date we checked the validity of the file (yyyyymmddThhmmss)
387 * version :: The version string from the swdb.
388 * reldate :: Release date of that version (yyyymmddThhmmss)
389 * size :: Size of the package in bytes.
390 * hash :: SHA-2 hash of the package.
391 *
392 */
393 static void
query_swdb(estream_t out,const char * name,const char * current_version)394 query_swdb (estream_t out, const char *name, const char *current_version)
395 {
396 gpg_error_t err;
397 const char *search_name;
398 char *fname = NULL;
399 estream_t fp = NULL;
400 char *line = NULL;
401 char *self_version = NULL;
402 size_t length_of_line = 0;
403 size_t maxlen;
404 ssize_t len;
405 const char *fields[2];
406 char *p;
407 gnupg_isotime_t filedate = {0};
408 gnupg_isotime_t verified = {0};
409 char *value_ver = NULL;
410 gnupg_isotime_t value_date = {0};
411 char *value_size = NULL;
412 char *value_sha2 = NULL;
413 unsigned long value_size_ul = 0;
414 int status, i;
415
416
417 if (!valid_swdb_name_p (name))
418 {
419 log_error ("error in package name '%s': %s\n",
420 name, gpg_strerror (GPG_ERR_INV_NAME));
421 goto leave;
422 }
423 if (!strcmp (name, "gnupg"))
424 search_name = GNUPG_SWDB_TAG;
425 else if (!strcmp (name, "gnupg1"))
426 search_name = "gnupg1";
427 else
428 search_name = name;
429
430 if (!current_version && !strcmp (name, "gnupg"))
431 {
432 /* Use our own version but string a possible beta string. */
433 self_version = xstrdup (PACKAGE_VERSION);
434 p = strchr (self_version, '-');
435 if (p)
436 *p = 0;
437 current_version = self_version;
438 }
439
440 if (current_version && (strchr (current_version, ':')
441 || compare_version_strings (current_version, NULL)))
442 {
443 log_error ("error in version string '%s': %s\n",
444 current_version, gpg_strerror (GPG_ERR_INV_ARG));
445 goto leave;
446 }
447
448 fname = make_filename (gnupg_homedir (), "swdb.lst", NULL);
449 fp = es_fopen (fname, "r");
450 if (!fp)
451 {
452 err = gpg_error_from_syserror ();
453 es_fprintf (out, "%s:%s:-::%u:::::::\n",
454 name,
455 current_version? current_version : "",
456 gpg_err_code (err));
457 if (gpg_err_code (err) != GPG_ERR_ENOENT)
458 log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
459 goto leave;
460 }
461
462 /* Note that the parser uses the first occurrence of a matching
463 * values and ignores possible duplicated values. */
464
465 maxlen = 2048; /* Set limit. */
466 while ((len = es_read_line (fp, &line, &length_of_line, &maxlen)) > 0)
467 {
468 if (!maxlen)
469 {
470 err = gpg_error (GPG_ERR_LINE_TOO_LONG);
471 log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
472 goto leave;
473 }
474 /* Strip newline and carriage return, if present. */
475 while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
476 line[--len] = '\0';
477
478 if (split_fields (line, fields, DIM (fields)) < DIM(fields))
479 continue; /* Skip empty lines and names w/o a value. */
480 if (*fields[0] == '#')
481 continue; /* Skip comments. */
482
483 /* Record the meta data. */
484 if (!*filedate && !strcmp (fields[0], ".filedate"))
485 {
486 string2isotime (filedate, fields[1]);
487 continue;
488 }
489 if (!*verified && !strcmp (fields[0], ".verified"))
490 {
491 string2isotime (verified, fields[1]);
492 continue;
493 }
494
495 /* Tokenize the name. */
496 p = strrchr (fields[0], '_');
497 if (!p)
498 continue; /* Name w/o an underscore. */
499 *p++ = 0;
500
501 /* Wait for the requested name. */
502 if (!strcmp (fields[0], search_name))
503 {
504 if (!strcmp (p, "ver") && !value_ver)
505 value_ver = xstrdup (fields[1]);
506 else if (!strcmp (p, "date") && !*value_date)
507 string2isotime (value_date, fields[1]);
508 else if (!strcmp (p, "size") && !value_size)
509 value_size = xstrdup (fields[1]);
510 else if (!strcmp (p, "sha2") && !value_sha2)
511 value_sha2 = xstrdup (fields[1]);
512 }
513 }
514 if (len < 0 || es_ferror (fp))
515 {
516 err = gpg_error_from_syserror ();
517 log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
518 goto leave;
519 }
520
521 if (!*filedate || !*verified)
522 {
523 err = gpg_error (GPG_ERR_INV_TIME);
524 es_fprintf (out, "%s:%s:-::%u:::::::\n",
525 name,
526 current_version? current_version : "",
527 gpg_err_code (err));
528 goto leave;
529 }
530
531 if (!value_ver)
532 {
533 es_fprintf (out, "%s:%s:?:::::::::\n",
534 name,
535 current_version? current_version : "");
536 goto leave;
537 }
538
539 if (value_size)
540 {
541 gpg_err_set_errno (0);
542 value_size_ul = strtoul (value_size, &p, 10);
543 if (errno)
544 value_size_ul = 0;
545 else if (*p == 'k')
546 value_size_ul *= 1024;
547 }
548
549 err = 0;
550 status = '-';
551 if (compare_version_strings (value_ver, NULL))
552 err = gpg_error (GPG_ERR_INV_VALUE);
553 else if (!current_version)
554 ;
555 else if (!(i = compare_version_strings (value_ver, current_version)))
556 status = 'c';
557 else if (i > 0)
558 status = 'u';
559 else
560 status = 'n';
561
562 es_fprintf (out, "%s:%s:%c::%d:%s:%s:%s:%s:%lu:%s:\n",
563 name,
564 current_version? current_version : "",
565 status,
566 err,
567 filedate,
568 verified,
569 value_ver,
570 value_date,
571 value_size_ul,
572 value_sha2? value_sha2 : "");
573
574 leave:
575 xfree (value_ver);
576 xfree (value_size);
577 xfree (value_sha2);
578 xfree (line);
579 es_fclose (fp);
580 xfree (fname);
581 xfree (self_version);
582 }
583
584
585 /* gpgconf main. */
586 int
main(int argc,char ** argv)587 main (int argc, char **argv)
588 {
589 gpg_error_t err;
590 gpgrt_argparse_t pargs;
591 const char *fname;
592 int no_more_options = 0;
593 enum cmd_and_opt_values cmd = 0;
594 estream_t outfp = NULL;
595 int show_socket = 0;
596 const char *changeuser = NULL;
597
598 early_system_init ();
599 gnupg_reopen_std (GPGCONF_NAME);
600 gpgrt_set_strusage (my_strusage);
601 log_set_prefix (GPGCONF_NAME, GPGRT_LOG_WITH_PREFIX);
602
603 /* Make sure that our subsystems are ready. */
604 i18n_init();
605 init_common_subsystems (&argc, &argv);
606 gc_components_init ();
607
608 /* Parse the command line. */
609 pargs.argc = &argc;
610 pargs.argv = &argv;
611 pargs.flags = ARGPARSE_FLAG_KEEP;
612 while (!no_more_options && gpgrt_argparse (NULL, &pargs, opts))
613 {
614 switch (pargs.r_opt)
615 {
616 case oOutput: opt.outfile = pargs.r.ret_str; break;
617 case oQuiet: opt.quiet = 1; break;
618 case oDryRun: opt.dry_run = 1; break;
619 case oRuntime: opt.runtime = 1; break;
620 case oVerbose: opt.verbose++; break;
621 case oNoVerbose: opt.verbose = 0; break;
622 case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
623 case oBuilddir: gnupg_set_builddir (pargs.r.ret_str); break;
624 case oNull: opt.null = 1; break;
625 case oStatusFD:
626 set_status_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
627 break;
628 case oShowSocket: show_socket = 1; break;
629 case oChUid: changeuser = pargs.r.ret_str; break;
630
631 case aListDirs:
632 case aListComponents:
633 case aCheckPrograms:
634 case aListOptions:
635 case aChangeOptions:
636 case aCheckOptions:
637 case aApplyDefaults:
638 case aApplyProfile:
639 case aListConfig:
640 case aCheckConfig:
641 case aQuerySWDB:
642 case aReload:
643 case aLaunch:
644 case aKill:
645 case aCreateSocketDir:
646 case aRemoveSocketDir:
647 case aShowVersions:
648 case aShowCodepages:
649 cmd = pargs.r_opt;
650 break;
651
652 default: pargs.err = 2; break;
653 }
654 }
655
656 gpgrt_argparse (NULL, &pargs, NULL); /* Release internal state. */
657
658 if (log_get_errorcount (0))
659 gpgconf_failure (GPG_ERR_USER_2);
660
661 /* Print a warning if an argument looks like an option. */
662 if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
663 {
664 int i;
665
666 for (i=0; i < argc; i++)
667 if (argv[i][0] == '-' && argv[i][1] == '-')
668 log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
669 }
670
671 fname = argc ? *argv : NULL;
672
673 /* If requested switch to the requested user or die. */
674 if (changeuser && (err = gnupg_chuid (changeuser, 0)))
675 gpgconf_failure (err);
676
677 /* Set the configuraton directories for use by gpgrt_argparser. We
678 * don't have a configuration file for this program but we have code
679 * which reads the component's config files. */
680 gpgrt_set_confdir (GPGRT_CONFDIR_SYS, gnupg_sysconfdir ());
681 gpgrt_set_confdir (GPGRT_CONFDIR_USER, gnupg_homedir ());
682
683 switch (cmd)
684 {
685 case aListComponents:
686 default:
687 /* List all components. */
688 gc_component_list_components (get_outfp (&outfp));
689 break;
690
691 case aCheckPrograms:
692 /* Check all programs. */
693 gc_check_programs (get_outfp (&outfp));
694 break;
695
696 case aListOptions:
697 case aChangeOptions:
698 case aCheckOptions:
699 if (!fname)
700 {
701 es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
702 es_putc ('\n', es_stderr);
703 es_fputs (_("Need one component argument"), es_stderr);
704 es_putc ('\n', es_stderr);
705 gpgconf_failure (GPG_ERR_USER_2);
706 }
707 else
708 {
709 int idx = gc_component_find (fname);
710 if (idx < 0)
711 {
712 es_fputs (_("Component not found"), es_stderr);
713 es_putc ('\n', es_stderr);
714 gpgconf_failure (0);
715 }
716 if (cmd == aCheckOptions)
717 gc_component_check_options (idx, get_outfp (&outfp), NULL);
718 else
719 {
720 gc_component_retrieve_options (idx);
721 if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
722 gpgconf_failure (0);
723 if (cmd == aListOptions)
724 gc_component_list_options (idx, get_outfp (&outfp));
725 else if (cmd == aChangeOptions)
726 gc_component_change_options (idx, es_stdin,
727 get_outfp (&outfp), 0);
728 }
729 }
730 break;
731
732 case aLaunch:
733 case aKill:
734 if (!fname)
735 {
736 es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
737 es_putc ('\n', es_stderr);
738 es_fputs (_("Need one component argument"), es_stderr);
739 es_putc ('\n', es_stderr);
740 gpgconf_failure (GPG_ERR_USER_2);
741 }
742 else if (!strcmp (fname, "all"))
743 {
744 if (cmd == aLaunch)
745 {
746 if (gc_component_launch (-1))
747 gpgconf_failure (0);
748 }
749 else
750 {
751 gc_component_kill (-1);
752 }
753 }
754 else
755 {
756 /* Launch/Kill a given component. */
757 int idx;
758
759 idx = gc_component_find (fname);
760 if (idx < 0)
761 {
762 es_fputs (_("Component not found"), es_stderr);
763 es_putc ('\n', es_stderr);
764 gpgconf_failure (0);
765 }
766 else if (cmd == aLaunch)
767 {
768 err = gc_component_launch (idx);
769 if (show_socket)
770 {
771 char *names[2];
772
773 if (idx == GC_COMPONENT_GPG_AGENT)
774 names[0] = "agent-socket";
775 else if (idx == GC_COMPONENT_DIRMNGR)
776 names[0] = "dirmngr-socket";
777 else if (idx == GC_COMPONENT_KEYBOXD)
778 names[0] = "keyboxd-socket";
779 else
780 names[0] = NULL;
781 names[1] = NULL;
782 get_outfp (&outfp);
783 list_dirs (outfp, names);
784 }
785 if (err)
786 gpgconf_failure (0);
787 }
788 else
789 {
790 /* We don't error out if the kill failed because this
791 command should do nothing if the component is not
792 running. */
793 gc_component_kill (idx);
794 }
795 }
796 break;
797
798 case aReload:
799 if (!fname || !strcmp (fname, "all"))
800 {
801 /* Reload all. */
802 gc_component_reload (-1);
803 }
804 else
805 {
806 /* Reload given component. */
807 int idx;
808
809 idx = gc_component_find (fname);
810 if (idx < 0)
811 {
812 es_fputs (_("Component not found"), es_stderr);
813 es_putc ('\n', es_stderr);
814 gpgconf_failure (0);
815 }
816 else
817 {
818 gc_component_reload (idx);
819 }
820 }
821 break;
822
823 case aListConfig:
824 if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
825 gpgconf_failure (0);
826 break;
827
828 case aCheckConfig:
829 if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
830 gpgconf_failure (0);
831 break;
832
833 case aApplyDefaults:
834 if (fname)
835 {
836 es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
837 es_putc ('\n', es_stderr);
838 es_fputs (_("No argument allowed"), es_stderr);
839 es_putc ('\n', es_stderr);
840 gpgconf_failure (GPG_ERR_USER_2);
841 }
842 if (!opt.dry_run && gnupg_access (gnupg_homedir (), F_OK))
843 gnupg_maybe_make_homedir (gnupg_homedir (), opt.quiet);
844 gc_component_retrieve_options (-1);
845 if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
846 gpgconf_failure (0);
847 break;
848
849 case aApplyProfile:
850 if (!opt.dry_run && gnupg_access (gnupg_homedir (), F_OK))
851 gnupg_maybe_make_homedir (gnupg_homedir (), opt.quiet);
852 gc_component_retrieve_options (-1);
853 if (gc_apply_profile (fname))
854 gpgconf_failure (0);
855 break;
856
857 case aListDirs:
858 /* Show the system configuration directories for gpgconf. */
859 get_outfp (&outfp);
860 list_dirs (outfp, argc? argv : NULL);
861 break;
862
863 case aQuerySWDB:
864 /* Query the software version database. */
865 if (!fname || argc > 2)
866 {
867 es_fprintf (es_stderr, "usage: %s --query-swdb NAME [VERSION]\n",
868 GPGCONF_NAME);
869 gpgconf_failure (GPG_ERR_USER_2);
870 }
871 get_outfp (&outfp);
872 query_swdb (outfp, fname, argc > 1? argv[1] : NULL);
873 break;
874
875 case aCreateSocketDir:
876 {
877 char *socketdir;
878 unsigned int flags;
879
880 /* Make sure that the top /run/user/UID/gnupg dir has been
881 * created. */
882 gnupg_socketdir ();
883
884 /* Check the /var/run dir. */
885 socketdir = _gnupg_socketdir_internal (1, &flags);
886 if ((flags & 64) && !opt.dry_run)
887 {
888 /* No sub dir - create it. */
889 if (gnupg_mkdir (socketdir, "-rwx"))
890 gc_error (1, errno, "error creating '%s'", socketdir);
891 /* Try again. */
892 xfree (socketdir);
893 socketdir = _gnupg_socketdir_internal (1, &flags);
894 }
895
896 /* Give some info. */
897 if ( (flags & ~32) || opt.verbose || opt.dry_run)
898 {
899 log_info ("socketdir is '%s'\n", socketdir);
900 if ((flags & 1)) log_info ("\tgeneral error\n");
901 if ((flags & 2)) log_info ("\tno /run/user dir\n");
902 if ((flags & 4)) log_info ("\tbad permissions\n");
903 if ((flags & 8)) log_info ("\tbad permissions (subdir)\n");
904 if ((flags & 16)) log_info ("\tmkdir failed\n");
905 if ((flags & 32)) log_info ("\tnon-default homedir\n");
906 if ((flags & 64)) log_info ("\tno such subdir\n");
907 if ((flags & 128)) log_info ("\tusing homedir as fallback\n");
908 }
909
910 if ((flags & ~32) && !opt.dry_run)
911 gc_error (1, 0, "error creating socket directory");
912
913 xfree (socketdir);
914 }
915 break;
916
917 case aRemoveSocketDir:
918 {
919 char *socketdir;
920 unsigned int flags;
921
922 /* Check the /var/run dir. */
923 socketdir = _gnupg_socketdir_internal (1, &flags);
924 if ((flags & 128))
925 log_info ("ignoring request to remove non /run/user socket dir\n");
926 else if (opt.dry_run)
927 ;
928 else if (gnupg_rmdir (socketdir))
929 {
930 /* If the director is not empty we first try to delete
931 * socket files. */
932 err = gpg_error_from_syserror ();
933 if (gpg_err_code (err) == GPG_ERR_ENOTEMPTY
934 || gpg_err_code (err) == GPG_ERR_EEXIST)
935 {
936 static const char * const names[] = {
937 GPG_AGENT_SOCK_NAME,
938 GPG_AGENT_EXTRA_SOCK_NAME,
939 GPG_AGENT_BROWSER_SOCK_NAME,
940 GPG_AGENT_SSH_SOCK_NAME,
941 SCDAEMON_SOCK_NAME,
942 KEYBOXD_SOCK_NAME,
943 DIRMNGR_SOCK_NAME
944 };
945 int i;
946 char *p;
947
948 for (i=0; i < DIM(names); i++)
949 {
950 p = strconcat (socketdir , "/", names[i], NULL);
951 if (p)
952 gnupg_remove (p);
953 xfree (p);
954 }
955 if (gnupg_rmdir (socketdir))
956 gc_error (1, 0, "error removing '%s': %s",
957 socketdir, gpg_strerror (err));
958 }
959 else if (gpg_err_code (err) == GPG_ERR_ENOENT)
960 gc_error (0, 0, "warning: removing '%s' failed: %s",
961 socketdir, gpg_strerror (err));
962 else
963 gc_error (1, 0, "error removing '%s': %s",
964 socketdir, gpg_strerror (err));
965 }
966
967 xfree (socketdir);
968 }
969 break;
970
971 case aShowVersions:
972 {
973 get_outfp (&outfp);
974 show_versions (outfp);
975 }
976 break;
977
978 case aShowCodepages:
979 #ifdef HAVE_W32_SYSTEM
980 {
981 get_outfp (&outfp);
982 if (GetConsoleCP () != GetConsoleOutputCP ())
983 es_fprintf (outfp, "Console: CP%u/CP%u\n",
984 GetConsoleCP (), GetConsoleOutputCP ());
985 else
986 es_fprintf (outfp, "Console: CP%u\n", GetConsoleCP ());
987 es_fprintf (outfp, "ANSI: CP%u\n", GetACP ());
988 es_fprintf (outfp, "OEM: CP%u\n", GetOEMCP ());
989 }
990 #endif
991 break;
992
993
994 }
995
996 if (outfp != es_stdout)
997 if (es_fclose (outfp))
998 gc_error (1, errno, "error closing '%s'", opt.outfile);
999
1000
1001 if (log_get_errorcount (0))
1002 gpgconf_failure (0);
1003 else
1004 gpgconf_write_status (STATUS_SUCCESS, NULL);
1005 return 0;
1006 }
1007
1008
1009 void
gpgconf_failure(gpg_error_t err)1010 gpgconf_failure (gpg_error_t err)
1011 {
1012 log_flush ();
1013 if (!err)
1014 err = gpg_error (GPG_ERR_GENERAL);
1015 gpgconf_write_status
1016 (STATUS_FAILURE, "- %u",
1017 gpg_err_code (err) == GPG_ERR_USER_2? GPG_ERR_EINVAL : err);
1018 exit (gpg_err_code (err) == GPG_ERR_USER_2? 2 : 1);
1019 }
1020
1021
1022
1023 /* Parse the revision part from the extended version blurb. */
1024 static const char *
get_revision_from_blurb(const char * blurb,int * r_len)1025 get_revision_from_blurb (const char *blurb, int *r_len)
1026 {
1027 const char *s = blurb? blurb : "";
1028 int n;
1029
1030 for (; *s; s++)
1031 if (*s == '\n' && s[1] == '(')
1032 break;
1033 if (s)
1034 {
1035 s += 2;
1036 for (n=0; s[n] && s[n] != ' '; n++)
1037 ;
1038 }
1039 else
1040 {
1041 s = "?";
1042 n = 1;
1043 }
1044 *r_len = n;
1045 return s;
1046 }
1047
1048
1049 static void
show_version_gnupg(estream_t fp)1050 show_version_gnupg (estream_t fp)
1051 {
1052 es_fprintf (fp, "* GnuPG %s (%s)\n%s\n",
1053 gpgrt_strusage (13), BUILD_REVISION, gpgrt_strusage (17));
1054 #ifdef HAVE_W32_SYSTEM
1055 {
1056 OSVERSIONINFO osvi = { sizeof (osvi) };
1057
1058 GetVersionEx (&osvi);
1059 es_fprintf (fp, "Windows %lu.%lu build %lu%s%s%s\n",
1060 (unsigned long)osvi.dwMajorVersion,
1061 (unsigned long)osvi.dwMinorVersion,
1062 (unsigned long)osvi.dwBuildNumber,
1063 *osvi.szCSDVersion? " (":"",
1064 osvi.szCSDVersion,
1065 *osvi.szCSDVersion? ")":""
1066 );
1067 }
1068 #endif /*HAVE_W32_SYSTEM*/
1069 }
1070
1071
1072 static void
show_version_libgcrypt(estream_t fp)1073 show_version_libgcrypt (estream_t fp)
1074 {
1075 const char *s;
1076 int n;
1077
1078 s = get_revision_from_blurb (gcry_check_version ("\x01\x01"), &n);
1079 es_fprintf (fp, "* Libgcrypt %s (%.*s)\n",
1080 gcry_check_version (NULL), n, s);
1081 s = gcry_get_config (0, NULL);
1082 if (s)
1083 es_fputs (s, fp);
1084 }
1085
1086
1087 static void
show_version_gpgrt(estream_t fp)1088 show_version_gpgrt (estream_t fp)
1089 {
1090 const char *s;
1091 int n;
1092
1093 s = get_revision_from_blurb (gpg_error_check_version ("\x01\x01"), &n);
1094 es_fprintf (fp, "* GpgRT %s (%.*s)\n",
1095 gpg_error_check_version (NULL), n, s);
1096 }
1097
1098
1099 /* Printing version information for other libraries is problematic
1100 * because we don't want to link gpgconf to all these libraries. The
1101 * best solution is delegating this to dirmngr which uses libassuan,
1102 * libksba, libnpth and ntbtls anyway. */
1103 static void
show_versions_via_dirmngr(estream_t fp)1104 show_versions_via_dirmngr (estream_t fp)
1105 {
1106 gpg_error_t err;
1107 const char *pgmname;
1108 const char *argv[2];
1109 estream_t outfp;
1110 pid_t pid;
1111 char *line = NULL;
1112 size_t line_len = 0;
1113 ssize_t length;
1114 int exitcode;
1115
1116 pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
1117 argv[0] = "--gpgconf-versions";
1118 argv[1] = NULL;
1119 err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
1120 NULL, &outfp, NULL, &pid);
1121 if (err)
1122 {
1123 log_error ("error spawning %s: %s", pgmname, gpg_strerror (err));
1124 es_fprintf (fp, "[error: can't get further info]\n");
1125 return;
1126 }
1127
1128 while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
1129 {
1130 /* Strip newline and carriage return, if present. */
1131 while (length > 0
1132 && (line[length - 1] == '\n' || line[length - 1] == '\r'))
1133 line[--length] = '\0';
1134 es_fprintf (fp, "%s\n", line);
1135 }
1136 if (length < 0 || es_ferror (outfp))
1137 {
1138 err = gpg_error_from_syserror ();
1139 log_error ("error reading from %s: %s\n", pgmname, gpg_strerror (err));
1140 }
1141 if (es_fclose (outfp))
1142 {
1143 err = gpg_error_from_syserror ();
1144 log_error ("error closing output stream of %s: %s\n",
1145 pgmname, gpg_strerror (err));
1146 }
1147
1148 err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
1149 if (err)
1150 {
1151 log_error ("running %s failed (exitcode=%d): %s\n",
1152 pgmname, exitcode, gpg_strerror (err));
1153 es_fprintf (fp, "[error: can't get further info]\n");
1154 }
1155 gnupg_release_process (pid);
1156 xfree (line);
1157 }
1158
1159
1160 /* Show all kind of version information. */
1161 static void
show_versions(estream_t fp)1162 show_versions (estream_t fp)
1163 {
1164 show_version_gnupg (fp);
1165 es_fputc ('\n', fp);
1166 show_version_libgcrypt (fp);
1167 es_fputc ('\n', fp);
1168 show_version_gpgrt (fp);
1169 es_fputc ('\n', fp);
1170 show_versions_via_dirmngr (fp);
1171 }
1172