Re-implemented GPG's --passwd command and improved it.
[gnupg.git] / common / miscellaneous.c
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  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <errno.h>
23
24 #define JNLIB_NEED_LOG_LOGV
25 #include "util.h"
26 #include "iobuf.h"
27 #include "i18n.h"
28
29 /* Used by libgcrypt for logging.  */
30 static void
31 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
32 {
33   (void)dummy;
34   
35   /* Map the log levels.  */
36   switch (level)
37     {
38     case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
39     case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
40     case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
41     case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
42     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
43     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
44     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
45     default:            level = JNLIB_LOG_ERROR; break;  
46     }
47   log_logv (level, fmt, arg_ptr);
48 }
49
50
51 /* This function is called by libgcrypt on a fatal error.  */
52 static void
53 my_gcry_fatalerror_handler (void *opaque, int rc, const char *text)
54 {
55   (void)opaque;
56
57   log_fatal ("libgcrypt problem: %s\n", text ? text : gpg_strerror (rc));
58   abort ();
59 }
60
61
62 /* This function is called by libgcrypt if it ran out of core and
63    there is no way to return that error to the caller.  We do our own
64    function here to make use of our logging functions. */
65 static int
66 my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
67 {
68   static int been_here;  /* Used to protect against recursive calls. */
69
70   (void)opaque;
71
72   if (!been_here)
73     {
74       been_here = 1;
75       if ( (flags & 1) )
76         log_fatal (_("out of core in secure memory "
77                      "while allocating %lu bytes"), (unsigned long)req_n);
78       else
79         log_fatal (_("out of core while allocating %lu bytes"),
80                    (unsigned long)req_n);
81     }
82   return 0; /* Let libgcrypt call its own fatal error handler.
83                Actually this will turn out to be
84                my_gcry_fatalerror_handler. */
85 }
86
87
88 /* Setup libgcrypt to use our own logging functions.  Should be used
89    early at startup. */
90 void
91 setup_libgcrypt_logging (void)
92 {
93   gcry_set_log_handler (my_gcry_logger, NULL);
94   gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
95   gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
96 }
97
98
99 /* Decide whether the filename is stdout or a real filename and return
100  * an appropriate string.  */
101 const char *
102 print_fname_stdout (const char *s)
103 {
104     if( !s || (*s == '-' && !s[1]) )
105         return "[stdout]";
106     return s;
107 }
108
109
110 /* Decide whether the filename is stdin or a real filename and return
111  * an appropriate string.  */
112 const char *
113 print_fname_stdin (const char *s)
114 {
115     if( !s || (*s == '-' && !s[1]) )
116         return "[stdin]";
117     return s;
118 }
119
120
121 void
122 print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim)
123 {
124   char tmp[2];
125   
126   tmp[0] = delim;
127   tmp[1] = 0;
128   es_write_sanitized_utf8_buffer (stream, p, n, tmp, NULL);
129 }
130
131
132 void
133 print_utf8_buffer (estream_t stream, const void *p, size_t n)
134 {
135   es_write_sanitized_utf8_buffer (stream, p, n, NULL, NULL);
136 }
137
138 /* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
139    RESERVED must be 0. */
140 void
141 print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
142 {
143 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
144   const unsigned char *s;
145
146   (void)reserved;
147
148   for (s = buffer; length; s++, length--)
149     {
150       putc ( tohex ((*s>>4)&15), fp);
151       putc ( tohex (*s&15), fp);
152     }
153 #undef tohex
154 }
155
156 char *
157 make_printable_string (const void *p, size_t n, int delim )
158 {
159   return sanitize_buffer (p, n, delim);
160 }
161
162
163
164 /*
165  * Check if the file is compressed.
166  */
167 int
168 is_file_compressed (const char *s, int *ret_rc)
169 {
170     iobuf_t a;
171     byte buf[4];
172     int i, rc = 0;
173     int overflow;
174
175     struct magic_compress_s {
176         size_t len;
177         byte magic[4];
178     } magic[] = {
179         { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
180         { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
181         { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
182     };
183     
184     if ( iobuf_is_pipe_filename (s) || !ret_rc )
185         return 0; /* We can't check stdin or no file was given */
186
187     a = iobuf_open( s );
188     if ( a == NULL ) {
189         *ret_rc = gpg_error_from_syserror ();
190         return 0;
191     }
192
193     if ( iobuf_get_filelength( a, &overflow ) < 4 && !overflow) {
194         *ret_rc = 0;
195         goto leave;
196     }
197
198     if ( iobuf_read( a, buf, 4 ) == -1 ) {
199         *ret_rc = a->error;
200         goto leave;
201     }
202
203     for ( i = 0; i < DIM( magic ); i++ ) {
204         if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) {
205             *ret_rc = 0;
206             rc = 1;
207             break;
208         }
209     }
210
211 leave:    
212     iobuf_close( a );
213     return rc;
214 }
215
216
217 /* Try match against each substring of multistr, delimited by | */
218 int
219 match_multistr (const char *multistr,const char *match)
220 {
221   do
222     {
223       size_t seglen = strcspn (multistr,"|");
224       if (!seglen)
225         break;
226       /* Using the localized strncasecmp! */
227       if (strncasecmp(multistr,match,seglen)==0)
228         return 1;
229       multistr += seglen;
230       if (*multistr == '|')
231         multistr++;
232     }
233   while (*multistr);
234
235   return 0;
236 }
237
238
239 \f
240 /* Parse the first portion of the version number S and store it at
241    NUMBER.  On success, the function returns a pointer into S starting
242    with the first character, which is not part of the initial number
243    portion; on failure, NULL is returned.  */
244 static const char*
245 parse_version_number (const char *s, int *number)
246 {
247   int val = 0;
248   
249   if (*s == '0' && digitp (s+1))
250     return NULL; /* Leading zeros are not allowed.  */
251   for (; digitp (s); s++ )
252     {
253       val *= 10;
254       val += *s - '0';
255     }
256   *number = val;
257   return val < 0? NULL : s;
258 }
259
260 /* Break up the complete string representation of the version number S,
261    which is expected to have this format:
262
263       <major number>.<minor number>.<micro number><patch level>.
264
265    The major, minor and micro number components will be stored at
266    MAJOR, MINOR and MICRO. On success, a pointer to the last
267    component, the patch level, will be returned; on failure, NULL will
268    be returned.  */
269 static const char *
270 parse_version_string (const char *s, int *major, int *minor, int *micro)
271 {
272   s = parse_version_number (s, major);
273   if (!s || *s != '.')
274     return NULL;
275   s++;
276   s = parse_version_number (s, minor);
277   if (!s || *s != '.')
278     return NULL;
279   s++;
280   s = parse_version_number (s, micro);
281   if (!s)
282     return NULL;
283   return s; /* Patchlevel.  */
284 }
285
286 /* Return true if version string is at least version B. */
287 int
288 gnupg_compare_version (const char *a, const char *b)
289 {
290   int a_major, a_minor, a_micro;
291   int b_major, b_minor, b_micro;
292   const char *a_plvl, *b_plvl;
293
294   if (!a || !b)
295     return 0;
296
297   /* Parse version A.  */
298   a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
299   if (!a_plvl )
300     return 0; /* Invalid version number.  */
301
302   /* Parse version B.  */
303   b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
304   if (!b_plvl )
305     return 0; /* Invalid version number.  */
306
307   /* Compare version numbers.  */
308   return (a_major > b_major
309           || (a_major == b_major && a_minor > b_minor)
310           || (a_major == b_major && a_minor == b_minor
311               && a_micro > b_micro)
312           || (a_major == b_major && a_minor == b_minor
313               && a_micro == b_micro
314               && strcmp (a_plvl, b_plvl) >= 0));
315 }
316