nmblookup.c: Added -A ability to do status on ip address.
[kai/samba.git] / source3 / smbd / trans2.c
index 9b5419010e2d68a5a09089c4e8b07ff11df6feb0..a56df9cb9cc68f03a4ed6017eb289f8bf4a2c4fe 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    SMB transaction2 handling
-   Copyright (C) Jeremy Allison 1994
+   Copyright (C) Jeremy Allison 1994-1997
 
    Extensively modified by Andrew Tridgell, 1995
 
@@ -40,13 +40,13 @@ extern int Client;
 static int send_trans2_replies(char *outbuf, int bufsize, char *params, 
                         int paramsize, char *pdata, int datasize)
 {
-  /* As we are using a protocol > LANMAN1 then the maxxmit
+  /* As we are using a protocol > LANMAN1 then the max_send
      variable must have been set in the sessetupX call.
      This takes precedence over the max_xmit field in the
      global struct. These different max_xmit variables should
      be merged as this is now too confusing */
 
-  extern int maxxmit;
+  extern int max_send;
   int data_to_send = datasize;
   int params_to_send = paramsize;
   int useable_space;
@@ -68,15 +68,18 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
     }
 
   /* Space is bufsize minus Netbios over TCP header minus SMB header */
-  /* The + 1 is to align the param and data bytes on an even byte
+  /* The alignment_offset is to align the param and data bytes on an even byte
      boundary. NT 4.0 Beta needs this to work correctly. */
   useable_space = bufsize - ((smb_buf(outbuf)+alignment_offset) - outbuf);
-  useable_space = MIN(useable_space, maxxmit); /* XXX is this needed? correct? */
+  /* useable_space can never be more than max_send minus the
+     alignment offset. */
+  useable_space = MIN(useable_space, max_send - alignment_offset);
 
   while( params_to_send || data_to_send)
     {
       /* Calculate whether we will totally or partially fill this packet */
       total_sent_thistime = params_to_send + data_to_send + alignment_offset;
+      /* We can never send more than useable_space */
       total_sent_thistime = MIN(total_sent_thistime, useable_space);
 
       set_message(outbuf, 10, total_sent_thistime, True);
@@ -163,6 +166,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
   char *params = *pparams;
   int16 open_mode = SVAL(params, 2);
   int16 open_attr = SVAL(params,6);
+  BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
 #if 0
   BOOL return_additional_info = BITSETW(params,0);
   int16 open_sattr = SVAL(params, 4);
@@ -180,6 +184,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
   int32 inode = 0;
   struct stat sbuf;
   int smb_action = 0;
+  BOOL bad_path = False;
 
   StrnCpy(fname,pname,namelen);
 
@@ -188,25 +193,39 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
 
   /* XXXX we need to handle passed times, sattr and flags */
 
-  unix_convert(fname,cnum);
+  unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   unixmode = unix_mode(cnum,open_attr | aARCH);
       
       
   open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
-                  &rmode,&smb_action);
+                  oplock_request, &rmode,&smb_action);
       
   if (!Files[fnum].open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
-  if (fstat(Files[fnum].fd,&sbuf) != 0) {
+  if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
@@ -232,6 +251,10 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
   SIVAL(params,8, size);
   SSVAL(params,12,rmode);
 
+  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
+  }
+
   SSVAL(params,18,smb_action);
   SIVAL(params,20,inode);
  
@@ -268,6 +291,8 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
                    strequal(Connections[cnum].dirpath,".") ||
                    strequal(Connections[cnum].dirpath,"/"));
   BOOL was_8_3;
+  int nt_extmode; /* Used for NT connections instead of mode */
+  BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
 
   *fname = 0;
   *out_of_space = False;
@@ -281,10 +306,10 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
       if(p[1] == '\0')
        strcpy(mask,"*.*");
       else
-       strcpy(mask, p+1);
+       pstrcpy(mask, p+1);
     }
   else
