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