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