tests,json: Fix and improve t-json
[gpgme.git] / tests / run-keysign.c
1 /* run-keysign.c  - Test tool to sign a key
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 /* We need to include config.h so that we know whether we are building
21    with large file system (LFS) support. */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include <gpgme.h>
32
33 #define PGM "run-keysign"
34
35 #include "run-support.h"
36
37
38 static int verbose;
39
40
41 static gpg_error_t
42 status_cb (void *opaque, const char *keyword, const char *value)
43 {
44   (void)opaque;
45   fprintf (stderr, "status_cb: %s %s\n", nonnull(keyword), nonnull(value));
46   return 0;
47 }
48
49
50 static unsigned long
51 parse_expire_string (const char *string)
52 {
53   unsigned long seconds;
54
55   if (!string || !*string || !strcmp (string, "none")
56       || !strcmp (string, "never") || !strcmp (string, "-"))
57     seconds = 0;
58   else if (strspn (string, "01234567890") == strlen (string))
59     seconds = strtoul (string, NULL, 10);
60   else
61     {
62       fprintf (stderr, PGM ": invalid value '%s'\n", string);
63       exit (1);
64     }
65
66   return seconds;
67 }
68
69
70
71 static int
72 show_usage (int ex)
73 {
74   fputs ("usage: " PGM " [options] FPR USERIDS\n\n"
75          "Options:\n"
76          "  --verbose        run in verbose mode\n"
77          "  --status         print status lines from the backend\n"
78          "  --loopback       use a loopback pinentry\n"
79          "  --signer NAME    use key NAME for signing\n"
80          "  --local          create a local signature\n"
81          "  --noexpire       force no expiration\n"
82          "  --expire EPOCH   expire the signature at EPOCH\n"
83          , stderr);
84   exit (ex);
85 }
86
87
88 int
89 main (int argc, char **argv)
90 {
91   int last_argc = -1;
92   gpgme_error_t err;
93   gpgme_ctx_t ctx;
94   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
95   const char *signer_string = NULL;
96   int print_status = 0;
97   int use_loopback = 0;
98   const char *userid;
99   unsigned int flags = 0;
100   unsigned long expire = 0;
101   gpgme_key_t thekey;
102   int i;
103   size_t n;
104   char *userid_buffer = NULL;
105
106   if (argc)
107     { argc--; argv++; }
108
109   while (argc && last_argc != argc )
110     {
111       last_argc = argc;
112       if (!strcmp (*argv, "--"))
113         {
114           argc--; argv++;
115           break;
116         }
117       else if (!strcmp (*argv, "--help"))
118         show_usage (0);
119       else if (!strcmp (*argv, "--verbose"))
120         {
121           verbose = 1;
122           argc--; argv++;
123         }
124       else if (!strcmp (*argv, "--status"))
125         {
126           print_status = 1;
127           argc--; argv++;
128         }
129       else if (!strcmp (*argv, "--signer"))
130         {
131           argc--; argv++;
132           if (!argc)
133             show_usage (1);
134           signer_string = *argv;
135           argc--; argv++;
136         }
137       else if (!strcmp (*argv, "--loopback"))
138         {
139           use_loopback = 1;
140           argc--; argv++;
141         }
142       else if (!strcmp (*argv, "--local"))
143         {
144           flags |= GPGME_KEYSIGN_LOCAL;
145           argc--; argv++;
146         }
147       else if (!strcmp (*argv, "--noexpire"))
148         {
149           flags |= GPGME_KEYSIGN_NOEXPIRE;
150           argc--; argv++;
151         }
152       else if (!strcmp (*argv, "--expire"))
153         {
154           argc--; argv++;
155           if (!argc)
156             show_usage (1);
157           expire = parse_expire_string (*argv);
158           argc--; argv++;
159         }
160       else if (!strncmp (*argv, "--", 2))
161         show_usage (1);
162     }
163
164   if (!argc)
165     show_usage (1);
166   userid = argv[0];
167   argc--; argv++;
168
169   init_gpgme (protocol);
170
171   err = gpgme_new (&ctx);
172   fail_if_err (err);
173   gpgme_set_protocol (ctx, protocol);
174   gpgme_set_armor (ctx, 1);
175   if (print_status)
176     {
177       gpgme_set_status_cb (ctx, status_cb, NULL);
178       gpgme_set_ctx_flag (ctx, "full-status", "1");
179     }
180   if (use_loopback)
181     {
182       gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
183       gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
184     }
185
186   if (signer_string)
187     {
188       gpgme_key_t akey;
189
190       err = gpgme_get_key (ctx, signer_string, &akey, 1);
191       if (err)
192         {
193           fprintf (stderr, PGM ": error getting signer key '%s': %s\n",
194                    signer_string, gpg_strerror (err));
195           exit (1);
196         }
197       err = gpgme_signers_add (ctx, akey);
198       if (err)
199         {
200           fprintf (stderr, PGM ": error adding signer key: %s\n",
201                    gpg_strerror (err));
202           exit (1);
203         }
204       gpgme_key_unref (akey);
205     }
206
207
208   err = gpgme_get_key (ctx, userid, &thekey, 0);
209   if (err)
210     {
211       fprintf (stderr, PGM ": error getting key for '%s': %s\n",
212                userid, gpg_strerror (err));
213       exit (1);
214     }
215
216   if (argc > 1)
217     {
218       /* Several user ids given  */
219       for (i=0, n = 0; i < argc; i++)
220         n += strlen (argv[1]) + 1;
221       n++;
222       userid_buffer = malloc (n);
223       if (!userid_buffer)
224         {
225           fprintf (stderr, PGM ": malloc failed: %s\n",
226                    gpg_strerror (gpg_error_from_syserror ()));
227           exit (1);
228         }
229       *userid_buffer = 0;
230       for (i=0; i < argc; i++)
231         {
232           strcat (userid_buffer, argv[i]);
233           strcat (userid_buffer, "\n");
234         }
235       userid = userid_buffer;
236       flags |= GPGME_KEYSIGN_LFSEP;
237     }
238   else if (argc)
239     {
240       /* One user id given  */
241       userid = *argv;
242     }
243   else
244     {
245       /* No user id given.  */
246       userid = NULL;
247     }
248
249   err = gpgme_op_keysign (ctx, thekey, userid, expire, flags);
250   if (err)
251     {
252       fprintf (stderr, PGM ": gpgme_op_adduid failed: %s\n",
253                gpg_strerror (err));
254       exit (1);
255     }
256
257   free (userid_buffer);
258   gpgme_key_unref (thekey);
259   gpgme_release (ctx);
260   return 0;
261 }