Line data Source code
1 : /* gpgconf.c - Configuration utility for GnuPG
2 : * Copyright (C) 2003, 2007, 2009, 2011 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <errno.h>
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <unistd.h>
26 :
27 : #include "gpgconf.h"
28 : #include "i18n.h"
29 : #include "sysutils.h"
30 : #include "../common/init.h"
31 :
32 :
33 : /* Constants to identify the commands and options. */
34 : enum cmd_and_opt_values
35 : {
36 : aNull = 0,
37 : oDryRun = 'n',
38 : oOutput = 'o',
39 : oQuiet = 'q',
40 : oVerbose = 'v',
41 : oRuntime = 'r',
42 : oComponent = 'c',
43 : oNull = '0',
44 : oNoVerbose = 500,
45 : oHomedir,
46 :
47 : aListComponents,
48 : aCheckPrograms,
49 : aListOptions,
50 : aChangeOptions,
51 : aCheckOptions,
52 : aApplyDefaults,
53 : aListConfig,
54 : aCheckConfig,
55 : aListDirs,
56 : aLaunch,
57 : aKill,
58 : aCreateSocketDir,
59 : aRemoveSocketDir,
60 : aReload
61 : };
62 :
63 :
64 : /* The list of commands and options. */
65 : static ARGPARSE_OPTS opts[] =
66 : {
67 : { 300, NULL, 0, N_("@Commands:\n ") },
68 :
69 : { aListComponents, "list-components", 256, N_("list all components") },
70 : { aCheckPrograms, "check-programs", 256, N_("check all programs") },
71 : { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
72 : { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
73 : { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
74 : { aApplyDefaults, "apply-defaults", 256,
75 : N_("apply global default values") },
76 : { aListDirs, "list-dirs", 256,
77 : N_("get the configuration directories for @GPGCONF@") },
78 : { aListConfig, "list-config", 256,
79 : N_("list global configuration file") },
80 : { aCheckConfig, "check-config", 256,
81 : N_("check global configuration file") },
82 : { aReload, "reload", 256, N_("reload all or a given component")},
83 : { aLaunch, "launch", 256, N_("launch a given component")},
84 : { aKill, "kill", 256, N_("kill a given component")},
85 : { aCreateSocketDir, "create-socketdir", 256, "@"},
86 : { aRemoveSocketDir, "remove-socketdir", 256, "@"},
87 :
88 : { 301, NULL, 0, N_("@\nOptions:\n ") },
89 :
90 : { oOutput, "output", 2, N_("use as output file") },
91 : { oVerbose, "verbose", 0, N_("verbose") },
92 : { oQuiet, "quiet", 0, N_("quiet") },
93 : { oDryRun, "dry-run", 0, N_("do not make any changes") },
94 : { oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") },
95 : /* hidden options */
96 : { oHomedir, "homedir", 2, "@" },
97 : { oNull, "null", 0, "@" },
98 : { oNoVerbose, "no-verbose", 0, "@"},
99 : {0}
100 : };
101 :
102 :
103 : /* Print usage information and and provide strings for help. */
104 : static const char *
105 0 : my_strusage( int level )
106 : {
107 : const char *p;
108 :
109 0 : switch (level)
110 : {
111 0 : case 11: p = "@GPGCONF@ (@GNUPG@)";
112 0 : break;
113 0 : case 13: p = VERSION; break;
114 0 : case 17: p = PRINTABLE_OS_NAME; break;
115 0 : case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
116 :
117 : case 1:
118 0 : case 40: p = _("Usage: @GPGCONF@ [options] (-h for help)");
119 0 : break;
120 : case 41:
121 0 : p = _("Syntax: @GPGCONF@ [options]\n"
122 : "Manage configuration options for tools of the @GNUPG@ system\n");
123 0 : break;
124 :
125 0 : default: p = NULL; break;
126 : }
127 0 : return p;
128 : }
129 :
130 :
131 : /* Return the fp for the output. This is usually stdout unless
132 : --output has been used. In the latter case this function opens
133 : that file. */
134 : static estream_t
135 1 : get_outfp (estream_t *fp)
136 : {
137 1 : if (!*fp)
138 : {
139 1 : if (opt.outfile)
140 : {
141 0 : *fp = es_fopen (opt.outfile, "w");
142 0 : if (!*fp)
143 0 : gc_error (1, errno, "can not open '%s'", opt.outfile);
144 : }
145 : else
146 1 : *fp = es_stdout;
147 : }
148 1 : return *fp;
149 : }
150 :
151 :
152 : static void
153 1 : list_dirs (estream_t fp, char **names)
154 : {
155 : static struct {
156 : const char *name;
157 : const char *(*fnc)(void);
158 : const char *extra;
159 : } list[] = {
160 : { "sysconfdir", gnupg_sysconfdir, NULL },
161 : { "bindir", gnupg_bindir, NULL },
162 : { "libexecdir", gnupg_libexecdir, NULL },
163 : { "libdir", gnupg_libdir, NULL },
164 : { "datadir", gnupg_datadir, NULL },
165 : { "localedir", gnupg_localedir, NULL },
166 : { "socketdir", gnupg_socketdir, NULL },
167 : { "dirmngr-socket", dirmngr_socket_name, NULL,},
168 : { "agent-ssh-socket", gnupg_socketdir, GPG_AGENT_SSH_SOCK_NAME },
169 : { "agent-socket", gnupg_socketdir, GPG_AGENT_SOCK_NAME },
170 : { "homedir", gnupg_homedir, NULL }
171 : };
172 : int idx, j;
173 : char *tmp;
174 : const char *s;
175 :
176 :
177 12 : for (idx = 0; idx < DIM (list); idx++)
178 : {
179 11 : s = list[idx].fnc ();
180 11 : if (list[idx].extra)
181 : {
182 2 : tmp = make_filename (s, list[idx].extra, NULL);
183 2 : s = tmp;
184 : }
185 : else
186 9 : tmp = NULL;
187 11 : if (!names)
188 0 : es_fprintf (fp, "%s:%s\n", list[idx].name, gc_percent_escape (s));
189 : else
190 : {
191 22 : for (j=0; names[j]; j++)
192 11 : if (!strcmp (names[j], list[idx].name))
193 : {
194 1 : es_fputs (s, fp);
195 1 : es_putc (opt.null? '\0':'\n', fp);
196 : }
197 : }
198 :
199 11 : xfree (tmp);
200 : }
201 1 : }
202 :
203 :
204 : /* gpgconf main. */
205 : int
206 1 : main (int argc, char **argv)
207 : {
208 : ARGPARSE_ARGS pargs;
209 : const char *fname;
210 1 : int no_more_options = 0;
211 1 : enum cmd_and_opt_values cmd = 0;
212 1 : estream_t outfp = NULL;
213 :
214 1 : early_system_init ();
215 1 : gnupg_reopen_std (GPGCONF_NAME);
216 1 : set_strusage (my_strusage);
217 1 : log_set_prefix (GPGCONF_NAME, GPGRT_LOG_WITH_PREFIX);
218 :
219 : /* Make sure that our subsystems are ready. */
220 1 : i18n_init();
221 1 : init_common_subsystems (&argc, &argv);
222 :
223 : /* Parse the command line. */
224 1 : pargs.argc = &argc;
225 1 : pargs.argv = &argv;
226 1 : pargs.flags = 1; /* Do not remove the args. */
227 4 : while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
228 : {
229 2 : switch (pargs.r_opt)
230 : {
231 0 : case oOutput: opt.outfile = pargs.r.ret_str; break;
232 0 : case oQuiet: opt.quiet = 1; break;
233 0 : case oDryRun: opt.dry_run = 1; break;
234 : case oRuntime:
235 0 : opt.runtime = 1;
236 0 : break;
237 0 : case oVerbose: opt.verbose++; break;
238 0 : case oNoVerbose: opt.verbose = 0; break;
239 0 : case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
240 1 : case oNull: opt.null = 1; break;
241 :
242 : case aListDirs:
243 : case aListComponents:
244 : case aCheckPrograms:
245 : case aListOptions:
246 : case aChangeOptions:
247 : case aCheckOptions:
248 : case aApplyDefaults:
249 : case aListConfig:
250 : case aCheckConfig:
251 : case aReload:
252 : case aLaunch:
253 : case aKill:
254 : case aCreateSocketDir:
255 : case aRemoveSocketDir:
256 1 : cmd = pargs.r_opt;
257 1 : break;
258 :
259 0 : default: pargs.err = 2; break;
260 : }
261 : }
262 :
263 1 : if (log_get_errorcount (0))
264 0 : exit (2);
265 :
266 : /* Print a warning if an argument looks like an option. */
267 1 : if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
268 : {
269 : int i;
270 :
271 2 : for (i=0; i < argc; i++)
272 1 : if (argv[i][0] == '-' && argv[i][1] == '-')
273 0 : log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
274 : }
275 :
276 1 : fname = argc ? *argv : NULL;
277 :
278 1 : switch (cmd)
279 : {
280 : case aListComponents:
281 : default:
282 : /* List all components. */
283 0 : gc_component_list_components (get_outfp (&outfp));
284 0 : break;
285 :
286 : case aCheckPrograms:
287 : /* Check all programs. */
288 0 : gc_check_programs (get_outfp (&outfp));
289 0 : break;
290 :
291 : case aListOptions:
292 : case aChangeOptions:
293 : case aCheckOptions:
294 0 : if (!fname)
295 : {
296 0 : es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
297 0 : es_putc ('\n', es_stderr);
298 0 : es_fputs (_("Need one component argument"), es_stderr);
299 0 : es_putc ('\n', es_stderr);
300 0 : exit (2);
301 : }
302 : else
303 : {
304 0 : int idx = gc_component_find (fname);
305 0 : if (idx < 0)
306 : {
307 0 : es_fputs (_("Component not found"), es_stderr);
308 0 : es_putc ('\n', es_stderr);
309 0 : exit (1);
310 : }
311 0 : if (cmd == aCheckOptions)
312 0 : gc_component_check_options (idx, get_outfp (&outfp), NULL);
313 : else
314 : {
315 0 : gc_component_retrieve_options (idx);
316 0 : if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
317 0 : exit (1);
318 0 : if (cmd == aListOptions)
319 0 : gc_component_list_options (idx, get_outfp (&outfp));
320 0 : else if (cmd == aChangeOptions)
321 0 : gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
322 : }
323 : }
324 0 : break;
325 :
326 : case aLaunch:
327 : case aKill:
328 0 : if (!fname)
329 : {
330 0 : es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
331 0 : es_putc ('\n', es_stderr);
332 0 : es_fputs (_("Need one component argument"), es_stderr);
333 0 : es_putc ('\n', es_stderr);
334 0 : exit (2);
335 : }
336 : else
337 : {
338 : /* Launch/Kill a given component. */
339 : int idx;
340 :
341 0 : idx = gc_component_find (fname);
342 0 : if (idx < 0)
343 : {
344 0 : es_fputs (_("Component not found"), es_stderr);
345 0 : es_putc ('\n', es_stderr);
346 0 : exit (1);
347 : }
348 0 : else if (cmd == aLaunch)
349 : {
350 0 : if (gc_component_launch (idx))
351 0 : exit (1);
352 : }
353 : else
354 : {
355 : /* We don't error out if the kill failed because this
356 : command should do nothing if the component is not
357 : running. */
358 0 : gc_component_kill (idx);
359 : }
360 : }
361 0 : break;
362 :
363 : case aReload:
364 0 : if (!fname)
365 : {
366 : /* Reload all. */
367 0 : gc_component_reload (-1);
368 : }
369 : else
370 : {
371 : /* Reload given component. */
372 : int idx;
373 :
374 0 : idx = gc_component_find (fname);
375 0 : if (idx < 0)
376 : {
377 0 : es_fputs (_("Component not found"), es_stderr);
378 0 : es_putc ('\n', es_stderr);
379 0 : exit (1);
380 : }
381 : else
382 : {
383 0 : gc_component_reload (idx);
384 : }
385 : }
386 0 : break;
387 :
388 : case aListConfig:
389 0 : if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
390 0 : exit (1);
391 0 : break;
392 :
393 : case aCheckConfig:
394 0 : if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
395 0 : exit (1);
396 0 : break;
397 :
398 : case aApplyDefaults:
399 0 : if (fname)
400 : {
401 0 : es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
402 0 : es_putc ('\n', es_stderr);
403 0 : es_fputs (_("No argument allowed"), es_stderr);
404 0 : es_putc ('\n', es_stderr);
405 0 : exit (2);
406 : }
407 0 : gc_component_retrieve_options (-1);
408 0 : if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
409 0 : exit (1);
410 0 : break;
411 :
412 : case aListDirs:
413 : /* Show the system configuration directories for gpgconf. */
414 1 : get_outfp (&outfp);
415 1 : list_dirs (outfp, argc? argv : NULL);
416 1 : break;
417 :
418 : case aCreateSocketDir:
419 : {
420 : char *socketdir;
421 : unsigned int flags;
422 :
423 : /* Make sure that the top /run/user/UID/gnupg dir has been
424 : * created. */
425 0 : gnupg_socketdir ();
426 :
427 : /* Check the /var/run dir. */
428 0 : socketdir = _gnupg_socketdir_internal (1, &flags);
429 0 : if ((flags & 64) && !opt.dry_run)
430 : {
431 : /* No sub dir - create it. */
432 0 : if (gnupg_mkdir (socketdir, "-rwx"))
433 0 : gc_error (1, errno, "error creating '%s'", socketdir);
434 : /* Try again. */
435 0 : socketdir = _gnupg_socketdir_internal (1, &flags);
436 : }
437 :
438 : /* Give some info. */
439 0 : if ( (flags & ~32) || opt.verbose || opt.dry_run)
440 : {
441 0 : log_info ("socketdir is '%s'\n", socketdir);
442 0 : if ((flags & 1)) log_info ("\tgeneral error\n");
443 0 : if ((flags & 2)) log_info ("\tno /run/user dir\n");
444 0 : if ((flags & 4)) log_info ("\tbad permissions\n");
445 0 : if ((flags & 8)) log_info ("\tbad permissions (subdir)\n");
446 0 : if ((flags & 16)) log_info ("\tmkdir failed\n");
447 0 : if ((flags & 32)) log_info ("\tnon-default homedir\n");
448 0 : if ((flags & 64)) log_info ("\tno such subdir\n");
449 0 : if ((flags & 128)) log_info ("\tusing homedir as fallback\n");
450 : }
451 :
452 0 : if ((flags & ~32) && !opt.dry_run)
453 0 : gc_error (1, 0, "error creating socket directory");
454 :
455 0 : xfree (socketdir);
456 : }
457 0 : break;
458 :
459 : case aRemoveSocketDir:
460 : {
461 : char *socketdir;
462 : unsigned int flags;
463 :
464 : /* Check the /var/run dir. */
465 0 : socketdir = _gnupg_socketdir_internal (1, &flags);
466 0 : if ((flags & 128))
467 0 : log_info ("ignoring request to remove non /run/user socket dir\n");
468 0 : else if (opt.dry_run)
469 : ;
470 0 : else if (rmdir (socketdir))
471 0 : gc_error (1, errno, "error removing '%s'", socketdir);
472 :
473 0 : xfree (socketdir);
474 : }
475 0 : break;
476 :
477 : }
478 :
479 1 : if (outfp != es_stdout)
480 0 : if (es_fclose (outfp))
481 0 : gc_error (1, errno, "error closing '%s'", opt.outfile);
482 :
483 1 : return 0;
484 : }
|