-    strcpy(mask, path_mask);
+    pstrcpy(mask, path_mask);
 
   while (!found)
     {
@@ -294,7 +319,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
 
       reskey = TellDir(Connections[cnum].dirptr);
 
-      DEBUG(6,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
+      DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
               Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
       
       if (!dname) 
@@ -302,7 +327,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
 
       matched = False;
 
-      strcpy(fname,dname);      
+      pstrcpy(fname,dname);      
 
       if(mask_match(fname, mask, case_sensitive, True))
        {
@@ -313,9 +338,10 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
          if (isrootdir && isdots)
            continue;
 
-         strcpy(pathreal,Connections[cnum].dirpath);
-         strcat(pathreal,"/");
-         strcat(pathreal,fname);
+         pstrcpy(pathreal,Connections[cnum].dirpath);
+          if(needslash)
+           strcat(pathreal,"/");
+         strcat(pathreal,dname);
          if (sys_stat(pathreal,&sbuf) != 0) 
            {
              DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
@@ -342,15 +368,12 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
        }
     }
 
-
-#ifndef KANJI
-  unix2dos_format(fname, True);
-#endif
+  name_map_mangle(fname,False,SNUM(cnum));
 
   p = pdata;
   nameptr = p;
 
-  name_map_mangle(fname,False,SNUM(cnum));
+  nt_extmode = mode ? mode : NT_FILE_ATTRIBUTE_NORMAL;
 
   switch (info_level)
     {
@@ -424,7 +447,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
       break;
 
     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
-      was_8_3 = is_8_3(fname);
+      was_8_3 = is_8_3(fname, True);
       len = 94+strlen(fname);
       len = (len + 3) & ~3;
       SIVAL(p,0,len); p += 4;
@@ -435,15 +458,11 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
       put_long_date(p,mdate); p += 8;
       SIVAL(p,0,size); p += 8;
       SIVAL(p,0,size); p += 8;
-      SIVAL(p,0,mode); p += 4;
+      SIVAL(p,0,nt_extmode); p += 4;
       SIVAL(p,0,strlen(fname)); p += 4;
       SIVAL(p,0,0); p += 4;
       if (!was_8_3) {
-#ifndef KANJI
-       strcpy(p+2,unix2dos_format(fname,False));
-#else 
        strcpy(p+2,fname);
-#endif
        if (!name_map_mangle(p+2,True,SNUM(cnum)))
          (p+2)[12] = 0;
       } else
@@ -467,7 +486,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
       put_long_date(p,mdate); p += 8;
       SIVAL(p,0,size); p += 8;
       SIVAL(p,0,size); p += 8;
-      SIVAL(p,0,mode); p += 4;
+      SIVAL(p,0,nt_extmode); p += 4;
       SIVAL(p,0,strlen(fname)); p += 4;
       strcpy(p,fname);
       p = pdata + len;
@@ -485,7 +504,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
       put_long_date(p,mdate); p += 8;
       SIVAL(p,0,size); p += 8;
       SIVAL(p,0,size); p += 8;
-      SIVAL(p,0,mode); p += 4;
+      SIVAL(p,0,nt_extmode); p += 4;
       SIVAL(p,0,strlen(fname)); p += 4;
       SIVAL(p,0,0); p += 4;
       strcpy(p,fname);
@@ -553,6 +572,7 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
   BOOL dont_descend = False;
   BOOL out_of_space = False;
   int space_remaining;
+  BOOL bad_path = False;
 
   *directory = *mask = 0;
 
@@ -575,13 +595,29 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
       return(ERROR(ERRDOS,ERRunknownlevel));
     }
 
-  strcpy(directory, params + 12); /* Complete directory path with 
+  pstrcpy(directory, params + 12); /* Complete directory path with 
                                     wildcard mask appended */
 
   DEBUG(5,("path=%s\n",directory));
 
-  unix_convert(directory,cnum);
+  unix_convert(directory,cnum,0,&bad_path);
   if(!check_name(directory,cnum)) {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+
+#if 0
+    /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+    if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
+       (get_remote_arch() == RA_WINNT))
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbaddirectory;
+    }
+#endif 
+
     return(ERROR(ERRDOS,ERRbadpath));
   }
 
@@ -608,7 +644,29 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
 
   dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
   if (dptr_num < 0)
-    return(ERROR(ERRDOS,ERRbadpath));
+    {
+      if(dptr_num == -2)
+      {
+        if((errno == ENOENT) && bad_path)
+        {
+          unix_ERR_class = ERRDOS;
+          unix_ERR_code = ERRbadpath;
+        }
+
+#if 0
+        /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+        if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
+           (get_remote_arch() == RA_WINNT))
+        {
+          unix_ERR_class = ERRDOS;
+          unix_ERR_code = ERRbaddirectory;
+        }
+#endif
+
+        return (UNIXERROR(ERRDOS,ERRbadpath));
+      }
+      return(ERROR(ERRDOS,ERRbadpath));
+    }
 
   /* convert the formatted masks */
   {
@@ -912,7 +970,7 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
       put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
       SCVAL(pdata,l2_vol_cch,volname_len);
       StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
-      DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime,volname_len,
+      DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len,
               pdata+l2_vol_szVolLabel));
       break;
     }
