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