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 :
35 : #include "gpgme.h"
36 : #include "util.h"
37 : #include "debug.h"
38 :
39 : #define atoi_1(p) (*(p) - '0' )
40 : #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
41 : #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
42 :
43 :
44 :
45 : /* Convert two hexadecimal digits from STR to the value they
46 : represent. Returns -1 if one of the characters is not a
47 : hexadecimal digit. */
48 : int
49 143 : _gpgme_hextobyte (const char *str)
50 : {
51 143 : int val = 0;
52 : int i;
53 :
54 : #define NROFHEXDIGITS 2
55 429 : for (i = 0; i < NROFHEXDIGITS; i++)
56 : {
57 286 : if (*str >= '0' && *str <= '9')
58 248 : val += *str - '0';
59 38 : else if (*str >= 'A' && *str <= 'F')
60 36 : val += 10 + *str - 'A';
61 2 : else if (*str >= 'a' && *str <= 'f')
62 2 : val += 10 + *str - 'a';
63 : else
64 0 : return -1;
65 286 : if (i < NROFHEXDIGITS - 1)
66 143 : val *= 16;
67 286 : str++;
68 : }
69 143 : return val;
70 : }
71 :
72 :
73 : /* Decode the C formatted string SRC and store the result in the
74 : buffer *DESTP which is LEN bytes long. If LEN is zero, then a
75 : large enough buffer is allocated with malloc and *DESTP is set to
76 : the result. Currently, LEN is only used to specify if allocation
77 : is desired or not, the caller is expected to make sure that *DESTP
78 : is large enough if LEN is not zero. */
79 : gpgme_error_t
80 363 : _gpgme_decode_c_string (const char *src, char **destp, size_t len)
81 : {
82 : char *dest;
83 :
84 : /* Set up the destination buffer. */
85 363 : if (len)
86 : {
87 357 : if (len < strlen (src) + 1)
88 0 : return gpg_error (GPG_ERR_INTERNAL);
89 :
90 357 : dest = *destp;
91 : }
92 : else
93 : {
94 : /* The converted string will never be larger than the original
95 : string. */
96 6 : dest = malloc (strlen (src) + 1);
97 6 : if (!dest)
98 0 : return gpg_error_from_syserror ();
99 :
100 6 : *destp = dest;
101 : }
102 :
103 : /* Convert the string. */
104 13776 : while (*src)
105 : {
106 13050 : if (*src != '\\')
107 : {
108 13048 : *(dest++) = *(src++);
109 13048 : continue;
110 : }
111 :
112 2 : switch (src[1])
113 : {
114 : #define DECODE_ONE(match,result) \
115 : case match: \
116 : src += 2; \
117 : *(dest++) = result; \
118 : break;
119 :
120 0 : DECODE_ONE ('\'', '\'');
121 0 : DECODE_ONE ('\"', '\"');
122 0 : DECODE_ONE ('\?', '\?');
123 0 : DECODE_ONE ('\\', '\\');
124 0 : DECODE_ONE ('a', '\a');
125 0 : DECODE_ONE ('b', '\b');
126 0 : DECODE_ONE ('f', '\f');
127 0 : DECODE_ONE ('n', '\n');
128 0 : DECODE_ONE ('r', '\r');
129 0 : DECODE_ONE ('t', '\t');
130 0 : DECODE_ONE ('v', '\v');
131 :
132 : case 'x':
133 : {
134 2 : int val = _gpgme_hextobyte (&src[2]);
135 :
136 2 : if (val == -1)
137 : {
138 : /* Should not happen. */
139 0 : *(dest++) = *(src++);
140 0 : *(dest++) = *(src++);
141 0 : if (*src)
142 0 : *(dest++) = *(src++);
143 0 : if (*src)
144 0 : *(dest++) = *(src++);
145 : }
146 : else
147 : {
148 2 : if (!val)
149 : {
150 : /* A binary zero is not representable in a C
151 : string. */
152 0 : *(dest++) = '\\';
153 0 : *(dest++) = '0';
154 : }
155 : else
156 2 : *((unsigned char *) dest++) = val;
157 2 : src += 4;
158 : }
159 : }
160 2 : break;
161 :
162 : default:
163 : {
164 : /* Should not happen. */
165 0 : *(dest++) = *(src++);
166 0 : *(dest++) = *(src++);
167 : }
168 : }
169 : }
170 363 : *(dest++) = 0;
171 :
172 363 : return 0;
173 : }
174 :
175 :
176 : /* Decode the percent escaped string SRC and store the result in the
177 : buffer *DESTP which is LEN bytes long. If LEN is zero, then a
178 : large enough buffer is allocated with malloc and *DESTP is set to
179 : the result. Currently, LEN is only used to specify if allocation
180 : is desired or not, the caller is expected to make sure that *DESTP
181 : is large enough if LEN is not zero. If BINARY is 1, then '\0'
182 : characters are allowed in the output. */
183 : gpgme_error_t
184 1022 : _gpgme_decode_percent_string (const char *src, char **destp, size_t len,
185 : int binary)
186 : {
187 : char *dest;
188 :
189 : /* Set up the destination buffer. */
190 1022 : if (len)
191 : {
192 971 : if (len < strlen (src) + 1)
193 0 : return gpg_error (GPG_ERR_INTERNAL);
194 :
195 971 : dest = *destp;
196 : }
197 : else
198 : {
199 : /* The converted string will never be larger than the original
200 : string. */
201 51 : dest = malloc (strlen (src) + 1);
202 51 : if (!dest)
203 0 : return gpg_error_from_syserror ();
204 :
205 51 : *destp = dest;
206 : }
207 :
208 : /* Convert the string. */
209 33327 : while (*src)
210 : {
211 31283 : if (*src != '%')
212 : {
213 31183 : *(dest++) = *(src++);
214 31183 : continue;
215 : }
216 : else
217 : {
218 100 : int val = _gpgme_hextobyte (&src[1]);
219 :
220 100 : if (val == -1)
221 : {
222 : /* Should not happen. */
223 0 : *(dest++) = *(src++);
224 0 : if (*src)
225 0 : *(dest++) = *(src++);
226 0 : if (*src)
227 0 : *(dest++) = *(src++);
228 : }
229 : else
230 : {
231 100 : if (!val && !binary)
232 : {
233 : /* A binary zero is not representable in a C
234 : string. */
235 0 : *(dest++) = '\\';
236 0 : *(dest++) = '0';
237 : }
238 : else
239 100 : *((unsigned char *) dest++) = val;
240 100 : src += 3;
241 : }
242 : }
243 : }
244 1022 : *(dest++) = 0;
245 :
246 1022 : return 0;
247 : }
248 :
249 :
250 : /* Encode the string SRC with percent escaping and store the result in
251 : the buffer *DESTP which is LEN bytes long. If LEN is zero, then a
252 : large enough buffer is allocated with malloc and *DESTP is set to
253 : the result. Currently, LEN is only used to specify if allocation
254 : is desired or not, the caller is expected to make sure that *DESTP
255 : is large enough if LEN is not zero. If BINARY is 1, then '\0'
256 : characters are allowed in the output. */
257 : gpgme_error_t
258 0 : _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
259 : {
260 : size_t destlen;
261 : char *dest;
262 : const char *str;
263 :
264 0 : destlen = 0;
265 0 : str = src;
266 : /* We percent-escape the + character because the user might need a
267 : "percent plus" escaped string (special gpg format). But we
268 : percent-escape the space character, which works with and without
269 : the special plus format. */
270 0 : while (*str)
271 : {
272 0 : if (*str == '+' || *str == '\"' || *str == '%'
273 0 : || *(const unsigned char *)str <= 0x20)
274 0 : destlen += 3;
275 : else
276 0 : destlen++;
277 0 : str++;
278 : }
279 : /* Terminating nul byte. */
280 0 : destlen++;
281 :
282 : /* Set up the destination buffer. */
283 0 : if (len)
284 : {
285 0 : if (len < destlen)
286 0 : return gpg_error (GPG_ERR_INTERNAL);
287 :
288 0 : dest = *destp;
289 : }
290 : else
291 : {
292 : /* The converted string will never be larger than the original
293 : string. */
294 0 : dest = malloc (destlen);
295 0 : if (!dest)
296 0 : return gpg_error_from_syserror ();
297 :
298 0 : *destp = dest;
299 : }
300 :
301 : /* Convert the string. */
302 0 : while (*src)
303 : {
304 0 : if (*src == '+' || *src == '\"' || *src == '%'
305 0 : || *(const unsigned char *)src <= 0x20)
306 : {
307 0 : snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
308 0 : dest += 3;
309 : }
310 : else
311 0 : *(dest++) = *src;
312 0 : src++;
313 : }
314 0 : *(dest++) = 0;
315 :
316 0 : return 0;
317 : }
318 :
319 :
320 : /* Split a string into space delimited fields and remove leading and
321 : * trailing spaces from each field. A pointer to the each field is
322 : * stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function
323 : * modifies STRING. The number of parsed fields is returned.
324 : */
325 : int
326 29 : _gpgme_split_fields (char *string, char **array, int arraysize)
327 : {
328 29 : int n = 0;
329 : char *p, *pend;
330 :
331 29 : for (p = string; *p == ' '; p++)
332 : ;
333 : do
334 : {
335 118 : if (n == arraysize)
336 0 : break;
337 118 : array[n++] = p;
338 118 : pend = strchr (p, ' ');
339 118 : if (!pend)
340 29 : break;
341 89 : *pend++ = 0;
342 89 : for (p = pend; *p == ' '; p++)
343 : ;
344 : }
345 89 : while (*p);
346 :
347 29 : return n;
348 : }
349 :
350 : /* Convert the field STRING into an unsigned long value. Check for
351 : * trailing garbage. */
352 : gpgme_error_t
353 110 : _gpgme_strtoul_field (const char *string, unsigned long *result)
354 : {
355 : char *endp;
356 :
357 110 : gpg_err_set_errno (0);
358 110 : *result = strtoul (string, &endp, 0);
359 110 : if (errno)
360 0 : return gpg_error_from_syserror ();
361 110 : if (endp == string || *endp)
362 0 : return gpg_error (GPG_ERR_INV_VALUE);
363 110 : return 0;
364 : }
365 :
366 :
367 : /* Convert STRING into an offset value. Note that this functions only
368 : * allows for a base-10 length. This function is similar to atoi()
369 : * and thus there is no error checking. */
370 : gpgme_off_t
371 64 : _gpgme_string_to_off (const char *string)
372 : {
373 64 : gpgme_off_t value = 0;
374 :
375 128 : while (*string == ' ' || *string == '\t')
376 0 : string++;
377 156 : for (; *string >= '0' && *string <= '9'; string++)
378 : {
379 92 : value *= 10;
380 92 : value += atoi_1 (string);
381 : }
382 64 : return value;
383 : }
384 :
385 :
386 : #ifdef HAVE_W32_SYSTEM
387 : static time_t
388 : _gpgme_timegm (struct tm *tm)
389 : {
390 : /* This one is thread safe. */
391 : SYSTEMTIME st;
392 : FILETIME ft;
393 : unsigned long long cnsecs;
394 :
395 : st.wYear = tm->tm_year + 1900;
396 : st.wMonth = tm->tm_mon + 1;
397 : st.wDay = tm->tm_mday;
398 : st.wHour = tm->tm_hour;
399 : st.wMinute = tm->tm_min;
400 : st.wSecond = tm->tm_sec;
401 : st.wMilliseconds = 0; /* Not available. */
402 : st.wDayOfWeek = 0; /* Ignored. */
403 :
404 : /* System time is UTC thus the conversion is pretty easy. */
405 : if (!SystemTimeToFileTime (&st, &ft))
406 : {
407 : gpg_err_set_errno (EINVAL);
408 : return (time_t)(-1);
409 : }
410 :
411 : cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
412 : | ft.dwLowDateTime);
413 : cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
414 : return (time_t)(cnsecs / 10000000ULL);
415 : }
416 : #endif
417 :
418 :
419 : /* Parse the string TIMESTAMP into a time_t. The string may either be
420 : seconds since Epoch or in the ISO 8601 format like
421 : "20390815T143012". Returns 0 for an empty string or seconds since
422 : Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
423 : point to the next non-parsed character in TIMESTRING. */
424 : time_t
425 868 : _gpgme_parse_timestamp (const char *timestamp, char **endp)
426 : {
427 : /* Need to skip leading spaces, because that is what strtoul does
428 : but not our ISO 8601 checking code. */
429 1834 : while (*timestamp && *timestamp== ' ')
430 98 : timestamp++;
431 868 : if (!*timestamp)
432 371 : return 0;
433 :
434 497 : if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
435 : {
436 : struct tm buf;
437 : int year;
438 :
439 15 : year = atoi_4 (timestamp);
440 15 : if (year < 1900)
441 0 : return (time_t)(-1);
442 :
443 15 : if (endp)
444 3 : *endp = (char*)(timestamp + 15);
445 :
446 : /* Fixme: We would better use a configure test to see whether
447 : mktime can handle dates beyond 2038. */
448 : if (sizeof (time_t) <= 4 && year >= 2038)
449 : return (time_t)2145914603; /* 2037-12-31 23:23:23 */
450 :
451 15 : memset (&buf, 0, sizeof buf);
452 15 : buf.tm_year = year - 1900;
453 15 : buf.tm_mon = atoi_2 (timestamp+4) - 1;
454 15 : buf.tm_mday = atoi_2 (timestamp+6);
455 15 : buf.tm_hour = atoi_2 (timestamp+9);
456 15 : buf.tm_min = atoi_2 (timestamp+11);
457 15 : buf.tm_sec = atoi_2 (timestamp+13);
458 :
459 : #ifdef HAVE_W32_SYSTEM
460 : return _gpgme_timegm (&buf);
461 : #else
462 : #ifdef HAVE_TIMEGM
463 15 : return timegm (&buf);
464 : #else
465 : {
466 : time_t tim;
467 :
468 : putenv ("TZ=UTC");
469 : tim = mktime (&buf);
470 : #ifdef __GNUC__
471 : #warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
472 : #endif
473 : return tim;
474 : }
475 : #endif /* !HAVE_TIMEGM */
476 : #endif /* !HAVE_W32_SYSTEM */
477 : }
478 : else
479 482 : return (time_t)strtoul (timestamp, endp, 10);
480 : }
481 :
482 :
483 : /* The GPG backend uses OpenPGP algorithm numbers which we need to map
484 : to our algorithm numbers. This function MUST not change ERRNO. */
485 : int
486 488 : _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
487 : {
488 488 : if (protocol == GPGME_PROTOCOL_OPENPGP)
489 : {
490 478 : switch (algo)
491 : {
492 478 : case 1: case 2: case 3: case 16: case 17: break;
493 0 : case 18: algo = GPGME_PK_ECDH; break;
494 0 : case 19: algo = GPGME_PK_ECDSA; break;
495 0 : case 20: break;
496 0 : case 22: algo = GPGME_PK_EDDSA; break;
497 0 : default: algo = 0; break; /* Unknown. */
498 : }
499 : }
500 :
501 488 : return algo;
502 : }
|