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