Line data Source code
1 : /* conversion.c - String conversion helper functions.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : 02111-1307, USA. */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #ifdef HAVE_SYS_TYPES_H
29 : /* Solaris 8 needs sys/types.h before time.h. */
30 : # include <sys/types.h>
31 : #endif
32 : #include <time.h>
33 : #include <errno.h>
34 : #include <stdarg.h>
35 :
36 : #include "gpgme.h"
37 : #include "util.h"
38 : #include "debug.h"
39 :
40 : #define atoi_1(p) (*(p) - '0' )
41 : #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
42 : #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
43 :
44 :
45 :
46 : static char *
47 0 : do_strconcat (const char *s1, va_list arg_ptr)
48 : {
49 : const char *argv[16];
50 : size_t argc;
51 : size_t needed;
52 : char *buffer, *p;
53 :
54 0 : argc = 0;
55 0 : argv[argc++] = s1;
56 0 : needed = strlen (s1);
57 0 : while (((argv[argc] = va_arg (arg_ptr, const char *))))
58 : {
59 0 : needed += strlen (argv[argc]);
60 0 : if (argc >= DIM (argv)-1)
61 : {
62 0 : gpg_err_set_errno (EINVAL);
63 0 : return NULL;
64 : }
65 0 : argc++;
66 : }
67 0 : needed++;
68 0 : buffer = malloc (needed);
69 0 : if (buffer)
70 : {
71 0 : for (p = buffer, argc=0; argv[argc]; argc++)
72 0 : p = stpcpy (p, argv[argc]);
73 : }
74 0 : return buffer;
75 : }
76 :
77 :
78 : /* Concatenate the string S1 with all the following strings up to a
79 : * NULL. Returns a malloced buffer with the new string or NULL on a
80 : malloc error or if too many arguments are given. */
81 : char *
82 0 : _gpgme_strconcat (const char *s1, ...)
83 : {
84 : va_list arg_ptr;
85 : char *result;
86 :
87 0 : if (!s1)
88 0 : result = strdup ("");
89 : else
90 : {
91 0 : va_start (arg_ptr, s1);
92 0 : result = do_strconcat (s1, arg_ptr);
93 0 : va_end (arg_ptr);
94 : }
95 0 : return result;
96 : }
97 :
98 :
99 :
100 :
101 : /* Convert two hexadecimal digits from STR to the value they
102 : represent. Returns -1 if one of the characters is not a
103 : hexadecimal digit. */
104 : int
105 1679 : _gpgme_hextobyte (const char *str)
106 : {
107 1679 : int val = 0;
108 : int i;
109 :
110 : #define NROFHEXDIGITS 2
111 5037 : for (i = 0; i < NROFHEXDIGITS; i++)
112 : {
113 3358 : if (*str >= '0' && *str <= '9')
114 3320 : val += *str - '0';
115 38 : else if (*str >= 'A' && *str <= 'F')
116 36 : val += 10 + *str - 'A';
117 2 : else if (*str >= 'a' && *str <= 'f')
118 2 : val += 10 + *str - 'a';
119 : else
120 0 : return -1;
121 3358 : if (i < NROFHEXDIGITS - 1)
122 1679 : val *= 16;
123 3358 : str++;
124 : }
125 1679 : return val;
126 : }
127 :
128 :
129 : /* Decode the C formatted string SRC and store the result in the
130 : buffer *DESTP which is LEN bytes long. If LEN is zero, then a
131 : large enough buffer is allocated with malloc and *DESTP is set to
132 : the result. Currently, LEN is only used to specify if allocation
133 : is desired or not, the caller is expected to make sure that *DESTP
134 : is large enough if LEN is not zero. */
135 : gpgme_error_t
136 7039 : _gpgme_decode_c_string (const char *src, char **destp, size_t len)
137 : {
138 : char *dest;
139 :
140 : /* Set up the destination buffer. */
141 7039 : if (len)
142 : {
143 7033 : if (len < strlen (src) + 1)
144 0 : return gpg_error (GPG_ERR_INTERNAL);
145 :
146 7033 : dest = *destp;
147 : }
148 : else
149 : {
150 : /* The converted string will never be larger than the original
151 : string. */
152 6 : dest = malloc (strlen (src) + 1);
153 6 : if (!dest)
154 0 : return gpg_error_from_syserror ();
155 :
156 6 : *destp = dest;
157 : }
158 :
159 : /* Convert the string. */
160 149526 : while (*src)
161 : {
162 135448 : if (*src != '\\')
163 : {
164 135446 : *(dest++) = *(src++);
165 135446 : continue;
166 : }
167 :
168 2 : switch (src[1])
169 : {
170 : #define DECODE_ONE(match,result) \
171 : case match: \
172 : src += 2; \
173 : *(dest++) = result; \
174 : break;
175 :
176 0 : DECODE_ONE ('\'', '\'');
177 0 : DECODE_ONE ('\"', '\"');
178 0 : DECODE_ONE ('\?', '\?');
179 0 : DECODE_ONE ('\\', '\\');
180 0 : DECODE_ONE ('a', '\a');
181 0 : DECODE_ONE ('b', '\b');
182 0 : DECODE_ONE ('f', '\f');
183 0 : DECODE_ONE ('n', '\n');
184 0 : DECODE_ONE ('r', '\r');
185 0 : DECODE_ONE ('t', '\t');
186 0 : DECODE_ONE ('v', '\v');
187 :
188 : case 'x':
189 : {
190 2 : int val = _gpgme_hextobyte (&src[2]);
191 :
192 2 : if (val == -1)
193 : {
194 : /* Should not happen. */
195 0 : *(dest++) = *(src++);
196 0 : *(dest++) = *(src++);
197 0 : if (*src)
198 0 : *(dest++) = *(src++);
199 0 : if (*src)
200 0 : *(dest++) = *(src++);
201 : }
202 : else
203 : {
204 2 : if (!val)
205 : {
206 : /* A binary zero is not representable in a C
207 : string. */
208 0 : *(dest++) = '\\';
209 0 : *(dest++) = '0';
210 : }
211 : else
212 2 : *((unsigned char *) dest++) = val;
213 2 : src += 4;
214 : }
215 : }
216 2 : break;
217 :
218 : default:
219 : {
220 : /* Should not happen. */
221 0 : *(dest++) = *(src++);
222 0 : *(dest++) = *(src++);
223 : }
224 : }
225 : }
226 7039 : *(dest++) = 0;
227 :
228 7039 : return 0;
229 : }
230 :
231 :
232 : /* Decode the percent escaped string SRC and store the result in the
233 : buffer *DESTP which is LEN bytes long. If LEN is zero, then a
234 : large enough buffer is allocated with malloc and *DESTP is set to
235 : the result. Currently, LEN is only used to specify if allocation
236 : is desired or not, the caller is expected to make sure that *DESTP
237 : is large enough if LEN is not zero. If BINARY is 1, then '\0'
238 : characters are allowed in the output. */
239 : gpgme_error_t
240 2189 : _gpgme_decode_percent_string (const char *src, char **destp, size_t len,
241 : int binary)
242 : {
243 : char *dest;
244 :
245 : /* Set up the destination buffer. */
246 2189 : if (len)
247 : {
248 1828 : if (len < strlen (src) + 1)
249 0 : return gpg_error (GPG_ERR_INTERNAL);
250 :
251 1828 : dest = *destp;
252 : }
253 : else
254 : {
255 : /* The converted string will never be larger than the original
256 : string. */
257 361 : dest = malloc (strlen (src) + 1);
258 361 : if (!dest)
259 0 : return gpg_error_from_syserror ();
260 :
261 361 : *destp = dest;
262 : }
263 :
264 : /* Convert the string. */
265 71049 : while (*src)
266 : {
267 66671 : if (*src != '%')
268 : {
269 65039 : *(dest++) = *(src++);
270 65039 : continue;
271 : }
272 : else
273 : {
274 1632 : int val = _gpgme_hextobyte (&src[1]);
275 :
276 1632 : if (val == -1)
277 : {
278 : /* Should not happen. */
279 0 : *(dest++) = *(src++);
280 0 : if (*src)
281 0 : *(dest++) = *(src++);
282 0 : if (*src)
283 0 : *(dest++) = *(src++);
284 : }
285 : else
286 : {
287 1632 : if (!val && !binary)
288 : {
289 : /* A binary zero is not representable in a C
290 : string. */
291 0 : *(dest++) = '\\';
292 0 : *(dest++) = '0';
293 : }
294 : else
295 1632 : *((unsigned char *) dest++) = val;
296 1632 : src += 3;
297 : }
298 : }
299 : }
300 2189 : *(dest++) = 0;
301 :
302 2189 : return 0;
303 : }
304 :
305 :
306 : /* Encode the string SRC with percent escaping and store the result in
307 : the buffer *DESTP which is LEN bytes long. If LEN is zero, then a
308 : large enough buffer is allocated with malloc and *DESTP is set to
309 : the result. Currently, LEN is only used to specify if allocation
310 : is desired or not, the caller is expected to make sure that *DESTP
311 : is large enough if LEN is not zero. If BINARY is 1, then '\0'
312 : characters are allowed in the output. */
313 : gpgme_error_t
314 0 : _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
315 : {
316 : size_t destlen;
317 : char *dest;
318 : const char *str;
319 :
320 0 : destlen = 0;
321 0 : str = src;
322 : /* We percent-escape the + character because the user might need a
323 : "percent plus" escaped string (special gpg format). But we
324 : percent-escape the space character, which works with and without
325 : the special plus format. */
326 0 : while (*str)
327 : {
328 0 : if (*str == '+' || *str == '\"' || *str == '%'
329 0 : || *(const unsigned char *)str <= 0x20)
330 0 : destlen += 3;
331 : else
332 0 : destlen++;
333 0 : str++;
334 : }
335 : /* Terminating nul byte. */
336 0 : destlen++;
337 :
338 : /* Set up the destination buffer. */
339 0 : if (len)
340 : {
341 0 : if (len < destlen)
342 0 : return gpg_error (GPG_ERR_INTERNAL);
343 :
344 0 : dest = *destp;
345 : }
346 : else
347 : {
348 : /* The converted string will never be larger than the original
349 : string. */
350 0 : dest = malloc (destlen);
351 0 : if (!dest)
352 0 : return gpg_error_from_syserror ();
353 :
354 0 : *destp = dest;
355 : }
356 :
357 : /* Convert the string. */
358 0 : while (*src)
359 : {
360 0 : if (*src == '+' || *src == '\"' || *src == '%'
361 0 : || *(const unsigned char *)src <= 0x20)
362 : {
363 0 : snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
364 0 : dest += 3;
365 : }
366 : else
367 0 : *(dest++) = *src;
368 0 : src++;
369 : }
370 0 : *(dest++) = 0;
371 :
372 0 : return 0;
373 : }
374 :
375 :
376 : /* Split a string into space delimited fields and remove leading and
377 : * trailing spaces from each field. A pointer to the each field is
378 : * stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function
379 : * modifies STRING. The number of parsed fields is returned.
380 : */
381 : int
382 235 : _gpgme_split_fields (char *string, char **array, int arraysize)
383 : {
384 235 : int n = 0;
385 : char *p, *pend;
386 :
387 235 : for (p = string; *p == ' '; p++)
388 : ;
389 : do
390 : {
391 560 : if (n == arraysize)
392 0 : break;
393 560 : array[n++] = p;
394 560 : pend = strchr (p, ' ');
395 560 : if (!pend)
396 235 : break;
397 325 : *pend++ = 0;
398 325 : for (p = pend; *p == ' '; p++)
399 : ;
400 : }
401 325 : while (*p);
402 :
403 235 : return n;
404 : }
405 :
406 : /* Convert the field STRING into an unsigned long value. Check for
407 : * trailing garbage. */
408 : gpgme_error_t
409 196 : _gpgme_strtoul_field (const char *string, unsigned long *result)
410 : {
411 : char *endp;
412 :
413 196 : gpg_err_set_errno (0);
414 196 : *result = strtoul (string, &endp, 0);
415 196 : if (errno)
416 0 : return gpg_error_from_syserror ();
417 196 : if (endp == string || *endp)
418 0 : return gpg_error (GPG_ERR_INV_VALUE);
419 196 : return 0;
420 : }
421 :
422 :
423 : /* Convert STRING into an offset value. Note that this functions only
424 : * allows for a base-10 length. This function is similar to atoi()
425 : * and thus there is no error checking. */
426 : gpgme_off_t
427 67 : _gpgme_string_to_off (const char *string)
428 : {
429 67 : gpgme_off_t value = 0;
430 :
431 134 : while (*string == ' ' || *string == '\t')
432 0 : string++;
433 166 : for (; *string >= '0' && *string <= '9'; string++)
434 : {
435 99 : value *= 10;
436 99 : value += atoi_1 (string);
437 : }
438 67 : return value;
439 : }
440 :
441 :
442 : #ifdef HAVE_W32_SYSTEM
443 : static time_t
444 : _gpgme_timegm (struct tm *tm)
445 : {
446 : /* This one is thread safe. */
447 : SYSTEMTIME st;
448 : FILETIME ft;
449 : unsigned long long cnsecs;
450 :
451 : st.wYear = tm->tm_year + 1900;
452 : st.wMonth = tm->tm_mon + 1;
453 : st.wDay = tm->tm_mday;
454 : st.wHour = tm->tm_hour;
455 : st.wMinute = tm->tm_min;
456 : st.wSecond = tm->tm_sec;
457 : st.wMilliseconds = 0; /* Not available. */
458 : st.wDayOfWeek = 0; /* Ignored. */
459 :
460 : /* System time is UTC thus the conversion is pretty easy. */
461 : if (!SystemTimeToFileTime (&st, &ft))
462 : {
463 : gpg_err_set_errno (EINVAL);
464 : return (time_t)(-1);
465 : }
466 :
467 : cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
468 : | ft.dwLowDateTime);
469 : cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
470 : return (time_t)(cnsecs / 10000000ULL);
471 : }
472 : #endif
473 :
474 :
475 : /* Parse the string TIMESTAMP into a time_t. The string may either be
476 : seconds since Epoch or in the ISO 8601 format like
477 : "20390815T143012". Returns 0 for an empty string or seconds since
478 : Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
479 : point to the next non-parsed character in TIMESTRING. */
480 : time_t
481 23630 : _gpgme_parse_timestamp (const char *timestamp, char **endp)
482 : {
483 : /* Need to skip leading spaces, because that is what strtoul does
484 : but not our ISO 8601 checking code. */
485 47611 : while (*timestamp && *timestamp== ' ')
486 351 : timestamp++;
487 23630 : if (!*timestamp)
488 11220 : return 0;
489 :
490 12410 : if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
491 : {
492 : struct tm buf;
493 : int year;
494 :
495 15 : year = atoi_4 (timestamp);
496 15 : if (year < 1900)
497 0 : return (time_t)(-1);
498 :
499 15 : if (endp)
500 3 : *endp = (char*)(timestamp + 15);
501 :
502 : /* Fixme: We would better use a configure test to see whether
503 : mktime can handle dates beyond 2038. */
504 : if (sizeof (time_t) <= 4 && year >= 2038)
505 : return (time_t)2145914603; /* 2037-12-31 23:23:23 */
506 :
507 15 : memset (&buf, 0, sizeof buf);
508 15 : buf.tm_year = year - 1900;
509 15 : buf.tm_mon = atoi_2 (timestamp+4) - 1;
510 15 : buf.tm_mday = atoi_2 (timestamp+6);
511 15 : buf.tm_hour = atoi_2 (timestamp+9);
512 15 : buf.tm_min = atoi_2 (timestamp+11);
513 15 : buf.tm_sec = atoi_2 (timestamp+13);
514 :
515 : #ifdef HAVE_W32_SYSTEM
516 : return _gpgme_timegm (&buf);
517 : #else
518 : #ifdef HAVE_TIMEGM
519 15 : return timegm (&buf);
520 : #else
521 : {
522 : time_t tim;
523 :
524 : putenv ("TZ=UTC");
525 : tim = mktime (&buf);
526 : #ifdef __GNUC__
527 : #warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
528 : #endif
529 : return tim;
530 : }
531 : #endif /* !HAVE_TIMEGM */
532 : #endif /* !HAVE_W32_SYSTEM */
533 : }
534 : else
535 12395 : return (time_t)strtoul (timestamp, endp, 10);
536 : }
537 :
538 :
539 : /* The GPG backend uses OpenPGP algorithm numbers which we need to map
540 : to our algorithm numbers. This function MUST not change ERRNO. */
541 : int
542 11893 : _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
543 : {
544 11893 : if (protocol == GPGME_PROTOCOL_OPENPGP)
545 : {
546 11878 : switch (algo)
547 : {
548 11878 : case 1: case 2: case 3: case 16: case 17: break;
549 0 : case 18: algo = GPGME_PK_ECDH; break;
550 0 : case 19: algo = GPGME_PK_ECDSA; break;
551 0 : case 20: break;
552 0 : case 22: algo = GPGME_PK_EDDSA; break;
553 0 : default: algo = 0; break; /* Unknown. */
554 : }
555 : }
556 :
557 11893 : return algo;
558 : }
|