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