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