Line data Source code
1 : /* op-support.c - Supporting functions.
2 : Copyright (C) 2002, 2003, 2004, 2007 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 : #if HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif
23 : #include <stdlib.h>
24 : #include <errno.h>
25 : #include <string.h>
26 : #ifdef HAVE_LOCALE_H
27 : #include <locale.h>
28 : #endif
29 :
30 : #include "gpgme.h"
31 : #include "context.h"
32 : #include "ops.h"
33 : #include "util.h"
34 : #include "debug.h"
35 :
36 : #if GPG_ERROR_VERSION_NUMBER < 0x011700 /* 1.23 */
37 : # define GPG_ERR_SUBKEYS_EXP_OR_REV 217
38 : #endif
39 :
40 :
41 :
42 : gpgme_error_t
43 42538 : _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook,
44 : int size, void (*cleanup) (void *))
45 : {
46 : struct ctx_op_data *data;
47 :
48 42538 : if (!ctx)
49 0 : return gpg_error (GPG_ERR_INV_VALUE);
50 :
51 42538 : data = ctx->op_data;
52 87363 : while (data && data->type != type)
53 2287 : data = data->next;
54 42538 : if (!data)
55 : {
56 829 : if (size < 0)
57 : {
58 0 : *hook = NULL;
59 0 : return 0;
60 : }
61 :
62 829 : data = calloc (1, sizeof (struct ctx_op_data) + size);
63 829 : if (!data)
64 0 : return gpg_error_from_syserror ();
65 829 : data->magic = CTX_OP_DATA_MAGIC;
66 829 : data->next = ctx->op_data;
67 829 : data->type = type;
68 829 : data->cleanup = cleanup;
69 829 : data->hook = (void *) (((char *) data) + sizeof (struct ctx_op_data));
70 829 : data->references = 1;
71 829 : ctx->op_data = data;
72 : }
73 42538 : *hook = data->hook;
74 42538 : return 0;
75 : }
76 :
77 :
78 : /* type is: 0: asynchronous operation (use global or user event loop).
79 : 1: synchronous operation (always use private event loop).
80 : 2: asynchronous private operation (use private or user
81 : event loop).
82 : 256: Modification flag to suppress the engine reset.
83 : */
84 : gpgme_error_t
85 692 : _gpgme_op_reset (gpgme_ctx_t ctx, int type)
86 : {
87 692 : gpgme_error_t err = 0;
88 : struct gpgme_io_cbs io_cbs;
89 692 : int no_reset = (type & 256);
90 692 : int reuse_engine = 0;
91 :
92 692 : type &= 255;
93 :
94 692 : _gpgme_release_result (ctx);
95 692 : LOCK (ctx->lock);
96 692 : ctx->canceled = 0;
97 692 : UNLOCK (ctx->lock);
98 :
99 692 : if (ctx->engine && no_reset)
100 39 : reuse_engine = 1;
101 653 : else if (ctx->engine)
102 : {
103 : /* Attempt to reset an existing engine. */
104 :
105 104 : err = _gpgme_engine_reset (ctx->engine);
106 104 : if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
107 : {
108 100 : _gpgme_engine_release (ctx->engine);
109 100 : ctx->engine = NULL;
110 : }
111 : }
112 :
113 692 : if (!ctx->engine)
114 : {
115 : gpgme_engine_info_t info;
116 650 : info = ctx->engine_info;
117 1314 : while (info && info->protocol != ctx->protocol)
118 14 : info = info->next;
119 :
120 650 : if (!info)
121 0 : return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
122 :
123 : /* Create an engine object. */
124 650 : err = _gpgme_engine_new (info, &ctx->engine);
125 645 : if (err)
126 0 : return err;
127 : }
128 :
129 687 : if (!reuse_engine)
130 : {
131 649 : err = 0;
132 : #ifdef LC_CTYPE
133 649 : err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype);
134 : #endif
135 : #ifdef LC_MESSAGES
136 649 : if (!err)
137 649 : err = _gpgme_engine_set_locale (ctx->engine,
138 649 : LC_MESSAGES, ctx->lc_messages);
139 : #endif
140 650 : if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
141 0 : err = 0;
142 :
143 650 : if (!err)
144 : {
145 650 : err = _gpgme_engine_set_pinentry_mode (ctx->engine,
146 : ctx->pinentry_mode);
147 648 : if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
148 14 : err = 0;
149 : }
150 :
151 649 : if (!err && ctx->status_cb && ctx->full_status)
152 : {
153 4 : _gpgme_engine_set_status_cb (ctx->engine,
154 : ctx->status_cb, ctx->status_cb_value);
155 : }
156 :
157 649 : if (err)
158 : {
159 0 : _gpgme_engine_release (ctx->engine);
160 0 : ctx->engine = NULL;
161 0 : return err;
162 : }
163 : }
164 :
165 687 : if (ctx->sub_protocol != GPGME_PROTOCOL_DEFAULT)
166 : {
167 0 : err = _gpgme_engine_set_protocol (ctx->engine, ctx->sub_protocol);
168 0 : if (err)
169 0 : return err;
170 : }
171 :
172 687 : if (type == 1 || (type == 2 && !ctx->io_cbs.add))
173 : {
174 : /* Use private event loop. */
175 683 : io_cbs.add = _gpgme_add_io_cb;
176 683 : io_cbs.add_priv = ctx;
177 683 : io_cbs.remove = _gpgme_remove_io_cb;
178 683 : io_cbs.event = _gpgme_wait_private_event_cb;
179 683 : io_cbs.event_priv = ctx;
180 : }
181 4 : else if (! ctx->io_cbs.add)
182 : {
183 : /* Use global event loop. */
184 3 : io_cbs.add = _gpgme_add_io_cb;
185 3 : io_cbs.add_priv = ctx;
186 3 : io_cbs.remove = _gpgme_remove_io_cb;
187 3 : io_cbs.event = _gpgme_wait_global_event_cb;
188 3 : io_cbs.event_priv = ctx;
189 : }
190 : else
191 : {
192 : /* Use user event loop. */
193 1 : io_cbs.add = _gpgme_wait_user_add_io_cb;
194 1 : io_cbs.add_priv = ctx;
195 1 : io_cbs.remove = _gpgme_wait_user_remove_io_cb;
196 1 : io_cbs.event = _gpgme_wait_user_event_cb;
197 1 : io_cbs.event_priv = ctx;
198 : }
199 687 : _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs);
200 686 : return err;
201 : }
202 :
203 :
204 : /* Parse the INV_RECP or INV_SNDR status line in ARGS and return the
205 : result in KEY. If KC_FPR (from the KEY_CONSIDERED status line) is
206 : not NULL take the KC_FLAGS in account. */
207 : gpgme_error_t
208 6 : _gpgme_parse_inv_recp (char *args, int for_signing,
209 : const char *kc_fpr, unsigned int kc_flags,
210 : gpgme_invalid_key_t *key)
211 : {
212 : gpgme_invalid_key_t inv_key;
213 : char *tail;
214 : long int reason;
215 :
216 : (void)for_signing;
217 :
218 6 : inv_key = calloc (1, sizeof (*inv_key));
219 6 : if (!inv_key)
220 0 : return gpg_error_from_syserror ();
221 6 : inv_key->next = NULL;
222 6 : gpg_err_set_errno (0);
223 6 : reason = strtol (args, &tail, 0);
224 6 : if (errno || args == tail || (*tail && *tail != ' '))
225 : {
226 : /* The crypto backend does not behave. */
227 0 : free (inv_key);
228 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
229 : }
230 :
231 6 : switch (reason)
232 : {
233 : case 0:
234 2 : if (kc_fpr && (kc_flags & 2))
235 2 : inv_key->reason = gpg_error (GPG_ERR_SUBKEYS_EXP_OR_REV);
236 : else
237 0 : inv_key->reason = gpg_error (GPG_ERR_GENERAL);
238 2 : break;
239 :
240 : case 1:
241 0 : inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY);
242 0 : break;
243 :
244 : case 2:
245 0 : inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
246 0 : break;
247 :
248 : case 3:
249 0 : inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
250 0 : break;
251 :
252 : case 4:
253 0 : inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED);
254 0 : break;
255 :
256 : case 5:
257 0 : inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED);
258 0 : break;
259 :
260 : case 6:
261 0 : inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN);
262 0 : break;
263 :
264 : case 7:
265 0 : inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD);
266 0 : break;
267 :
268 : case 8:
269 0 : inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH);
270 0 : break;
271 :
272 : case 9:
273 4 : inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY);
274 4 : break;
275 :
276 : case 10:
277 0 : inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED);
278 0 : break;
279 :
280 : case 11:
281 0 : inv_key->reason = gpg_error (GPG_ERR_MISSING_CERT);
282 0 : break;
283 :
284 : case 12:
285 0 : inv_key->reason = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
286 0 : break;
287 :
288 : case 13:
289 0 : inv_key->reason = gpg_error (252); /*GPG_ERR_KEY_DISABLED*/
290 0 : break;
291 :
292 : case 14:
293 0 : inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID);
294 0 : break;
295 :
296 : default:
297 0 : inv_key->reason = gpg_error (GPG_ERR_GENERAL);
298 0 : break;
299 : }
300 :
301 18 : while (*tail && *tail == ' ')
302 6 : tail++;
303 6 : if (*tail)
304 : {
305 6 : inv_key->fpr = strdup (tail);
306 6 : if (!inv_key->fpr)
307 : {
308 0 : free (inv_key);
309 0 : return gpg_error_from_syserror ();
310 : }
311 : }
312 :
313 6 : *key = inv_key;
314 6 : return 0;
315 : }
316 :
317 :
318 :
319 : /* Parse a KEY_CONSIDERED status line in ARGS and store the
320 : * fingerprint and the flags at R_FPR and R_FLAGS. The caller must
321 : * free the value at R_FPR on success. */
322 : gpgme_error_t
323 306 : _gpgme_parse_key_considered (const char *args,
324 : char **r_fpr, unsigned int *r_flags)
325 : {
326 : char *pend;
327 : size_t n;
328 :
329 306 : *r_fpr = NULL;
330 :
331 306 : pend = strchr (args, ' ');
332 306 : if (!pend || pend == args)
333 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Bogus status line. */
334 306 : n = pend - args;
335 306 : *r_fpr = malloc (n + 1);
336 306 : if (!*r_fpr)
337 0 : return gpg_error_from_syserror ();
338 306 : memcpy (*r_fpr, args, n);
339 306 : (*r_fpr)[n] = 0;
340 306 : args = pend + 1;
341 :
342 306 : gpg_err_set_errno (0);
343 306 : *r_flags = strtoul (args, &pend, 0);
344 306 : if (errno || args == pend || (*pend && *pend != ' '))
345 : {
346 0 : free (*r_fpr);
347 0 : *r_fpr = NULL;
348 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
349 : }
350 :
351 306 : return 0;
352 : }
353 :
354 :
355 : /* Parse the PLAINTEXT status line in ARGS and return the result in
356 : FILENAMEP. */
357 : gpgme_error_t
358 85 : _gpgme_parse_plaintext (char *args, char **filenamep)
359 : {
360 : char *tail;
361 :
362 170 : while (*args == ' ')
363 0 : args++;
364 85 : if (*args == '\0')
365 0 : return 0;
366 :
367 : /* First argument is file type. */
368 340 : while (*args != ' ' && *args != '\0')
369 170 : args++;
370 255 : while (*args == ' ')
371 85 : args++;
372 85 : if (*args == '\0')
373 0 : return 0;
374 :
375 : /* Second argument is the timestamp. */
376 994 : while (*args != ' ' && *args != '\0')
377 824 : args++;
378 255 : while (*args == ' ')
379 85 : args++;
380 85 : if (*args == '\0')
381 54 : return 0;
382 :
383 31 : tail = args;
384 228 : while (*tail != ' ' && *tail != '\0')
385 166 : tail++;
386 31 : *tail = '\0';
387 31 : if (filenamep && *args != '\0')
388 : {
389 31 : char *filename = strdup (args);
390 31 : if (!filename)
391 0 : return gpg_error_from_syserror ();
392 :
393 31 : *filenamep = filename;
394 : }
395 31 : return 0;
396 : }
397 :
398 :
399 : /* Parse a FAILURE status line and return the error code. ARGS is
400 : modified to contain the location part. */
401 : gpgme_error_t
402 8 : _gpgme_parse_failure (char *args)
403 : {
404 : char *where, *which;
405 :
406 8 : where = strchr (args, ' ');
407 8 : if (!where)
408 2 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
409 :
410 6 : *where = '\0';
411 6 : which = where + 1;
412 :
413 6 : where = strchr (which, ' ');
414 6 : if (where)
415 0 : *where = '\0';
416 :
417 6 : where = args;
418 :
419 6 : return atoi (which);
420 : }
|