xref: /freebsd/contrib/tcpdump/smbutil.c (revision 5b0fe478)
1b0453382SBill Fenner /*
2a90e161bSBill Fenner  * Copyright (C) Andrew Tridgell 1995-1999
3a90e161bSBill Fenner  *
4a90e161bSBill Fenner  * This software may be distributed either under the terms of the
5a90e161bSBill Fenner  * BSD-style license that accompanies tcpdump or the GNU GPL version 2
6a90e161bSBill Fenner  * or later
7a90e161bSBill Fenner  */
8b0453382SBill Fenner 
9b0453382SBill Fenner #ifdef HAVE_CONFIG_H
10b0453382SBill Fenner #include "config.h"
11b0453382SBill Fenner #endif
12b0453382SBill Fenner 
13b0453382SBill Fenner #ifndef lint
145b0fe478SBruce M Simpson static const char rcsid[] _U_ =
155b0fe478SBruce M Simpson      "@(#) $Header: /tcpdump/master/tcpdump/smbutil.c,v 1.26.2.2 2003/11/16 08:51:56 guy Exp $";
16b0453382SBill Fenner #endif
17b0453382SBill Fenner 
185b0fe478SBruce M Simpson #include <tcpdump-stdinc.h>
19b0453382SBill Fenner 
20b0453382SBill Fenner #include <stdio.h>
21b0453382SBill Fenner #include <stdlib.h>
22b0453382SBill Fenner #include <string.h>
23b0453382SBill Fenner 
24b0453382SBill Fenner #include "interface.h"
25a90e161bSBill Fenner #include "extract.h"
26b0453382SBill Fenner #include "smb.h"
27b0453382SBill Fenner 
28a90e161bSBill Fenner extern const u_char *startbuf;
29b0453382SBill Fenner 
30a90e161bSBill Fenner /*
31a90e161bSBill Fenner  * interpret a 32 bit dos packed date/time to some parameters
32a90e161bSBill Fenner  */
33a90e161bSBill Fenner static void
34a90e161bSBill Fenner interpret_dos_date(u_int32_t date, struct tm *tp)
35b0453382SBill Fenner {
36a90e161bSBill Fenner     u_int32_t p0, p1, p2, p3;
37b0453382SBill Fenner 
38a90e161bSBill Fenner     p0 = date & 0xFF;
39a90e161bSBill Fenner     p1 = ((date & 0xFF00) >> 8) & 0xFF;
40a90e161bSBill Fenner     p2 = ((date & 0xFF0000) >> 16) & 0xFF;
41a90e161bSBill Fenner     p3 = ((date & 0xFF000000) >> 24) & 0xFF;
42b0453382SBill Fenner 
43a90e161bSBill Fenner     tp->tm_sec = 2 * (p0 & 0x1F);
44a90e161bSBill Fenner     tp->tm_min = ((p0 >> 5) & 0xFF) + ((p1 & 0x7) << 3);
45a90e161bSBill Fenner     tp->tm_hour = (p1 >> 3) & 0xFF;
46a90e161bSBill Fenner     tp->tm_mday = (p2 & 0x1F);
47a90e161bSBill Fenner     tp->tm_mon = ((p2 >> 5) & 0xFF) + ((p3 & 0x1) << 3) - 1;
48a90e161bSBill Fenner     tp->tm_year = ((p3 >> 1) & 0xFF) + 80;
49b0453382SBill Fenner }
50b0453382SBill Fenner 
51a90e161bSBill Fenner /*
52a90e161bSBill Fenner  * common portion:
53a90e161bSBill Fenner  * create a unix date from a dos date
54a90e161bSBill Fenner  */
55a90e161bSBill Fenner static time_t
56a90e161bSBill Fenner int_unix_date(u_int32_t dos_date)
57b0453382SBill Fenner {
58b0453382SBill Fenner     struct tm t;
59b0453382SBill Fenner 
60a90e161bSBill Fenner     if (dos_date == 0)
61a90e161bSBill Fenner 	return(0);
62b0453382SBill Fenner 
63a90e161bSBill Fenner     interpret_dos_date(dos_date, &t);
64b0453382SBill Fenner     t.tm_wday = 1;
65b0453382SBill Fenner     t.tm_yday = 1;
66b0453382SBill Fenner     t.tm_isdst = 0;
67b0453382SBill Fenner 
68b0453382SBill Fenner     return (mktime(&t));
69b0453382SBill Fenner }
70b0453382SBill Fenner 
71a90e161bSBill Fenner /*
72a90e161bSBill Fenner  * create a unix date from a dos date
73a90e161bSBill Fenner  * in network byte order
74a90e161bSBill Fenner  */
75a90e161bSBill Fenner static time_t
76a90e161bSBill Fenner make_unix_date(const u_char *date_ptr)
77b0453382SBill Fenner {
78a90e161bSBill Fenner     u_int32_t dos_date = 0;
79b0453382SBill Fenner 
80a90e161bSBill Fenner     dos_date = EXTRACT_LE_32BITS(date_ptr);
81b0453382SBill Fenner 
82a90e161bSBill Fenner     return int_unix_date(dos_date);
83b0453382SBill Fenner }
84b0453382SBill Fenner 
85a90e161bSBill Fenner /*
86a90e161bSBill Fenner  * create a unix date from a dos date
87a90e161bSBill Fenner  * in halfword-swapped network byte order!
88a90e161bSBill Fenner  */
89a90e161bSBill Fenner static time_t
90a90e161bSBill Fenner make_unix_date2(const u_char *date_ptr)
91a90e161bSBill Fenner {
92a90e161bSBill Fenner     u_int32_t x, x2;
93a90e161bSBill Fenner 
94a90e161bSBill Fenner     x = EXTRACT_LE_32BITS(date_ptr);
95a90e161bSBill Fenner     x2 = ((x & 0xFFFF) << 16) | ((x & 0xFFFF0000) >> 16);
96a90e161bSBill Fenner     return int_unix_date(x2);
97a90e161bSBill Fenner }
98a90e161bSBill Fenner 
99a90e161bSBill Fenner /*
100a90e161bSBill Fenner  * interpret an 8 byte "filetime" structure to a time_t
101a90e161bSBill Fenner  * It's originally in "100ns units since jan 1st 1601"
102a90e161bSBill Fenner  */
103a90e161bSBill Fenner static time_t
104a90e161bSBill Fenner interpret_long_date(const u_char *p)
105b0453382SBill Fenner {
106b0453382SBill Fenner     double d;
107b0453382SBill Fenner     time_t ret;
108b0453382SBill Fenner 
109a90e161bSBill Fenner     TCHECK2(p[4], 4);
110a90e161bSBill Fenner 
111b0453382SBill Fenner     /* this gives us seconds since jan 1st 1601 (approx) */
112a90e161bSBill Fenner     d = (EXTRACT_LE_32BITS(p + 4) * 256.0 + p[3]) * (1.0e-7 * (1 << 24));
113b0453382SBill Fenner 
114b0453382SBill Fenner     /* now adjust by 369 years to make the secs since 1970 */
115b0453382SBill Fenner     d -= 369.0 * 365.25 * 24 * 60 * 60;
116b0453382SBill Fenner 
117b0453382SBill Fenner     /* and a fudge factor as we got it wrong by a few days */
118b0453382SBill Fenner     d += (3 * 24 * 60 * 60 + 6 * 60 * 60 + 2);
119b0453382SBill Fenner 
120b0453382SBill Fenner     if (d < 0)
121b0453382SBill Fenner 	return(0);
122b0453382SBill Fenner 
123b0453382SBill Fenner     ret = (time_t)d;
124b0453382SBill Fenner 
125b0453382SBill Fenner     return(ret);
126a90e161bSBill Fenner trunc:
127a90e161bSBill Fenner     return(0);
128b0453382SBill Fenner }
129b0453382SBill Fenner 
130a90e161bSBill Fenner /*
131a90e161bSBill Fenner  * interpret the weird netbios "name". Return the name type, or -1 if
132a90e161bSBill Fenner  * we run past the end of the buffer
133a90e161bSBill Fenner  */
134a90e161bSBill Fenner static int
135a90e161bSBill Fenner name_interpret(const u_char *in, const u_char *maxbuf, char *out)
136b0453382SBill Fenner {
137b0453382SBill Fenner     int ret;
138685295f4SBill Fenner     int len;
139685295f4SBill Fenner 
140685295f4SBill Fenner     if (in >= maxbuf)
141685295f4SBill Fenner 	return(-1);	/* name goes past the end of the buffer */
142685295f4SBill Fenner     TCHECK2(*in, 1);
143685295f4SBill Fenner     len = (*in++) / 2;
144b0453382SBill Fenner 
145b0453382SBill Fenner     *out=0;
146b0453382SBill Fenner 
147a90e161bSBill Fenner     if (len > 30 || len < 1)
148a90e161bSBill Fenner 	return(0);
149b0453382SBill Fenner 
150a90e161bSBill Fenner     while (len--) {
151a90e161bSBill Fenner 	TCHECK2(*in, 2);
152685295f4SBill Fenner 	if (in + 1 >= maxbuf)
153685295f4SBill Fenner 	    return(-1);	/* name goes past the end of the buffer */
154b0453382SBill Fenner 	if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
155b0453382SBill Fenner 	    *out = 0;
156b0453382SBill Fenner 	    return(0);
157b0453382SBill Fenner 	}
158b0453382SBill Fenner 	*out = ((in[0] - 'A') << 4) + (in[1] - 'A');
159b0453382SBill Fenner 	in += 2;
160b0453382SBill Fenner 	out++;
161b0453382SBill Fenner     }
162b0453382SBill Fenner     *out = 0;
163b0453382SBill Fenner     ret = out[-1];
164b0453382SBill Fenner 
165b0453382SBill Fenner     return(ret);
166685295f4SBill Fenner 
167685295f4SBill Fenner trunc:
168685295f4SBill Fenner     return(-1);
169b0453382SBill Fenner }
170b0453382SBill Fenner 
171a90e161bSBill Fenner /*
172a90e161bSBill Fenner  * find a pointer to a netbios name
173a90e161bSBill Fenner  */
174a90e161bSBill Fenner static const u_char *
175a90e161bSBill Fenner name_ptr(const u_char *buf, int ofs, const u_char *maxbuf)
176b0453382SBill Fenner {
177a90e161bSBill Fenner     const u_char *p;
178a90e161bSBill Fenner     u_char c;
179b0453382SBill Fenner 
180685295f4SBill Fenner     p = buf + ofs;
181685295f4SBill Fenner     if (p >= maxbuf)
182685295f4SBill Fenner 	return(NULL);	/* name goes past the end of the buffer */
183685295f4SBill Fenner     TCHECK2(*p, 1);
184685295f4SBill Fenner 
185685295f4SBill Fenner     c = *p;
186685295f4SBill Fenner 
187685295f4SBill Fenner     /* XXX - this should use the same code that the DNS dissector does */
188a90e161bSBill Fenner     if ((c & 0xC0) == 0xC0) {
189a90e161bSBill Fenner 	u_int16_t l = EXTRACT_16BITS(buf + ofs) & 0x3FFF;
190a90e161bSBill Fenner 	if (l == 0) {
191685295f4SBill Fenner 	    /* We have a pointer that points to itself. */
192685295f4SBill Fenner 	    return(NULL);
193685295f4SBill Fenner 	}
194685295f4SBill Fenner 	p = buf + l;
195685295f4SBill Fenner 	if (p >= maxbuf)
196685295f4SBill Fenner 	    return(NULL);	/* name goes past the end of the buffer */
197685295f4SBill Fenner 	TCHECK2(*p, 1);
198b0453382SBill Fenner 	return(buf + l);
199a90e161bSBill Fenner     } else
200b0453382SBill Fenner 	return(buf + ofs);
201685295f4SBill Fenner 
202685295f4SBill Fenner trunc:
203685295f4SBill Fenner     return(NULL);	/* name goes past the end of the buffer */
204b0453382SBill Fenner }
205b0453382SBill Fenner 
206a90e161bSBill Fenner /*
207a90e161bSBill Fenner  * extract a netbios name from a buf
208a90e161bSBill Fenner  */
209a90e161bSBill Fenner static int
210a90e161bSBill Fenner name_extract(const u_char *buf, int ofs, const u_char *maxbuf, char *name)
211b0453382SBill Fenner {
212a90e161bSBill Fenner     const u_char *p = name_ptr(buf, ofs, maxbuf);
213685295f4SBill Fenner     if (p == NULL)
214685295f4SBill Fenner 	return(-1);	/* error (probably name going past end of buffer) */
215a90e161bSBill Fenner     name[0] = '\0';
216685295f4SBill Fenner     return(name_interpret(p, maxbuf, name));
217b0453382SBill Fenner }
218b0453382SBill Fenner 
219b0453382SBill Fenner 
220a90e161bSBill Fenner /*
221a90e161bSBill Fenner  * return the total storage length of a mangled name
222a90e161bSBill Fenner  */
223a90e161bSBill Fenner static int
224a90e161bSBill Fenner name_len(const unsigned char *s, const unsigned char *maxbuf)
225b0453382SBill Fenner {
226685295f4SBill Fenner     const unsigned char *s0 = s;
227685295f4SBill Fenner     unsigned char c;
228685295f4SBill Fenner 
229685295f4SBill Fenner     if (s >= maxbuf)
230685295f4SBill Fenner 	return(-1);	/* name goes past the end of the buffer */
231685295f4SBill Fenner     TCHECK2(*s, 1);
232685295f4SBill Fenner     c = *s;
233b0453382SBill Fenner     if ((c & 0xC0) == 0xC0)
234b0453382SBill Fenner 	return(2);
235a90e161bSBill Fenner     while (*s) {
236685295f4SBill Fenner 	if (s >= maxbuf)
237685295f4SBill Fenner 	    return(-1);	/* name goes past the end of the buffer */
238685295f4SBill Fenner 	TCHECK2(*s, 1);
239685295f4SBill Fenner 	s += (*s) + 1;
240685295f4SBill Fenner     }
241b0453382SBill Fenner     return(PTR_DIFF(s, s0) + 1);
242685295f4SBill Fenner 
243685295f4SBill Fenner trunc:
244685295f4SBill Fenner     return(-1);	/* name goes past the end of the buffer */
245b0453382SBill Fenner }
246b0453382SBill Fenner 
247a90e161bSBill Fenner static void
248a90e161bSBill Fenner print_asc(const unsigned char *buf, int len)
249b0453382SBill Fenner {
250b0453382SBill Fenner     int i;
251b0453382SBill Fenner     for (i = 0; i < len; i++)
252a90e161bSBill Fenner 	safeputchar(buf[i]);
253b0453382SBill Fenner }
254b0453382SBill Fenner 
2555b0fe478SBruce M Simpson static const char *
256a90e161bSBill Fenner name_type_str(int name_type)
257b0453382SBill Fenner {
2585b0fe478SBruce M Simpson     const char *f = NULL;
259a90e161bSBill Fenner 
260b0453382SBill Fenner     switch (name_type) {
261b0453382SBill Fenner     case 0:    f = "Workstation"; break;
262b0453382SBill Fenner     case 0x03: f = "Client?"; break;
263b0453382SBill Fenner     case 0x20: f = "Server"; break;
264b0453382SBill Fenner     case 0x1d: f = "Master Browser"; break;
265b0453382SBill Fenner     case 0x1b: f = "Domain Controller"; break;
266b0453382SBill Fenner     case 0x1e: f = "Browser Server"; break;
267b0453382SBill Fenner     default:   f = "Unknown"; break;
268b0453382SBill Fenner     }
269b0453382SBill Fenner     return(f);
270b0453382SBill Fenner }
271b0453382SBill Fenner 
272a90e161bSBill Fenner void
273a90e161bSBill Fenner print_data(const unsigned char *buf, int len)
274b0453382SBill Fenner {
275b0453382SBill Fenner     int i = 0;
276a90e161bSBill Fenner 
277a90e161bSBill Fenner     if (len <= 0)
278a90e161bSBill Fenner 	return;
279b0453382SBill Fenner     printf("[%03X] ", i);
280a90e161bSBill Fenner     for (i = 0; i < len; /*nothing*/) {
281a90e161bSBill Fenner 	printf("%02X ", buf[i] & 0xff);
282b0453382SBill Fenner 	i++;
283a90e161bSBill Fenner 	if (i%8 == 0)
284a90e161bSBill Fenner 	    printf(" ");
285b0453382SBill Fenner 	if (i % 16 == 0) {
286a90e161bSBill Fenner 	    print_asc(&buf[i - 16], 8);
287a90e161bSBill Fenner 	    printf(" ");
288a90e161bSBill Fenner 	    print_asc(&buf[i - 8], 8);
289a90e161bSBill Fenner 	    printf("\n");
290a90e161bSBill Fenner 	    if (i < len)
291a90e161bSBill Fenner 		printf("[%03X] ", i);
292b0453382SBill Fenner 	}
293b0453382SBill Fenner     }
294b0453382SBill Fenner     if (i % 16) {
295b0453382SBill Fenner 	int n;
296b0453382SBill Fenner 
297b0453382SBill Fenner 	n = 16 - (i % 16);
298b0453382SBill Fenner 	printf(" ");
299a90e161bSBill Fenner 	if (n>8)
300a90e161bSBill Fenner 	    printf(" ");
301a90e161bSBill Fenner 	while (n--)
302a90e161bSBill Fenner 	    printf("   ");
303b0453382SBill Fenner 
304a90e161bSBill Fenner 	n = SMBMIN(8, i % 16);
305a90e161bSBill Fenner 	print_asc(&buf[i - (i % 16)], n);
306a90e161bSBill Fenner 	printf(" ");
307b0453382SBill Fenner 	n = (i % 16) - n;
308a90e161bSBill Fenner 	if (n > 0)
309a90e161bSBill Fenner 	    print_asc(&buf[i - n], n);
310b0453382SBill Fenner 	printf("\n");
311b0453382SBill Fenner     }
312b0453382SBill Fenner }
313b0453382SBill Fenner 
314b0453382SBill Fenner 
315a90e161bSBill Fenner static void
3165b0fe478SBruce M Simpson write_bits(unsigned int val, const char *fmt)
317b0453382SBill Fenner {
3185b0fe478SBruce M Simpson     const char *p = fmt;
319b0453382SBill Fenner     int i = 0;
320b0453382SBill Fenner 
321b0453382SBill Fenner     while ((p = strchr(fmt, '|'))) {
322a90e161bSBill Fenner 	size_t l = PTR_DIFF(p, fmt);
323b0453382SBill Fenner 	if (l && (val & (1 << i)))
324a90e161bSBill Fenner 	    printf("%.*s ", (int)l, fmt);
325b0453382SBill Fenner 	fmt = p + 1;
326b0453382SBill Fenner 	i++;
327b0453382SBill Fenner     }
328b0453382SBill Fenner }
329b0453382SBill Fenner 
330a90e161bSBill Fenner /* convert a UCS2 string into iso-8859-1 string */
331a90e161bSBill Fenner static const char *
3329afd0c29SBill Fenner unistr(const u_char *s, int *len)
333b0453382SBill Fenner {
334b0453382SBill Fenner     static char buf[1000];
335b0453382SBill Fenner     int l=0;
336b0453382SBill Fenner     static int use_unicode = -1;
337b0453382SBill Fenner 
338b0453382SBill Fenner     if (use_unicode == -1) {
339b0453382SBill Fenner 	char *p = getenv("USE_UNICODE");
340b0453382SBill Fenner 	if (p && (atoi(p) == 1))
341b0453382SBill Fenner 	    use_unicode = 1;
342b0453382SBill Fenner 	else
343b0453382SBill Fenner 	    use_unicode = 0;
344b0453382SBill Fenner     }
345b0453382SBill Fenner 
346b0453382SBill Fenner     /* maybe it isn't unicode - a cheap trick */
347b0453382SBill Fenner     if (!use_unicode || (s[0] && s[1])) {
3489afd0c29SBill Fenner 	*len = strlen((const char *)s) + 1;
3499afd0c29SBill Fenner 	return (const char *)s;
350b0453382SBill Fenner     }
351b0453382SBill Fenner 
352b0453382SBill Fenner     *len = 0;
353b0453382SBill Fenner 
354b0453382SBill Fenner     if (s[0] == 0 && s[1] != 0) {
355b0453382SBill Fenner 	s++;
356b0453382SBill Fenner 	*len = 1;
357b0453382SBill Fenner     }
358b0453382SBill Fenner 
3595b0fe478SBruce M Simpson     while (l < (int)(sizeof(buf) - 1) && s[0] && s[1] == 0) {
360b0453382SBill Fenner 	buf[l] = s[0];
361a90e161bSBill Fenner 	s += 2;
362a90e161bSBill Fenner 	l++;
363b0453382SBill Fenner 	*len += 2;
364b0453382SBill Fenner     }
365b0453382SBill Fenner     buf[l] = 0;
366b0453382SBill Fenner     *len += 2;
367b0453382SBill Fenner     return buf;
368b0453382SBill Fenner }
369b0453382SBill Fenner 
370a90e161bSBill Fenner static const u_char *
371a90e161bSBill Fenner smb_fdata1(const u_char *buf, const char *fmt, const u_char *maxbuf)
372b0453382SBill Fenner {
373b0453382SBill Fenner     int reverse = 0;
3745b0fe478SBruce M Simpson     const char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|";
375b0453382SBill Fenner     int len;
376b0453382SBill Fenner 
377b0453382SBill Fenner     while (*fmt && buf<maxbuf) {
378b0453382SBill Fenner 	switch (*fmt) {
379b0453382SBill Fenner 	case 'a':
380a90e161bSBill Fenner 	    write_bits(buf[0], attrib_fmt);
381a90e161bSBill Fenner 	    buf++;
382a90e161bSBill Fenner 	    fmt++;
383b0453382SBill Fenner 	    break;
384b0453382SBill Fenner 
385b0453382SBill Fenner 	case 'A':
386a90e161bSBill Fenner 	    write_bits(EXTRACT_LE_16BITS(buf), attrib_fmt);
387a90e161bSBill Fenner 	    buf += 2;
388a90e161bSBill Fenner 	    fmt++;
389b0453382SBill Fenner 	    break;
390b0453382SBill Fenner 
391b0453382SBill Fenner 	case '{':
392b0453382SBill Fenner 	  {
393b0453382SBill Fenner 	    char bitfmt[128];
3949afd0c29SBill Fenner 	    char *p;
3959afd0c29SBill Fenner 	    int l;
3969afd0c29SBill Fenner 
3979afd0c29SBill Fenner 	    p = strchr(++fmt, '}');
3989afd0c29SBill Fenner 	    l = PTR_DIFF(p, fmt);
3995b0fe478SBruce M Simpson 
4005b0fe478SBruce M Simpson 	    if ((unsigned int)l > sizeof(bitfmt) - 1)
4015b0fe478SBruce M Simpson 		    l = sizeof(bitfmt)-1;
4025b0fe478SBruce M Simpson 
403b0453382SBill Fenner 	    strncpy(bitfmt, fmt, l);
4045b0fe478SBruce M Simpson 	    bitfmt[l] = '\0';
405b0453382SBill Fenner 	    fmt = p + 1;
406a90e161bSBill Fenner 	    write_bits(buf[0], bitfmt);
407b0453382SBill Fenner 	    buf++;
408b0453382SBill Fenner 	    break;
409b0453382SBill Fenner 	  }
410b0453382SBill Fenner 
411b0453382SBill Fenner 	case 'P':
412b0453382SBill Fenner 	  {
413b0453382SBill Fenner 	    int l = atoi(fmt + 1);
414b0453382SBill Fenner 	    buf += l;
415b0453382SBill Fenner 	    fmt++;
4169afd0c29SBill Fenner 	    while (isdigit((unsigned char)*fmt))
417a90e161bSBill Fenner 		fmt++;
418b0453382SBill Fenner 	    break;
419b0453382SBill Fenner 	  }
420b0453382SBill Fenner 	case 'r':
421b0453382SBill Fenner 	    reverse = !reverse;
422b0453382SBill Fenner 	    fmt++;
423b0453382SBill Fenner 	    break;
424b0453382SBill Fenner 	case 'D':
425b0453382SBill Fenner 	  {
426a90e161bSBill Fenner 	    unsigned int x;
427a90e161bSBill Fenner 
428a90e161bSBill Fenner 	    TCHECK2(buf[0], 4);
429a90e161bSBill Fenner 	    x = reverse ? EXTRACT_32BITS(buf) : EXTRACT_LE_32BITS(buf);
430b0453382SBill Fenner 	    printf("%d (0x%x)", x, x);
431b0453382SBill Fenner 	    buf += 4;
432b0453382SBill Fenner 	    fmt++;
433b0453382SBill Fenner 	    break;
434b0453382SBill Fenner 	  }
435b0453382SBill Fenner 	case 'L':
436b0453382SBill Fenner 	  {
437a90e161bSBill Fenner 	    unsigned int x1, x2;
438a90e161bSBill Fenner 
439a90e161bSBill Fenner 	    TCHECK2(buf[4], 4);
440a90e161bSBill Fenner 	    x1 = reverse ? EXTRACT_32BITS(buf) :
441a90e161bSBill Fenner 			   EXTRACT_LE_32BITS(buf);
442a90e161bSBill Fenner 	    x2 = reverse ? EXTRACT_32BITS(buf + 4) :
443a90e161bSBill Fenner 			   EXTRACT_LE_32BITS(buf + 4);
444a90e161bSBill Fenner 	    if (x2)
445b0453382SBill Fenner 		printf("0x%08x:%08x", x2, x1);
446a90e161bSBill Fenner 	    else
447b0453382SBill Fenner 		printf("%d (0x%08x%08x)", x1, x2, x1);
448b0453382SBill Fenner 	    buf += 8;
449b0453382SBill Fenner 	    fmt++;
450b0453382SBill Fenner 	    break;
451b0453382SBill Fenner 	  }
452b0453382SBill Fenner 	case 'd':
453b0453382SBill Fenner 	  {
454a90e161bSBill Fenner 	    unsigned int x;
455a90e161bSBill Fenner 	    TCHECK2(buf[0], 2);
456a90e161bSBill Fenner 	    x = reverse ? EXTRACT_16BITS(buf) :
457a90e161bSBill Fenner 			  EXTRACT_LE_16BITS(buf);
458b0453382SBill Fenner 	    printf("%d (0x%x)", x, x);
459b0453382SBill Fenner 	    buf += 2;
460b0453382SBill Fenner 	    fmt++;
461b0453382SBill Fenner 	    break;
462b0453382SBill Fenner 	  }
463b0453382SBill Fenner 	case 'W':
464b0453382SBill Fenner 	  {
465a90e161bSBill Fenner 	    unsigned int x;
466a90e161bSBill Fenner 	    TCHECK2(buf[0], 4);
467a90e161bSBill Fenner 	    x = reverse ? EXTRACT_32BITS(buf) :
468a90e161bSBill Fenner 			  EXTRACT_LE_32BITS(buf);
469b0453382SBill Fenner 	    printf("0x%X", x);
470b0453382SBill Fenner 	    buf += 4;
471b0453382SBill Fenner 	    fmt++;
472b0453382SBill Fenner 	    break;
473b0453382SBill Fenner 	  }
474b0453382SBill Fenner 	case 'w':
475b0453382SBill Fenner 	  {
476a90e161bSBill Fenner 	    unsigned int x;
477a90e161bSBill Fenner 	    TCHECK2(buf[0], 2);
478a90e161bSBill Fenner 	    x = reverse ? EXTRACT_16BITS(buf) :
479a90e161bSBill Fenner 			  EXTRACT_LE_16BITS(buf);
480b0453382SBill Fenner 	    printf("0x%X", x);
481b0453382SBill Fenner 	    buf += 2;
482b0453382SBill Fenner 	    fmt++;
483b0453382SBill Fenner 	    break;
484b0453382SBill Fenner 	  }
485b0453382SBill Fenner 	case 'B':
486b0453382SBill Fenner 	  {
487a90e161bSBill Fenner 	    unsigned int x;
488a90e161bSBill Fenner 	    TCHECK(buf[0]);
489a90e161bSBill Fenner 	    x = buf[0];
490b0453382SBill Fenner 	    printf("0x%X", x);
491b0453382SBill Fenner 	    buf += 1;
492b0453382SBill Fenner 	    fmt++;
493b0453382SBill Fenner 	    break;
494b0453382SBill Fenner 	  }
495b0453382SBill Fenner 	case 'b':
496b0453382SBill Fenner 	  {
497a90e161bSBill Fenner 	    unsigned int x;
498a90e161bSBill Fenner 	    TCHECK(buf[0]);
499a90e161bSBill Fenner 	    x = buf[0];
500a90e161bSBill Fenner 	    printf("%u (0x%x)", x, x);
501b0453382SBill Fenner 	    buf += 1;
502b0453382SBill Fenner 	    fmt++;
503b0453382SBill Fenner 	    break;
504b0453382SBill Fenner 	  }
505b0453382SBill Fenner 	case 'S':
506b0453382SBill Fenner 	  {
507a90e161bSBill Fenner 	    /*XXX unistr() */
508b0453382SBill Fenner 	    printf("%.*s", (int)PTR_DIFF(maxbuf, buf), unistr(buf, &len));
509b0453382SBill Fenner 	    buf += len;
510b0453382SBill Fenner 	    fmt++;
511b0453382SBill Fenner 	    break;
512b0453382SBill Fenner 	  }
513b0453382SBill Fenner 	case 'Z':
514b0453382SBill Fenner 	  {
515b0453382SBill Fenner 	    if (*buf != 4 && *buf != 2)
516a90e161bSBill Fenner 		printf("Error! ASCIIZ buffer of type %u (safety=%lu)\n", *buf,
517a90e161bSBill Fenner 		    (unsigned long)PTR_DIFF(maxbuf, buf));
518a90e161bSBill Fenner 	    printf("%.*s", (int)PTR_DIFF(maxbuf, buf + 1),
519a90e161bSBill Fenner 		unistr(buf + 1, &len));
520b0453382SBill Fenner 	    buf += len + 1;
521b0453382SBill Fenner 	    fmt++;
522b0453382SBill Fenner 	    break;
523b0453382SBill Fenner 	  }
524b0453382SBill Fenner 	case 's':
525b0453382SBill Fenner 	  {
526b0453382SBill Fenner 	    int l = atoi(fmt + 1);
527b0453382SBill Fenner 	    printf("%-*.*s", l, l, buf);
528b0453382SBill Fenner 	    buf += l;
529a90e161bSBill Fenner 	    fmt++;
5309afd0c29SBill Fenner 	    while (isdigit((unsigned char)*fmt))
531a90e161bSBill Fenner 		fmt++;
532b0453382SBill Fenner 	    break;
533b0453382SBill Fenner 	  }
534b0453382SBill Fenner 	case 'h':
535b0453382SBill Fenner 	  {
536b0453382SBill Fenner 	    int l = atoi(fmt + 1);
537a90e161bSBill Fenner 	    while (l--)
538a90e161bSBill Fenner 		printf("%02x", *buf++);
539a90e161bSBill Fenner 	    fmt++;
5409afd0c29SBill Fenner 	    while (isdigit((unsigned char)*fmt))
541a90e161bSBill Fenner 		fmt++;
542b0453382SBill Fenner 	    break;
543b0453382SBill Fenner 	  }
544b0453382SBill Fenner 	case 'n':
545b0453382SBill Fenner 	  {
546b0453382SBill Fenner 	    int t = atoi(fmt+1);
547b0453382SBill Fenner 	    char nbuf[255];
548b0453382SBill Fenner 	    int name_type;
549685295f4SBill Fenner 	    int len;
550a90e161bSBill Fenner 
551b0453382SBill Fenner 	    switch (t) {
552b0453382SBill Fenner 	    case 1:
553a90e161bSBill Fenner 		name_type = name_extract(startbuf, PTR_DIFF(buf, startbuf),
554a90e161bSBill Fenner 		    maxbuf, nbuf);
555685295f4SBill Fenner 		if (name_type < 0)
556685295f4SBill Fenner 		    goto trunc;
557685295f4SBill Fenner 		len = name_len(buf, maxbuf);
558685295f4SBill Fenner 		if (len < 0)
559685295f4SBill Fenner 		    goto trunc;
560685295f4SBill Fenner 		buf += len;
561a90e161bSBill Fenner 		printf("%-15.15s NameType=0x%02X (%s)", nbuf, name_type,
562a90e161bSBill Fenner 		    name_type_str(name_type));
563b0453382SBill Fenner 		break;
564b0453382SBill Fenner 	    case 2:
565b0453382SBill Fenner 		name_type = buf[15];
566a90e161bSBill Fenner 		printf("%-15.15s NameType=0x%02X (%s)", buf, name_type,
567a90e161bSBill Fenner 		    name_type_str(name_type));
568b0453382SBill Fenner 		buf += 16;
569b0453382SBill Fenner 		break;
570b0453382SBill Fenner 	    }
571a90e161bSBill Fenner 	    fmt++;
5729afd0c29SBill Fenner 	    while (isdigit((unsigned char)*fmt))
573a90e161bSBill Fenner 		fmt++;
574b0453382SBill Fenner 	    break;
575b0453382SBill Fenner 	  }
576b0453382SBill Fenner 	case 'T':
577b0453382SBill Fenner 	  {
578b0453382SBill Fenner 	    time_t t;
5795b0fe478SBruce M Simpson 	    struct tm *lt;
5805b0fe478SBruce M Simpson 	    const char *tstring;
5815b0fe478SBruce M Simpson 	    u_int32_t x;
582a90e161bSBill Fenner 	    x = EXTRACT_LE_32BITS(buf);
583a90e161bSBill Fenner 
584b0453382SBill Fenner 	    switch (atoi(fmt + 1)) {
585b0453382SBill Fenner 	    case 1:
5865b0fe478SBruce M Simpson 		if (x == 0 || x == 0xFFFFFFFF)
587b0453382SBill Fenner 		    t = 0;
588b0453382SBill Fenner 		else
589b0453382SBill Fenner 		    t = make_unix_date(buf);
590b0453382SBill Fenner 		buf += 4;
591b0453382SBill Fenner 		break;
592b0453382SBill Fenner 	    case 2:
5935b0fe478SBruce M Simpson 		if (x == 0 || x == 0xFFFFFFFF)
594b0453382SBill Fenner 		    t = 0;
595b0453382SBill Fenner 		else
596b0453382SBill Fenner 		    t = make_unix_date2(buf);
597b0453382SBill Fenner 		buf += 4;
598b0453382SBill Fenner 		break;
599b0453382SBill Fenner 	    case 3:
600b0453382SBill Fenner 		t = interpret_long_date(buf);
601b0453382SBill Fenner 		buf += 8;
602b0453382SBill Fenner 		break;
603b0453382SBill Fenner 	    }
6045b0fe478SBruce M Simpson 	    if (t != 0) {
6055b0fe478SBruce M Simpson 		lt = localtime(&t);
6065b0fe478SBruce M Simpson 		if (lt != NULL)
6075b0fe478SBruce M Simpson 		    tstring = asctime(lt);
6085b0fe478SBruce M Simpson 		else
6095b0fe478SBruce M Simpson 		    tstring = "(Can't convert time)\n";
6105b0fe478SBruce M Simpson 	    } else
6115b0fe478SBruce M Simpson 		tstring = "NULL\n";
6125b0fe478SBruce M Simpson 	    printf("%s", tstring);
613a90e161bSBill Fenner 	    fmt++;
6149afd0c29SBill Fenner 	    while (isdigit((unsigned char)*fmt))
615a90e161bSBill Fenner 		fmt++;
616b0453382SBill Fenner 	    break;
617b0453382SBill Fenner 	  }
618b0453382SBill Fenner 	default:
619b0453382SBill Fenner 	    putchar(*fmt);
620b0453382SBill Fenner 	    fmt++;
621b0453382SBill Fenner 	    break;
622b0453382SBill Fenner 	}
623b0453382SBill Fenner     }
624b0453382SBill Fenner 
625b0453382SBill Fenner     if (buf >= maxbuf && *fmt)
626b0453382SBill Fenner 	printf("END OF BUFFER\n");
627b0453382SBill Fenner 
628b0453382SBill Fenner     return(buf);
629685295f4SBill Fenner 
630685295f4SBill Fenner trunc:
631685295f4SBill Fenner     printf("\n");
632685295f4SBill Fenner     printf("WARNING: Short packet. Try increasing the snap length\n");
633685295f4SBill Fenner     return(NULL);
634b0453382SBill Fenner }
635b0453382SBill Fenner 
636a90e161bSBill Fenner const u_char *
637a90e161bSBill Fenner smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf)
638b0453382SBill Fenner {
639b0453382SBill Fenner     static int depth = 0;
640b0453382SBill Fenner     char s[128];
641b0453382SBill Fenner     char *p;
642b0453382SBill Fenner 
643b0453382SBill Fenner     while (*fmt) {
644b0453382SBill Fenner 	switch (*fmt) {
645b0453382SBill Fenner 	case '*':
646b0453382SBill Fenner 	    fmt++;
647b0453382SBill Fenner 	    while (buf < maxbuf) {
648a90e161bSBill Fenner 		const u_char *buf2;
649b0453382SBill Fenner 		depth++;
650a90e161bSBill Fenner 		buf2 = smb_fdata(buf, fmt, maxbuf);
651b0453382SBill Fenner 		depth--;
652a90e161bSBill Fenner 		if (buf2 == NULL)
653a90e161bSBill Fenner 		    return(NULL);
654a90e161bSBill Fenner 		if (buf2 == buf)
655a90e161bSBill Fenner 		    return(buf);
656b0453382SBill Fenner 		buf = buf2;
657b0453382SBill Fenner 	    }
658a90e161bSBill Fenner 	    return(buf);
659b0453382SBill Fenner 
660b0453382SBill Fenner 	case '|':
661b0453382SBill Fenner 	    fmt++;
662a90e161bSBill Fenner 	    if (buf >= maxbuf)
663a90e161bSBill Fenner 		return(buf);
664b0453382SBill Fenner 	    break;
665b0453382SBill Fenner 
666b0453382SBill Fenner 	case '%':
667b0453382SBill Fenner 	    fmt++;
668b0453382SBill Fenner 	    buf = maxbuf;
669b0453382SBill Fenner 	    break;
670b0453382SBill Fenner 
671b0453382SBill Fenner 	case '#':
672b0453382SBill Fenner 	    fmt++;
673b0453382SBill Fenner 	    return(buf);
674b0453382SBill Fenner 	    break;
675b0453382SBill Fenner 
676b0453382SBill Fenner 	case '[':
677b0453382SBill Fenner 	    fmt++;
678a90e161bSBill Fenner 	    if (buf >= maxbuf)
679a90e161bSBill Fenner 		return(buf);
680685295f4SBill Fenner 	    memset(s, 0, sizeof(s));
681b0453382SBill Fenner 	    p = strchr(fmt, ']');
6825b0fe478SBruce M Simpson 	    if ((size_t)(p - fmt + 1) > sizeof(s)) {
683a90e161bSBill Fenner 		/* overrun */
684a90e161bSBill Fenner 		return(buf);
685a90e161bSBill Fenner 	    }
686b0453382SBill Fenner 	    strncpy(s, fmt, p - fmt);
687a90e161bSBill Fenner 	    s[p - fmt] = '\0';
688b0453382SBill Fenner 	    fmt = p + 1;
689a90e161bSBill Fenner 	    buf = smb_fdata1(buf, s, maxbuf);
690685295f4SBill Fenner 	    if (buf == NULL)
691685295f4SBill Fenner 		return(NULL);
692b0453382SBill Fenner 	    break;
693b0453382SBill Fenner 
694b0453382SBill Fenner 	default:
695a90e161bSBill Fenner 	    putchar(*fmt);
696a90e161bSBill Fenner 	    fmt++;
697b0453382SBill Fenner 	    fflush(stdout);
698b0453382SBill Fenner 	    break;
699b0453382SBill Fenner 	}
700b0453382SBill Fenner     }
701b0453382SBill Fenner     if (!depth && buf < maxbuf) {
702a90e161bSBill Fenner 	size_t len = PTR_DIFF(maxbuf, buf);
703a90e161bSBill Fenner 	printf("Data: (%lu bytes)\n", (unsigned long)len);
704b0453382SBill Fenner 	print_data(buf, len);
705b0453382SBill Fenner 	return(buf + len);
706b0453382SBill Fenner     }
707b0453382SBill Fenner     return(buf);
708b0453382SBill Fenner }
709b0453382SBill Fenner 
710a90e161bSBill Fenner typedef struct {
711a90e161bSBill Fenner     const char *name;
712b0453382SBill Fenner     int code;
713a90e161bSBill Fenner     const char *message;
714b0453382SBill Fenner } err_code_struct;
715b0453382SBill Fenner 
716b0453382SBill Fenner /* Dos Error Messages */
717b0453382SBill Fenner static err_code_struct dos_msgs[] = {
718b0453382SBill Fenner     { "ERRbadfunc", 1, "Invalid function." },
719b0453382SBill Fenner     { "ERRbadfile", 2, "File not found." },
720b0453382SBill Fenner     { "ERRbadpath", 3, "Directory invalid." },
721b0453382SBill Fenner     { "ERRnofids", 4, "No file descriptors available" },
722b0453382SBill Fenner     { "ERRnoaccess", 5, "Access denied." },
723b0453382SBill Fenner     { "ERRbadfid", 6, "Invalid file handle." },
724b0453382SBill Fenner     { "ERRbadmcb", 7, "Memory control blocks destroyed." },
725b0453382SBill Fenner     { "ERRnomem", 8, "Insufficient server memory to perform the requested function." },
726b0453382SBill Fenner     { "ERRbadmem", 9, "Invalid memory block address." },
727b0453382SBill Fenner     { "ERRbadenv", 10, "Invalid environment." },
728b0453382SBill Fenner     { "ERRbadformat", 11, "Invalid format." },
729b0453382SBill Fenner     { "ERRbadaccess", 12, "Invalid open mode." },
730b0453382SBill Fenner     { "ERRbaddata", 13, "Invalid data." },
731b0453382SBill Fenner     { "ERR", 14, "reserved." },
732b0453382SBill Fenner     { "ERRbaddrive", 15, "Invalid drive specified." },
733b0453382SBill Fenner     { "ERRremcd", 16, "A Delete Directory request attempted  to  remove  the  server's  current directory." },
734b0453382SBill Fenner     { "ERRdiffdevice", 17, "Not same device." },
735b0453382SBill Fenner     { "ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria." },
736b0453382SBill Fenner     { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing  FIDs  on the file." },
737b0453382SBill Fenner     { "ERRlock", 33, "A Lock request conflicted with an existing lock or specified an  invalid mode,   or an Unlock requested attempted to remove a lock held by another process." },
738b0453382SBill Fenner     { "ERRfilexists", 80, "The file named in a Create Directory,  Make  New  File  or  Link  request already exists." },
739b0453382SBill Fenner     { "ERRbadpipe", 230, "Pipe invalid." },
740b0453382SBill Fenner     { "ERRpipebusy", 231, "All instances of the requested pipe are busy." },
741b0453382SBill Fenner     { "ERRpipeclosing", 232, "Pipe close in progress." },
742b0453382SBill Fenner     { "ERRnotconnected", 233, "No process on other end of pipe." },
743b0453382SBill Fenner     { "ERRmoredata", 234, "There is more data to be returned." },
744a90e161bSBill Fenner     { NULL, -1, NULL }
745a90e161bSBill Fenner  };
746b0453382SBill Fenner 
747b0453382SBill Fenner /* Server Error Messages */
748b0453382SBill Fenner err_code_struct server_msgs[] = {
749b0453382SBill Fenner     { "ERRerror", 1, "Non-specific error code." },
750b0453382SBill Fenner     { "ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid." },
751b0453382SBill Fenner     { "ERRbadtype", 3, "reserved." },
752b0453382SBill Fenner     { "ERRaccess", 4, "The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID." },
753b0453382SBill Fenner     { "ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid." },
754b0453382SBill Fenner     { "ERRinvnetname", 6, "Invalid network name in tree connect." },
755b0453382SBill Fenner     { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection." },
756b0453382SBill Fenner     { "ERRqfull", 49, "Print queue full (files) -- returned by open print file." },
757b0453382SBill Fenner     { "ERRqtoobig", 50, "Print queue full -- no space." },
758b0453382SBill Fenner     { "ERRqeof", 51, "EOF on print queue dump." },
759b0453382SBill Fenner     { "ERRinvpfid", 52, "Invalid print file FID." },
760b0453382SBill Fenner     { "ERRsmbcmd", 64, "The server did not recognize the command received." },
761b0453382SBill Fenner     { "ERRsrverror", 65, "The server encountered an internal error,  e.g.,  system file unavailable." },
762b0453382SBill Fenner     { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid  combination of values." },
763b0453382SBill Fenner     { "ERRreserved", 68, "reserved." },
764b0453382SBill Fenner     { "ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute." },
765b0453382SBill Fenner     { "ERRreserved", 70, "reserved." },
766b0453382SBill Fenner     { "ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid." },
767b0453382SBill Fenner     { "ERRpaused", 81, "Server is paused." },
768b0453382SBill Fenner     { "ERRmsgoff", 82, "Not receiving messages." },
769b0453382SBill Fenner     { "ERRnoroom", 83, "No room to buffer message." },
770b0453382SBill Fenner     { "ERRrmuns", 87, "Too many remote user names." },
771b0453382SBill Fenner     { "ERRtimeout", 88, "Operation timed out." },
772b0453382SBill Fenner     { "ERRnoresource", 89, "No resources currently available for request." },
773b0453382SBill Fenner     { "ERRtoomanyuids", 90, "Too many UIDs active on this session." },
774b0453382SBill Fenner     { "ERRbaduid", 91, "The UID is not known as a valid ID on this session." },
775b0453382SBill Fenner     { "ERRusempx", 250, "Temp unable to support Raw,  use MPX mode." },
776b0453382SBill Fenner     { "ERRusestd", 251, "Temp unable to support Raw,  use standard read/write." },
777b0453382SBill Fenner     { "ERRcontmpx", 252, "Continue in MPX mode." },
778b0453382SBill Fenner     { "ERRreserved", 253, "reserved." },
779b0453382SBill Fenner     { "ERRreserved", 254, "reserved." },
780b0453382SBill Fenner     { "ERRnosupport", 0xFFFF, "Function not supported." },
781a90e161bSBill Fenner     { NULL, -1, NULL }
782a90e161bSBill Fenner };
783b0453382SBill Fenner 
784b0453382SBill Fenner /* Hard Error Messages */
785b0453382SBill Fenner err_code_struct hard_msgs[] = {
786b0453382SBill Fenner     { "ERRnowrite", 19, "Attempt to write on write-protected diskette." },
787b0453382SBill Fenner     { "ERRbadunit", 20, "Unknown unit." },
788b0453382SBill Fenner     { "ERRnotready", 21, "Drive not ready." },
789b0453382SBill Fenner     { "ERRbadcmd", 22, "Unknown command." },
790b0453382SBill Fenner     { "ERRdata", 23, "Data error (CRC)." },
791b0453382SBill Fenner     { "ERRbadreq", 24, "Bad request structure length." },
792b0453382SBill Fenner     { "ERRseek", 25 , "Seek error." },
793b0453382SBill Fenner     { "ERRbadmedia", 26, "Unknown media type." },
794b0453382SBill Fenner     { "ERRbadsector", 27, "Sector not found." },
795b0453382SBill Fenner     { "ERRnopaper", 28, "Printer out of paper." },
796b0453382SBill Fenner     { "ERRwrite", 29, "Write fault." },
797b0453382SBill Fenner     { "ERRread", 30, "Read fault." },
798b0453382SBill Fenner     { "ERRgeneral", 31, "General failure." },
799b0453382SBill Fenner     { "ERRbadshare", 32, "A open conflicts with an existing open." },
800b0453382SBill Fenner     { "ERRlock", 33, "A Lock request conflicted with an existing lock or specified an invalid mode,  or an Unlock requested attempted to remove a lock held by another process." },
801b0453382SBill Fenner     { "ERRwrongdisk", 34, "The wrong disk was found in a drive." },
802b0453382SBill Fenner     { "ERRFCBUnavail", 35, "No FCBs are available to process request." },
803b0453382SBill Fenner     { "ERRsharebufexc", 36, "A sharing buffer has been exceeded." },
804a90e161bSBill Fenner     { NULL, -1, NULL }
805a90e161bSBill Fenner };
806b0453382SBill Fenner 
807a90e161bSBill Fenner static struct {
808b0453382SBill Fenner     int code;
8095b0fe478SBruce M Simpson     const char *class;
810b0453382SBill Fenner     err_code_struct *err_msgs;
811b0453382SBill Fenner } err_classes[] = {
812b0453382SBill Fenner     { 0, "SUCCESS", NULL },
813b0453382SBill Fenner     { 0x01, "ERRDOS", dos_msgs },
814b0453382SBill Fenner     { 0x02, "ERRSRV", server_msgs },
815b0453382SBill Fenner     { 0x03, "ERRHRD", hard_msgs },
816b0453382SBill Fenner     { 0x04, "ERRXOS", NULL },
817b0453382SBill Fenner     { 0xE1, "ERRRMX1", NULL },
818b0453382SBill Fenner     { 0xE2, "ERRRMX2", NULL },
819b0453382SBill Fenner     { 0xE3, "ERRRMX3", NULL },
820b0453382SBill Fenner     { 0xFF, "ERRCMD", NULL },
821a90e161bSBill Fenner     { -1, NULL, NULL }
822a90e161bSBill Fenner };
823b0453382SBill Fenner 
824a90e161bSBill Fenner /*
825a90e161bSBill Fenner  * return a SMB error string from a SMB buffer
826a90e161bSBill Fenner  */
827a90e161bSBill Fenner char *
828a90e161bSBill Fenner smb_errstr(int class, int num)
829b0453382SBill Fenner {
830b0453382SBill Fenner     static char ret[128];
831b0453382SBill Fenner     int i, j;
832b0453382SBill Fenner 
833b0453382SBill Fenner     ret[0] = 0;
834b0453382SBill Fenner 
835b0453382SBill Fenner     for (i = 0; err_classes[i].class; i++)
836a90e161bSBill Fenner 	if (err_classes[i].code == class) {
837a90e161bSBill Fenner 	    if (err_classes[i].err_msgs) {
838b0453382SBill Fenner 		err_code_struct *err = err_classes[i].err_msgs;
839b0453382SBill Fenner 		for (j = 0; err[j].name; j++)
840a90e161bSBill Fenner 		    if (num == err[j].code) {
841a90e161bSBill Fenner 			snprintf(ret, sizeof(ret), "%s - %s (%s)",
842a90e161bSBill Fenner 			    err_classes[i].class, err[j].name, err[j].message);
843b0453382SBill Fenner 			return ret;
844b0453382SBill Fenner 		    }
845b0453382SBill Fenner 	    }
846b0453382SBill Fenner 
847685295f4SBill Fenner 	    snprintf(ret, sizeof(ret), "%s - %d", err_classes[i].class, num);
848b0453382SBill Fenner 	    return ret;
849b0453382SBill Fenner 	}
850b0453382SBill Fenner 
851685295f4SBill Fenner     snprintf(ret, sizeof(ret), "ERROR: Unknown error (%d,%d)", class, num);
852b0453382SBill Fenner     return(ret);
853b0453382SBill Fenner }
854