Line data Source code
1 : /* miscellaneous.c - Stuff not fitting elsewhere
2 : * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * This file is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * This file is distributed in the hope that it will be useful,
22 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 : * GNU General Public License for more details.
25 : *
26 : * You should have received a copy of the GNU General Public License
27 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 : */
29 :
30 : #include <config.h>
31 : #include <stdlib.h>
32 : #include <limits.h>
33 : #include <errno.h>
34 :
35 : #include "util.h"
36 : #include "iobuf.h"
37 : #include "i18n.h"
38 :
39 : /* Used by libgcrypt for logging. */
40 : static void
41 0 : my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
42 : {
43 : (void)dummy;
44 :
45 : /* Map the log levels. */
46 0 : switch (level)
47 : {
48 0 : case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break;
49 0 : case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break;
50 0 : case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break;
51 0 : case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break;
52 0 : case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break;
53 0 : case GCRY_LOG_BUG: level = GPGRT_LOG_BUG; break;
54 0 : case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break;
55 0 : default: level = GPGRT_LOG_ERROR; break;
56 : }
57 0 : log_logv (level, fmt, arg_ptr);
58 0 : }
59 :
60 :
61 : /* This function is called by libgcrypt on a fatal error. */
62 : static void
63 0 : my_gcry_fatalerror_handler (void *opaque, int rc, const char *text)
64 : {
65 : (void)opaque;
66 :
67 0 : log_fatal ("libgcrypt problem: %s\n", text ? text : gpg_strerror (rc));
68 : abort ();
69 : }
70 :
71 :
72 : /* This function is called by libgcrypt if it ran out of core and
73 : there is no way to return that error to the caller. We do our own
74 : function here to make use of our logging functions. */
75 : static int
76 0 : my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
77 : {
78 : static int been_here; /* Used to protect against recursive calls. */
79 :
80 : (void)opaque;
81 :
82 0 : if (!been_here)
83 : {
84 0 : been_here = 1;
85 0 : if ( (flags & 1) )
86 0 : log_fatal (_("out of core in secure memory "
87 : "while allocating %lu bytes"), (unsigned long)req_n);
88 : else
89 0 : log_fatal (_("out of core while allocating %lu bytes"),
90 : (unsigned long)req_n);
91 : }
92 0 : return 0; /* Let libgcrypt call its own fatal error handler.
93 : Actually this will turn out to be
94 : my_gcry_fatalerror_handler. */
95 : }
96 :
97 :
98 : /* Setup libgcrypt to use our own logging functions. Should be used
99 : early at startup. */
100 : void
101 1334 : setup_libgcrypt_logging (void)
102 : {
103 1334 : gcry_set_log_handler (my_gcry_logger, NULL);
104 1334 : gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
105 1334 : gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
106 1334 : }
107 :
108 :
109 : /* A wrapper around gcry_cipher_algo_name to return the string
110 : "AES-128" instead of "AES". Given that we have an alias in
111 : libgcrypt for it, it does not harm to too much to return this other
112 : string. Some users complained that we print "AES" but "AES192"
113 : and "AES256". We can't fix that in libgcrypt but it is pretty
114 : safe to do it in an application. */
115 : const char *
116 0 : gnupg_cipher_algo_name (int algo)
117 : {
118 : const char *s;
119 :
120 0 : s = gcry_cipher_algo_name (algo);
121 0 : if (!strcmp (s, "AES"))
122 0 : s = "AES128";
123 0 : return s;
124 : }
125 :
126 :
127 : void
128 4 : obsolete_option (const char *configname, unsigned int configlineno,
129 : const char *name)
130 : {
131 4 : if (configname)
132 3 : log_info (_("%s:%u: obsolete option \"%s\" - it has no effect\n"),
133 : configname, configlineno, name);
134 : else
135 1 : log_info (_("WARNING: \"%s%s\" is an obsolete option - it has no effect\n"),
136 : "--", name);
137 4 : }
138 :
139 :
140 : /* Decide whether the filename is stdout or a real filename and return
141 : * an appropriate string. */
142 : const char *
143 0 : print_fname_stdout (const char *s)
144 : {
145 0 : if( !s || (*s == '-' && !s[1]) )
146 0 : return "[stdout]";
147 0 : return s;
148 : }
149 :
150 :
151 : /* Decide whether the filename is stdin or a real filename and return
152 : * an appropriate string. */
153 : const char *
154 0 : print_fname_stdin (const char *s)
155 : {
156 0 : if( !s || (*s == '-' && !s[1]) )
157 0 : return "[stdin]";
158 0 : return s;
159 : }
160 :
161 :
162 : static int
163 3 : do_print_utf8_buffer (estream_t stream,
164 : const void *buffer, size_t length,
165 : const char *delimiters, size_t *bytes_written)
166 : {
167 3 : const char *p = buffer;
168 : size_t i;
169 :
170 : /* We can handle plain ascii simpler, so check for it first. */
171 60 : for (i=0; i < length; i++ )
172 : {
173 57 : if ( (p[i] & 0x80) )
174 0 : break;
175 : }
176 3 : if (i < length)
177 : {
178 0 : int delim = delimiters? *delimiters : 0;
179 : char *buf;
180 : int ret;
181 :
182 : /*(utf8 conversion already does the control character quoting). */
183 0 : buf = utf8_to_native (p, length, delim);
184 0 : if (bytes_written)
185 0 : *bytes_written = strlen (buf);
186 0 : ret = es_fputs (buf, stream);
187 0 : xfree (buf);
188 0 : return ret == EOF? ret : (int)i;
189 : }
190 : else
191 3 : return es_write_sanitized (stream, p, length, delimiters, bytes_written);
192 : }
193 :
194 :
195 : void
196 0 : print_utf8_buffer3 (estream_t stream, const void *p, size_t n,
197 : const char *delim)
198 : {
199 0 : do_print_utf8_buffer (stream, p, n, delim, NULL);
200 0 : }
201 :
202 :
203 : void
204 0 : print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim)
205 : {
206 : char tmp[2];
207 :
208 0 : tmp[0] = delim;
209 0 : tmp[1] = 0;
210 0 : do_print_utf8_buffer (stream, p, n, tmp, NULL);
211 0 : }
212 :
213 :
214 : void
215 3 : print_utf8_buffer (estream_t stream, const void *p, size_t n)
216 : {
217 3 : do_print_utf8_buffer (stream, p, n, NULL, NULL);
218 3 : }
219 :
220 : /* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
221 : RESERVED must be 0. */
222 : void
223 0 : print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
224 : {
225 : #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
226 : const unsigned char *s;
227 :
228 : (void)reserved;
229 :
230 0 : for (s = buffer; length; s++, length--)
231 : {
232 0 : putc ( tohex ((*s>>4)&15), fp);
233 0 : putc ( tohex (*s&15), fp);
234 : }
235 : #undef tohex
236 0 : }
237 :
238 : char *
239 0 : make_printable_string (const void *p, size_t n, int delim )
240 : {
241 0 : return sanitize_buffer (p, n, delim);
242 : }
243 :
244 :
245 :
246 : /*
247 : * Check if the file is compressed.
248 : */
249 : int
250 378 : is_file_compressed (const char *s, int *ret_rc)
251 : {
252 : iobuf_t a;
253 : byte buf[4];
254 378 : int i, rc = 0;
255 : int overflow;
256 :
257 : struct magic_compress_s {
258 : size_t len;
259 : byte magic[4];
260 378 : } magic[] = {
261 : { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
262 : { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
263 : { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
264 : };
265 :
266 378 : if ( iobuf_is_pipe_filename (s) || !ret_rc )
267 14 : return 0; /* We can't check stdin or no file was given */
268 :
269 364 : a = iobuf_open( s );
270 364 : if ( a == NULL ) {
271 0 : *ret_rc = gpg_error_from_syserror ();
272 0 : return 0;
273 : }
274 :
275 364 : if ( iobuf_get_filelength( a, &overflow ) < 4 && !overflow) {
276 44 : *ret_rc = 0;
277 44 : goto leave;
278 : }
279 :
280 320 : if ( iobuf_read( a, buf, 4 ) == -1 ) {
281 0 : *ret_rc = a->error;
282 0 : goto leave;
283 : }
284 :
285 1280 : for ( i = 0; i < DIM( magic ); i++ ) {
286 960 : if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) {
287 0 : *ret_rc = 0;
288 0 : rc = 1;
289 0 : break;
290 : }
291 : }
292 :
293 : leave:
294 364 : iobuf_close( a );
295 364 : return rc;
296 : }
297 :
298 :
299 : /* Try match against each substring of multistr, delimited by | */
300 : int
301 12 : match_multistr (const char *multistr,const char *match)
302 : {
303 : do
304 : {
305 12 : size_t seglen = strcspn (multistr,"|");
306 12 : if (!seglen)
307 0 : break;
308 : /* Using the localized strncasecmp! */
309 12 : if (strncasecmp(multistr,match,seglen)==0)
310 0 : return 1;
311 12 : multistr += seglen;
312 12 : if (*multistr == '|')
313 6 : multistr++;
314 : }
315 12 : while (*multistr);
316 :
317 6 : return 0;
318 : }
319 :
320 :
321 :
322 : /* Parse the first portion of the version number S and store it at
323 : NUMBER. On success, the function returns a pointer into S starting
324 : with the first character, which is not part of the initial number
325 : portion; on failure, NULL is returned. */
326 : static const char*
327 2346 : parse_version_number (const char *s, int *number)
328 : {
329 2346 : int val = 0;
330 :
331 2346 : if (*s == '0' && digitp (s+1))
332 0 : return NULL; /* Leading zeros are not allowed. */
333 4692 : for (; digitp (s); s++ )
334 : {
335 2346 : val *= 10;
336 2346 : val += *s - '0';
337 : }
338 2346 : *number = val;
339 2346 : return val < 0? NULL : s;
340 : }
341 :
342 : /* Break up the complete string representation of the version number S,
343 : which is expected to have this format:
344 :
345 : <major number>.<minor number>.<micro number><patch level>.
346 :
347 : The major, minor and micro number components will be stored at
348 : MAJOR, MINOR and MICRO. On success, a pointer to the last
349 : component, the patch level, will be returned; on failure, NULL will
350 : be returned. */
351 : static const char *
352 782 : parse_version_string (const char *s, int *major, int *minor, int *micro)
353 : {
354 782 : s = parse_version_number (s, major);
355 782 : if (!s || *s != '.')
356 0 : return NULL;
357 782 : s++;
358 782 : s = parse_version_number (s, minor);
359 782 : if (!s || *s != '.')
360 0 : return NULL;
361 782 : s++;
362 782 : s = parse_version_number (s, micro);
363 782 : if (!s)
364 0 : return NULL;
365 782 : return s; /* Patchlevel. */
366 : }
367 :
368 : /* Return true if version string is at least version B. */
369 : int
370 391 : gnupg_compare_version (const char *a, const char *b)
371 : {
372 : int a_major, a_minor, a_micro;
373 : int b_major, b_minor, b_micro;
374 : const char *a_plvl, *b_plvl;
375 :
376 391 : if (!a || !b)
377 0 : return 0;
378 :
379 : /* Parse version A. */
380 391 : a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
381 391 : if (!a_plvl )
382 0 : return 0; /* Invalid version number. */
383 :
384 : /* Parse version B. */
385 391 : b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
386 391 : if (!b_plvl )
387 0 : return 0; /* Invalid version number. */
388 :
389 : /* Compare version numbers. */
390 782 : return (a_major > b_major
391 391 : || (a_major == b_major && a_minor > b_minor)
392 391 : || (a_major == b_major && a_minor == b_minor
393 391 : && a_micro > b_micro)
394 1173 : || (a_major == b_major && a_minor == b_minor
395 391 : && a_micro == b_micro
396 391 : && strcmp (a_plvl, b_plvl) >= 0));
397 : }
398 :
399 :
400 :
401 : /* Parse an --debug style argument. We allow the use of number values
402 : * in the usual C notation or a string with comma separated keywords.
403 : *
404 : * Returns: 0 on success or -1 and ERRNO set on error. On success the
405 : * supplied variable is updated by the parsed flags.
406 : *
407 : * If STRING is NULL the enabled debug flags are printed.
408 : */
409 : int
410 0 : parse_debug_flag (const char *string, unsigned int *debugvar,
411 : const struct debug_flags_s *flags)
412 :
413 : {
414 0 : unsigned long result = 0;
415 : int i, j;
416 :
417 0 : if (!string)
418 : {
419 0 : if (debugvar)
420 : {
421 0 : log_info ("enabled debug flags:");
422 0 : for (i=0; flags[i].name; i++)
423 0 : if ((*debugvar & flags[i].flag))
424 0 : log_printf (" %s", flags[i].name);
425 0 : log_printf ("\n");
426 : }
427 0 : return 0;
428 : }
429 :
430 0 : while (spacep (string))
431 0 : string++;
432 0 : if (*string == '-')
433 : {
434 0 : errno = EINVAL;
435 0 : return -1;
436 : }
437 :
438 0 : if (!strcmp (string, "?") || !strcmp (string, "help"))
439 : {
440 0 : log_info ("available debug flags:\n");
441 0 : for (i=0; flags[i].name; i++)
442 0 : log_info (" %5u %s\n", flags[i].flag, flags[i].name);
443 0 : if (flags[i].flag != 77)
444 0 : exit (0);
445 : }
446 0 : else if (digitp (string))
447 : {
448 0 : errno = 0;
449 0 : result = strtoul (string, NULL, 0);
450 0 : if (result == ULONG_MAX && errno == ERANGE)
451 0 : return -1;
452 : }
453 : else
454 : {
455 : char **words;
456 0 : words = strtokenize (string, ",");
457 0 : if (!words)
458 0 : return -1;
459 0 : for (i=0; words[i]; i++)
460 : {
461 0 : if (*words[i])
462 : {
463 0 : for (j=0; flags[j].name; j++)
464 0 : if (!strcmp (words[i], flags[j].name))
465 : {
466 0 : result |= flags[j].flag;
467 0 : break;
468 : }
469 0 : if (!flags[j].name)
470 : {
471 0 : if (!strcmp (words[i], "none"))
472 : {
473 0 : *debugvar = 0;
474 0 : result = 0;
475 : }
476 0 : else if (!strcmp (words[i], "all"))
477 0 : result = ~0;
478 : else
479 0 : log_info (_("unknown debug flag '%s' ignored\n"), words[i]);
480 : }
481 : }
482 : }
483 0 : xfree (words);
484 : }
485 :
486 0 : *debugvar |= result;
487 0 : return 0;
488 : }
|