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