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