1 /* edit.c - Key edit function.
2 * Copyright (C) 2002, 2003, 2004 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 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25
26 #include "gpgme.h"
27 #include "debug.h"
28 #include "context.h"
29 #include "ops.h"
30 #include "util.h"
31
32
33
34 typedef struct
35 {
36 /* The user callback function and its hook value. */
37 gpgme_interact_cb_t fnc;
38 gpgme_edit_cb_t fnc_old;
39 void *fnc_value;
40 } *op_data_t;
41
42
43 static gpgme_error_t
edit_status_handler(void * priv,gpgme_status_code_t status,char * args)44 edit_status_handler (void *priv, gpgme_status_code_t status, char *args)
45 {
46 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
47 gpgme_error_t err;
48 void *hook;
49 op_data_t opd;
50
51 err = _gpgme_passphrase_status_handler (priv, status, args);
52 if (err)
53 return err;
54
55 err = _gpgme_progress_status_handler (priv, status, args);
56 if (err)
57 return err;
58
59 err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, -1, NULL);
60 opd = hook;
61 if (err)
62 return err;
63
64 if (opd->fnc_old)
65 return (*opd->fnc_old) (opd->fnc_value, status, args, -1);
66
67 return (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
68 args, -1);
69 }
70
71
72 static gpgme_error_t
command_handler(void * priv,gpgme_status_code_t status,const char * args,int fd,int * processed_r)73 command_handler (void *priv, gpgme_status_code_t status, const char *args,
74 int fd, int *processed_r)
75 {
76 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
77 gpgme_error_t err;
78 int processed = 0;
79
80 if (ctx->passphrase_cb)
81 {
82 err = _gpgme_passphrase_command_handler (ctx, status, args,
83 fd, &processed);
84 if (err)
85 return err;
86 }
87 else
88 err = 0;
89
90 if (!processed)
91 {
92 void *hook;
93 op_data_t opd;
94
95 err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, -1, NULL);
96 opd = hook;
97 if (err)
98 return err;
99
100 if (opd->fnc_old)
101 err = (*opd->fnc_old) (opd->fnc_value, status, args, fd);
102 else
103 err = (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
104 args, fd);
105
106 if (gpg_err_code (err) == GPG_ERR_FALSE)
107 err = 0;
108 else
109 processed = 1;
110 }
111
112 *processed_r = processed;
113 return err;
114 }
115
116
117 static gpgme_error_t
interact_start(gpgme_ctx_t ctx,int synchronous,gpgme_key_t key,unsigned int flags,gpgme_interact_cb_t fnc,void * fnc_value,gpgme_data_t out)118 interact_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
119 unsigned int flags,
120 gpgme_interact_cb_t fnc, void *fnc_value, gpgme_data_t out)
121 {
122 gpgme_error_t err;
123 void *hook;
124 op_data_t opd;
125
126 err = _gpgme_op_reset (ctx, synchronous);
127 if (err)
128 return err;
129
130 if (!fnc || !out)
131 return gpg_error (GPG_ERR_INV_VALUE);
132
133 err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
134 opd = hook;
135 if (err)
136 return err;
137
138 opd->fnc = fnc;
139 opd->fnc_old = NULL;
140 opd->fnc_value = fnc_value;
141
142 err = _gpgme_engine_set_command_handler (ctx->engine, command_handler, ctx);
143 if (err)
144 return err;
145
146 _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
147
148 return _gpgme_engine_op_edit (ctx->engine,
149 (flags & GPGME_INTERACT_CARD)? 1: 0,
150 key, out, ctx);
151 }
152
153
154 gpgme_error_t
gpgme_op_interact_start(gpgme_ctx_t ctx,gpgme_key_t key,unsigned int flags,gpgme_interact_cb_t fnc,void * fnc_value,gpgme_data_t out)155 gpgme_op_interact_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
156 gpgme_interact_cb_t fnc, void *fnc_value,
157 gpgme_data_t out)
158 {
159 gpgme_error_t err;
160
161 TRACE_BEG (DEBUG_CTX, "gpgme_op_interact_start", ctx,
162 "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
163 key, flags,fnc, fnc_value, out);
164
165 if (!ctx)
166 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
167
168 err = interact_start (ctx, 0, key, flags, fnc, fnc_value, out);
169 return err;
170 }
171
172
173 gpgme_error_t
gpgme_op_interact(gpgme_ctx_t ctx,gpgme_key_t key,unsigned int flags,gpgme_interact_cb_t fnc,void * fnc_value,gpgme_data_t out)174 gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
175 gpgme_interact_cb_t fnc, void *fnc_value,
176 gpgme_data_t out)
177 {
178 gpgme_error_t err;
179
180 TRACE_BEG (DEBUG_CTX, "gpgme_op_interact", ctx,
181 "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
182 key, flags,fnc, fnc_value, out);
183
184 if (!ctx)
185 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
186
187 err = interact_start (ctx, 1, key, flags, fnc, fnc_value, out);
188 if (!err)
189 err = _gpgme_wait_one (ctx);
190 return err;
191 }
192
193
194
195
196 /* The deprecated interface. */
197 static gpgme_error_t
edit_start(gpgme_ctx_t ctx,int synchronous,int type,gpgme_key_t key,gpgme_edit_cb_t fnc,void * fnc_value,gpgme_data_t out)198 edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
199 gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
200 {
201 gpgme_error_t err;
202 void *hook;
203 op_data_t opd;
204
205 err = _gpgme_op_reset (ctx, synchronous);
206 if (err)
207 return err;
208
209 if (!fnc || !out)
210 return gpg_error (GPG_ERR_INV_VALUE);
211
212 err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
213 opd = hook;
214 if (err)
215 return err;
216
217 opd->fnc = NULL;
218 opd->fnc_old = fnc;
219 opd->fnc_value = fnc_value;
220
221 err = _gpgme_engine_set_command_handler (ctx->engine, command_handler, ctx);
222 if (err)
223 return err;
224
225 _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
226
227 return _gpgme_engine_op_edit (ctx->engine, type, key, out, ctx);
228 }
229
230
231 gpgme_error_t
gpgme_op_edit_start(gpgme_ctx_t ctx,gpgme_key_t key,gpgme_edit_cb_t fnc,void * fnc_value,gpgme_data_t out)232 gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
233 gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
234 {
235 gpgme_error_t err;
236
237 TRACE_BEG (DEBUG_CTX, "gpgme_op_edit_start", ctx,
238 "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
239 (key && key->subkeys && key->subkeys->fpr) ?
240 key->subkeys->fpr : "invalid", fnc, fnc_value, out);
241
242 if (!ctx)
243 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
244
245 err = edit_start (ctx, 0, 0, key, fnc, fnc_value, out);
246 return err;
247 }
248
249
250 /* Edit the key KEY. Send status and command requests to FNC and
251 output of edit commands to OUT. */
252 gpgme_error_t
gpgme_op_edit(gpgme_ctx_t ctx,gpgme_key_t key,gpgme_edit_cb_t fnc,void * fnc_value,gpgme_data_t out)253 gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
254 gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
255 {
256 gpgme_error_t err;
257
258 TRACE_BEG (DEBUG_CTX, "gpgme_op_edit", ctx,
259 "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
260 (key && key->subkeys && key->subkeys->fpr) ?
261 key->subkeys->fpr : "invalid", fnc, fnc_value, out);
262
263 if (!ctx)
264 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
265
266 err = edit_start (ctx, 1, 0, key, fnc, fnc_value, out);
267
268 if (!err)
269 err = _gpgme_wait_one (ctx);
270 return TRACE_ERR (err);
271 }
272
273
274 gpgme_error_t
gpgme_op_card_edit_start(gpgme_ctx_t ctx,gpgme_key_t key,gpgme_edit_cb_t fnc,void * fnc_value,gpgme_data_t out)275 gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
276 gpgme_edit_cb_t fnc, void *fnc_value,
277 gpgme_data_t out)
278 {
279 gpgme_error_t err;
280
281 TRACE_BEG (DEBUG_CTX, "gpgme_op_card_edit_start", ctx,
282 "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
283 (key && key->subkeys && key->subkeys->fpr) ?
284 key->subkeys->fpr : "invalid", fnc, fnc_value, out);
285
286 if (!ctx)
287 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
288
289 err = edit_start (ctx, 0, 1, key, fnc, fnc_value, out);
290 return err;
291 }
292
293
294 /* Edit the card for the key KEY. Send status and command requests to
295 FNC and output of edit commands to OUT. */
296 gpgme_error_t
gpgme_op_card_edit(gpgme_ctx_t ctx,gpgme_key_t key,gpgme_edit_cb_t fnc,void * fnc_value,gpgme_data_t out)297 gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
298 gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
299 {
300 gpgme_error_t err;
301
302 TRACE_BEG (DEBUG_CTX, "gpgme_op_card_edit", ctx,
303 "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
304 (key && key->subkeys && key->subkeys->fpr) ?
305 key->subkeys->fpr : "invalid", fnc, fnc_value, out);
306
307 if (!ctx)
308 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
309
310 err = edit_start (ctx, 1, 1, key, fnc, fnc_value, out);
311 if (!err)
312 err = _gpgme_wait_one (ctx);
313 return TRACE_ERR (err);
314 }
315