]> The Tcpdump Group git mirrors - tcpdump/blob - smbutil.c
Get rid of casts of pointers-to-const to pointers-to-nonconst.
[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.19 2002-04-20 09:42:58 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
37 extern const u_char *startbuf;
38
39 /*
40 * interpret a 32 bit dos packed date/time to some parameters
41 */
42 static void
43 interpret_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 */
64 static time_t
65 int_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 */
84 static time_t
85 make_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 */
98 static time_t
99 make_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 */
112 static time_t
113 interpret_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);
135 trunc:
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 */
143 static int
144 name_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
176 trunc:
177 return(-1);
178 }
179
180 /*
181 * find a pointer to a netbios name
182 */
183 static const u_char *
184 name_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
211 trunc:
212 return(NULL); /* name goes past the end of the buffer */
213 }
214
215 /*
216 * extract a netbios name from a buf
217 */
218 static int
219 name_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 */
232 static int
233 name_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
252 trunc:
253 return(-1); /* name goes past the end of the buffer */
254 }
255
256 static void
257 print_asc(const unsigned char *buf, int len)
258 {
259 int i;
260 for (i = 0; i < len; i++)
261 safeputchar(buf[i]);
262 }
263
264 static char *
265 name_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
281 void
282 print_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
324 static void
325 write_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 */
340 static const char *
341 unistr(const 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(s) + 1;
358 return 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
379 static const u_char *
380 smb_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 = strchr(++fmt, '}');
404 int l = PTR_DIFF(p, fmt);
405 strncpy(bitfmt, fmt, l);
406 bitfmt[l] = 0;
407 fmt = p + 1;
408 write_bits(buf[0], bitfmt);
409 buf++;
410 break;
411 }
412
413 case 'P':
414 {
415 int l = atoi(fmt + 1);
416 buf += l;
417 fmt++;
418 while (isdigit(*fmt))
419 fmt++;
420 break;
421 }
422 case 'r':
423 reverse = !reverse;
424 fmt++;
425 break;
426 case 'D':
427 {
428 unsigned int x;
429
430 TCHECK2(buf[0], 4);
431 x = reverse ? EXTRACT_32BITS(buf) : EXTRACT_LE_32BITS(buf);
432 printf("%d (0x%x)", x, x);
433 buf += 4;
434 fmt++;
435 break;
436 }
437 case 'L':
438 {
439 unsigned int x1, x2;
440
441 TCHECK2(buf[4], 4);
442 x1 = reverse ? EXTRACT_32BITS(buf) :
443 EXTRACT_LE_32BITS(buf);
444 x2 = reverse ? EXTRACT_32BITS(buf + 4) :
445 EXTRACT_LE_32BITS(buf + 4);
446 if (x2)
447 printf("0x%08x:%08x", x2, x1);
448 else
449 printf("%d (0x%08x%08x)", x1, x2, x1);
450 buf += 8;
451 fmt++;
452 break;
453 }
454 case 'd':
455 {
456 unsigned int x;
457 TCHECK2(buf[0], 2);
458 x = reverse ? EXTRACT_16BITS(buf) :
459 EXTRACT_LE_16BITS(buf);
460 printf("%d (0x%x)", x, x);
461 buf += 2;
462 fmt++;
463 break;
464 }
465 case 'W':
466 {
467 unsigned int x;
468 TCHECK2(buf[0], 4);
469 x = reverse ? EXTRACT_32BITS(buf) :
470 EXTRACT_LE_32BITS(buf);
471 printf("0x%X", x);
472 buf += 4;
473 fmt++;
474 break;
475 }
476 case 'w':
477 {
478 unsigned int x;
479 TCHECK2(buf[0], 2);
480 x = reverse ? EXTRACT_16BITS(buf) :
481 EXTRACT_LE_16BITS(buf);
482 printf("0x%X", x);
483 buf += 2;
484 fmt++;
485 break;
486 }
487 case 'B':
488 {
489 unsigned int x;
490 TCHECK(buf[0]);
491 x = buf[0];
492 printf("0x%X", x);
493 buf += 1;
494 fmt++;
495 break;
496 }
497 case 'b':
498 {
499 unsigned int x;
500 TCHECK(buf[0]);
501 x = buf[0];
502 printf("%u (0x%x)", x, x);
503 buf += 1;
504 fmt++;
505 break;
506 }
507 case 'S':
508 {
509 /*XXX unistr() */
510 printf("%.*s", (int)PTR_DIFF(maxbuf, buf), unistr(buf, &len));
511 buf += len;
512 fmt++;
513 break;
514 }
515 case 'Z':
516 {
517 if (*buf != 4 && *buf != 2)
518 printf("Error! ASCIIZ buffer of type %u (safety=%lu)\n", *buf,
519 (unsigned long)PTR_DIFF(maxbuf, buf));
520 printf("%.*s", (int)PTR_DIFF(maxbuf, buf + 1),
521 unistr(buf + 1, &len));
522 buf += len + 1;
523 fmt++;
524 break;
525 }
526 case 's':
527 {
528 int l = atoi(fmt + 1);
529 printf("%-*.*s", l, l, buf);
530 buf += l;
531 fmt++;
532 while (isdigit(*fmt))
533 fmt++;
534 break;
535 }
536 case 'h':
537 {
538 int l = atoi(fmt + 1);
539 while (l--)
540 printf("%02x", *buf++);
541 fmt++;
542 while (isdigit(*fmt))
543 fmt++;
544 break;
545 }
546 case 'n':
547 {
548 int t = atoi(fmt+1);
549 char nbuf[255];
550 int name_type;
551 int len;
552
553 switch (t) {
554 case 1:
555 name_type = name_extract(startbuf, PTR_DIFF(buf, startbuf),
556 maxbuf, nbuf);
557 if (name_type < 0)
558 goto trunc;
559 len = name_len(buf, maxbuf);
560 if (len < 0)
561 goto trunc;
562 buf += len;
563 printf("%-15.15s NameType=0x%02X (%s)", nbuf, name_type,
564 name_type_str(name_type));
565 break;
566 case 2:
567 name_type = buf[15];
568 printf("%-15.15s NameType=0x%02X (%s)", buf, name_type,
569 name_type_str(name_type));
570 buf += 16;
571 break;
572 }
573 fmt++;
574 while (isdigit(*fmt))
575 fmt++;
576 break;
577 }
578 case 'T':
579 {
580 time_t t;
581 int x;
582 x = EXTRACT_LE_32BITS(buf);
583
584 switch (atoi(fmt + 1)) {
585 case 1:
586 if (x == 0 || x == -1 || x == 0xFFFFFFFF)
587 t = 0;
588 else
589 t = make_unix_date(buf);
590 buf += 4;
591 break;
592 case 2:
593 if (x == 0 || x == -1 || x == 0xFFFFFFFF)
594 t = 0;
595 else
596 t = make_unix_date2(buf);
597 buf += 4;
598 break;
599 case 3:
600 t = interpret_long_date(buf);
601 buf += 8;
602 break;
603 }
604 printf("%s", t ? asctime(localtime(&t)) : "NULL\n");
605 fmt++;
606 while (isdigit(*fmt))
607 fmt++;
608 break;
609 }
610 default:
611 putchar(*fmt);
612 fmt++;
613 break;
614 }
615 }
616
617 if (buf >= maxbuf && *fmt)
618 printf("END OF BUFFER\n");
619
620 return(buf);
621
622 trunc:
623 printf("\n");
624 printf("WARNING: Short packet. Try increasing the snap length\n");
625 return(NULL);
626 }
627
628 const u_char *
629 smb_fdata(const u_char *buf, const char *fmt, const u_char *maxbuf)
630 {
631 static int depth = 0;
632 char s[128];
633 char *p;
634
635 while (*fmt) {
636 switch (*fmt) {
637 case '*':
638 fmt++;
639 while (buf < maxbuf) {
640 const u_char *buf2;
641 depth++;
642 buf2 = smb_fdata(buf, fmt, maxbuf);
643 depth--;
644 if (buf2 == NULL)
645 return(NULL);
646 if (buf2 == buf)
647 return(buf);
648 buf = buf2;
649 }
650 return(buf);
651
652 case '|':
653 fmt++;
654 if (buf >= maxbuf)
655 return(buf);
656 break;
657
658 case '%':
659 fmt++;
660 buf = maxbuf;
661 break;
662
663 case '#':
664 fmt++;
665 return(buf);
666 break;
667
668 case '[':
669 fmt++;
670 if (buf >= maxbuf)
671 return(buf);
672 memset(s, 0, sizeof(s));
673 p = strchr(fmt, ']');
674 if (p - fmt + 1 > sizeof(s)) {
675 /* overrun */
676 return(buf);
677 }
678 strncpy(s, fmt, p - fmt);
679 s[p - fmt] = '\0';
680 fmt = p + 1;
681 buf = smb_fdata1(buf, s, maxbuf);
682 if (buf == NULL)
683 return(NULL);
684 break;
685
686 default:
687 putchar(*fmt);
688 fmt++;
689 fflush(stdout);
690 break;
691 }
692 }
693 if (!depth && buf < maxbuf) {
694 size_t len = PTR_DIFF(maxbuf, buf);
695 printf("Data: (%lu bytes)\n", (unsigned long)len);
696 print_data(buf, len);
697 return(buf + len);
698 }
699 return(buf);
700 }
701
702 typedef struct {
703 const char *name;
704 int code;
705 const char *message;
706 } err_code_struct;
707
708 /* Dos Error Messages */
709 static err_code_struct dos_msgs[] = {
710 { "ERRbadfunc", 1, "Invalid function." },
711 { "ERRbadfile", 2, "File not found." },
712 { "ERRbadpath", 3, "Directory invalid." },
713 { "ERRnofids", 4, "No file descriptors available" },
714 { "ERRnoaccess", 5, "Access denied." },
715 { "ERRbadfid", 6, "Invalid file handle." },
716 { "ERRbadmcb", 7, "Memory control blocks destroyed." },
717 { "ERRnomem", 8, "Insufficient server memory to perform the requested function." },
718 { "ERRbadmem", 9, "Invalid memory block address." },
719 { "ERRbadenv", 10, "Invalid environment." },
720 { "ERRbadformat", 11, "Invalid format." },
721 { "ERRbadaccess", 12, "Invalid open mode." },
722 { "ERRbaddata", 13, "Invalid data." },
723 { "ERR", 14, "reserved." },
724 { "ERRbaddrive", 15, "Invalid drive specified." },
725 { "ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory." },
726 { "ERRdiffdevice", 17, "Not same device." },
727 { "ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria." },
728 { "ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file." },
729 { "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." },
730 { "ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists." },
731 { "ERRbadpipe", 230, "Pipe invalid." },
732 { "ERRpipebusy", 231, "All instances of the requested pipe are busy." },
733 { "ERRpipeclosing", 232, "Pipe close in progress." },
734 { "ERRnotconnected", 233, "No process on other end of pipe." },
735 { "ERRmoredata", 234, "There is more data to be returned." },
736 { NULL, -1, NULL }
737 };
738
739 /* Server Error Messages */
740 err_code_struct server_msgs[] = {
741 { "ERRerror", 1, "Non-specific error code." },
742 { "ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid." },
743 { "ERRbadtype", 3, "reserved." },
744 { "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." },
745 { "ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid." },
746 { "ERRinvnetname", 6, "Invalid network name in tree connect." },
747 { "ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection." },
748 { "ERRqfull", 49, "Print queue full (files) -- returned by open print file." },
749 { "ERRqtoobig", 50, "Print queue full -- no space." },
750 { "ERRqeof", 51, "EOF on print queue dump." },
751 { "ERRinvpfid", 52, "Invalid print file FID." },
752 { "ERRsmbcmd", 64, "The server did not recognize the command received." },
753 { "ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable." },
754 { "ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values." },
755 { "ERRreserved", 68, "reserved." },
756 { "ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute." },
757 { "ERRreserved", 70, "reserved." },
758 { "ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid." },
759 { "ERRpaused", 81, "Server is paused." },
760 { "ERRmsgoff", 82, "Not receiving messages." },
761 { "ERRnoroom", 83, "No room to buffer message." },
762 { "ERRrmuns", 87, "Too many remote user names." },
763 { "ERRtimeout", 88, "Operation timed out." },
764 { "ERRnoresource", 89, "No resources currently available for request." },
765 { "ERRtoomanyuids", 90, "Too many UIDs active on this session." },
766 { "ERRbaduid", 91, "The UID is not known as a valid ID on this session." },
767 { "ERRusempx", 250, "Temp unable to support Raw, use MPX mode." },
768 { "ERRusestd", 251, "Temp unable to support Raw, use standard read/write." },
769 { "ERRcontmpx", 252, "Continue in MPX mode." },
770 { "ERRreserved", 253, "reserved." },
771 { "ERRreserved", 254, "reserved." },
772 { "ERRnosupport", 0xFFFF, "Function not supported." },
773 { NULL, -1, NULL }
774 };
775
776 /* Hard Error Messages */
777 err_code_struct hard_msgs[] = {
778 { "ERRnowrite", 19, "Attempt to write on write-protected diskette." },
779 { "ERRbadunit", 20, "Unknown unit." },
780 { "ERRnotready", 21, "Drive not ready." },
781 { "ERRbadcmd", 22, "Unknown command." },
782 { "ERRdata", 23, "Data error (CRC)." },
783 { "ERRbadreq", 24, "Bad request structure length." },
784 { "ERRseek", 25 , "Seek error." },
785 { "ERRbadmedia", 26, "Unknown media type." },
786 { "ERRbadsector", 27, "Sector not found." },
787 { "ERRnopaper", 28, "Printer out of paper." },
788 { "ERRwrite", 29, "Write fault." },
789 { "ERRread", 30, "Read fault." },
790 { "ERRgeneral", 31, "General failure." },
791 { "ERRbadshare", 32, "A open conflicts with an existing open." },
792 { "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." },
793 { "ERRwrongdisk", 34, "The wrong disk was found in a drive." },
794 { "ERRFCBUnavail", 35, "No FCBs are available to process request." },
795 { "ERRsharebufexc", 36, "A sharing buffer has been exceeded." },
796 { NULL, -1, NULL }
797 };
798
799 static struct {
800 int code;
801 char *class;
802 err_code_struct *err_msgs;
803 } err_classes[] = {
804 { 0, "SUCCESS", NULL },
805 { 0x01, "ERRDOS", dos_msgs },
806 { 0x02, "ERRSRV", server_msgs },
807 { 0x03, "ERRHRD", hard_msgs },
808 { 0x04, "ERRXOS", NULL },
809 { 0xE1, "ERRRMX1", NULL },
810 { 0xE2, "ERRRMX2", NULL },
811 { 0xE3, "ERRRMX3", NULL },
812 { 0xFF, "ERRCMD", NULL },
813 { -1, NULL, NULL }
814 };
815
816 /*
817 * return a SMB error string from a SMB buffer
818 */
819 char *
820 smb_errstr(int class, int num)
821 {
822 static char ret[128];
823 int i, j;
824
825 ret[0] = 0;
826
827 for (i = 0; err_classes[i].class; i++)
828 if (err_classes[i].code == class) {
829 if (err_classes[i].err_msgs) {
830 err_code_struct *err = err_classes[i].err_msgs;
831 for (j = 0; err[j].name; j++)
832 if (num == err[j].code) {
833 snprintf(ret, sizeof(ret), "%s - %s (%s)",
834 err_classes[i].class, err[j].name, err[j].message);
835 return ret;
836 }
837 }
838
839 snprintf(ret, sizeof(ret), "%s - %d", err_classes[i].class, num);
840 return ret;
841 }
842
843 snprintf(ret, sizeof(ret), "ERROR: Unknown error (%d,%d)", class, num);
844 return(ret);
845 }