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