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