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