qt: Add job for tofupolicy
[gpgme.git] / src / keysign.c
1 /* keysign.c - OpenPGP key signing
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 <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "gpgme.h"
28 #include "debug.h"
29 #include "context.h"
30 #include "ops.h"
31 #include "util.h"
32
33 \f
34 typedef struct
35 {
36   /* The error code from a FAILURE status line or 0.  */
37   gpg_error_t failure_code;
38
39   /* The error code from certain ERROR status lines or 0.  */
40   gpg_error_t error_code;
41
42 } *op_data_t;
43
44
45 static void
46 release_op_data (void *hook)
47 {
48   op_data_t opd = (op_data_t) hook;
49
50   (void)opd;
51 }
52
53
54 /* Parse an error status line.  Return the error location and the
55    error code.  The function may modify ARGS. */
56 static char *
57 parse_error (char *args, gpg_error_t *r_err)
58 {
59   char *where = strchr (args, ' ');
60   char *which;
61
62   if (where)
63     {
64       *where = '\0';
65       which = where + 1;
66
67       where = strchr (which, ' ');
68       if (where)
69         *where = '\0';
70
71       where = args;
72     }
73   else
74     {
75       *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
76       return NULL;
77     }
78
79   *r_err = atoi (which);
80
81   return where;
82 }
83
84
85 static gpgme_error_t
86 keysign_status_handler (void *priv, gpgme_status_code_t code, char *args)
87 {
88   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
89   gpgme_error_t err;
90   void *hook;
91   op_data_t opd;
92   char *loc;
93
94   /* Pipe the status code through the progress status handler.  */
95   err = _gpgme_progress_status_handler (ctx, code, args);
96   if (err)
97     return err;
98
99   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook, -1, NULL);
100   opd = hook;
101   if (err)
102     return err;
103
104   switch (code)
105     {
106     case GPGME_STATUS_ERROR:
107       loc = parse_error (args, &err);
108       if (!loc)
109         return err;
110       if (!opd->error_code)
111         opd->error_code = err;
112       break;
113
114     case GPGME_STATUS_FAILURE:
115       opd->failure_code = _gpgme_parse_failure (args);
116       break;
117
118     case GPGME_STATUS_EOF:
119       if (opd->error_code)
120         return opd->error_code;
121       else if (opd->failure_code)
122         return opd->failure_code;
123       break;
124
125     case GPGME_STATUS_INQUIRE_MAXLEN:
126       if (ctx->status_cb && !ctx->full_status)
127         {
128           err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
129           if (err)
130             return err;
131         }
132       break;
133
134     default:
135       break;
136     }
137   return 0;
138 }
139
140
141 /* Sign the USERID of KEY using the current set of signers.  If USERID
142  * is NULL, sign all user ids.  To put several user ids into USERID,
143  * separate them by LF and set the flag GPGME_KEYSIGN_LFSEP.  */
144 static gpgme_error_t
145 keysign_start (gpgme_ctx_t ctx, int synchronous,
146                gpgme_key_t key, const char *userid,
147                unsigned long expires, unsigned int flags)
148 {
149   gpgme_error_t err;
150   void *hook;
151   op_data_t opd;
152
153   if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
154     return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
155
156   err = _gpgme_op_reset (ctx, synchronous);
157   if (err)
158     return err;
159
160   if (!key)
161     return gpg_error (GPG_ERR_INV_ARG);
162
163   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook,
164                                sizeof (*opd), release_op_data);
165   opd = hook;
166   if (err)
167     return err;
168
169   _gpgme_engine_set_status_handler (ctx->engine, keysign_status_handler, ctx);
170
171   if (ctx->passphrase_cb)
172     {
173       err = _gpgme_engine_set_command_handler
174         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
175       if (err)
176         return err;
177     }
178
179   return _gpgme_engine_op_keysign (ctx->engine,
180                                    key, userid, expires, flags, ctx);
181 }
182
183
184 /* Sign the USERID of KEY using the current set of signers.  */
185 gpgme_error_t
186 gpgme_op_keysign_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
187                         unsigned long expires, unsigned int flags)
188 {
189   gpgme_error_t err;
190
191   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign_start", ctx,
192               "key=%p, uid='%s' flags=0x%x", key, userid, flags);
193
194   if (!ctx)
195     return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
196
197   err = keysign_start (ctx, 0, key, userid, expires, flags);
198   return TRACE_ERR (err);
199 }
200
201
202 gpgme_error_t
203 gpgme_op_keysign (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
204                   unsigned long expires, unsigned int flags)
205 {
206   gpgme_error_t err;
207
208   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign", ctx,
209               "key=%p, uid='%s' flags=0x%x", key, userid, flags);
210
211   if (!ctx)
212     return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
213
214   err = keysign_start (ctx, 1, key, userid, expires, flags);
215   if (!err)
216     err = _gpgme_wait_one (ctx);
217   return TRACE_ERR (err);
218 }