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