@@ -929,9 +987,11 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
       strcpy(pdata+4,vname);      
       break;
     case SMB_QUERY_FS_VOLUME_INFO:      
-      data_len = 17 + strlen(vname);
-      SIVAL(pdata,12,strlen(vname));
-      strcpy(pdata+17,vname);      
+      data_len = 18 + 2*strlen(vname);
+      SIVAL(pdata,12,2*strlen(vname));
+      PutUniCode(pdata+18,vname);      
+      DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname),
+              vname));
       break;
     case SMB_QUERY_FS_SIZE_INFO:
       {
@@ -1000,7 +1060,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
   char *fname;
   char *p;
   int l,pos;
-
+  BOOL bad_path = False;
 
   if (tran_call == TRANSACT2_QFILEINFO) {
     int16 fnum = SVALS(params,0);
@@ -1010,19 +1070,24 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
     CHECK_ERROR(fnum);
 
     fname = Files[fnum].name;
-    if (fstat(Files[fnum].fd,&sbuf) != 0) {
+    if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
       DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
       return(UNIXERROR(ERRDOS,ERRbadfid));
     }
-    pos = lseek(Files[fnum].fd,0,SEEK_CUR);
+    pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR);
   } else {
     /* qpathinfo */
     info_level = SVAL(params,0);
     fname = &fname1[0];
-    strcpy(fname,&params[6]);
-    unix_convert(fname,cnum);
+    pstrcpy(fname,&params[6]);
+    unix_convert(fname,cnum,0,&bad_path);
     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,ERRbadpath));
     }
     pos = 0;
@@ -1049,34 +1114,28 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
   if (total_data > 0 && IVAL(pdata,0) == total_data) {
     /* uggh, EAs for OS2 */
     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
-#if 0
-    SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
-    send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
-    return(-1);
-#else
     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
-#endif
   }
 
   bzero(pdata,data_size);
 
   switch (info_level) 
     {
-    case 1:
-    case 2:
+    case SMB_INFO_STANDARD:
+    case SMB_INFO_QUERY_EA_SIZE:
       data_size = (info_level==1?22:26);
-      put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime);
-      put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
-      put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime);
+      put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
+      put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
+      put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
       SIVAL(pdata,l1_cbFile,size);
       SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
       SSVAL(pdata,l1_attrFile,mode);
       SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
       break;
 
-    case 3:
+    case SMB_INFO_QUERY_EAS_FROM_LIST:
       data_size = 24;
-      put_dos_date2(pdata,0,sbuf.st_ctime);
+      put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
       put_dos_date2(pdata,4,sbuf.st_atime);
       put_dos_date2(pdata,8,sbuf.st_mtime);
       SIVAL(pdata,12,size);
@@ -1084,7 +1143,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
       SIVAL(pdata,20,mode);
       break;
 
-    case 4:
+    case SMB_INFO_QUERY_ALL_EAS:
       data_size = 4;
       SIVAL(pdata,0,data_size);
       break;
@@ -1093,12 +1152,20 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
       return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */      
 
     case SMB_QUERY_FILE_BASIC_INFO:
-      data_size = 36;
-      put_long_date(pdata,sbuf.st_ctime);
-      put_long_date(pdata+8,sbuf.st_atime);
-      put_long_date(pdata+16,sbuf.st_mtime);
-      put_long_date(pdata+24,sbuf.st_mtime);
+      data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
+      put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
+      put_long_date(pdata+8,sbuf.st_atime); /* access time */
+      put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+      put_long_date(pdata+24,sbuf.st_mtime); /* change time */
       SIVAL(pdata,32,mode);
+
+      DEBUG(5,("SMB_QFBI - "));
+      DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
+      DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
+      DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
+      DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
+      DEBUG(5,("mode: %x\n", mode));
+
       break;
 
     case SMB_QUERY_FILE_STANDARD_INFO:
@@ -1114,12 +1181,32 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
       data_size = 4;
       break;
 
-    case SMB_QUERY_FILE_NAME_INFO:
+    /* Get the 8.3 name - used if NT SMB was negotiated. */
     case SMB_QUERY_FILE_ALT_NAME_INFO:
