- correctly handle non-encrypted share mode session-setup. We were
[samba.git] / source / smbd / reply.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Main SMB reply routines
5    Copyright (C) Andrew Tridgell 1992-1995
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22    This file handles most of the reply_ calls that the server
23    makes to handle specific protocols
24 */
25
26
27 #include "includes.h"
28 #include "trans2.h"
29
30 /* look in server.c for some explanation of these variables */
31 extern int Protocol;
32 extern int DEBUGLEVEL;
33 extern int maxxmit;
34 extern int chain_fnum;
35 extern char magic_char;
36 extern connection_struct Connections[];
37 extern files_struct Files[];
38 extern BOOL case_sensitive;
39 extern pstring sesssetup_user;
40 extern int Client;
41
42 /* this macro should always be used to extract an fnum (smb_fid) from
43 a packet to ensure chaining works correctly */
44 #define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
45
46
47 /****************************************************************************
48   reply to an special message 
49 ****************************************************************************/
50 int reply_special(char *inbuf,char *outbuf)
51 {
52   int outsize = 4;
53   int msg_type = CVAL(inbuf,0);
54   int msg_flags = CVAL(inbuf,1);
55   pstring name1,name2;
56   extern fstring remote_machine;
57   extern fstring local_machine;
58   char *p;
59
60   *name1 = *name2 = 0;
61
62   smb_setlen(outbuf,0);
63
64   switch (msg_type)
65     {
66     case 0x81: /* session request */
67       CVAL(outbuf,0) = 0x82;
68       CVAL(outbuf,3) = 0;
69       if (name_len(inbuf+4) > 50)
70         {
71           DEBUG(0,("Invalid name length in session request\n"));
72           return(0);
73         }
74       name_extract(inbuf,4,name1);
75       name_extract(inbuf,4 + name_len(inbuf + 4),name2);
76       DEBUG(2,("netbios connect: name1=%s name2=%s\n",name1,name2));      
77
78       strcpy(remote_machine,name2);
79       trim_string(remote_machine," "," ");
80       p = strchr(remote_machine,' ');
81       strlower(remote_machine);
82       if (p) *p = 0;
83
84       strcpy(local_machine,name1);
85       trim_string(local_machine," "," ");
86       p = strchr(local_machine,' ');
87       strlower(local_machine);
88       if (p) *p = 0;
89
90       add_session_user(remote_machine);
91
92       reload_services(True);
93       reopen_logs();
94
95       break;
96     case 0x85: /* session keepalive */
97     default:
98       return(0);
99     }
100   
101   DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",timestring(),msg_type,msg_flags));
102   
103   return(outsize);
104 }
105
106
107 /*******************************************************************
108 work out what error to give to a failed connection
109 ********************************************************************/
110 static int connection_error(char *inbuf,char *outbuf,int connection_num)
111 {
112   switch (connection_num)
113     {
114     case -8:
115       return(ERROR(ERRSRV,ERRnoresource));
116     case -7:
117       return(ERROR(ERRSRV,ERRbaduid));
118     case -6:
119       return(ERROR(ERRSRV,ERRinvdevice));
120     case -5:
121       return(ERROR(ERRSRV,ERRinvnetname));
122     case -4:
123       return(ERROR(ERRSRV,ERRaccess));
124     case -3:
125       return(ERROR(ERRDOS,ERRnoipc));
126     case -2:
127       return(ERROR(ERRSRV,ERRinvnetname));
128     }
129   return(ERROR(ERRSRV,ERRbadpw));
130 }
131
132
133
134 /****************************************************************************
135   parse a share descriptor string
136 ****************************************************************************/
137 static void parse_connect(char *p,char *service,char *user,
138                           char *password,int *pwlen,char *dev)
139 {
140   char *p2;
141
142   DEBUG(4,("parsing connect string %s\n",p));
143     
144   p2 = strrchr(p,'\\');
145   if (p2 == NULL)
146     strcpy(service,p);
147   else
148     strcpy(service,p2+1);
149   
150   p += strlen(p) + 2;
151   
152   strcpy(password,p);
153   *pwlen = strlen(password);
154
155   p += strlen(p) + 2;
156
157   strcpy(dev,p);
158   
159   *user = 0;
160   p = strchr(service,'%');
161   if (p != NULL)
162     {
163       *p = 0;
164       strcpy(user,p+1);
165     }
166 }
167
168
169
170
171 /****************************************************************************
172   reply to a tcon
173 ****************************************************************************/
174 int reply_tcon(char *inbuf,char *outbuf)
175 {
176   pstring service;
177   pstring user;
178   pstring password;
179   pstring dev;
180   int connection_num;
181   int outsize = 0;
182   int uid = SVAL(inbuf,smb_uid);
183   int vuid;
184   int pwlen=0;
185
186   *service = *user = *password = *dev = 0;
187
188   vuid = valid_uid(uid);
189   
190   parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
191
192   connection_num = make_connection(service,user,password,pwlen,dev,vuid);
193   
194   if (connection_num < 0)
195     return(connection_error(inbuf,outbuf,connection_num));
196   
197   outsize = set_message(outbuf,2,0,True);
198   SSVAL(outbuf,smb_vwv0,maxxmit);
199   SSVAL(outbuf,smb_vwv1,connection_num);
200   SSVAL(outbuf,smb_tid,connection_num);
201   
202   DEBUG(3,("%s tcon service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
203   
204   return(outsize);
205 }
206
207
208 /****************************************************************************
209   reply to a tcon and X
210 ****************************************************************************/
211 int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
212 {
213   pstring service;
214   pstring user;
215   pstring password;
216   pstring devicename;
217   int connection_num;
218   int uid = SVAL(inbuf,smb_uid);
219   int vuid;
220   int passlen = SVAL(inbuf,smb_vwv3);
221   BOOL doencrypt = SMBENCRYPT();
222
223   *service = *user = *password = *devicename = 0;
224
225   /* we might have to close an old one */
226   if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
227     close_cnum(SVAL(inbuf,smb_tid),uid);
228   
229   vuid = valid_uid(uid);
230   
231   {
232     char *path;
233     char *p;
234     memcpy(password,smb_buf(inbuf),passlen);
235     password[passlen]=0;    
236     path = smb_buf(inbuf) + passlen;
237
238     if (!doencrypt || passlen != 24) {
239       if (strequal(password," "))
240         *password = 0;
241       passlen = strlen(password);
242     }
243     
244     DEBUG(4,("parsing net-path %s, passlen=%d\n",path,passlen));
245     strcpy(service,path+2);
246     p = strchr(service,'\\');
247     if (!p)
248       return(ERROR(ERRSRV,ERRinvnetname));
249     *p = 0;
250     strcpy(service,p+1);
251     p = strchr(service,'%');
252     if (p)
253       {
254         *p++ = 0;
255         strcpy(user,p);
256       }
257     StrnCpy(devicename,path + strlen(path) + 1,6);
258     DEBUG(4,("Got device type %s\n",devicename));
259   }
260
261   connection_num = make_connection(service,user,password,passlen,devicename,vuid);
262   
263   if (connection_num < 0)
264     return(connection_error(inbuf,outbuf,connection_num));
265
266   set_message(outbuf,2,strlen(devicename)+1,True);
267   
268   DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
269   
270   /* set the incoming and outgoing tid to the just created one */
271   SSVAL(inbuf,smb_tid,connection_num);
272   SSVAL(outbuf,smb_tid,connection_num);
273
274   strcpy(smb_buf(outbuf),devicename);
275
276   return chain_reply(inbuf,outbuf,length,bufsize);
277 }
278
279
280 /****************************************************************************
281   reply to an unknown type
282 ****************************************************************************/
283 int reply_unknown(char *inbuf,char *outbuf)
284 {
285   int cnum;
286   int type;
287   cnum = SVAL(inbuf,smb_tid);
288   type = CVAL(inbuf,smb_com);
289   
290   DEBUG(0,("%s unknown command type (%s): cnum=%d type=%d (0x%X)\n",
291         timestring(),
292         smb_fn_name(type),
293         cnum,type,type));
294   
295   return(ERROR(ERRSRV,ERRunknownsmb));
296 }
297
298
299 /****************************************************************************
300   reply to an ioctl
301 ****************************************************************************/
302 int reply_ioctl(char *inbuf,char *outbuf)
303 {
304   DEBUG(3,("ignoring ioctl\n"));
305 #if 0
306   /* we just say it succeeds and hope its all OK. 
307      some day it would be nice to interpret them individually */
308   return set_message(outbuf,1,0,True); 
309 #else
310   return(ERROR(ERRSRV,ERRnosupport));
311 #endif
312 }
313
314
315 /****************************************************************************
316 reply to a session setup command
317 ****************************************************************************/
318 int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
319 {
320   int sess_uid;
321   int gid;
322   int   smb_bufsize;    
323   int   smb_mpxmax;     
324   int   smb_vc_num;     
325   uint32   smb_sesskey;    
326   int   smb_apasslen = 0;   
327   pstring smb_apasswd;
328   int   smb_ntpasslen = 0;   
329   pstring smb_ntpasswd;
330   BOOL valid_nt_password = False;
331   pstring user;
332   BOOL guest=False;
333   BOOL computer_id=False;
334   static BOOL done_sesssetup = False;
335   BOOL doencrypt = SMBENCRYPT();
336
337   *smb_apasswd = 0;
338   
339   sess_uid = SVAL(inbuf,smb_uid);
340   smb_bufsize = SVAL(inbuf,smb_vwv2);
341   smb_mpxmax = SVAL(inbuf,smb_vwv3);
342   smb_vc_num = SVAL(inbuf,smb_vwv4);
343   smb_sesskey = IVAL(inbuf,smb_vwv5);
344
345   if (Protocol < PROTOCOL_NT1) {
346     smb_apasslen = SVAL(inbuf,smb_vwv7);
347     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
348     StrnCpy(user,smb_buf(inbuf)+smb_apasslen,sizeof(user)-1);
349
350     if (lp_security() != SEC_SERVER && !doencrypt)
351       smb_apasslen = strlen(smb_apasswd);
352   } else {
353     uint16 passlen1 = SVAL(inbuf,smb_vwv7);
354     uint16 passlen2 = SVAL(inbuf,smb_vwv8);
355     char *p = smb_buf(inbuf);    
356
357     if (passlen1 != 24 && passlen2 != 24)
358       doencrypt = False;
359
360     if(doencrypt) {
361       /* Save the lanman2 password and the NT md4 password. */
362       smb_apasslen = passlen1;
363       memcpy(smb_apasswd,p,smb_apasslen);
364       smb_ntpasslen = passlen2;
365       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
366     } else {
367       /* both Win95 and WinNT stuff up the password lengths for
368          non-encrypting systems. Uggh. 
369       
370          if passlen1==24 its a win95 system, and its setting the
371          password length incorrectly. Luckily it still works with the
372          default code because Win95 will null terminate the password
373          anyway 
374
375          if passlen1>0 and passlen2>0 then maybe its a NT box and its
376          setting passlen2 to some random value which really stuffs
377          things up. we need to fix that one.  */
378       if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
379           passlen2 != 1) {
380         passlen2 = 0;
381       }
382       /* we use the first password that they gave */
383       smb_apasslen = passlen1;
384       StrnCpy(smb_apasswd,p,smb_apasslen);      
385       
386       /* trim the password */
387       smb_apasslen = strlen(smb_apasswd);
388
389       /* wfwg sometimes uses a space instead of a null */
390       if (strequal(smb_apasswd," ")) {
391         smb_apasslen = 0;
392         *smb_apasswd = 0;
393       }
394     }
395     
396     p += passlen1 + passlen2;
397     strcpy(user,p); p = skip_string(p,1);
398     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
399              p,skip_string(p,1),skip_string(p,2)));
400   }
401
402
403   DEBUG(3,("sesssetupX:name=[%s]\n",user));
404
405   /* If name ends in $ then I think it's asking about whether a */
406   /* computer with that name (minus the $) has access. For now */
407   /* say yes to everything ending in $. */
408   if (user[strlen(user) - 1] == '$') {
409     computer_id = True;
410     user[strlen(user) - 1] = '\0';
411   }
412
413
414   if (!*user)
415     strcpy(user,lp_guestaccount(-1));
416
417   strlower(user);
418
419   strcpy(sesssetup_user,user);
420
421   reload_services(True);
422
423   add_session_user(user);
424
425
426   if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
427       !check_hosts_equiv(user))
428     {
429
430       if (strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
431         guest = True;
432   
433       /* now check if it's a valid username/password */
434       /* If an NT password was supplied try and validate with that
435          first. This is superior as the passwords are mixed case 128 length unicode */
436       if(smb_ntpasslen && !guest)
437         {
438           if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL))
439             DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
440           else
441             valid_nt_password = True;
442         } 
443       if (!valid_nt_password && !guest && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
444         {
445           if (!computer_id && lp_security() >= SEC_USER) {
446 #if (GUEST_SESSSETUP == 0)
447             return(ERROR(ERRSRV,ERRbadpw));
448 #endif
449 #if (GUEST_SESSSETUP == 1)
450             if (Get_Pwnam(user,True))
451               return(ERROR(ERRSRV,ERRbadpw));
452 #endif
453           }
454           if (*smb_apasswd || !Get_Pwnam(user,True))
455             strcpy(user,lp_guestaccount(-1));
456           DEBUG(3,("Registered username %s for guest access\n",user));
457           guest = True;
458         }
459     }
460
461   if (!Get_Pwnam(user,True)) {
462     DEBUG(3,("No such user %s - using guest account\n",user));
463     strcpy(user,lp_guestaccount(-1));
464     guest = True;
465   }
466
467   if (!strequal(user,lp_guestaccount(-1)) &&
468       lp_servicenumber(user) < 0)      
469     {
470       int homes = lp_servicenumber(HOMES_NAME);
471       char *home = get_home_dir(user);
472       if (homes >= 0 && home)
473         lp_add_home(user,homes,home);
474     }
475
476
477   /* it's ok - setup a reply */
478   if (Protocol < PROTOCOL_NT1) {
479     set_message(outbuf,3,0,True);
480   } else {
481     char *p;
482     set_message(outbuf,3,3,True);
483     p = smb_buf(outbuf);
484     strcpy(p,"Unix"); p = skip_string(p,1);
485     strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
486     strcpy(p,lp_workgroup()); p = skip_string(p,1);
487     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
488     /* perhaps grab OS version here?? */
489   }
490
491   /* Set the correct uid in the outgoing and incoming packets
492      We will use this on future requests to determine which
493      user we should become.
494      */
495   {
496     struct passwd *pw = Get_Pwnam(user,False);
497     if (!pw) {
498       DEBUG(1,("Username %s is invalid on this system\n",user));
499       return(ERROR(ERRSRV,ERRbadpw));
500     }
501     gid = pw->pw_gid;
502     SSVAL(outbuf,smb_uid,(uint16)pw->pw_uid);
503     SSVAL(inbuf,smb_uid,(uint16)pw->pw_uid);
504   }
505
506   if (guest && !computer_id)
507     SSVAL(outbuf,smb_vwv2,1);
508
509   /* register the name and uid as being validated, so further connections
510      to a uid can get through without a password, on the same VC */
511   register_uid(SVAL(inbuf,smb_uid),gid,user,guest);
512  
513   if (!done_sesssetup)
514     maxxmit = MIN(maxxmit,smb_bufsize);
515
516   done_sesssetup = True;
517
518   return chain_reply(inbuf,outbuf,length,bufsize);
519 }
520
521
522 /****************************************************************************
523   reply to a chkpth
524 ****************************************************************************/
525 int reply_chkpth(char *inbuf,char *outbuf)
526 {
527   int outsize = 0;
528   int cnum,mode;
529   pstring name;
530   BOOL ok = False;
531   
532   cnum = SVAL(inbuf,smb_tid);
533   
534   strcpy(name,smb_buf(inbuf) + 1);
535   unix_convert(name,cnum);
536
537   mode = SVAL(inbuf,smb_vwv0);
538
539   if (check_name(name,cnum))
540     ok = directory_exist(name,NULL);
541
542   if (!ok)
543     return(ERROR(ERRDOS,ERRbadpath));
544   
545   outsize = set_message(outbuf,0,0,True);
546   
547   DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
548   
549   return(outsize);
550 }
551
552
553 /****************************************************************************
554   reply to a getatr
555 ****************************************************************************/
556 int reply_getatr(char *inbuf,char *outbuf)
557 {
558   pstring fname;
559   int cnum;
560   int outsize = 0;
561   struct stat sbuf;
562   BOOL ok = False;
563   int mode=0;
564   uint32 size=0;
565   time_t mtime=0;
566   
567   cnum = SVAL(inbuf,smb_tid);
568
569   strcpy(fname,smb_buf(inbuf) + 1);
570   unix_convert(fname,cnum);
571
572   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
573      under WfWg - weird! */
574   if (! (*fname))
575     {
576       mode = aHIDDEN | aDIR;
577       if (!CAN_WRITE(cnum)) mode |= aRONLY;
578       size = 0;
579       mtime = 0;
580       ok = True;
581     }
582   else
583     if (check_name(fname,cnum))
584       {
585         if (sys_stat(fname,&sbuf) == 0)
586           {
587             mode = dos_mode(cnum,fname,&sbuf);
588             size = sbuf.st_size;
589             mtime = sbuf.st_mtime;
590             if (mode & aDIR)
591               size = 0;
592             ok = True;
593           }
594         else
595           DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
596     }
597   
598   if (!ok)
599     return(UNIXERROR(ERRDOS,ERRbadfile));
600   
601   outsize = set_message(outbuf,10,0,True);
602
603   SSVAL(outbuf,smb_vwv0,mode);
604   put_dos_date3(outbuf,smb_vwv1,mtime);
605   SIVAL(outbuf,smb_vwv3,size);
606
607   if (Protocol >= PROTOCOL_NT1) {
608     char *p = strrchr(fname,'/');
609     uint16 flg2 = SVAL(outbuf,smb_flg2);
610     if (!p) p = fname;
611     if (!is_8_3(fname))
612       SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
613   }
614   
615   DEBUG(3,("%s getatr name=%s mode=%d size=%d\n",timestring(),fname,mode,size));
616   
617   return(outsize);
618 }
619
620
621 /****************************************************************************
622   reply to a setatr
623 ****************************************************************************/
624 int reply_setatr(char *inbuf,char *outbuf)
625 {
626   pstring fname;
627   int cnum;
628   int outsize = 0;
629   BOOL ok=False;
630   int mode;
631   time_t mtime;
632   
633   cnum = SVAL(inbuf,smb_tid);
634   
635   strcpy(fname,smb_buf(inbuf) + 1);
636   unix_convert(fname,cnum);
637
638   mode = SVAL(inbuf,smb_vwv0);
639   mtime = make_unix_date3(inbuf+smb_vwv1);
640   
641   if (directory_exist(fname,NULL))
642     mode |= aDIR;
643   if (check_name(fname,cnum))
644     ok =  (dos_chmod(cnum,fname,mode,NULL) == 0);
645   if (ok)
646     ok = set_filetime(fname,mtime);
647   
648   if (!ok)
649     return(UNIXERROR(ERRDOS,ERRnoaccess));
650   
651   outsize = set_message(outbuf,0,0,True);
652   
653   DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
654   
655   return(outsize);
656 }
657
658
659 /****************************************************************************
660   reply to a dskattr
661 ****************************************************************************/
662 int reply_dskattr(char *inbuf,char *outbuf)
663 {
664   int cnum;
665   int outsize = 0;
666   int dfree,dsize,bsize;
667   
668   cnum = SVAL(inbuf,smb_tid);
669   
670   sys_disk_free(".",&bsize,&dfree,&dsize);
671   
672   outsize = set_message(outbuf,5,0,True);
673   
674   SSVAL(outbuf,smb_vwv0,dsize);
675   SSVAL(outbuf,smb_vwv1,bsize/512);
676   SSVAL(outbuf,smb_vwv2,512);
677   SSVAL(outbuf,smb_vwv3,dfree);
678   
679   DEBUG(3,("%s dskattr cnum=%d dfree=%d\n",timestring(),cnum,dfree));
680   
681   return(outsize);
682 }
683
684
685 /****************************************************************************
686   reply to a search
687   Can be called from SMBsearch, SMBffirst or SMBfunique.
688 ****************************************************************************/
689 int reply_search(char *inbuf,char *outbuf)
690 {
691   pstring mask;
692   pstring directory;
693   pstring fname;
694   int size,mode;
695   time_t date;
696   int dirtype;
697   int cnum;
698   int outsize = 0;
699   int numentries = 0;
700   BOOL finished = False;
701   int maxentries;
702   int i;
703   char *p;
704   BOOL ok = False;
705   int status_len;
706   char *path;
707   char status[21];
708   int dptr_num= -1;
709   BOOL check_descend = False;
710   BOOL expect_close = False;
711   BOOL can_open = True;
712
713   *mask = *directory = *fname = 0;
714
715   /* If we were called as SMBffirst then we must expect close. */
716   if(CVAL(inbuf,smb_com) == SMBffirst)
717     expect_close = True;
718   
719   cnum = SVAL(inbuf,smb_tid);
720
721   outsize = set_message(outbuf,1,3,True);
722   maxentries = SVAL(inbuf,smb_vwv0); 
723   dirtype = SVAL(inbuf,smb_vwv1);
724   path = smb_buf(inbuf) + 1;
725   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
726
727   
728   /* dirtype &= ~aDIR; */
729   
730   DEBUG(5,("path=%s status_len=%d\n",path,status_len));
731
732   
733   if (status_len == 0)
734     {
735       pstring dir2;
736
737       strcpy(directory,smb_buf(inbuf)+1);
738       strcpy(dir2,smb_buf(inbuf)+1);
739       unix_convert(directory,cnum);
740       unix_format(dir2);
741
742       if (!check_name(directory,cnum))
743         can_open = False;
744
745       p = strrchr(dir2,'/');
746       if (p == NULL) 
747         {strcpy(mask,dir2);*dir2 = 0;}
748       else
749         {*p = 0;strcpy(mask,p+1);}
750
751       p = strrchr(directory,'/');
752       if (!p) 
753         *directory = 0;
754       else
755         *p = 0;
756
757       if (strlen(directory) == 0)
758         strcpy(directory,"./");
759       bzero(status,21);
760       CVAL(status,0) = dirtype;
761     }
762   else
763     {
764       memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
765       memcpy(mask,status+1,11);
766       mask[11] = 0;
767       dirtype = CVAL(status,0) & 0x1F;
768       Connections[cnum].dirptr = dptr_fetch(status+12,&dptr_num);      
769       if (!Connections[cnum].dirptr)
770         goto SearchEmpty;
771       string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
772       if (!case_sensitive)
773         strnorm(mask);
774     }
775
776   /* turn strings of spaces into a . */  
777   {
778     trim_string(mask,NULL," ");
779     if ((p = strrchr(mask,' ')))
780       {
781         fstring ext;
782         strcpy(ext,p+1);
783         *p = 0;
784         trim_string(mask,NULL," ");
785         strcat(mask,".");
786         strcat(mask,ext);
787       }
788   }
789
790   {
791     for (p=mask; *p; p++)
792       {
793         if (*p != '?' && *p != '*' && !isdoschar(*p))
794           {
795             DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
796             *p = '?';
797           }
798       }
799   }
800
801   if (!strchr(mask,'.') && strlen(mask)>8)
802     {
803       fstring tmp;
804       strcpy(tmp,&mask[8]);
805       mask[8] = '.';
806       mask[9] = 0;
807       strcat(mask,tmp);
808     }
809
810   DEBUG(5,("mask=%s directory=%s\n",mask,directory));
811   
812   if (can_open)
813     {
814       p = smb_buf(outbuf) + 3;
815       
816       ok = True;
817       
818       if (status_len == 0)
819         {
820           dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
821           if (dptr_num < 0)
822             return(ERROR(ERRDOS,ERRnofids));
823         }
824
825       DEBUG(4,("dptr_num is %d\n",dptr_num));
826
827       if (ok)
828         {
829           if ((dirtype&0x1F) == aVOLID)
830             {     
831               memcpy(p,status,21);
832               make_dir_struct(p,"???????????",volume_label(SNUM(cnum)),0,aVOLID,0);
833               dptr_fill(p+12,dptr_num);
834               if (dptr_zero(p+12) && (status_len==0))
835                 numentries = 1;
836               else
837                 numentries = 0;
838               p += DIR_STRUCT_SIZE;
839             }
840           else 
841             {
842               DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
843               if (in_list(Connections[cnum].dirpath,
844                           lp_dontdescend(SNUM(cnum)),True))
845                 check_descend = True;
846
847               for (i=numentries;(i<maxentries) && !finished;i++)
848                 {
849                   finished = 
850                     !get_dir_entry(cnum,mask,dirtype,fname,&size,&mode,&date,check_descend);
851                   if (!finished)
852                     {
853                       memcpy(p,status,21);
854                       make_dir_struct(p,mask,fname,size,mode,date);
855                       dptr_fill(p+12,dptr_num);
856                       numentries++;
857                     }
858                   p += DIR_STRUCT_SIZE;
859                 }
860             }
861         }
862     }
863
864
865  SearchEmpty:
866
867   if (numentries == 0 || !ok)
868     {
869       CVAL(outbuf,smb_rcls) = ERRDOS;
870       SSVAL(outbuf,smb_err,ERRnofiles);
871     }
872
873   /* If we were called as SMBffirst with smb_search_id == NULL
874      and no entries were found then return error and close dirptr 
875      (X/Open spec) */
876
877   if(ok && expect_close && numentries == 0 && status_len == 0)
878     {
879       CVAL(outbuf,smb_rcls) = ERRDOS;
880       SSVAL(outbuf,smb_err,ERRnofiles);
881       /* Also close the dptr - we know it's gone */
882       dptr_close(dptr_num);
883     }
884
885   /* If we were called as SMBfunique, then we can close the dirptr now ! */
886   if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
887     dptr_close(dptr_num);
888
889   SSVAL(outbuf,smb_vwv0,numentries);
890   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
891   CVAL(smb_buf(outbuf),0) = 5;
892   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
893
894   if (Protocol >= PROTOCOL_NT1) {
895     uint16 flg2 = SVAL(outbuf,smb_flg2);
896     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
897   }
898   
899   outsize += DIR_STRUCT_SIZE*numentries;
900   smb_setlen(outbuf,outsize - 4);
901   
902   if ((! *directory) && dptr_path(dptr_num))
903     sprintf(directory,"(%s)",dptr_path(dptr_num));
904
905   DEBUG(4,("%s %s mask=%s path=%s cnum=%d dtype=%d nument=%d of %d\n",
906         timestring(),
907         smb_fn_name(CVAL(inbuf,smb_com)), 
908         mask,directory,cnum,dirtype,numentries,maxentries));
909
910   return(outsize);
911 }
912
913
914 /****************************************************************************
915   reply to a fclose (stop directory search)
916 ****************************************************************************/
917 int reply_fclose(char *inbuf,char *outbuf)
918 {
919   int cnum;
920   int outsize = 0;
921   int status_len;
922   char *path;
923   char status[21];
924   int dptr_num= -1;
925
926   cnum = SVAL(inbuf,smb_tid);
927
928   outsize = set_message(outbuf,1,0,True);
929   path = smb_buf(inbuf) + 1;
930   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
931
932   
933   if (status_len == 0)
934     return(ERROR(ERRSRV,ERRsrverror));
935
936   memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
937
938   if(dptr_fetch(status+12,&dptr_num)) {
939     /*  Close the dptr - we know it's gone */
940     dptr_close(dptr_num);
941   }
942
943   SSVAL(outbuf,smb_vwv0,0);
944
945   DEBUG(3,("%s search close cnum=%d\n",timestring(),cnum));
946
947   return(outsize);
948 }
949
950
951 /****************************************************************************
952   reply to an open
953 ****************************************************************************/
954 int reply_open(char *inbuf,char *outbuf)
955 {
956   pstring fname;
957   int cnum;
958   int fnum = -1;
959   int outsize = 0;
960   int fmode=0;
961   int share_mode;
962   int size = 0;
963   time_t mtime=0;
964   int unixmode;
965   int rmode=0;
966   struct stat sbuf;
967   
968   cnum = SVAL(inbuf,smb_tid);
969
970   share_mode = SVAL(inbuf,smb_vwv0);
971
972   strcpy(fname,smb_buf(inbuf)+1);
973   unix_convert(fname,cnum);
974     
975   fnum = find_free_file();
976   if (fnum < 0)
977     return(ERROR(ERRSRV,ERRnofids));
978
979   if (!check_name(fname,cnum))
980     return(UNIXERROR(ERRDOS,ERRnoaccess));
981   
982   unixmode = unix_mode(cnum,aARCH);
983       
984   open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
985
986   if (!Files[fnum].open)
987     return(UNIXERROR(ERRDOS,ERRnoaccess));
988
989   if (fstat(Files[fnum].fd,&sbuf) != 0) {
990     close_file(fnum);
991     return(ERROR(ERRDOS,ERRnoaccess));
992   }
993     
994   size = sbuf.st_size;
995   fmode = dos_mode(cnum,fname,&sbuf);
996   mtime = sbuf.st_mtime;
997
998   if (fmode & aDIR) {
999     DEBUG(3,("attempt to open a directory %s\n",fname));
1000     close_file(fnum);
1001     return(ERROR(ERRDOS,ERRnoaccess));
1002   }
1003   
1004   outsize = set_message(outbuf,7,0,True);
1005   SSVAL(outbuf,smb_vwv0,fnum);
1006   SSVAL(outbuf,smb_vwv1,fmode);
1007   put_dos_date3(outbuf,smb_vwv2,mtime);
1008   SIVAL(outbuf,smb_vwv4,size);
1009   SSVAL(outbuf,smb_vwv6,rmode);
1010
1011   if (lp_fake_oplocks(SNUM(cnum))) {
1012     CVAL(outbuf,smb_flg) |= (CVAL(inbuf,smb_flg) & (1<<5));
1013   }
1014     
1015   return(outsize);
1016 }
1017
1018
1019 /****************************************************************************
1020   reply to an open and X
1021 ****************************************************************************/
1022 int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
1023 {
1024   pstring fname;
1025   int cnum = SVAL(inbuf,smb_tid);
1026   int fnum = -1;
1027   int openmode = 0;
1028   int smb_mode = SVAL(inbuf,smb_vwv3);
1029   int smb_attr = SVAL(inbuf,smb_vwv5);
1030   BOOL oplock_request = BITSETW(inbuf+smb_vwv2,1);
1031 #if 0
1032   int open_flags = SVAL(inbuf,smb_vwv2);
1033   int smb_sattr = SVAL(inbuf,smb_vwv4); 
1034   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
1035 #endif
1036   int smb_ofun = SVAL(inbuf,smb_vwv8);
1037   int unixmode;
1038   int size=0,fmode=0,mtime=0,rmode=0;
1039   struct stat sbuf;
1040   int smb_action = 0;
1041
1042   /* If it's an IPC, pass off the pipe handler. */
1043   if (IS_IPC(cnum))
1044     return reply_open_pipe_and_X(inbuf,outbuf,length,bufsize);
1045
1046   /* XXXX we need to handle passed times, sattr and flags */
1047
1048   strcpy(fname,smb_buf(inbuf));
1049   unix_convert(fname,cnum);
1050     
1051   /* now add create and trunc bits */
1052   if (smb_ofun & 0x10)
1053     openmode |= O_CREAT;
1054   if ((smb_ofun & 0x3) == 2)
1055     openmode |= O_TRUNC;
1056   
1057   fnum = find_free_file();
1058   if (fnum < 0)
1059     return(ERROR(ERRSRV,ERRnofids));
1060
1061   if (!check_name(fname,cnum))
1062     return(UNIXERROR(ERRDOS,ERRnoaccess));
1063
1064   unixmode = unix_mode(cnum,smb_attr | aARCH);
1065       
1066   open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
1067                    &rmode,&smb_action);
1068       
1069   if (!Files[fnum].open)
1070     return(UNIXERROR(ERRDOS,ERRnoaccess));
1071
1072   if (fstat(Files[fnum].fd,&sbuf) != 0) {
1073     close_file(fnum);
1074     return(ERROR(ERRDOS,ERRnoaccess));
1075   }
1076
1077   size = sbuf.st_size;
1078   fmode = dos_mode(cnum,fname,&sbuf);
1079   mtime = sbuf.st_mtime;
1080   if (fmode & aDIR) {
1081     close_file(fnum);
1082     return(ERROR(ERRDOS,ERRnoaccess));
1083   }
1084
1085   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1086     smb_action |= (1<<15);
1087   }
1088
1089   set_message(outbuf,15,0,True);
1090   SSVAL(outbuf,smb_vwv2,fnum);
1091   SSVAL(outbuf,smb_vwv3,fmode);
1092   put_dos_date3(outbuf,smb_vwv4,mtime);
1093   SIVAL(outbuf,smb_vwv6,size);
1094   SSVAL(outbuf,smb_vwv8,rmode);
1095   SSVAL(outbuf,smb_vwv11,smb_action);
1096
1097   chain_fnum = fnum;
1098
1099   return chain_reply(inbuf,outbuf,length,bufsize);
1100 }
1101
1102
1103 /****************************************************************************
1104   reply to a SMBulogoffX
1105 ****************************************************************************/
1106 int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
1107 {
1108   int uid = SVAL(inbuf,smb_uid);
1109
1110   invalidate_uid(uid);
1111
1112   /* in user level security we are supposed to close any files
1113      open by this user */
1114   if (lp_security() != SEC_SHARE) {
1115     int i;
1116     for (i=0;i<MAX_OPEN_FILES;i++)
1117       if (Files[i].uid == uid && Files[i].open) {
1118         close_file(i);
1119       }
1120   }
1121
1122   set_message(outbuf,2,0,True);
1123
1124   DEBUG(3,("%s ulogoffX uid=%d\n",timestring(),uid));
1125
1126   return chain_reply(inbuf,outbuf,length,bufsize);
1127 }
1128
1129
1130 /****************************************************************************
1131   reply to a mknew
1132 ****************************************************************************/
1133 int reply_mknew(char *inbuf,char *outbuf)
1134 {
1135   pstring fname;
1136   int cnum,com;
1137   int fnum = -1;
1138   int outsize = 0;
1139   int createmode;
1140   mode_t unixmode;
1141   
1142   com = SVAL(inbuf,smb_com);
1143   cnum = SVAL(inbuf,smb_tid);
1144
1145   createmode = SVAL(inbuf,smb_vwv0);
1146   strcpy(fname,smb_buf(inbuf)+1);
1147   unix_convert(fname,cnum);
1148
1149   if (createmode & aVOLID)
1150     {
1151       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1152     }
1153   
1154   unixmode = unix_mode(cnum,createmode);
1155   
1156   if (com == SMBmknew && file_exist(fname,NULL))
1157     return(ERROR(ERRDOS,ERRfilexists));
1158     
1159   fnum = find_free_file();
1160   if (fnum < 0)
1161     return(ERROR(ERRSRV,ERRnofids));
1162
1163   if (!check_name(fname,cnum))
1164     return(UNIXERROR(ERRDOS,ERRnoaccess));
1165
1166   open_file(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode);
1167   
1168   if (!Files[fnum].open)
1169     return(UNIXERROR(ERRDOS,ERRnoaccess));
1170   
1171   outsize = set_message(outbuf,1,0,True);
1172   SSVAL(outbuf,smb_vwv0,fnum);
1173
1174   if (lp_fake_oplocks(SNUM(cnum))) {
1175     CVAL(outbuf,smb_flg) |= (CVAL(inbuf,smb_flg) & (1<<5));
1176   }
1177   
1178   DEBUG(2,("new file %s\n",fname));
1179   DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd,fnum,cnum,createmode,unixmode));
1180   
1181   return(outsize);
1182 }
1183
1184
1185 /****************************************************************************
1186   reply to a create temporary file
1187 ****************************************************************************/
1188 int reply_ctemp(char *inbuf,char *outbuf)
1189 {
1190   pstring fname;
1191   pstring fname2;
1192   int cnum;
1193   int fnum = -1;
1194   int outsize = 0;
1195   int createmode;
1196   mode_t unixmode;
1197   
1198   cnum = SVAL(inbuf,smb_tid);
1199   createmode = SVAL(inbuf,smb_vwv0);
1200   sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
1201   unix_convert(fname,cnum);
1202   
1203   unixmode = unix_mode(cnum,createmode);
1204   
1205   fnum = find_free_file();
1206   if (fnum < 0)
1207     return(ERROR(ERRSRV,ERRnofids));
1208
1209   if (!check_name(fname,cnum))
1210     return(UNIXERROR(ERRDOS,ERRnoaccess));
1211
1212   strcpy(fname2,(char *)mktemp(fname));
1213
1214   open_file(fnum,cnum,fname2,O_RDWR | O_CREAT | O_TRUNC,unixmode);
1215
1216   if (!Files[fnum].open)
1217     return(UNIXERROR(ERRDOS,ERRnoaccess));
1218
1219   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
1220   SSVAL(outbuf,smb_vwv0,fnum);
1221   CVAL(smb_buf(outbuf),0) = 4;
1222   strcpy(smb_buf(outbuf) + 1,fname2);
1223
1224   if (lp_fake_oplocks(SNUM(cnum))) {
1225     CVAL(outbuf,smb_flg) |= (CVAL(inbuf,smb_flg) & (1<<5));
1226   }
1227   
1228   DEBUG(2,("created temp file %s\n",fname2));
1229   DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd,fnum,cnum,createmode,unixmode));
1230   
1231   return(outsize);
1232 }
1233
1234
1235 /*******************************************************************
1236 check if a user is allowed to delete a file
1237 ********************************************************************/
1238 static BOOL can_delete(char *fname,int cnum,int dirtype)
1239 {
1240   struct stat sbuf;
1241   int fmode;
1242
1243   if (!CAN_WRITE(cnum)) return(False);
1244
1245   if (sys_lstat(fname,&sbuf) != 0) return(False);
1246   fmode = dos_mode(cnum,fname,&sbuf);
1247   if (fmode & aDIR) return(False);
1248   if (!lp_delete_readonly(SNUM(cnum))) {
1249     if (fmode & aRONLY) return(False);
1250   }
1251   if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1252     return(False);
1253   if (!check_file_sharing(cnum,fname)) return(False);
1254   return(True);
1255 }
1256
1257 /****************************************************************************
1258   reply to a unlink
1259 ****************************************************************************/
1260 int reply_unlink(char *inbuf,char *outbuf)
1261 {
1262   int outsize = 0;
1263   pstring name;
1264   int cnum;
1265   int dirtype;
1266   pstring directory;
1267   pstring mask;
1268   char *p;
1269   int count=0;
1270   int error = ERRnoaccess;
1271   BOOL has_wild;
1272   BOOL exists=False;
1273
1274   *directory = *mask = 0;
1275
1276   cnum = SVAL(inbuf,smb_tid);
1277   dirtype = SVAL(inbuf,smb_vwv0);
1278   
1279   strcpy(name,smb_buf(inbuf) + 1);
1280    
1281   DEBUG(3,("reply_unlink : %s\n",name));
1282    
1283   unix_convert(name,cnum);
1284
1285   p = strrchr(name,'/');
1286   if (!p) {
1287     strcpy(directory,"./");
1288     strcpy(mask,name);
1289   } else {
1290     *p = 0;
1291     strcpy(directory,name);
1292     strcpy(mask,p+1);
1293   }
1294
1295   if (is_mangled(mask))
1296     check_mangled_stack(mask);
1297
1298   has_wild = strchr(mask,'*') || strchr(mask,'?');
1299
1300   if (!has_wild) {
1301     strcat(directory,"/");
1302     strcat(directory,mask);
1303     if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++;
1304     if (!count) exists = file_exist(directory,NULL);    
1305   } else {
1306     void *dirptr = NULL;
1307     char *dname;
1308
1309     if (check_name(directory,cnum))
1310       dirptr = OpenDir(directory);
1311
1312     /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
1313        the pattern matches against the long name, otherwise the short name 
1314        We don't implement this yet XXXX
1315        */
1316
1317     if (dirptr)
1318       {
1319         error = ERRbadfile;
1320
1321         if (strequal(mask,"????????.???"))
1322           strcpy(mask,"*");
1323
1324         while ((dname = ReadDirName(dirptr)))
1325           {
1326             pstring fname;
1327             strcpy(fname,dname);
1328             
1329             if(!mask_match(fname, mask, case_sensitive, False)) continue;
1330
1331             error = ERRnoaccess;
1332             sprintf(fname,"%s/%s",directory,dname);
1333             if (!can_delete(fname,cnum,dirtype)) continue;
1334             if (!sys_unlink(fname)) count++;
1335             DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
1336           }
1337         CloseDir(dirptr);
1338       }
1339   }
1340   
1341   if (count == 0) {
1342     if (exists)
1343       return(ERROR(ERRDOS,error));
1344     else
1345       return(UNIXERROR(ERRDOS,error));
1346   }
1347   
1348   outsize = set_message(outbuf,0,0,True);
1349   
1350   return(outsize);
1351 }
1352
1353
1354 /****************************************************************************
1355    reply to a readbraw (core+ protocol)
1356 ****************************************************************************/
1357 int reply_readbraw(char *inbuf, char *outbuf)
1358 {
1359   int cnum,maxcount,mincount,fnum;
1360   int nread = 0;
1361   int startpos;
1362   char *header = outbuf;
1363   int ret=0;
1364   int fd;
1365   char *fname;
1366
1367   cnum = SVAL(inbuf,smb_tid);
1368   fnum = GETFNUM(inbuf,smb_vwv0);
1369
1370   startpos = IVAL(inbuf,smb_vwv1);
1371   maxcount = SVAL(inbuf,smb_vwv3);
1372   mincount = SVAL(inbuf,smb_vwv4);
1373
1374   /* ensure we don't overrun the packet size */
1375   maxcount = MIN(65535,maxcount);
1376   maxcount = MAX(mincount,maxcount);
1377
1378   if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read)
1379     {
1380       DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum));
1381       _smb_setlen(header,0);
1382       transfer_file(0,Client,0,header,4,0);
1383       return(-1);
1384     }
1385   else
1386     {
1387       fd = Files[fnum].fd;
1388       fname = Files[fnum].name;
1389     }
1390
1391
1392   if (!is_locked(fnum,cnum,maxcount,startpos))
1393     {
1394       int size = Files[fnum].size;
1395       int sizeneeded = startpos + maxcount;
1396             
1397       if (size < sizeneeded) {
1398         struct stat st;
1399         if (fstat(Files[fnum].fd,&st) == 0)
1400           size = st.st_size;
1401         if (!Files[fnum].can_write) 
1402           Files[fnum].size = size;
1403       }
1404
1405       nread = MIN(maxcount,size - startpos);      
1406     }
1407
1408   if (nread < mincount)
1409     nread = 0;
1410   
1411   DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n",
1412            timestring(),
1413            fnum,cnum,startpos,
1414            maxcount,mincount,nread));
1415   
1416 #if UNSAFE_READRAW
1417   {
1418     int predict=0;
1419     _smb_setlen(header,nread);
1420
1421     if (!Files[fnum].can_write)
1422       predict = read_predict(fd,startpos,header+4,NULL,nread);
1423
1424     if ((nread-predict) > 0)
1425       seek_file(fnum,startpos + predict);
1426     
1427     ret = transfer_file(fd,Client,nread-predict,header,4+predict,
1428                         startpos+predict);
1429   }
1430
1431   if (ret != nread+4)
1432     DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
1433              fname,startpos,nread,ret));
1434
1435 #else
1436   ret = read_file(fnum,header+4,startpos,nread);
1437   if (ret < mincount) ret = 0;
1438
1439   _smb_setlen(header,ret);
1440   transfer_file(0,Client,0,header,4+ret,0);
1441 #endif
1442
1443   DEBUG(5,("readbraw finished\n"));
1444   return -1;
1445 }
1446
1447
1448 /****************************************************************************
1449   reply to a lockread (core+ protocol)
1450 ****************************************************************************/
1451 int reply_lockread(char *inbuf,char *outbuf)
1452 {
1453   int cnum,fnum;
1454   int nread = -1;
1455   char *data;
1456   int outsize = 0;
1457   uint32 startpos, numtoread;
1458   int eclass;
1459   uint32 ecode;
1460   
1461   cnum = SVAL(inbuf,smb_tid);
1462   fnum = GETFNUM(inbuf,smb_vwv0);
1463
1464   CHECK_FNUM(fnum,cnum);
1465   CHECK_READ(fnum);
1466   CHECK_ERROR(fnum);
1467
1468   numtoread = SVAL(inbuf,smb_vwv1);
1469   startpos = IVAL(inbuf,smb_vwv2);
1470   
1471   outsize = set_message(outbuf,5,3,True);
1472   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1473   data = smb_buf(outbuf) + 3;
1474   
1475   if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
1476     return (ERROR(eclass,ecode));
1477
1478   nread = read_file(fnum,data,startpos,numtoread);
1479   
1480   if (nread < 0)
1481     return(UNIXERROR(ERRDOS,ERRnoaccess));
1482   
1483   outsize += nread;
1484   SSVAL(outbuf,smb_vwv0,nread);
1485   SSVAL(outbuf,smb_vwv5,nread+3);
1486   SSVAL(smb_buf(outbuf),1,nread);
1487   
1488   DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1489   
1490   return(outsize);
1491 }
1492
1493
1494 /****************************************************************************
1495   reply to a read
1496 ****************************************************************************/
1497 int reply_read(char *inbuf,char *outbuf)
1498 {
1499   int cnum,numtoread,fnum;
1500   int nread = 0;
1501   char *data;
1502   int startpos;
1503   int outsize = 0;
1504   
1505   cnum = SVAL(inbuf,smb_tid);
1506   fnum = GETFNUM(inbuf,smb_vwv0);
1507
1508   CHECK_FNUM(fnum,cnum);
1509   CHECK_READ(fnum);
1510   CHECK_ERROR(fnum);
1511
1512   numtoread = SVAL(inbuf,smb_vwv1);
1513   startpos = IVAL(inbuf,smb_vwv2);
1514   
1515   outsize = set_message(outbuf,5,3,True);
1516   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1517   data = smb_buf(outbuf) + 3;
1518   
1519   if (is_locked(fnum,cnum,numtoread,startpos))
1520     return(ERROR(ERRDOS,ERRlock));      
1521
1522   if (numtoread > 0)
1523     nread = read_file(fnum,data,startpos,numtoread);
1524   
1525   if (nread < 0)
1526     return(UNIXERROR(ERRDOS,ERRnoaccess));
1527   
1528   outsize += nread;
1529   SSVAL(outbuf,smb_vwv0,nread);
1530   SSVAL(outbuf,smb_vwv5,nread+3);
1531   CVAL(smb_buf(outbuf),0) = 1;
1532   SSVAL(smb_buf(outbuf),1,nread);
1533   
1534   DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1535   
1536   return(outsize);
1537 }
1538
1539
1540 /****************************************************************************
1541   reply to a read and X
1542 ****************************************************************************/
1543 int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
1544 {
1545   int fnum = GETFNUM(inbuf,smb_vwv2);
1546   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
1547   int smb_maxcnt = SVAL(inbuf,smb_vwv5);
1548   int smb_mincnt = SVAL(inbuf,smb_vwv6);
1549   int cnum;
1550   int nread = -1;
1551   char *data;
1552   BOOL ok = False;
1553
1554   cnum = SVAL(inbuf,smb_tid);
1555
1556   CHECK_FNUM(fnum,cnum);
1557   CHECK_READ(fnum);
1558   CHECK_ERROR(fnum);
1559
1560   set_message(outbuf,12,0,True);
1561   data = smb_buf(outbuf);
1562
1563   if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
1564     return(ERROR(ERRDOS,ERRlock));
1565   nread = read_file(fnum,data,smb_offs,smb_maxcnt);
1566   ok = True;
1567   
1568   if (nread < 0)
1569     return(UNIXERROR(ERRDOS,ERRnoaccess));
1570   
1571   SSVAL(outbuf,smb_vwv5,nread);
1572   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
1573   SSVAL(smb_buf(outbuf),-2,nread);
1574   
1575   DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d\n",
1576         timestring(),fnum,cnum,
1577         smb_mincnt,smb_maxcnt,nread));
1578
1579   chain_fnum = fnum;
1580
1581   return chain_reply(inbuf,outbuf,length,bufsize);
1582 }
1583
1584
1585 /****************************************************************************
1586   reply to a writebraw (core+ or LANMAN1.0 protocol)
1587 ****************************************************************************/
1588 int reply_writebraw(char *inbuf,char *outbuf)
1589 {
1590   int nwritten=0;
1591   int total_written=0;
1592   int numtowrite=0;
1593   int cnum,fnum;
1594   int outsize = 0;
1595   long startpos;
1596   char *data=NULL;
1597   BOOL write_through;
1598   int tcount;
1599
1600   cnum = SVAL(inbuf,smb_tid);
1601   fnum = GETFNUM(inbuf,smb_vwv0);
1602
1603   CHECK_FNUM(fnum,cnum);
1604   CHECK_WRITE(fnum);
1605   CHECK_ERROR(fnum);
1606   
1607   tcount = IVAL(inbuf,smb_vwv1);
1608   startpos = IVAL(inbuf,smb_vwv3);
1609   write_through = BITSETW(inbuf+smb_vwv7,0);
1610
1611   /* We have to deal with slightly different formats depending
1612      on whether we are using the core+ or lanman1.0 protocol */
1613   if(Protocol <= PROTOCOL_COREPLUS) {
1614     numtowrite = SVAL(smb_buf(inbuf),-2);
1615     data = smb_buf(inbuf);
1616   } else {
1617     numtowrite = SVAL(inbuf,smb_vwv10);
1618     data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
1619   }
1620
1621   /* force the error type */
1622   CVAL(inbuf,smb_com) = SMBwritec;
1623   CVAL(outbuf,smb_com) = SMBwritec;
1624
1625   if (is_locked(fnum,cnum,tcount,startpos))
1626     return(ERROR(ERRDOS,ERRlock));
1627
1628   if (seek_file(fnum,startpos) != startpos)
1629     DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
1630
1631   if (numtowrite>0)
1632     nwritten = write_file(fnum,data,numtowrite);
1633   
1634   DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n",
1635            timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through));
1636
1637   if (nwritten < numtowrite) 
1638     return(UNIXERROR(ERRHRD,ERRdiskfull));
1639
1640   total_written = nwritten;
1641
1642   /* Return a message to the redirector to tell it
1643      to send more bytes */
1644   CVAL(outbuf,smb_com) = SMBwritebraw;
1645   SSVALS(outbuf,smb_vwv0,-1);
1646   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
1647   send_smb(Client,outbuf);
1648   
1649   /* Now read the raw data into the buffer and write it */
1650   if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
1651     exit_server("secondary writebraw failed");
1652   }
1653   
1654   /* Even though this is not an smb message, smb_len
1655      returns the generic length of an smb message */
1656   numtowrite = smb_len(inbuf);
1657
1658   if (tcount > nwritten+numtowrite) {
1659     DEBUG(3,("Client overestimated the write %d %d %d\n",
1660              tcount,nwritten,numtowrite));
1661   }
1662
1663   nwritten = transfer_file(Client,Files[fnum].fd,numtowrite,NULL,0,
1664                            startpos+nwritten);
1665   total_written += nwritten;
1666   
1667   /* Set up outbuf to return the correct return */
1668   outsize = set_message(outbuf,1,0,True);
1669   CVAL(outbuf,smb_com) = SMBwritec;
1670   SSVAL(outbuf,smb_vwv0,total_written);
1671
1672   if (nwritten < numtowrite) {
1673     CVAL(outbuf,smb_rcls) = ERRHRD;
1674     SSVAL(outbuf,smb_err,ERRdiskfull);      
1675   }
1676
1677   if (lp_syncalways(SNUM(cnum)) || write_through)
1678     sync_file(fnum);
1679
1680   DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
1681            timestring(),fnum,cnum,startpos,numtowrite,total_written));
1682
1683   /* we won't return a status if write through is not selected - this 
1684      follows what WfWg does */
1685   if (!write_through && total_written==tcount)
1686     return(-1);
1687
1688   return(outsize);
1689 }
1690
1691
1692 /****************************************************************************
1693   reply to a writeunlock (core+)
1694 ****************************************************************************/
1695 int reply_writeunlock(char *inbuf,char *outbuf)
1696 {
1697   int cnum,fnum;
1698   int nwritten = -1;
1699   int outsize = 0;
1700   char *data;
1701   uint32 numtowrite,startpos;
1702   int eclass;
1703   uint32 ecode;
1704   
1705   cnum = SVAL(inbuf,smb_tid);
1706   fnum = GETFNUM(inbuf,smb_vwv0);
1707
1708   CHECK_FNUM(fnum,cnum);
1709   CHECK_WRITE(fnum);
1710   CHECK_ERROR(fnum);
1711
1712   numtowrite = SVAL(inbuf,smb_vwv1);
1713   startpos = IVAL(inbuf,smb_vwv2);
1714   data = smb_buf(inbuf) + 3;
1715   
1716   if (is_locked(fnum,cnum,numtowrite,startpos))
1717     return(ERROR(ERRDOS,ERRlock));
1718
1719   seek_file(fnum,startpos);
1720
1721   /* The special X/Open SMB protocol handling of
1722      zero length writes is *NOT* done for
1723      this call */
1724   if(numtowrite == 0)
1725     nwritten = 0;
1726   else
1727     nwritten = write_file(fnum,data,numtowrite);
1728   
1729   if (lp_syncalways(SNUM(cnum)))
1730     sync_file(fnum);
1731
1732   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
1733     return(UNIXERROR(ERRDOS,ERRnoaccess));
1734
1735   if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode))
1736     return(ERROR(eclass,ecode));
1737
1738   outsize = set_message(outbuf,1,0,True);
1739   
1740   SSVAL(outbuf,smb_vwv0,nwritten);
1741   
1742   DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n",
1743            timestring(),fnum,cnum,numtowrite,nwritten));
1744   
1745   return(outsize);
1746 }
1747
1748
1749 /****************************************************************************
1750   reply to a write
1751 ****************************************************************************/
1752 int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
1753 {
1754   int cnum,numtowrite,fnum;
1755   int nwritten = -1;
1756   int outsize = 0;
1757   int startpos;
1758   char *data;
1759
1760   dum1 = dum2 = 0;
1761
1762   
1763   cnum = SVAL(inbuf,smb_tid);
1764   fnum = GETFNUM(inbuf,smb_vwv0);
1765
1766   CHECK_FNUM(fnum,cnum);
1767   CHECK_WRITE(fnum);
1768   CHECK_ERROR(fnum);
1769
1770   numtowrite = SVAL(inbuf,smb_vwv1);
1771   startpos = IVAL(inbuf,smb_vwv2);
1772   data = smb_buf(inbuf) + 3;
1773   
1774   if (is_locked(fnum,cnum,numtowrite,startpos))
1775     return(ERROR(ERRDOS,ERRlock));
1776
1777   seek_file(fnum,startpos);
1778
1779   /* X/Open SMB protocol says that if smb_vwv1 is
1780      zero then the file size should be extended or
1781      truncated to the size given in smb_vwv[2-3] */
1782   if(numtowrite == 0)
1783     nwritten = set_filelen(Files[fnum].fd, startpos);
1784   else
1785     nwritten = write_file(fnum,data,numtowrite);
1786   
1787   if (lp_syncalways(SNUM(cnum)))
1788     sync_file(fnum);
1789
1790   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
1791     return(UNIXERROR(ERRDOS,ERRnoaccess));
1792
1793   outsize = set_message(outbuf,1,0,True);
1794   
1795   SSVAL(outbuf,smb_vwv0,nwritten);
1796
1797   if (nwritten < numtowrite) {
1798     CVAL(outbuf,smb_rcls) = ERRHRD;
1799     SSVAL(outbuf,smb_err,ERRdiskfull);      
1800   }
1801   
1802   DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten));
1803   
1804   return(outsize);
1805 }
1806
1807
1808 /****************************************************************************
1809   reply to a write and X
1810 ****************************************************************************/
1811 int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
1812 {
1813   int fnum = GETFNUM(inbuf,smb_vwv2);
1814   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
1815   int smb_dsize = SVAL(inbuf,smb_vwv10);
1816   int smb_doff = SVAL(inbuf,smb_vwv11);
1817   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
1818   int cnum;
1819   int nwritten = -1;
1820   char *data;
1821
1822   cnum = SVAL(inbuf,smb_tid);
1823
1824   CHECK_FNUM(fnum,cnum);
1825   CHECK_WRITE(fnum);
1826   CHECK_ERROR(fnum);
1827
1828   data = smb_base(inbuf) + smb_doff;
1829
1830   if (is_locked(fnum,cnum,smb_dsize,smb_offs))
1831     return(ERROR(ERRDOS,ERRlock));
1832
1833   seek_file(fnum,smb_offs);
1834   
1835   /* X/Open SMB protocol says that, unlike SMBwrite
1836      if the length is zero then NO truncation is
1837      done, just a write of zero. To truncate a file,
1838      use SMBwrite. */
1839   if(smb_dsize == 0)
1840     nwritten = 0;
1841   else
1842     nwritten = write_file(fnum,data,smb_dsize);
1843   
1844   if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
1845     return(UNIXERROR(ERRDOS,ERRnoaccess));
1846
1847   set_message(outbuf,6,0,True);
1848   
1849   SSVAL(outbuf,smb_vwv2,nwritten);
1850   
1851   if (nwritten < smb_dsize) {
1852     CVAL(outbuf,smb_rcls) = ERRHRD;
1853     SSVAL(outbuf,smb_err,ERRdiskfull);      
1854   }
1855
1856   DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten));
1857
1858   chain_fnum = fnum;
1859
1860   if (lp_syncalways(SNUM(cnum)) || write_through)
1861     sync_file(fnum);
1862
1863   return chain_reply(inbuf,outbuf,length,bufsize);
1864 }
1865
1866
1867 /****************************************************************************
1868   reply to a lseek
1869 ****************************************************************************/
1870 int reply_lseek(char *inbuf,char *outbuf)
1871 {
1872   int cnum,fnum;
1873   uint32 startpos;
1874   int32 res= -1;
1875   int mode,umode;
1876   int outsize = 0;
1877   
1878   cnum = SVAL(inbuf,smb_tid);
1879   fnum = GETFNUM(inbuf,smb_vwv0);
1880
1881   CHECK_FNUM(fnum,cnum);
1882   CHECK_ERROR(fnum);
1883
1884   mode = SVAL(inbuf,smb_vwv1) & 3;
1885   startpos = IVAL(inbuf,smb_vwv2);
1886
1887   switch (mode & 3) 
1888     {
1889     case 0: umode = SEEK_SET; break;
1890     case 1: umode = SEEK_CUR; break;
1891     case 2: umode = SEEK_END; break;
1892     default:
1893       umode = SEEK_SET; break;
1894     }
1895   
1896   res = lseek(Files[fnum].fd,startpos,umode);
1897   Files[fnum].pos = res;
1898   
1899   outsize = set_message(outbuf,2,0,True);
1900   SIVALS(outbuf,smb_vwv0,res);
1901   
1902   DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode));
1903   
1904   return(outsize);
1905 }
1906
1907
1908 /****************************************************************************
1909   reply to a flush
1910 ****************************************************************************/
1911 int reply_flush(char *inbuf,char *outbuf)
1912 {
1913   int cnum, fnum;
1914   int outsize = set_message(outbuf,0,0,True);
1915
1916   cnum = SVAL(inbuf,smb_tid);
1917   fnum = GETFNUM(inbuf,smb_vwv0);
1918
1919   if (fnum != 0xFFFF) {
1920     CHECK_FNUM(fnum,cnum);
1921     CHECK_ERROR(fnum);
1922   }
1923
1924   if (fnum == 0xFFFF)
1925     {
1926       int i;
1927       for (i=0;i<MAX_OPEN_FILES;i++)
1928         if (OPEN_FNUM(i))
1929           sync_file(i);
1930     }
1931   else
1932     sync_file(fnum);
1933
1934   DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
1935   return(outsize);
1936 }
1937
1938
1939 /****************************************************************************
1940   reply to a exit
1941 ****************************************************************************/
1942 int reply_exit(char *inbuf,char *outbuf)
1943 {
1944   int outsize = set_message(outbuf,0,0,True);
1945   DEBUG(3,("%s exit\n",timestring()));
1946   
1947   return(outsize);
1948 }
1949
1950
1951 /****************************************************************************
1952   reply to a close
1953 ****************************************************************************/
1954 int reply_close(char *inbuf,char *outbuf)
1955 {
1956   int fnum,cnum;
1957   int outsize = 0;
1958   time_t mtime;
1959   int32 eclass = 0, err = 0;
1960
1961   outsize = set_message(outbuf,0,0,True);
1962
1963   cnum = SVAL(inbuf,smb_tid);
1964
1965   fnum = GETFNUM(inbuf,smb_vwv0);
1966   CHECK_FNUM(fnum,cnum);
1967
1968   if(HAS_CACHED_ERROR(fnum)) {
1969     eclass = Files[fnum].wbmpx_ptr->wr_errclass;
1970     err = Files[fnum].wbmpx_ptr->wr_error;
1971   }
1972
1973   mtime = make_unix_date3(inbuf+smb_vwv1);
1974
1975   /* try and set the date */
1976   set_filetime(Files[fnum].name,mtime);
1977
1978   close_file(fnum);
1979
1980   /* We have a cached error */
1981   if(eclass || err)
1982     return(ERROR(eclass,err));
1983
1984   DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
1985            timestring(),Files[fnum].fd,fnum,cnum,
1986            Connections[cnum].num_files_open));
1987   
1988   return(outsize);
1989 }
1990
1991
1992 /****************************************************************************
1993   reply to a writeclose (Core+ protocol)
1994 ****************************************************************************/
1995 int reply_writeclose(char *inbuf,char *outbuf)
1996 {
1997   int cnum,numtowrite,fnum;
1998   int nwritten = -1;
1999   int outsize = 0;
2000   int startpos;
2001   char *data;
2002   time_t mtime;
2003   
2004   cnum = SVAL(inbuf,smb_tid);
2005   fnum = GETFNUM(inbuf,smb_vwv0);
2006
2007   CHECK_FNUM(fnum,cnum);
2008   CHECK_WRITE(fnum);
2009   CHECK_ERROR(fnum);
2010
2011   numtowrite = SVAL(inbuf,smb_vwv1);
2012   startpos = IVAL(inbuf,smb_vwv2);
2013   mtime = make_unix_date3(inbuf+smb_vwv4);
2014   data = smb_buf(inbuf) + 1;
2015   
2016   if (is_locked(fnum,cnum,numtowrite,startpos))
2017     return(ERROR(ERRDOS,ERRlock));
2018       
2019   seek_file(fnum,startpos);
2020       
2021   nwritten = write_file(fnum,data,numtowrite);
2022
2023   set_filetime(Files[fnum].name,mtime);
2024   
2025   close_file(fnum);
2026
2027   DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
2028            timestring(),fnum,cnum,numtowrite,nwritten,
2029            Connections[cnum].num_files_open));
2030   
2031   if (nwritten <= 0)
2032     return(UNIXERROR(ERRDOS,ERRnoaccess));
2033   
2034   outsize = set_message(outbuf,1,0,True);
2035   
2036   SSVAL(outbuf,smb_vwv0,nwritten);
2037   return(outsize);
2038 }
2039
2040
2041 /****************************************************************************
2042   reply to a lock
2043 ****************************************************************************/
2044 int reply_lock(char *inbuf,char *outbuf)
2045 {
2046   int fnum,cnum;
2047   int outsize = set_message(outbuf,0,0,True);
2048   uint32 count,offset;
2049   int eclass;
2050   uint32 ecode;
2051
2052   cnum = SVAL(inbuf,smb_tid);
2053   fnum = GETFNUM(inbuf,smb_vwv0);
2054
2055   CHECK_FNUM(fnum,cnum);
2056   CHECK_ERROR(fnum);
2057
2058   count = IVAL(inbuf,smb_vwv1);
2059   offset = IVAL(inbuf,smb_vwv3);
2060
2061   DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
2062
2063   if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
2064     return (ERROR(eclass,ecode));
2065   
2066   return(outsize);
2067 }
2068
2069
2070 /****************************************************************************
2071   reply to a unlock
2072 ****************************************************************************/
2073 int reply_unlock(char *inbuf,char *outbuf)
2074 {
2075   int fnum,cnum;
2076   int outsize = set_message(outbuf,0,0,True);
2077   uint32 count,offset;
2078   int eclass;
2079   uint32 ecode;
2080   
2081   cnum = SVAL(inbuf,smb_tid);
2082   fnum = GETFNUM(inbuf,smb_vwv0);
2083
2084   CHECK_FNUM(fnum,cnum);
2085   CHECK_ERROR(fnum);
2086
2087   count = IVAL(inbuf,smb_vwv1);
2088   offset = IVAL(inbuf,smb_vwv3);
2089
2090   if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
2091     return (ERROR(eclass,ecode));
2092
2093   DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
2094   
2095   return(outsize);
2096 }
2097
2098
2099 /****************************************************************************
2100   reply to a tdis
2101 ****************************************************************************/
2102 int reply_tdis(char *inbuf,char *outbuf)
2103 {
2104   int cnum, uid;
2105   int outsize = set_message(outbuf,0,0,True);
2106   
2107   cnum = SVAL(inbuf,smb_tid);
2108   uid = SVAL(inbuf,smb_uid);
2109
2110   if (!OPEN_CNUM(cnum)) {
2111     DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
2112     return(ERROR(ERRSRV,ERRinvnid));
2113   }
2114
2115   Connections[cnum].used = False;
2116
2117   close_cnum(cnum,uid);
2118   
2119   DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
2120
2121   return outsize;
2122 }
2123
2124
2125
2126 /****************************************************************************
2127   reply to a echo
2128 ****************************************************************************/
2129 int reply_echo(char *inbuf,char *outbuf)
2130 {
2131   int cnum;
2132   int smb_reverb = SVAL(inbuf,smb_vwv0);
2133   int seq_num;
2134   int data_len = smb_buflen(inbuf);
2135   int outsize = set_message(outbuf,1,data_len,True);
2136
2137   cnum = SVAL(inbuf,smb_tid);
2138
2139   if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
2140     {
2141       DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
2142       return(ERROR(ERRSRV,ERRinvnid));
2143     }
2144
2145   /* copy any incoming data back out */
2146   if (data_len > 0)
2147     memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2148
2149   if (smb_reverb > 100)
2150     {
2151       DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2152       smb_reverb = 100;
2153     }
2154
2155   for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++)
2156     {
2157       SSVAL(outbuf,smb_vwv0,seq_num);
2158
2159       smb_setlen(outbuf,outsize - 4);
2160
2161       send_smb(Client,outbuf);
2162     }
2163
2164   DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
2165
2166   return -1;
2167 }
2168
2169
2170 /****************************************************************************
2171   reply to a printopen
2172 ****************************************************************************/
2173 int reply_printopen(char *inbuf,char *outbuf)
2174 {
2175   pstring fname;
2176   pstring fname2;
2177   int cnum;
2178   int fnum = -1;
2179   int outsize = 0;
2180
2181   *fname = *fname2 = 0;
2182
2183   cnum = SVAL(inbuf,smb_tid);
2184
2185   if (!CAN_PRINT(cnum))
2186     return(ERROR(ERRDOS,ERRnoaccess));
2187
2188   {
2189     pstring s;
2190     char *p;
2191     StrnCpy(s,smb_buf(inbuf)+1,sizeof(pstring)-1);
2192     p = s;
2193     while (*p)
2194       {
2195         if (!(isalnum(*p) || strchr("._-",*p)))
2196           *p = 'X';
2197         p++;
2198       }
2199
2200     if (strlen(s) > 10) s[10] = 0;
2201
2202     sprintf(fname,"%s.XXXXXX",s);  
2203   }
2204
2205   fnum = find_free_file();
2206   if (fnum < 0)
2207     return(ERROR(ERRSRV,ERRnofids));
2208
2209   strcpy(fname2,(char *)mktemp(fname));
2210
2211   if (!check_name(fname2,cnum))
2212     return(ERROR(ERRDOS,ERRnoaccess));
2213
2214   open_file(fnum,cnum,fname2,O_WRONLY | O_CREAT | O_TRUNC,
2215             unix_mode(cnum,0));
2216
2217   if (!Files[fnum].open)
2218     return(UNIXERROR(ERRDOS,ERRnoaccess));
2219
2220   /* force it to be a print file */
2221   Files[fnum].print_file = True;
2222   
2223   outsize = set_message(outbuf,1,0,True);
2224   SSVAL(outbuf,smb_vwv0,fnum);
2225   
2226   DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd,fnum,cnum));
2227   
2228   return(outsize);
2229 }
2230
2231
2232 /****************************************************************************
2233   reply to a printclose
2234 ****************************************************************************/
2235 int reply_printclose(char *inbuf,char *outbuf)
2236 {
2237   int fnum,cnum;
2238   int outsize = set_message(outbuf,0,0,True);
2239   
2240   cnum = SVAL(inbuf,smb_tid);
2241   fnum = GETFNUM(inbuf,smb_vwv0);
2242
2243   CHECK_FNUM(fnum,cnum);
2244   CHECK_ERROR(fnum);
2245
2246   if (!CAN_PRINT(cnum))
2247     return(ERROR(ERRDOS,ERRnoaccess));
2248   
2249   close_file(fnum);
2250   
2251   DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd,fnum,cnum));
2252   
2253   return(outsize);
2254 }
2255
2256
2257 /****************************************************************************
2258   reply to a printqueue
2259 ****************************************************************************/
2260 int reply_printqueue(char *inbuf,char *outbuf)
2261 {
2262   int cnum, uid;
2263   int outsize = set_message(outbuf,2,3,True);
2264   int max_count = SVAL(inbuf,smb_vwv0);
2265   int start_index = SVAL(inbuf,smb_vwv1);
2266
2267   cnum = SVAL(inbuf,smb_tid);
2268   uid = SVAL(inbuf,smb_uid);
2269
2270 /* allow checking the queue for anyone */
2271 #if 0
2272   if (!CAN_PRINT(cnum))
2273     return(ERROR(ERRDOS,ERRnoaccess));
2274 #endif
2275
2276   SSVAL(outbuf,smb_vwv0,0);
2277   SSVAL(outbuf,smb_vwv1,0);
2278   CVAL(smb_buf(outbuf),0) = 1;
2279   SSVAL(smb_buf(outbuf),1,0);
2280   
2281   DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n",
2282         timestring(),cnum,start_index,max_count));
2283
2284   if (!OPEN_CNUM(cnum) || !Connections[cnum].printer)
2285     {
2286       int i;
2287       cnum = -1;
2288
2289       for (i=0;i<MAX_CONNECTIONS;i++)
2290         if (CAN_PRINT(i) && Connections[i].printer)
2291           cnum = i;
2292
2293       if (cnum == -1)
2294         for (i=0;i<MAX_CONNECTIONS;i++)
2295           if (OPEN_CNUM(i))
2296             cnum = i;
2297
2298       if (!OPEN_CNUM(cnum))
2299         return(ERROR(ERRSRV,ERRinvnid));
2300
2301       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
2302     }
2303
2304   if (!become_user(cnum,uid))
2305     return(ERROR(ERRSRV,ERRinvnid));
2306
2307   {
2308     print_queue_struct *queue = NULL;
2309     char *p = smb_buf(outbuf) + 3;
2310     int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL);
2311     int num_to_get = ABS(max_count);
2312     int first = (max_count>0?start_index:start_index+max_count+1);
2313     int i;
2314
2315     if (first >= count)
2316       num_to_get = 0;
2317     else
2318       num_to_get = MIN(num_to_get,count-first);
2319     
2320
2321     for (i=first;i<first+num_to_get;i++)
2322       {
2323         put_dos_date2(p,0,queue[i].time);
2324         CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
2325         SSVAL(p,5,queue[i].job);
2326         SIVAL(p,7,queue[i].size);
2327         CVAL(p,11) = 0;
2328         StrnCpy(p+12,queue[i].user,16);
2329         p += 28;
2330       }
2331
2332     if (count > 0)
2333       {
2334         outsize = set_message(outbuf,2,28*count+3,False);         
2335         SSVAL(outbuf,smb_vwv0,count);
2336         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
2337         CVAL(smb_buf(outbuf),0) = 1;
2338         SSVAL(smb_buf(outbuf),1,28*count);
2339       }
2340
2341     if (queue) free(queue);
2342           
2343     DEBUG(3,("%d entries returned in queue\n",count));
2344   }
2345   
2346   return(outsize);
2347 }
2348
2349
2350 /****************************************************************************
2351   reply to a printwrite
2352 ****************************************************************************/
2353 int reply_printwrite(char *inbuf,char *outbuf)
2354 {
2355   int cnum,numtowrite,fnum;
2356   int outsize = set_message(outbuf,0,0,True);
2357   char *data;
2358   
2359   cnum = SVAL(inbuf,smb_tid);
2360
2361   if (!CAN_PRINT(cnum))
2362     return(ERROR(ERRDOS,ERRnoaccess));
2363
2364   fnum = GETFNUM(inbuf,smb_vwv0);
2365
2366   CHECK_FNUM(fnum,cnum);
2367   CHECK_WRITE(fnum);
2368   CHECK_ERROR(fnum);
2369
2370   numtowrite = SVAL(smb_buf(inbuf),1);
2371   data = smb_buf(inbuf) + 3;
2372   
2373   if (write_file(fnum,data,numtowrite) != numtowrite)
2374     return(UNIXERROR(ERRDOS,ERRnoaccess));
2375   
2376   DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
2377   
2378   return(outsize);
2379 }
2380
2381
2382 /****************************************************************************
2383   reply to a mkdir
2384 ****************************************************************************/
2385 int reply_mkdir(char *inbuf,char *outbuf)
2386 {
2387   pstring directory;
2388   int cnum;
2389   int outsize,ret= -1;
2390   
2391   strcpy(directory,smb_buf(inbuf) + 1);
2392   cnum = SVAL(inbuf,smb_tid);
2393   unix_convert(directory,cnum);
2394   
2395   if (check_name(directory,cnum))
2396     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
2397   
2398   if (ret < 0)
2399     return(UNIXERROR(ERRDOS,ERRnoaccess));
2400   
2401   outsize = set_message(outbuf,0,0,True);
2402   
2403   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
2404   
2405   return(outsize);
2406 }
2407
2408
2409 /****************************************************************************
2410   reply to a rmdir
2411 ****************************************************************************/
2412 int reply_rmdir(char *inbuf,char *outbuf)
2413 {
2414   pstring directory;
2415   int cnum;
2416   int outsize = 0;
2417   BOOL ok = False;
2418   
2419   cnum = SVAL(inbuf,smb_tid);
2420   strcpy(directory,smb_buf(inbuf) + 1);
2421   unix_convert(directory,cnum);
2422   
2423   if (check_name(directory,cnum))
2424     {
2425       dptr_closepath(directory,SVAL(inbuf,smb_pid));
2426       ok = (sys_rmdir(directory) == 0);
2427       if (!ok)
2428         DEBUG(3,("couldn't remove directory %s : %s\n",
2429                  directory,strerror(errno)));
2430     }
2431   
2432   if (!ok)
2433     return(UNIXERROR(ERRDOS,ERRbadpath));
2434   
2435   outsize = set_message(outbuf,0,0,True);
2436   
2437   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
2438   
2439   return(outsize);
2440 }
2441
2442
2443 /*******************************************************************
2444 resolve wildcards in a filename rename
2445 ********************************************************************/
2446 static BOOL resolve_wildcards(char *name1,char *name2)
2447 {
2448   fstring root1,root2;
2449   fstring ext1,ext2;
2450   char *p,*p2;
2451
2452   name1 = strrchr(name1,'/');
2453   name2 = strrchr(name2,'/');
2454
2455   if (!name1 || !name2) return(False);
2456   
2457   strcpy(root1,name1);
2458   strcpy(root2,name2);
2459   p = strrchr(root1,'.');
2460   if (p) {
2461     *p = 0;
2462     strcpy(ext1,p+1);
2463   } else {
2464     strcpy(ext1,"");    
2465   }
2466   p = strrchr(root2,'.');
2467   if (p) {
2468     *p = 0;
2469     strcpy(ext2,p+1);
2470   } else {
2471     strcpy(ext2,"");    
2472   }
2473
2474   p = root1;
2475   p2 = root2;
2476   while (*p2) {
2477     if (*p2 == '?') {
2478       *p2 = *p;
2479       p2++;
2480     } else {
2481       p2++;
2482     }
2483     if (*p) p++;
2484   }
2485
2486   p = ext1;
2487   p2 = ext2;
2488   while (*p2) {
2489     if (*p2 == '?') {
2490       *p2 = *p;
2491       p2++;
2492     } else {
2493       p2++;
2494     }
2495     if (*p) p++;
2496   }
2497
2498   strcpy(name2,root2);
2499   if (ext2[0]) {
2500     strcat(name2,".");
2501     strcat(name2,ext2);
2502   }
2503
2504   return(True);
2505 }
2506
2507 /*******************************************************************
2508 check if a user is allowed to rename a file
2509 ********************************************************************/
2510 static BOOL can_rename(char *fname,int cnum)
2511 {
2512   struct stat sbuf;
2513
2514   if (!CAN_WRITE(cnum)) return(False);
2515
2516   if (sys_lstat(fname,&sbuf) != 0) return(False);
2517   if (!check_file_sharing(cnum,fname)) return(False);
2518
2519   return(True);
2520 }
2521
2522 /****************************************************************************
2523   reply to a mv
2524 ****************************************************************************/
2525 int reply_mv(char *inbuf,char *outbuf)
2526 {
2527   int outsize = 0;
2528   pstring name;
2529   int cnum;
2530   pstring directory;
2531   pstring mask,newname;
2532   char *p;
2533   int count=0;
2534   int error = ERRnoaccess;
2535   BOOL has_wild;
2536   BOOL exists=False;
2537
2538   *directory = *mask = 0;
2539
2540   cnum = SVAL(inbuf,smb_tid);
2541   
2542   strcpy(name,smb_buf(inbuf) + 1);
2543   strcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
2544    
2545   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
2546    
2547   unix_convert(name,cnum);
2548   unix_convert(newname,cnum);
2549
2550   p = strrchr(name,'/');
2551   if (!p) {
2552     strcpy(directory,"./");
2553     strcpy(mask,name);
2554   } else {
2555     *p = 0;
2556     strcpy(directory,name);
2557     strcpy(mask,p+1);
2558   }
2559
2560   if (is_mangled(mask))
2561     check_mangled_stack(mask);
2562
2563   has_wild = strchr(mask,'*') || strchr(mask,'?');
2564
2565   if (!has_wild) {
2566     strcat(directory,"/");
2567     strcat(directory,mask);
2568     if (resolve_wildcards(directory,newname) && 
2569         can_rename(directory,cnum) && 
2570         !file_exist(newname,NULL) &&
2571         !sys_rename(directory,newname)) count++;
2572     if (!count) exists = file_exist(directory,NULL);
2573     if (!count && exists && file_exist(newname,NULL)) {
2574       exists = True;
2575       error = 183;
2576     }
2577   } else {
2578     void *dirptr = NULL;
2579     char *dname;
2580     pstring destname;
2581
2582     if (check_name(directory,cnum))
2583       dirptr = OpenDir(directory);
2584
2585     if (dirptr)
2586       {
2587         error = ERRbadfile;
2588
2589         if (strequal(mask,"????????.???"))
2590           strcpy(mask,"*");
2591
2592         while ((dname = ReadDirName(dirptr)))
2593           {
2594             pstring fname;
2595             strcpy(fname,dname);
2596             
2597             if(!mask_match(fname, mask, case_sensitive, False)) continue;
2598
2599             error = ERRnoaccess;
2600             sprintf(fname,"%s/%s",directory,dname);
2601             if (!can_rename(fname,cnum)) continue;
2602             strcpy(destname,newname);
2603
2604             if (!resolve_wildcards(fname,destname)) continue;
2605
2606             if (file_exist(destname,NULL)) {
2607               error = 183;
2608               continue;
2609             }
2610             if (!sys_rename(fname,destname)) count++;
2611             DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
2612           }
2613         CloseDir(dirptr);
2614       }
2615   }
2616   
2617   if (count == 0) {
2618     if (exists)
2619       return(ERROR(ERRDOS,error));
2620     else
2621       return(UNIXERROR(ERRDOS,error));
2622   }
2623   
2624   outsize = set_message(outbuf,0,0,True);
2625   
2626   return(outsize);
2627 }
2628
2629 /*******************************************************************
2630   copy a file as part of a reply_copy
2631   ******************************************************************/
2632 static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
2633                       int count,BOOL target_is_directory)
2634 {
2635   int Access,action;
2636   struct stat st;
2637   int ret=0;
2638   int fnum1,fnum2;
2639   pstring dest;
2640   
2641   strcpy(dest,dest1);
2642   if (target_is_directory) {
2643     char *p = strrchr(src,'/');
2644     if (p) 
2645       p++;
2646     else
2647       p = src;
2648     strcat(dest,"/");
2649     strcat(dest,p);
2650   }
2651
2652   if (!file_exist(src,&st)) return(False);
2653
2654   fnum1 = find_free_file();
2655   if (fnum1<0) return(False);
2656   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
2657                    1,0,&Access,&action);
2658
2659   if (!Files[fnum1].open) return(False);
2660
2661   if (!target_is_directory && count)
2662     ofun = 1;
2663
2664   fnum2 = find_free_file();
2665   if (fnum2<0) {
2666     close_file(fnum1);
2667     return(False);
2668   }
2669   open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
2670                    ofun,st.st_mode,&Access,&action);
2671
2672   if (!Files[fnum2].open) {
2673     close_file(fnum1);
2674     return(False);
2675   }
2676
2677   if ((ofun&3) == 1) {
2678     lseek(Files[fnum2].fd,0,SEEK_END);
2679   }
2680   
2681   if (st.st_size)
2682     ret = transfer_file(Files[fnum1].fd,Files[fnum2].fd,st.st_size,NULL,0,0);
2683
2684   close_file(fnum1);
2685   close_file(fnum2);
2686
2687   return(ret == st.st_size);
2688 }
2689
2690
2691
2692 /****************************************************************************
2693   reply to a file copy.
2694   ****************************************************************************/
2695 int reply_copy(char *inbuf,char *outbuf)
2696 {
2697   int outsize = 0;
2698   pstring name;
2699   int cnum;
2700   pstring directory;
2701   pstring mask,newname;
2702   char *p;
2703   int count=0;
2704   int error = ERRnoaccess;
2705   BOOL has_wild;
2706   BOOL exists=False;
2707   int tid2 = SVAL(inbuf,smb_vwv0);
2708   int ofun = SVAL(inbuf,smb_vwv1);
2709   int flags = SVAL(inbuf,smb_vwv2);
2710   BOOL target_is_directory=False;
2711
2712   *directory = *mask = 0;
2713
2714   cnum = SVAL(inbuf,smb_tid);
2715   
2716   strcpy(name,smb_buf(inbuf));
2717   strcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
2718    
2719   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
2720    
2721   if (tid2 != cnum) {
2722     /* can't currently handle inter share copies XXXX */
2723     DEBUG(3,("Rejecting inter-share copy\n"));
2724     return(ERROR(ERRSRV,ERRinvdevice));
2725   }
2726
2727   unix_convert(name,cnum);
2728   unix_convert(newname,cnum);
2729
2730   target_is_directory = directory_exist(newname,NULL);
2731
2732   if ((flags&1) && target_is_directory) {
2733     return(ERROR(ERRDOS,ERRbadfile));
2734   }
2735
2736   if ((flags&2) && !target_is_directory) {
2737     return(ERROR(ERRDOS,ERRbadpath));
2738   }
2739
2740   if ((flags&(1<<5)) && directory_exist(name,NULL)) {
2741     /* wants a tree copy! XXXX */
2742     DEBUG(3,("Rejecting tree copy\n"));
2743     return(ERROR(ERRSRV,ERRerror));    
2744   }
2745
2746   p = strrchr(name,'/');
2747   if (!p) {
2748     strcpy(directory,"./");
2749     strcpy(mask,name);
2750   } else {
2751     *p = 0;
2752     strcpy(directory,name);
2753     strcpy(mask,p+1);
2754   }
2755
2756   if (is_mangled(mask))
2757     check_mangled_stack(mask);
2758
2759   has_wild = strchr(mask,'*') || strchr(mask,'?');
2760
2761   if (!has_wild) {
2762     strcat(directory,"/");
2763     strcat(directory,mask);
2764     if (resolve_wildcards(directory,newname) && 
2765         copy_file(directory,newname,cnum,ofun,
2766                   count,target_is_directory)) count++;
2767     if (!count) exists = file_exist(directory,NULL);
2768   } else {
2769     void *dirptr = NULL;
2770     char *dname;
2771     pstring destname;
2772
2773     if (check_name(directory,cnum))
2774       dirptr = OpenDir(directory);
2775
2776     if (dirptr)
2777       {
2778         error = ERRbadfile;
2779
2780         if (strequal(mask,"????????.???"))
2781           strcpy(mask,"*");
2782
2783         while ((dname = ReadDirName(dirptr)))
2784           {
2785             pstring fname;
2786             strcpy(fname,dname);
2787             
2788             if(!mask_match(fname, mask, case_sensitive, False)) continue;
2789
2790             error = ERRnoaccess;
2791             sprintf(fname,"%s/%s",directory,dname);
2792             strcpy(destname,newname);
2793             if (resolve_wildcards(fname,destname) && 
2794                 copy_file(directory,newname,cnum,ofun,
2795                           count,target_is_directory)) count++;
2796             DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
2797           }
2798         CloseDir(dirptr);
2799       }
2800   }
2801   
2802   if (count == 0) {
2803     if (exists)
2804       return(ERROR(ERRDOS,error));
2805     else
2806       return(UNIXERROR(ERRDOS,error));
2807   }
2808   
2809   outsize = set_message(outbuf,1,0,True);
2810   SSVAL(outbuf,smb_vwv0,count);
2811
2812   return(outsize);
2813 }
2814
2815
2816
2817 /****************************************************************************
2818   reply to a setdir
2819 ****************************************************************************/
2820 int reply_setdir(char *inbuf,char *outbuf)
2821 {
2822   int cnum,snum;
2823   int outsize = 0;
2824   BOOL ok = False;
2825   pstring newdir;
2826   
2827   cnum = SVAL(inbuf,smb_tid);
2828   
2829   snum = Connections[cnum].service;
2830   if (!CAN_SETDIR(snum))
2831     return(ERROR(ERRDOS,ERRnoaccess));
2832   
2833   strcpy(newdir,smb_buf(inbuf) + 1);
2834   strlower(newdir);
2835   
2836   if (strlen(newdir) == 0)
2837     ok = True;
2838   else
2839     {
2840       ok = directory_exist(newdir,NULL);
2841       if (ok)
2842         string_set(&Connections[cnum].connectpath,newdir);
2843     }
2844   
2845   if (!ok)
2846     return(ERROR(ERRDOS,ERRbadpath));
2847   
2848   outsize = set_message(outbuf,0,0,True);
2849   CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
2850   
2851   DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum));
2852   
2853   return(outsize);
2854 }
2855
2856
2857 /****************************************************************************
2858   reply to a lockingX request
2859 ****************************************************************************/
2860 int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
2861 {
2862   int fnum = GETFNUM(inbuf,smb_vwv2);
2863   uint16 locktype = SVAL(inbuf,smb_vwv3);
2864   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
2865   uint16 num_locks = SVAL(inbuf,smb_vwv7);
2866   uint32 count, offset;
2867
2868   int cnum;
2869   int i;
2870   char *data;
2871   uint32 ecode=0, dummy2;
2872   int eclass=0, dummy1;
2873
2874   cnum = SVAL(inbuf,smb_tid);
2875
2876   CHECK_FNUM(fnum,cnum);
2877   CHECK_ERROR(fnum);
2878
2879   data = smb_buf(inbuf);
2880   /* Data now points at the beginning of the list
2881      of smb_unlkrng structs */
2882   for(i = 0; i < (int)num_ulocks; i++) {
2883     count = IVAL(data,SMB_LKLEN_OFFSET(i));
2884     offset = IVAL(data,SMB_LKOFF_OFFSET(i));
2885     if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode))
2886       return ERROR(eclass,ecode);
2887   }
2888
2889   /* Now do any requested locks */
2890   data += 10*num_ulocks;
2891   /* Data now points at the beginning of the list
2892      of smb_lkrng structs */
2893   for(i = 0; i < (int)num_locks; i++) {
2894     count = IVAL(data,SMB_LKLEN_OFFSET(i)); 
2895     offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
2896     if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
2897       break;
2898   }
2899
2900   /* If any of the above locks failed, then we must unlock
2901      all of the previous locks (X/Open spec). */
2902   if(i != num_locks && num_locks != 0) {
2903     for(; i >= 0; i--) {
2904       count = IVAL(data,SMB_LKLEN_OFFSET(i));  
2905       offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
2906       do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2);
2907     }
2908     return ERROR(eclass,ecode);
2909   }
2910
2911   set_message(outbuf,2,0,True);
2912   
2913   DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
2914         timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
2915
2916   chain_fnum = fnum;
2917
2918   return chain_reply(inbuf,outbuf,length,bufsize);
2919 }
2920
2921
2922 /****************************************************************************
2923   reply to a SMBreadbmpx (read block multiplex) request
2924 ****************************************************************************/
2925 int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
2926 {
2927   int cnum,fnum;
2928   int nread = -1;
2929   int total_read;
2930   char *data;
2931   int32 startpos;
2932   int outsize, mincount, maxcount;
2933   int max_per_packet;
2934   int tcount;
2935   int pad;
2936
2937   /* this function doesn't seem to work - disable by default */
2938   if (!lp_readbmpx())
2939     return(ERROR(ERRSRV,ERRuseSTD));
2940
2941   outsize = set_message(outbuf,8,0,True);
2942
2943   cnum = SVAL(inbuf,smb_tid);
2944   fnum = GETFNUM(inbuf,smb_vwv0);
2945
2946   CHECK_FNUM(fnum,cnum);
2947   CHECK_READ(fnum);
2948   CHECK_ERROR(fnum);
2949
2950   startpos = IVAL(inbuf,smb_vwv1);
2951   maxcount = SVAL(inbuf,smb_vwv3);
2952   mincount = SVAL(inbuf,smb_vwv4);
2953
2954   data = smb_buf(outbuf);
2955   pad = ((int)data)%4;
2956   if (pad) pad = 4 - pad;
2957   data += pad;
2958
2959   max_per_packet = bufsize-(outsize+pad);
2960   tcount = maxcount;
2961   total_read = 0;
2962
2963   if (is_locked(fnum,cnum,maxcount,startpos))
2964     return(ERROR(ERRDOS,ERRlock));
2965         
2966   do
2967     {
2968       int N = MIN(max_per_packet,tcount-total_read);
2969   
2970       nread = read_file(fnum,data,startpos,N);
2971
2972       if (nread <= 0) nread = 0;
2973
2974       if (nread < N)
2975         tcount = total_read + nread;
2976
2977       set_message(outbuf,8,nread,False);
2978       SIVAL(outbuf,smb_vwv0,startpos);
2979       SSVAL(outbuf,smb_vwv2,tcount);
2980       SSVAL(outbuf,smb_vwv6,nread);
2981       SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
2982
2983       send_smb(Client,outbuf);
2984
2985       total_read += nread;
2986       startpos += nread;
2987     }
2988   while (total_read < tcount);
2989
2990   return(-1);
2991 }
2992
2993
2994 /****************************************************************************
2995   reply to a SMBwritebmpx (write block multiplex primary) request
2996 ****************************************************************************/
2997 int reply_writebmpx(char *inbuf,char *outbuf)
2998 {
2999   int cnum,numtowrite,fnum;
3000   int nwritten = -1;
3001   int outsize = 0;
3002   int32 startpos;
3003   int tcount, write_through, smb_doff;
3004   char *data;
3005   
3006   cnum = SVAL(inbuf,smb_tid);
3007   fnum = GETFNUM(inbuf,smb_vwv0);
3008
3009   CHECK_FNUM(fnum,cnum);
3010   CHECK_WRITE(fnum);
3011   CHECK_ERROR(fnum);
3012
3013   tcount = SVAL(inbuf,smb_vwv1);
3014   startpos = IVAL(inbuf,smb_vwv3);
3015   write_through = BITSETW(inbuf+smb_vwv7,0);
3016   numtowrite = SVAL(inbuf,smb_vwv10);
3017   smb_doff = SVAL(inbuf,smb_vwv11);
3018
3019   data = smb_base(inbuf) + smb_doff;
3020
3021   /* If this fails we need to send an SMBwriteC response,
3022      not an SMBwritebmpx - set this up now so we don't forget */
3023   CVAL(outbuf,smb_com) = SMBwritec;
3024
3025   if (is_locked(fnum,cnum,tcount,startpos))
3026     return(ERROR(ERRDOS,ERRlock));
3027
3028   seek_file(fnum,startpos);
3029   nwritten = write_file(fnum,data,numtowrite);
3030
3031   if(lp_syncalways(SNUM(cnum)) || write_through)
3032     sync_file(fnum);
3033   
3034   if(nwritten < numtowrite)
3035     return(UNIXERROR(ERRHRD,ERRdiskfull));
3036
3037   /* If the maximum to be written to this file
3038      is greater than what we just wrote then set
3039      up a secondary struct to be attached to this
3040      fd, we will use this to cache error messages etc. */
3041   if(tcount > nwritten) 
3042     {
3043       write_bmpx_struct *wbms;
3044       if(Files[fnum].wbmpx_ptr != NULL)
3045         wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */
3046       else
3047         wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
3048       if(!wbms)
3049         {
3050           DEBUG(0,("Out of memory in reply_readmpx\n"));
3051           return(ERROR(ERRSRV,ERRnoresource));
3052         }
3053       wbms->wr_mode = write_through;
3054       wbms->wr_discard = False; /* No errors yet */
3055       wbms->wr_total_written = nwritten;
3056       wbms->wr_errclass = 0;
3057       wbms->wr_error = 0;
3058       Files[fnum].wbmpx_ptr = wbms;
3059     }
3060
3061   /* We are returning successfully, set the message type back to
3062      SMBwritebmpx */
3063   CVAL(outbuf,smb_com) = SMBwriteBmpx;
3064   
3065   outsize = set_message(outbuf,1,0,True);
3066   
3067   SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
3068   
3069   DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n",
3070         timestring(),fnum,cnum,numtowrite,nwritten));
3071   
3072   if (write_through && tcount==nwritten) {
3073     /* we need to send both a primary and a secondary response */
3074     smb_setlen(outbuf,outsize - 4);
3075     send_smb(Client,outbuf);
3076
3077     /* now the secondary */
3078     outsize = set_message(outbuf,1,0,True);
3079     CVAL(outbuf,smb_com) = SMBwritec;
3080     SSVAL(outbuf,smb_vwv0,nwritten);
3081   }
3082
3083   return(outsize);
3084 }
3085
3086
3087 /****************************************************************************
3088   reply to a SMBwritebs (write block multiplex secondary) request
3089 ****************************************************************************/
3090 int reply_writebs(char *inbuf,char *outbuf)
3091 {
3092   int cnum,numtowrite,fnum;
3093   int nwritten = -1;
3094   int outsize = 0;
3095   int32 startpos;
3096   int tcount, write_through, smb_doff;
3097   char *data;
3098   write_bmpx_struct *wbms;
3099   BOOL send_response = False;
3100   
3101   cnum = SVAL(inbuf,smb_tid);
3102   fnum = GETFNUM(inbuf,smb_vwv0);
3103   CHECK_FNUM(fnum,cnum);
3104   CHECK_WRITE(fnum);
3105
3106   tcount = SVAL(inbuf,smb_vwv1);
3107   startpos = IVAL(inbuf,smb_vwv2);
3108   numtowrite = SVAL(inbuf,smb_vwv6);
3109   smb_doff = SVAL(inbuf,smb_vwv7);
3110
3111   data = smb_base(inbuf) + smb_doff;
3112
3113   /* We need to send an SMBwriteC response, not an SMBwritebs */
3114   CVAL(outbuf,smb_com) = SMBwritec;
3115
3116   /* This fd should have an auxiliary struct attached,
3117      check that it does */
3118   wbms = Files[fnum].wbmpx_ptr;
3119   if(!wbms) return(-1);
3120
3121   /* If write through is set we can return errors, else we must
3122      cache them */
3123   write_through = wbms->wr_mode;
3124
3125   /* Check for an earlier error */
3126   if(wbms->wr_discard)
3127     return -1; /* Just discard the packet */
3128
3129   seek_file(fnum,startpos);
3130   nwritten = write_file(fnum,data,numtowrite);
3131
3132   if(lp_syncalways(SNUM(cnum)) || write_through)
3133     sync_file(fnum);
3134   
3135   if (nwritten < numtowrite)
3136     {
3137       if(write_through) {
3138         /* We are returning an error - we can delete the aux struct */
3139         if (wbms) free((char *)wbms);
3140         Files[fnum].wbmpx_ptr = NULL;
3141         return(ERROR(ERRHRD,ERRdiskfull));
3142       }
3143       return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
3144     }
3145
3146   /* Increment the total written, if this matches tcount
3147      we can discard the auxiliary struct (hurrah !) and return a writeC */
3148   wbms->wr_total_written += nwritten;
3149   if(wbms->wr_total_written >= tcount)
3150     {
3151       if (write_through) {
3152         outsize = set_message(outbuf,1,0,True);
3153         SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
3154         send_response = True;
3155       }
3156
3157       free((char *)wbms);
3158       Files[fnum].wbmpx_ptr = NULL;
3159     }
3160
3161   if(send_response)
3162     return(outsize);
3163
3164   return(-1);
3165 }
3166
3167
3168 /****************************************************************************
3169   reply to a SMBsetattrE
3170 ****************************************************************************/
3171 int reply_setattrE(char *inbuf,char *outbuf)
3172 {
3173   int cnum,fnum;
3174   struct utimbuf unix_times;
3175   int outsize = 0;
3176
3177   outsize = set_message(outbuf,0,0,True);
3178
3179   cnum = SVAL(inbuf,smb_tid);
3180   fnum = GETFNUM(inbuf,smb_vwv0);
3181
3182   CHECK_FNUM(fnum,cnum);
3183   CHECK_ERROR(fnum);
3184
3185   /* Convert the DOS times into unix times. Ignore create
3186      time as UNIX can't set this.
3187      */
3188   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
3189   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
3190   
3191   /* Set the date on this file */
3192   if(sys_utime(Files[fnum].name, &unix_times))
3193     return(ERROR(ERRDOS,ERRnoaccess));
3194   
3195   DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
3196
3197   return(outsize);
3198 }
3199
3200
3201 /****************************************************************************
3202   reply to a SMBgetattrE
3203 ****************************************************************************/
3204 int reply_getattrE(char *inbuf,char *outbuf)
3205 {
3206   int cnum,fnum;
3207   struct stat sbuf;
3208   int outsize = 0;
3209   int mode;
3210
3211   outsize = set_message(outbuf,11,0,True);
3212
3213   cnum = SVAL(inbuf,smb_tid);
3214   fnum = GETFNUM(inbuf,smb_vwv0);
3215
3216   CHECK_FNUM(fnum,cnum);
3217   CHECK_ERROR(fnum);
3218
3219   /* Do an fstat on this file */
3220   if(fstat(Files[fnum].fd, &sbuf))
3221     return(UNIXERROR(ERRDOS,ERRnoaccess));
3222   
3223   mode = dos_mode(cnum,Files[fnum].name,&sbuf);
3224   
3225   /* Convert the times into dos times. Set create
3226      date to be last modify date as UNIX doesn't save
3227      this */
3228   put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime);
3229   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
3230   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
3231   if (mode & aDIR)
3232     {
3233       SIVAL(outbuf,smb_vwv6,0);
3234       SIVAL(outbuf,smb_vwv8,0);
3235     }
3236   else
3237     {
3238       SIVAL(outbuf,smb_vwv6,sbuf.st_size);
3239       SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
3240     }
3241   SSVAL(outbuf,smb_vwv10, mode);
3242   
3243   DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
3244   
3245   return(outsize);
3246 }
3247
3248
3249
3250
3251