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