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