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