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