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