+      {
+        pstring short_name;
+        pstrcpy(short_name,fname);
+        /* Mangle if not already 8.3 */
+        if(!is_8_3(short_name, True))
+        {
+          if(!name_map_mangle(short_name,True,SNUM(cnum)))
+            *short_name = '\0';
+        }
+        strncpy(pdata + 4,short_name,12);
+        (pdata + 4)[12] = 0;
+        strupper(pdata + 4);
+        l = strlen(pdata + 4);
+        data_size = 4 + l;
+        SIVAL(pdata,0,l);
+      }
+      break;
+
+    case SMB_QUERY_FILE_NAME_INFO:
       data_size = 4 + l;
       SIVAL(pdata,0,l);
-      strcpy(pdata+4,fname);
+      pstrcpy(pdata+4,fname);
       break;
+
     case SMB_QUERY_FILE_ALLOCATION_INFO:
     case SMB_QUERY_FILE_END_OF_FILEINFO:
       data_size = 8;
@@ -1127,10 +1214,10 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
       break;
 
     case SMB_QUERY_FILE_ALL_INFO:
-      put_long_date(pdata,sbuf.st_ctime);
-      put_long_date(pdata+8,sbuf.st_atime);
-      put_long_date(pdata+16,sbuf.st_mtime);
-      put_long_date(pdata+24,sbuf.st_mtime);
+      put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
+      put_long_date(pdata+8,sbuf.st_atime); /* access time */
+      put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+      put_long_date(pdata+24,sbuf.st_mtime); /* change time */
       SIVAL(pdata,32,mode);
       pdata += 40;
       SIVAL(pdata,0,size);
@@ -1152,7 +1239,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
       pdata += 4;
       pdata += 4; /* alignment */
       SIVAL(pdata,0,l);
-      strcpy(pdata+4,fname);
+      pstrcpy(pdata+4,fname);
       pdata += 4 + l;
       data_size = PTR_DIFF(pdata,(*ppdata));
       break;
@@ -1163,7 +1250,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
       SIVAL(pdata,4,size);
       SIVAL(pdata,12,size);
       SIVAL(pdata,20,l);       
-      strcpy(pdata+24,fname);
+      pstrcpy(pdata+24,fname);
       break;
     default:
       return(ERROR(ERRDOS,ERRunknownlevel));
@@ -1192,6 +1279,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
   pstring fname1;
   char *fname;
   int fd = -1;
+  BOOL bad_path = False;
 
   if (!CAN_WRITE(cnum))
     return(ERROR(ERRSRV,ERRaccess));
@@ -1204,7 +1292,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
     CHECK_ERROR(fnum);
 
     fname = Files[fnum].name;
-    fd = Files[fnum].fd;
+    fd = Files[fnum].fd_ptr->fd;
 
     if(fstat(fd,&st)!=0) {
       DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
@@ -1214,14 +1302,26 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
     /* set path info */
     info_level = SVAL(params,0);    
     fname = fname1;
-    strcpy(fname,&params[6]);
-    unix_convert(fname,cnum);
+    pstrcpy(fname,&params[6]);
+    unix_convert(fname,cnum,0,&bad_path);
     if(!check_name(fname, cnum))
-      return(ERROR(ERRDOS,ERRbadpath));
-    
+    {
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
+      return(UNIXERROR(ERRDOS,ERRbadpath));
+    }
     if(sys_stat(fname,&st)!=0) {
       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
-      return(ERROR(ERRDOS,ERRbadpath));
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
+      return(UNIXERROR(ERRDOS,ERRbadpath));
     }    
   }
 
@@ -1241,37 +1341,37 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
   if (total_data > 0 && IVAL(pdata,0) == total_data) {
     /* uggh, EAs for OS2 */
     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
-    SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
-
-    send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
-  
-    return(-1);    
+    return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
   }
 
   switch (info_level)
