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