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