+  {
+    case SMB_INFO_STANDARD:
+    case SMB_INFO_QUERY_EA_SIZE:
     {
-    case 1:
+      /* access time */
       tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
-      tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
-      mode = SVAL(pdata,l1_attrFile);
-      size = IVAL(pdata,l1_cbFile);
-      break;
 
-    case 2:
-      tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
+      /* write time */
       tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
+
       mode = SVAL(pdata,l1_attrFile);
       size = IVAL(pdata,l1_cbFile);
       break;
+    }
 
-    case 3:
+    /* XXXX um, i don't think this is right.
+       it's also not in the cifs6.txt spec.
+     */
+    case SMB_INFO_QUERY_EAS_FROM_LIST:
       tvs.actime = make_unix_date2(pdata+8);
       tvs.modtime = make_unix_date2(pdata+12);
       size = IVAL(pdata,16);
       mode = IVAL(pdata,24);
       break;
 
-    case 4:
+    /* XXXX nor this.  not in cifs6.txt, either. */
+    case SMB_INFO_QUERY_ALL_EAS:
       tvs.actime = make_unix_date2(pdata+8);
       tvs.modtime = make_unix_date2(pdata+12);
       size = IVAL(pdata,16);
@@ -1279,48 +1379,87 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
       break;
 
     case SMB_SET_FILE_BASIC_INFO:
-      pdata += 8;              /* create time */
-      tvs.actime = interpret_long_date(pdata); pdata += 8;
-      tvs.modtime=MAX(interpret_long_date(pdata),interpret_long_date(pdata+8));
-      pdata += 16;
-      mode = IVAL(pdata,0);
+    {
+      /* Ignore create time at offset pdata. */
+
+      /* access time */
+      tvs.actime = interpret_long_date(pdata+8);
+
+      /* write time + changed time, combined. */
+      tvs.modtime=MAX(interpret_long_date(pdata+16),
+                      interpret_long_date(pdata+24));
+
+#if 0 /* Needs more testing... */
+      /* Test from Luke to prevent Win95 from
+         setting incorrect values here.
+       */
+      if (tvs.actime < tvs.modtime)
+        return(ERROR(ERRDOS,ERRnoaccess));
+#endif /* Needs more testing... */
+
+      /* attributes */
+      mode = IVAL(pdata,32);
       break;
+    }
 
     case SMB_SET_FILE_END_OF_FILE_INFO:
+    {
       if (IVAL(pdata,4) != 0)  /* more than 32 bits? */
-       return(ERROR(ERRDOS,ERRunknownlevel));
+         return(ERROR(ERRDOS,ERRunknownlevel));
       size = IVAL(pdata,0);
       break;
+    }
 
     case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
     case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
     default:
+    {
       return(ERROR(ERRDOS,ERRunknownlevel));
     }
+  }
 
+  DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
+  DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
+  DEBUG(6,("size: %x "   , size));
+  DEBUG(6,("mode: %x\n"  , mode));
 
+  /* get some defaults (no modifications) if any info is zero. */
   if (!tvs.actime) tvs.actime = st.st_atime;
   if (!tvs.modtime) tvs.modtime = st.st_mtime;
   if (!size) size = st.st_size;
 
-  /* Try and set the times, size and mode of this file - if they are different 
-   from the current values */
-  if(st.st_mtime != tvs.modtime || st.st_atime != tvs.actime) {
+  /* Try and set the times, size and mode of this file -
+     if they are different from the current values
+   */
+  if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
+  {
     if(sys_utime(fname, &tvs)!=0)
+    {
       return(ERROR(ERRDOS,ERRnoaccess));
+    }
   }
-  if(mode != dos_mode(cnum,fname,&st) && dos_chmod(cnum,fname,mode,NULL)) {
+
+  /* check the mode isn't different, before changing it */
+  if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
+  {
     DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
     return(ERROR(ERRDOS,ERRnoaccess));
   }
-  if(size != st.st_size) {
-    if (fd == -1) {
+
+  if(size != st.st_size)
+  {
+    if (fd == -1)
+    {
       fd = sys_open(fname,O_RDWR,0);
       if (fd == -1)
-       return(ERROR(ERRDOS,ERRbadpath));
+      {
+        return(ERROR(ERRDOS,ERRbadpath));
+      }
       set_filelen(fd, size);
       close(fd);
-    } else {
+    }
+    else
+    {
       set_filelen(fd, size);
     }
   }
@@ -1341,21 +1480,27 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
   char *params = *pparams;
   pstring directory;
   int ret = -1;
+  BOOL bad_path = False;
 
   if (!CAN_WRITE(cnum))
     return(ERROR(ERRSRV,ERRaccess));
 
-  strcpy(directory, &params[4]);
+  pstrcpy(directory, &params[4]);
 
   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
-  unix_convert(directory,cnum);
+  unix_convert(directory,cnum,0,&bad_path);
   if (check_name(directory,cnum))
     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
   
   if(ret < 0)
     {
       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,ERRnoaccess));
     }
 
@@ -1542,6 +1687,9 @@ int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
   num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
   num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
 
+  if (num_params > total_params || num_data > total_data)
+         exit_server("invalid params in reply_trans2");
+
   memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
   memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
 
@@ -1569,6 +1717,9 @@ int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
          total_data = SVAL(inbuf, smb_tdscnt);
          num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
          num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
+         if (num_params_sofar > total_params || num_data_sofar > total_data)
+                 exit_server("data overflow in trans2");
+
          memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
                 smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
          memcpy( &data[SVAL(inbuf, smb_sdsdisp)],