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