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