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