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