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