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