New protocol: PKCS#1 (rfc2313 pplus some extra oid's)
[obnox/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <errno.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #ifdef HAVE_SYS_STAT_H
41 #include <sys/stat.h>
42 #endif
43
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #ifdef NEED_MKSTEMP
49 #include "mkstemp.h"
50 #endif
51
52 #ifdef HAVE_IO_H
53 #include <io.h>
54 #ifndef __MINGW32__
55 typedef int mode_t;     /* for win32 */
56 #endif /* __MINGW32__ */
57 #endif /* HAVE_IO_H */
58
59 #include <epan/resolv.h>
60
61 /*
62  * This has to come after the include of <pcap.h>, as the include of
63  * <pcap.h> might cause <winsock2.h> to be included, and if we've
64  * already included <winsock.h> as a result of including <windows.h>,
65  * we get a bunch of redefinitions.
66  */
67 #ifdef HAVE_WINDOWS_H
68 #include <windows.h>
69 #endif
70
71 #include "util.h"
72
73 /*
74  * Collect command-line arguments as a string consisting of the arguments,
75  * separated by spaces.
76  */
77 char *
78 get_args_as_string(int argc, char **argv, int optind)
79 {
80         int len;
81         int i;
82         char *argstring;
83
84         /*
85          * Find out how long the string will be.
86          */
87         len = 0;
88         for (i = optind; i < argc; i++) {
89                 len += strlen(argv[i]);
90                 len++;  /* space, or '\0' if this is the last argument */
91         }
92
93         /*
94          * Allocate the buffer for the string.
95          */
96         argstring = g_malloc(len);
97
98         /*
99          * Now construct the string.
100          */
101         strcpy(argstring, "");
102         i = optind;
103         for (;;) {
104                 strcat(argstring, argv[i]);
105                 i++;
106                 if (i == argc)
107                         break;
108                 strcat(argstring, " ");
109         }
110         return argstring;
111 }
112
113 static char *
114 setup_tmpdir(char *dir)
115 {
116         int len = strlen(dir);
117         char *newdir;
118
119         /* Append path separator if necessary */
120         if (dir[len - 1] == G_DIR_SEPARATOR) {
121                 newdir = dir;
122         }
123         else {
124                 newdir = g_malloc(len + 2);
125                 strcpy(newdir, dir);
126                 strcat(newdir, G_DIR_SEPARATOR_S);
127         }
128         return newdir;
129 }
130
131 static int
132 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
133 {
134         static const char suffix[] = "XXXXXXXXXX";
135         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
136         mode_t old_umask;
137         int tmp_fd;
138
139         if (namebuflen < namelen) {
140                 /* Stick in a truncated name, so that if this error is
141                    reported with the file name, you at least get
142                    something. */
143                 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
144                 errno = ENAMETOOLONG;
145                 return -1;
146         }
147         strcpy(namebuf, dir);
148         strcat(namebuf, pfx);
149         strcat(namebuf, suffix);
150
151         /* The Single UNIX Specification doesn't say that "mkstemp()"
152            creates the temporary file with mode rw-------, so we
153            won't assume that all UNIXes will do so; instead, we set
154            the umask to 0077 to take away all group and other
155            permissions, attempt to create the file, and then put
156            the umask back. */
157         old_umask = umask(0077);
158         tmp_fd = mkstemp(namebuf);
159         umask(old_umask);
160         return tmp_fd;
161 }
162
163 static char *tmpdir = NULL;
164 #ifdef WIN32
165 static char *temp = NULL;
166 #endif
167 static char *E_tmpdir;
168
169 #ifndef P_tmpdir
170 #define P_tmpdir "/var/tmp"
171 #endif
172
173 int
174 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
175 {
176         char *dir;
177         int fd;
178         static gboolean initialized;
179
180         if (!initialized) {
181                 if ((dir = getenv("TMPDIR")) != NULL)
182                         tmpdir = setup_tmpdir(dir);
183 #ifdef WIN32
184                 if ((dir = getenv("TEMP")) != NULL)
185                         temp = setup_tmpdir(dir);
186 #endif
187
188                 E_tmpdir = setup_tmpdir(P_tmpdir);
189                 initialized = TRUE;
190         }
191
192         if (tmpdir != NULL) {
193                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
194                 if (fd != -1)
195                         return fd;
196         }
197
198 #ifdef WIN32
199         if (temp != NULL) {
200                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
201                 if (fd != -1)
202                         return fd;
203         }
204 #endif
205
206         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
207         if (fd != -1)
208                 return fd;
209
210         return try_tempfile(namebuf, namebuflen, G_DIR_SEPARATOR_S "tmp", pfx);
211 }
212
213 /* ASCII/EBCDIC conversion tables from
214  * http://www.room42.com/store/computer_center/code_tables.shtml
215  */
216 #if 0
217 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
218     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
219     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
220     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
221     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
222     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
223     0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
224     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
225     0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
226     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
227     0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
228     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
229     0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
230     0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
231     0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
232     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
233     0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
234     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
235     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
236     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
237     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
238     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
239     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
240     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
241     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
242     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
243     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
244     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
245     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
246     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
247     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
248     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
249     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
250 };
251
252 void
253 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
254 {
255         guint   i;
256         guint8  *bufptr;
257
258         bufptr = buf;
259
260         for (i = 0; i < bytes; i++, bufptr++) {
261                 *bufptr = ASCII_translate_EBCDIC[*bufptr];
262         }
263 }
264
265 guint8
266 ASCII_to_EBCDIC1(guint8 c)
267 {
268         return ASCII_translate_EBCDIC[c];
269 }
270 #endif
271
272 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
273     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
274     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
275     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
276     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
277     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
278     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
279     0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
280     0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
281     0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
282     0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
283     0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
284     0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
285     0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
286     0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
287     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
288     0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
289     0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
290     0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
291     0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
292     0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
293     0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
294     0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
295     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
296     0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
297     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
298     0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
299     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
300     0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
301     0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
302     0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
303     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
304     0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
305 };
306
307 void
308 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
309 {
310         guint   i;
311         guint8  *bufptr;
312
313         bufptr = buf;
314
315         for (i = 0; i < bytes; i++, bufptr++) {
316                 *bufptr = EBCDIC_translate_ASCII[*bufptr];
317         }
318 }
319
320 guint8
321 EBCDIC_to_ASCII1(guint8 c)
322 {
323         return EBCDIC_translate_ASCII[c];
324 }
325
326 /* Compute the difference between two seconds/microseconds time stamps. */
327 void
328 compute_timestamp_diff(gint *diffsec, gint *diffusec,
329         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
330 {
331   if (sec1 == sec2) {
332     /* The seconds part of the first time is the same as the seconds
333        part of the second time, so if the microseconds part of the first
334        time is less than the microseconds part of the second time, the
335        first time is before the second time.  The microseconds part of
336        the delta should just be the difference between the microseconds
337        part of the first time and the microseconds part of the second
338        time; don't adjust the seconds part of the delta, as it's OK if
339        the microseconds part is negative. */
340
341     *diffsec = sec1 - sec2;
342     *diffusec = usec1 - usec2;
343   } else if (sec1 <= sec2) {
344     /* The seconds part of the first time is less than the seconds part
345        of the second time, so the first time is before the second time.
346
347        Both the "seconds" and "microseconds" value of the delta
348        should have the same sign, so if the difference between the
349        microseconds values would be *positive*, subtract 1,000,000
350        from it, and add one to the seconds value. */
351     *diffsec = sec1 - sec2;
352     if (usec2 >= usec1) {
353       *diffusec = usec1 - usec2;
354     } else {
355       *diffusec = (usec1 - 1000000) - usec2;
356       (*diffsec)++;
357     }
358   } else {
359     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
360     *diffsec = sec1 - sec2;
361     if (usec2 <= usec1) {
362       *diffusec = usec1 - usec2;
363     } else {
364       *diffusec = (usec1 + 1000000) - usec2;
365       (*diffsec)--;
366     }
367   }
368 }
369
370 /* Decode a base64 string in-place - simple and slow algorithm.
371    Return length of result. Taken from rproxy/librsync/base64.c by
372    Andrew Tridgell. */
373
374 size_t epan_base64_decode(char *s)
375 {
376         static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
377         int bit_offset, byte_offset, idx, i, n;
378         unsigned char *d = (unsigned char *)s;
379         char *p;
380
381         n=i=0;
382
383         while (*s && (p=strchr(b64, *s))) {
384                 idx = (int)(p - b64);
385                 byte_offset = (i*6)/8;
386                 bit_offset = (i*6)%8;
387                 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
388                 if (bit_offset < 3) {
389                         d[byte_offset] |= (idx << (2-bit_offset));
390                         n = byte_offset+1;
391                 } else {
392                         d[byte_offset] |= (idx >> (bit_offset-2));
393                         d[byte_offset+1] = 0;
394                         d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
395                         n = byte_offset+2;
396                 }
397                 s++; i++;
398         }
399
400         return n;
401 }
402
403 /* Try to figure out if we're remotely connected, e.g. via ssh or
404    Terminal Server, and create a capture filter that matches aspects of the
405    connection.  We match the following environment variables:
406
407    SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
408    SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
409    REMOTEHOST (tcsh, others?): <remote name>
410    DISPLAY (x11): [remote name]:<display num>
411    CLIENTNAME (terminal server): <remote name>
412  */
413
414 gchar *get_conn_cfilter(void) {
415         static GString *filter_str = NULL;
416         gchar *env, **tokens;
417
418         if (filter_str == NULL) {
419                 filter_str = g_string_new("");
420         }
421         if ((env = getenv("SSH_CONNECTION")) != NULL) {
422                 tokens = g_strsplit(env, " ", 4);
423                 if (tokens[3]) {
424                         g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
425                                                          "and tcp port %s and %s host %s)", tokens[1], host_ip_af(tokens[0]), tokens[0],
426                                 tokens[3], host_ip_af(tokens[2]), tokens[2]);
427                         return filter_str->str;
428                 }
429         } else if ((env = getenv("SSH_CLIENT")) != NULL) {
430                 tokens = g_strsplit(env, " ", 3);
431                 g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
432                         "and tcp port %s)", tokens[1], host_ip_af(tokens[0]), tokens[0], tokens[2]);
433                 return filter_str->str;
434         } else if ((env = getenv("REMOTEHOST")) != NULL) {
435                 if (strcasecmp(env, "localhost") == 0 || strcmp(env, "127.0.0.1") == 0) {
436                         return "";
437                 }
438                 g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
439                 return filter_str->str;
440         } else if ((env = getenv("DISPLAY")) != NULL) {
441                 tokens = g_strsplit(env, ":", 2);
442                 if (tokens[0] && tokens[0][0] != 0) {
443                         if (strcasecmp(tokens[0], "localhost") == 0 ||
444                                         strcmp(tokens[0], "127.0.0.1") == 0) {
445                                 return "";
446                         }
447                         g_string_sprintf(filter_str, "not %s host %s",
448                                 host_ip_af(tokens[0]), tokens[0]);
449                         return filter_str->str;
450                 }
451         } else if ((env = getenv("CLIENTNAME")) != NULL) {
452                 if (g_strcasecmp("console", env) != 0) {
453                         g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
454                         return filter_str->str;
455                 }
456         }
457         return "";
458 }