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