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