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