Line data Source code
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 : */
20 :
21 : #include <config.h>
22 : #include <errno.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <unistd.h>
27 :
28 : #include "gpgconf.h"
29 : #include "i18n.h"
30 : #include "sysutils.h"
31 : #include "../common/init.h"
32 :
33 :
34 : /* Constants to identify the commands and options. */
35 : enum cmd_and_opt_values
36 : {
37 : aNull = 0,
38 : oDryRun = 'n',
39 : oOutput = 'o',
40 : oQuiet = 'q',
41 : oVerbose = 'v',
42 : oRuntime = 'r',
43 : oComponent = 'c',
44 : oNull = '0',
45 : oNoVerbose = 500,
46 : oHomedir,
47 :
48 : aListComponents,
49 : aCheckPrograms,
50 : aListOptions,
51 : aChangeOptions,
52 : aCheckOptions,
53 : aApplyDefaults,
54 : aListConfig,
55 : aCheckConfig,
56 : aQuerySWDB,
57 : aListDirs,
58 : aLaunch,
59 : aKill,
60 : aCreateSocketDir,
61 : aRemoveSocketDir,
62 : aReload
63 : };
64 :
65 :
66 : /* The list of commands and options. */
67 : static ARGPARSE_OPTS opts[] =
68 : {
69 : { 300, NULL, 0, N_("@Commands:\n ") },
70 :
71 : { aListComponents, "list-components", 256, N_("list all components") },
72 : { aCheckPrograms, "check-programs", 256, N_("check all programs") },
73 : { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
74 : { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
75 : { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
76 : { aApplyDefaults, "apply-defaults", 256,
77 : N_("apply global default values") },
78 : { aListDirs, "list-dirs", 256,
79 : N_("get the configuration directories for @GPGCONF@") },
80 : { aListConfig, "list-config", 256,
81 : N_("list global configuration file") },
82 : { aCheckConfig, "check-config", 256,
83 : N_("check global configuration file") },
84 : { aQuerySWDB, "query-swdb", 256,
85 : N_("query the software version database") },
86 : { aReload, "reload", 256, N_("reload all or a given component")},
87 : { aLaunch, "launch", 256, N_("launch a given component")},
88 : { aKill, "kill", 256, N_("kill a given component")},
89 : { aCreateSocketDir, "create-socketdir", 256, "@"},
90 : { aRemoveSocketDir, "remove-socketdir", 256, "@"},
91 :
92 : { 301, NULL, 0, N_("@\nOptions:\n ") },
93 :
94 : { oOutput, "output", 2, N_("use as output file") },
95 : { oVerbose, "verbose", 0, N_("verbose") },
96 : { oQuiet, "quiet", 0, N_("quiet") },
97 : { oDryRun, "dry-run", 0, N_("do not make any changes") },
98 : { oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") },
99 : /* hidden options */
100 : { oHomedir, "homedir", 2, "@" },
101 : { oNull, "null", 0, "@" },
102 : { oNoVerbose, "no-verbose", 0, "@"},
103 : {0}
104 : };
105 :
106 :
107 : /* Print usage information and and provide strings for help. */
108 : static const char *
109 0 : my_strusage( int level )
110 : {
111 : const char *p;
112 :
113 0 : switch (level)
114 : {
115 0 : case 11: p = "@GPGCONF@ (@GNUPG@)";
116 0 : break;
117 0 : case 13: p = VERSION; break;
118 0 : case 17: p = PRINTABLE_OS_NAME; break;
119 0 : case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
120 :
121 : case 1:
122 0 : case 40: p = _("Usage: @GPGCONF@ [options] (-h for help)");
123 0 : break;
124 : case 41:
125 0 : p = _("Syntax: @GPGCONF@ [options]\n"
126 : "Manage configuration options for tools of the @GNUPG@ system\n");
127 0 : break;
128 :
129 0 : default: p = NULL; break;
130 : }
131 0 : return p;
132 : }
133 :
134 :
135 : /* Return the fp for the output. This is usually stdout unless
136 : --output has been used. In the latter case this function opens
137 : that file. */
138 : static estream_t
139 1 : get_outfp (estream_t *fp)
140 : {
141 1 : if (!*fp)
142 : {
143 1 : if (opt.outfile)
144 : {
145 0 : *fp = es_fopen (opt.outfile, "w");
146 0 : if (!*fp)
147 0 : gc_error (1, errno, "can not open '%s'", opt.outfile);
148 : }
149 : else
150 1 : *fp = es_stdout;
151 : }
152 1 : return *fp;
153 : }
154 :
155 :
156 : static void
157 1 : list_dirs (estream_t fp, char **names)
158 : {
159 : static struct {
160 : const char *name;
161 : const char *(*fnc)(void);
162 : const char *extra;
163 : } list[] = {
164 : { "sysconfdir", gnupg_sysconfdir, NULL },
165 : { "bindir", gnupg_bindir, NULL },
166 : { "libexecdir", gnupg_libexecdir, NULL },
167 : { "libdir", gnupg_libdir, NULL },
168 : { "datadir", gnupg_datadir, NULL },
169 : { "localedir", gnupg_localedir, NULL },
170 : { "socketdir", gnupg_socketdir, NULL },
171 : { "dirmngr-socket", dirmngr_socket_name, NULL,},
172 : { "agent-ssh-socket", gnupg_socketdir, GPG_AGENT_SSH_SOCK_NAME },
173 : { "agent-extra-socket", gnupg_socketdir, GPG_AGENT_EXTRA_SOCK_NAME },
174 : { "agent-browser-socket",gnupg_socketdir, GPG_AGENT_BROWSER_SOCK_NAME },
175 : { "agent-socket", gnupg_socketdir, GPG_AGENT_SOCK_NAME },
176 : { "homedir", gnupg_homedir, NULL }
177 : };
178 : int idx, j;
179 : char *tmp;
180 : const char *s;
181 :
182 :
183 14 : for (idx = 0; idx < DIM (list); idx++)
184 : {
185 13 : s = list[idx].fnc ();
186 13 : if (list[idx].extra)
187 : {
188 4 : tmp = make_filename (s, list[idx].extra, NULL);
189 4 : s = tmp;
190 : }
191 : else
192 9 : tmp = NULL;
193 13 : if (!names)
194 0 : es_fprintf (fp, "%s:%s\n", list[idx].name, gc_percent_escape (s));
195 : else
196 : {
197 26 : for (j=0; names[j]; j++)
198 13 : if (!strcmp (names[j], list[idx].name))
199 : {
200 1 : es_fputs (s, fp);
201 1 : es_putc (opt.null? '\0':'\n', fp);
202 : }
203 : }
204 :
205 13 : xfree (tmp);
206 : }
207 1 : }
208 :
209 :
210 :
211 : /* Check whether NAME is valid argument for query_swdb(). Valid names
212 : * start with a letter and contain only alphanumeric characters or an
213 : * underscore. */
214 : static int
215 0 : valid_swdb_name_p (const char *name)
216 : {
217 0 : if (!name || !*name || !alphap (name))
218 0 : return 0;
219 :
220 0 : for (name++; *name; name++)
221 0 : if (!alnump (name) && *name != '_')
222 0 : return 0;
223 :
224 0 : return 1;
225 : }
226 :
227 :
228 : /* Query the SWDB file. If necessary and possible this functions asks
229 : * the dirmngr to load an updated version of that file. The caller
230 : * needs to provide the NAME to query (e.g. "gnupg", "libgcrypt") and
231 : * optional the currently installed version in CURRENT_VERSION. The
232 : * output written to OUT is a colon delimited line with these fields:
233 : *
234 : * name :: The name of the package
235 : * curvers:: The installed version if given.
236 : * status :: This value tells the status of the software package
237 : * '-' :: No information available
238 : * (error or CURRENT_VERSION not given)
239 : * '?' :: Unknown NAME
240 : * 'u' :: Update available
241 : * 'c' :: The version is Current
242 : * 'n' :: The current version is already Newer than the
243 : * available one.
244 : * urgency :: If the value is greater than zero an urgent update is required.
245 : * error :: 0 on success or an gpg_err_code_t
246 : * Common codes seen:
247 : * GPG_ERR_TOO_OLD :: The SWDB file is to old to be used.
248 : * GPG_ERR_ENOENT :: The SWDB file is not available.
249 : * GPG_ERR_BAD_SIGNATURE :: Currupted SWDB file.
250 : * filedate:: Date of the swdb file (yyyymmddThhmmss)
251 : * verified:: Date we checked the validity of the file (yyyyymmddThhmmss)
252 : * version :: The version string from the swdb.
253 : * reldate :: Release date of that version (yyyymmddThhmmss)
254 : * size :: Size of the package in bytes.
255 : * hash :: SHA-2 hash of the package.
256 : *
257 : */
258 : static void
259 0 : query_swdb (estream_t out, const char *name, const char *current_version)
260 : {
261 : gpg_error_t err;
262 : const char *search_name;
263 0 : char *fname = NULL;
264 0 : estream_t fp = NULL;
265 0 : char *line = NULL;
266 0 : char *self_version = NULL;
267 0 : size_t length_of_line = 0;
268 : size_t maxlen;
269 : ssize_t len;
270 : char *fields[2];
271 : char *p;
272 0 : gnupg_isotime_t filedate = {0};
273 0 : gnupg_isotime_t verified = {0};
274 0 : char *value_ver = NULL;
275 0 : gnupg_isotime_t value_date = {0};
276 0 : char *value_size = NULL;
277 0 : char *value_sha2 = NULL;
278 : unsigned long value_size_ul;
279 : int status, i;
280 :
281 :
282 0 : if (!valid_swdb_name_p (name))
283 : {
284 0 : log_error ("error in package name '%s': %s\n",
285 : name, gpg_strerror (GPG_ERR_INV_NAME));
286 0 : goto leave;
287 : }
288 0 : if (!strcmp (name, "gnupg"))
289 0 : search_name = "gnupg21";
290 0 : else if (!strcmp (name, "gnupg1"))
291 0 : search_name = "gnupg1";
292 : else
293 0 : search_name = name;
294 :
295 0 : if (!current_version && !strcmp (name, "gnupg"))
296 : {
297 : /* Use our own version but string a possible beta string. */
298 0 : self_version = xstrdup (PACKAGE_VERSION);
299 0 : p = strchr (self_version, '-');
300 0 : if (p)
301 0 : *p = 0;
302 0 : current_version = self_version;
303 : }
304 :
305 0 : if (current_version && (strchr (current_version, ':')
306 0 : || compare_version_strings (current_version, NULL)))
307 : {
308 0 : log_error ("error in version string '%s': %s\n",
309 : current_version, gpg_strerror (GPG_ERR_INV_ARG));
310 0 : goto leave;
311 : }
312 :
313 0 : fname = make_filename (gnupg_homedir (), "swdb.lst", NULL);
314 0 : fp = es_fopen (fname, "r");
315 0 : if (!fp)
316 : {
317 0 : err = gpg_error_from_syserror ();
318 0 : es_fprintf (out, "%s:%s:-::%u:::::::\n",
319 : name,
320 : current_version? current_version : "",
321 0 : gpg_err_code (err));
322 0 : if (gpg_err_code (err) != GPG_ERR_ENOENT)
323 0 : log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
324 0 : goto leave;
325 : }
326 :
327 : /* Note that the parser uses the first occurance of a matching
328 : * values and ignores possible duplicated values. */
329 :
330 0 : maxlen = 2048; /* Set limit. */
331 0 : while ((len = es_read_line (fp, &line, &length_of_line, &maxlen)) > 0)
332 : {
333 0 : if (!maxlen)
334 : {
335 0 : err = gpg_error (GPG_ERR_LINE_TOO_LONG);
336 0 : log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
337 0 : goto leave;
338 : }
339 : /* Strip newline and carriage return, if present. */
340 0 : while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
341 0 : line[--len] = '\0';
342 :
343 0 : if (split_fields (line, fields, DIM (fields)) < DIM(fields))
344 0 : continue; /* Skip empty lines and names w/o a value. */
345 0 : if (*fields[0] == '#')
346 0 : continue; /* Skip comments. */
347 :
348 : /* Record the meta data. */
349 0 : if (!*filedate && !strcmp (fields[0], ".filedate"))
350 : {
351 0 : string2isotime (filedate, fields[1]);
352 0 : continue;
353 : }
354 0 : if (!*verified && !strcmp (fields[0], ".verified"))
355 : {
356 0 : string2isotime (verified, fields[1]);
357 0 : continue;
358 : }
359 :
360 : /* Tokenize the name. */
361 0 : p = strrchr (fields[0], '_');
362 0 : if (!p)
363 0 : continue; /* Name w/o an underscore. */
364 0 : *p++ = 0;
365 :
366 : /* Wait for the requested name. */
367 0 : if (!strcmp (fields[0], search_name))
368 : {
369 0 : if (!strcmp (p, "ver") && !value_ver)
370 0 : value_ver = xstrdup (fields[1]);
371 0 : else if (!strcmp (p, "date") && !*value_date)
372 0 : string2isotime (value_date, fields[1]);
373 0 : else if (!strcmp (p, "size") && !value_size)
374 0 : value_size = xstrdup (fields[1]);
375 0 : else if (!strcmp (p, "sha2") && !value_sha2)
376 0 : value_sha2 = xstrdup (fields[1]);
377 : }
378 : }
379 0 : if (len < 0 || es_ferror (fp))
380 : {
381 0 : err = gpg_error_from_syserror ();
382 0 : log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
383 0 : goto leave;
384 : }
385 :
386 0 : if (!*filedate || !*verified)
387 : {
388 0 : err = gpg_error (GPG_ERR_INV_TIME);
389 0 : es_fprintf (out, "%s:%s:-::%u:::::::\n",
390 : name,
391 : current_version? current_version : "",
392 0 : gpg_err_code (err));
393 0 : goto leave;
394 : }
395 :
396 0 : if (!value_ver)
397 : {
398 0 : es_fprintf (out, "%s:%s:?:::::::::\n",
399 : name,
400 : current_version? current_version : "");
401 0 : goto leave;
402 : }
403 :
404 0 : if (value_size)
405 : {
406 0 : gpg_err_set_errno (0);
407 0 : value_size_ul = strtoul (value_size, &p, 10);
408 0 : if (errno)
409 0 : value_size_ul = 0;
410 0 : else if (*p == 'k')
411 0 : value_size_ul *= 1024;
412 : }
413 :
414 0 : err = 0;
415 0 : status = '-';
416 0 : if (compare_version_strings (value_ver, NULL))
417 0 : err = gpg_error (GPG_ERR_INV_VALUE);
418 0 : else if (!current_version)
419 : ;
420 0 : else if (!(i = compare_version_strings (value_ver, current_version)))
421 0 : status = 'c';
422 0 : else if (i > 0)
423 0 : status = 'u';
424 : else
425 0 : status = 'n';
426 :
427 0 : es_fprintf (out, "%s:%s:%c::%d:%s:%s:%s:%s:%lu:%s:\n",
428 : name,
429 : current_version? current_version : "",
430 : status,
431 : err,
432 : filedate,
433 : verified,
434 : value_ver,
435 : value_date,
436 : value_size_ul,
437 : value_sha2? value_sha2 : "");
438 :
439 : leave:
440 0 : xfree (value_ver);
441 0 : xfree (value_size);
442 0 : xfree (value_sha2);
443 0 : xfree (line);
444 0 : es_fclose (fp);
445 0 : xfree (fname);
446 0 : xfree (self_version);
447 0 : }
448 :
449 :
450 : /* gpgconf main. */
451 : int
452 92 : main (int argc, char **argv)
453 : {
454 : ARGPARSE_ARGS pargs;
455 : const char *fname;
456 92 : int no_more_options = 0;
457 92 : enum cmd_and_opt_values cmd = 0;
458 92 : estream_t outfp = NULL;
459 :
460 92 : early_system_init ();
461 92 : gnupg_reopen_std (GPGCONF_NAME);
462 92 : set_strusage (my_strusage);
463 92 : log_set_prefix (GPGCONF_NAME, GPGRT_LOG_WITH_PREFIX);
464 :
465 : /* Make sure that our subsystems are ready. */
466 92 : i18n_init();
467 92 : init_common_subsystems (&argc, &argv);
468 :
469 : /* Parse the command line. */
470 92 : pargs.argc = &argc;
471 92 : pargs.argv = &argv;
472 92 : pargs.flags = 1; /* Do not remove the args. */
473 277 : while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
474 : {
475 93 : switch (pargs.r_opt)
476 : {
477 0 : case oOutput: opt.outfile = pargs.r.ret_str; break;
478 0 : case oQuiet: opt.quiet = 1; break;
479 0 : case oDryRun: opt.dry_run = 1; break;
480 : case oRuntime:
481 0 : opt.runtime = 1;
482 0 : break;
483 0 : case oVerbose: opt.verbose++; break;
484 0 : case oNoVerbose: opt.verbose = 0; break;
485 0 : case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
486 1 : case oNull: opt.null = 1; break;
487 :
488 : case aListDirs:
489 : case aListComponents:
490 : case aCheckPrograms:
491 : case aListOptions:
492 : case aChangeOptions:
493 : case aCheckOptions:
494 : case aApplyDefaults:
495 : case aListConfig:
496 : case aCheckConfig:
497 : case aQuerySWDB:
498 : case aReload:
499 : case aLaunch:
500 : case aKill:
501 : case aCreateSocketDir:
502 : case aRemoveSocketDir:
503 92 : cmd = pargs.r_opt;
504 92 : break;
505 :
506 0 : default: pargs.err = 2; break;
507 : }
508 : }
509 :
510 92 : if (log_get_errorcount (0))
511 0 : exit (2);
512 :
513 : /* Print a warning if an argument looks like an option. */
514 92 : if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
515 : {
516 : int i;
517 :
518 93 : for (i=0; i < argc; i++)
519 1 : if (argv[i][0] == '-' && argv[i][1] == '-')
520 0 : log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
521 : }
522 :
523 92 : fname = argc ? *argv : NULL;
524 :
525 92 : switch (cmd)
526 : {
527 : case aListComponents:
528 : default:
529 : /* List all components. */
530 0 : gc_component_list_components (get_outfp (&outfp));
531 0 : break;
532 :
533 : case aCheckPrograms:
534 : /* Check all programs. */
535 0 : gc_check_programs (get_outfp (&outfp));
536 0 : break;
537 :
538 : case aListOptions:
539 : case aChangeOptions:
540 : case aCheckOptions:
541 0 : if (!fname)
542 : {
543 0 : es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
544 0 : es_putc ('\n', es_stderr);
545 0 : es_fputs (_("Need one component argument"), es_stderr);
546 0 : es_putc ('\n', es_stderr);
547 0 : exit (2);
548 : }
549 : else
550 : {
551 0 : int idx = gc_component_find (fname);
552 0 : if (idx < 0)
553 : {
554 0 : es_fputs (_("Component not found"), es_stderr);
555 0 : es_putc ('\n', es_stderr);
556 0 : exit (1);
557 : }
558 0 : if (cmd == aCheckOptions)
559 0 : gc_component_check_options (idx, get_outfp (&outfp), NULL);
560 : else
561 : {
562 0 : gc_component_retrieve_options (idx);
563 0 : if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
564 0 : exit (1);
565 0 : if (cmd == aListOptions)
566 0 : gc_component_list_options (idx, get_outfp (&outfp));
567 0 : else if (cmd == aChangeOptions)
568 0 : gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
569 : }
570 : }
571 0 : break;
572 :
573 : case aLaunch:
574 : case aKill:
575 0 : if (!fname)
576 : {
577 0 : es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
578 0 : es_putc ('\n', es_stderr);
579 0 : es_fputs (_("Need one component argument"), es_stderr);
580 0 : es_putc ('\n', es_stderr);
581 0 : exit (2);
582 : }
583 : else
584 : {
585 : /* Launch/Kill a given component. */
586 : int idx;
587 :
588 0 : idx = gc_component_find (fname);
589 0 : if (idx < 0)
590 : {
591 0 : es_fputs (_("Component not found"), es_stderr);
592 0 : es_putc ('\n', es_stderr);
593 0 : exit (1);
594 : }
595 0 : else if (cmd == aLaunch)
596 : {
597 0 : if (gc_component_launch (idx))
598 0 : exit (1);
599 : }
600 : else
601 : {
602 : /* We don't error out if the kill failed because this
603 : command should do nothing if the component is not
604 : running. */
605 0 : gc_component_kill (idx);
606 : }
607 : }
608 0 : break;
609 :
610 : case aReload:
611 0 : if (!fname)
612 : {
613 : /* Reload all. */
614 0 : gc_component_reload (-1);
615 : }
616 : else
617 : {
618 : /* Reload given component. */
619 : int idx;
620 :
621 0 : idx = gc_component_find (fname);
622 0 : if (idx < 0)
623 : {
624 0 : es_fputs (_("Component not found"), es_stderr);
625 0 : es_putc ('\n', es_stderr);
626 0 : exit (1);
627 : }
628 : else
629 : {
630 0 : gc_component_reload (idx);
631 : }
632 : }
633 0 : break;
634 :
635 : case aListConfig:
636 0 : if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
637 0 : exit (1);
638 0 : break;
639 :
640 : case aCheckConfig:
641 0 : if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
642 0 : exit (1);
643 0 : break;
644 :
645 : case aApplyDefaults:
646 0 : if (fname)
647 : {
648 0 : es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
649 0 : es_putc ('\n', es_stderr);
650 0 : es_fputs (_("No argument allowed"), es_stderr);
651 0 : es_putc ('\n', es_stderr);
652 0 : exit (2);
653 : }
654 0 : gc_component_retrieve_options (-1);
655 0 : if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
656 0 : exit (1);
657 0 : break;
658 :
659 : case aListDirs:
660 : /* Show the system configuration directories for gpgconf. */
661 1 : get_outfp (&outfp);
662 1 : list_dirs (outfp, argc? argv : NULL);
663 1 : break;
664 :
665 : case aQuerySWDB:
666 : /* Query the software version database. */
667 0 : if (!fname || argc > 2)
668 : {
669 0 : es_fprintf (es_stderr, "usage: %s --query-swdb NAME [VERSION]\n",
670 : GPGCONF_NAME);
671 0 : exit (2);
672 : }
673 0 : get_outfp (&outfp);
674 0 : query_swdb (outfp, fname, argc > 1? argv[1] : NULL);
675 0 : break;
676 :
677 : case aCreateSocketDir:
678 : {
679 : char *socketdir;
680 : unsigned int flags;
681 :
682 : /* Make sure that the top /run/user/UID/gnupg dir has been
683 : * created. */
684 45 : gnupg_socketdir ();
685 :
686 : /* Check the /var/run dir. */
687 45 : socketdir = _gnupg_socketdir_internal (1, &flags);
688 45 : if ((flags & 64) && !opt.dry_run)
689 : {
690 : /* No sub dir - create it. */
691 45 : if (gnupg_mkdir (socketdir, "-rwx"))
692 0 : gc_error (1, errno, "error creating '%s'", socketdir);
693 : /* Try again. */
694 45 : socketdir = _gnupg_socketdir_internal (1, &flags);
695 : }
696 :
697 : /* Give some info. */
698 45 : if ( (flags & ~32) || opt.verbose || opt.dry_run)
699 : {
700 0 : log_info ("socketdir is '%s'\n", socketdir);
701 0 : if ((flags & 1)) log_info ("\tgeneral error\n");
702 0 : if ((flags & 2)) log_info ("\tno /run/user dir\n");
703 0 : if ((flags & 4)) log_info ("\tbad permissions\n");
704 0 : if ((flags & 8)) log_info ("\tbad permissions (subdir)\n");
705 0 : if ((flags & 16)) log_info ("\tmkdir failed\n");
706 0 : if ((flags & 32)) log_info ("\tnon-default homedir\n");
707 0 : if ((flags & 64)) log_info ("\tno such subdir\n");
708 0 : if ((flags & 128)) log_info ("\tusing homedir as fallback\n");
709 : }
710 :
711 45 : if ((flags & ~32) && !opt.dry_run)
712 0 : gc_error (1, 0, "error creating socket directory");
713 :
714 45 : xfree (socketdir);
715 : }
716 45 : break;
717 :
718 : case aRemoveSocketDir:
719 : {
720 : char *socketdir;
721 : unsigned int flags;
722 :
723 : /* Check the /var/run dir. */
724 46 : socketdir = _gnupg_socketdir_internal (1, &flags);
725 46 : if ((flags & 128))
726 0 : log_info ("ignoring request to remove non /run/user socket dir\n");
727 46 : else if (opt.dry_run)
728 : ;
729 46 : else if (rmdir (socketdir))
730 46 : gc_error (1, errno, "error removing '%s'", socketdir);
731 :
732 0 : xfree (socketdir);
733 : }
734 0 : break;
735 :
736 : }
737 :
738 46 : if (outfp != es_stdout)
739 45 : if (es_fclose (outfp))
740 0 : gc_error (1, errno, "error closing '%s'", opt.outfile);
741 :
742 46 : return 0;
743 : }
|