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