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